Skip to content

Commit

Permalink
Implement Axis3d.intersectionWithRectangle
Browse files Browse the repository at this point in the history
  • Loading branch information
w0rm committed May 15, 2021
1 parent dc160e8 commit 470a31d
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 5 deletions.
45 changes: 42 additions & 3 deletions src/Axis3d.elm
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ module Axis3d exposing
, x, y, z
, through, withDirection, throughPoints, on
, originPoint, direction
, intersectionWithPlane, intersectionWithSphere
, intersectionWithPlane, intersectionWithRectangle, intersectionWithSphere
, reverse, moveTo, rotateAround, translateBy, translateIn, mirrorAcross, projectOnto
, at, at_
, relativeTo, placeIn, projectInto
Expand Down Expand Up @@ -46,7 +46,7 @@ by an origin point and direction. Axes have several uses, such as:
# Intersection
@docs intersectionWithPlane, intersectionWithSphere
@docs intersectionWithPlane, intersectionWithRectangle, intersectionWithSphere
# Transformations
Expand All @@ -68,9 +68,10 @@ by an origin point and direction. Axes have several uses, such as:
import Angle exposing (Angle)
import Axis2d exposing (Axis2d)
import Direction3d exposing (Direction3d)
import Geometry.Types as Types exposing (Frame3d, Plane3d, SketchPlane3d, Sphere3d, Triangle3d)
import Geometry.Types as Types exposing (Frame3d, LineSegment3d, Plane3d, Rectangle3d, SketchPlane3d, Sphere3d, Triangle3d)
import Point3d exposing (Point3d)
import Quantity exposing (Quantity(..), Rate)
import Unsafe.Direction3d as Direction3d
import Vector3d exposing (Vector3d)


Expand Down Expand Up @@ -308,6 +309,44 @@ intersectionWithTriangle triangle axis =
|> Just


{-| Try to find the unique intersection point of an axis with a rectangle. If
the axis does not intersect the rectangle, or if it is coplanar with it (lying
perfectly in the plane of the rectangle), returns `Nothing`.
-}
intersectionWithRectangle : Rectangle3d units coordinates -> Axis3d units coordinates -> Maybe (Point3d units coordinates)
intersectionWithRectangle (Types.Rectangle3d { axes, dimensions }) axis =
let
(Types.SketchPlane3d sketchPlane) =
axes

plane =
Types.Plane3d
{ normalDirection =
Direction3d.unsafeCrossProduct
sketchPlane.xDirection
sketchPlane.yDirection
, originPoint = sketchPlane.originPoint
}
in
case intersectionWithPlane plane axis of
(Just point) as result ->
let
( Quantity width, Quantity height ) =
dimensions

(Types.Point2d p) =
Point3d.projectInto (Types.SketchPlane3d sketchPlane) point
in
if abs p.x / width <= 0.5 && abs p.y / height <= 0.5 then
result

else
Nothing

Nothing ->
Nothing


{-| Attempt to find the intersection of an axis with a sphere. The two points
will be in order of signed distance along the axis. Returns `Nothing` if there
is no intersection.
Expand Down
12 changes: 10 additions & 2 deletions tests/Geometry/Fuzz.elm
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module Geometry.Fuzz exposing
, length, positiveLength, angle, quantityRange
, point2d, point3d, vector2d, vector3d, direction2d, direction3d, boundingBox2d, boundingBox3d
, axis2d, axis3d, frame2d, frame3d, plane3d, sketchPlane3d
, lineSegment2d, lineSegment3d, triangle2d, triangle3d, rectangle2d, block3d, polyline2d, polyline3d, polygon2d
, lineSegment2d, lineSegment3d, triangle2d, triangle3d, rectangle2d, rectangle3d, block3d, polyline2d, polyline3d, polygon2d
, arc2d, arc3d, circle2d, circle3d, cubicSpline2d, cubicSpline3d, cylinder3d, cone3d, ellipse2d, ellipticalArc2d, ellipticalArc3d, ellipsoid3d, quadraticSpline2d, quadraticSpline3d, rationalCubicSpline2d, rationalCubicSpline3d, rationalQuadraticSpline2d, rationalQuadraticSpline3d, sphere3d
)

Expand Down Expand Up @@ -47,7 +47,7 @@ running into any naming conflicts.
# Simple geometry
@docs lineSegment2d, lineSegment3d, triangle2d, triangle3d, rectangle2d, block3d, polyline2d, polyline3d, polygon2d
@docs lineSegment2d, lineSegment3d, triangle2d, triangle3d, rectangle2d, rectangle3d, block3d, polyline2d, polyline3d, polygon2d
# Complex geometry
Expand Down Expand Up @@ -97,6 +97,7 @@ import RationalCubicSpline3d exposing (RationalCubicSpline3d)
import RationalQuadraticSpline2d exposing (RationalQuadraticSpline2d)
import RationalQuadraticSpline3d exposing (RationalQuadraticSpline3d)
import Rectangle2d exposing (Rectangle2d)
import Rectangle3d exposing (Rectangle3d)
import Shrink
import SketchPlane3d exposing (SketchPlane3d)
import Sphere3d exposing (Sphere3d)
Expand Down Expand Up @@ -571,6 +572,13 @@ rectangle2d =
Fuzz.map3 rectangle frame2d positiveLength positiveLength


{-| Generate a random `Rectangle3d`.
-}
rectangle3d : Fuzzer (Rectangle3d Meters coordinates)
rectangle3d =
Fuzz.map2 Rectangle3d.on sketchPlane3d rectangle2d


{-| Generate a random `Block3d`.
-}
block3d : Fuzzer (Block3d Meters coordinates)
Expand Down
60 changes: 60 additions & 0 deletions tests/Tests/Axis3d.elm
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module Tests.Axis3d exposing
( directionExample
, intersectionWithPlane
, intersectionWithRectangle
, intersectionWithSphere
, intersectionWithTriangle
, onExamples
Expand All @@ -26,6 +27,8 @@ import Plane3d
import Point2d
import Point3d
import Quantity
import Rectangle2d exposing (Rectangle2d)
import Rectangle3d
import SketchPlane3d
import Sphere3d
import Test exposing (Test)
Expand Down Expand Up @@ -205,6 +208,63 @@ intersectionWithTriangle =
)


intersectionWithRectangle : Test
intersectionWithRectangle =
Test.fuzz3
Fuzz.rectangle3d
Fuzz.direction3d
(ElmFuzz.tuple3
( ElmFuzz.floatRange -0.5 1.5
, ElmFuzz.floatRange -0.5 1.5
, ElmFuzz.floatRange -10 10
)
)
"intersectionWithRectangle works properly"
(\rectangle axisDirection parameters ->
let
s =
Rectangle3d.axes rectangle
|> SketchPlane3d.normalDirection
|> Direction3d.componentIn axisDirection
in
if abs s < 1.0e-3 then
Expect.pass

else
let
( u, v, t ) =
parameters

planeIntersection =
Rectangle3d.interpolate rectangle u v

direction =
Vector3d.withLength (Length.meters 1) axisDirection

axisOrigin =
planeIntersection
|> Point3d.translateBy (Vector3d.scaleBy -t direction)

axis =
Axis3d.through axisOrigin axisDirection
in
case Axis3d.intersectionWithRectangle rectangle axis of
Nothing ->
if u < 0 || v < 0 || u > 1 || v > 1 then
Expect.pass

else
Expect.fail "Expected an intersection"

Just point ->
if u < 0 || v < 0 || u > 1 || v > 1 then
Expect.fail "Expected no intersection"

else
Expect.point3d planeIntersection point
)


intersectionWithSphere : Test
intersectionWithSphere =
Test.describe "intersectionWithSphere"
Expand Down

0 comments on commit 470a31d

Please sign in to comment.