Copyright | (C) Frank Staals |
---|---|
License | see the LICENSE file |
Maintainer | Frank Staals |
Safe Haskell | None |
Language | Haskell2010 |
Line segment data type and some basic functions on line segments
Synopsis
- data LineSegment d p r where
- pattern LineSegment :: EndPoint (Point d r :+ p) -> EndPoint (Point d r :+ p) -> LineSegment d p r
- pattern LineSegment' :: (Point d r :+ p) -> (Point d r :+ p) -> LineSegment d p r
- pattern ClosedLineSegment :: (Point d r :+ p) -> (Point d r :+ p) -> LineSegment d p r
- pattern OpenLineSegment :: (Point d r :+ p) -> (Point d r :+ p) -> LineSegment d p r
- endPoints :: Traversal (LineSegment d p r) (LineSegment d' q s) (Point d r :+ p) (Point d' s :+ q)
- _SubLine :: (Num r, Arity d) => Iso' (LineSegment d p r) (SubLine d p r r)
- shiftRight :: Num r => r -> Range r -> Range r
- shiftLeft :: Num r => r -> Range r -> Range r
- isValidRange :: Ord a => Range a -> Bool
- covers :: Ord a => Range a -> Range a -> Bool
- clipUpper :: Ord a => EndPoint a -> Range a -> Maybe (Range a)
- clipLower :: Ord a => EndPoint a -> Range a -> Maybe (Range a)
- clampTo :: Ord r => Range r -> r -> r
- inRange :: Ord a => a -> Range a -> Bool
- prettyShow :: Show a => Range a -> String
- upper :: Lens' (Range a) (EndPoint a)
- lower :: Lens' (Range a) (EndPoint a)
- isClosed :: EndPoint a -> Bool
- isOpen :: EndPoint a -> Bool
- unEndPoint :: Lens (EndPoint a) (EndPoint b) a b
- data EndPoint a
- data Range a where
- class HasEnd t where
- class HasStart t where
- type StartCore t
- type StartExtra t
- start :: Lens' t (StartCore t :+ StartExtra t)
- data Interval a r where
- toRange :: Interval a r -> Range (r :+ a)
- _Range :: Iso' (Interval a r) (Range (r :+ a))
- fromRange :: Range (r :+ a) -> Interval a r
- intersectsInterval :: Ord r => r -> Interval a r -> Bool
- inInterval :: Ord r => r -> Interval a r -> PointLocationResult
- shiftLeft' :: Num r => r -> Interval a r -> Interval a r
- asProperInterval :: Ord r => Interval p r -> Interval p r
- flipInterval :: Interval a r -> Interval a r
- toLineSegment :: (Monoid p, Num r, Arity d) => Line d r -> LineSegment d p r
- onSegment :: (Ord r, Fractional r, Arity d) => Point d r -> LineSegment d p r -> Bool
- onSegment2 :: (Ord r, Num r) => Point 2 r -> LineSegment 2 p r -> Bool
- orderedEndPoints :: Ord r => LineSegment 2 p r -> (Point 2 r :+ p, Point 2 r :+ p)
- segmentLength :: (Arity d, Floating r) => LineSegment d p r -> r
- sqSegmentLength :: (Arity d, Num r) => LineSegment d p r -> r
- sqDistanceToSeg :: (Arity d, Fractional r, Ord r) => Point d r -> LineSegment d p r -> r
- sqDistanceToSegArg :: (Arity d, Fractional r, Ord r) => Point d r -> LineSegment d p r -> (r, Point d r)
- flipSegment :: LineSegment d p r -> LineSegment d p r
- interpolate :: (Fractional r, Arity d) => r -> LineSegment d p r -> Point d r
- validSegment :: (Eq r, Arity d) => EndPoint (Point d r :+ p) -> EndPoint (Point d r :+ p) -> Maybe (LineSegment d p r)
- sampleLineSegment :: (Arity d, RandomGen g, Random r) => Rand g (LineSegment d () r)
- ordAtX :: (Fractional r, Ord r) => r -> LineSegment 2 p r -> LineSegment 2 p r -> Ordering
- ordAtY :: (Fractional r, Ord r) => r -> LineSegment 2 p r -> LineSegment 2 p r -> Ordering
- xCoordAt :: (Fractional r, Ord r) => r -> LineSegment 2 p r -> r
- yCoordAt :: (Fractional r, Ord r) => r -> LineSegment 2 p r -> r
Documentation
data LineSegment d p r where Source #
Line segments. LineSegments have a start and end point, both of which may contain additional data of type p. We can think of a Line-Segment being defined as
>>>
data LineSegment d p r = LineSegment (EndPoint (Point d r :+ p)) (EndPoint (Point d r :+ p))
it is assumed that the two endpoints of the line segment are disjoint. This is not checked.
pattern LineSegment :: EndPoint (Point d r :+ p) -> EndPoint (Point d r :+ p) -> LineSegment d p r | |
pattern LineSegment' :: (Point d r :+ p) -> (Point d r :+ p) -> LineSegment d p r | Gets the start and end point, but forgetting if they are open or closed. |
pattern ClosedLineSegment :: (Point d r :+ p) -> (Point d r :+ p) -> LineSegment d p r | |
pattern OpenLineSegment :: (Point d r :+ p) -> (Point d r :+ p) -> LineSegment d p r |
Instances
endPoints :: Traversal (LineSegment d p r) (LineSegment d' q s) (Point d r :+ p) (Point d' s :+ q) Source #
Traversal to access the endpoints. Note that this traversal allows you to change more or less everything, even the dimension and the numeric type used, but it preservers if the segment is open or closed.
shiftRight :: Num r => r -> Range r -> Range r #
Shifts the range to the right
>>>
prettyShow $ shiftRight 10 (ClosedRange 10 20)
"[20,30]">>>
prettyShow $ shiftRight 10 (OpenRange 15 25)
"(25,35)"
shiftLeft :: Num r => r -> Range r -> Range r #
Shift a range x units to the left
>>>
prettyShow $ shiftLeft 10 (ClosedRange 10 20)
"[0,10]">>>
prettyShow $ shiftLeft 10 (OpenRange 15 25)
"(5,15)"
isValidRange :: Ord a => Range a -> Bool #
Check if the range is valid and nonEmpty, i.e. if the lower endpoint is indeed smaller than the right endpoint. Note that we treat empty open-ranges as invalid as well.
>>>
isValidRange $ Range (Open 4) (Closed 4)
False>>>
isValidRange $ Range (Open 5) (Closed 4)
False>>>
isValidRange $ Range (Open 4) (Closed 5)
True>>>
isValidRange $ Range (Closed 5) (Closed 40)
True
covers :: Ord a => Range a -> Range a -> Bool #
Wether or not the first range completely covers the second one
clipUpper :: Ord a => EndPoint a -> Range a -> Maybe (Range a) #
Clip the interval from above. I.e. intersect with (-infty, u}, where } is either open, ), or closed, ],
clipLower :: Ord a => EndPoint a -> Range a -> Maybe (Range a) #
Clip the interval from below. I.e. intersect with the interval {l,infty), where { is either open, (, orr closed, [.
clampTo :: Ord r => Range r -> r -> r #
Clamps a value to a range. I.e. if the value lies outside the range we report the closest value "in the range". Note that if an endpoint of the range is open we report that value anyway, so we return a value that is truely inside the range only if that side of the range is closed.
>>>
clampTo (ClosedRange 0 10) 20
10>>>
clampTo (ClosedRange 0 10) (-20)
0>>>
clampTo (ClosedRange 0 10) 5
5>>>
clampTo (OpenRange 0 10) 20
10>>>
clampTo (OpenRange 0 10) (-20)
0>>>
clampTo (OpenRange 0 10) 5
5
inRange :: Ord a => a -> Range a -> Bool #
Test if a value lies in a range.
>>>
1 `inRange` (OpenRange 0 2)
True>>>
1 `inRange` (OpenRange 0 1)
False>>>
1 `inRange` (ClosedRange 0 1)
True>>>
1 `inRange` (ClosedRange 1 1)
True>>>
10 `inRange` (OpenRange 1 10)
False>>>
10 `inRange` (ClosedRange 0 1)
False
This one is kind of weird
>>>
0 `inRange` Range (Closed 0) (Open 0)
False
prettyShow :: Show a => Range a -> String #
Helper function to show a range in mathematical notation.
>>>
prettyShow $ OpenRange 0 2
"(0,2)">>>
prettyShow $ ClosedRange 0 2
"[0,2]">>>
prettyShow $ Range (Open 0) (Closed 5)
"(0,5]"
unEndPoint :: Lens (EndPoint a) (EndPoint b) a b #
Access lens for EndPoint value regardless of whether it is open or closed.
>>>
Open 5 ^. unEndPoint
5>>>
Closed 10 ^. unEndPoint
10>>>
Open 4 & unEndPoint .~ 0
Open 0
Endpoints of a range may either be open or closed.
Instances
Data type for representing ranges.
pattern OpenRange :: a -> a -> Range a | |
pattern ClosedRange :: a -> a -> Range a | |
pattern Range' :: a -> a -> Range a | A range from l to u, ignoring/forgetting the type of the endpoints |
Instances
Instances
HasEnd (Interval a r) Source # | |
HasEnd (LineSegment d p r) Source # | |
Defined in Data.Geometry.LineSegment.Internal type EndCore (LineSegment d p r) Source # type EndExtra (LineSegment d p r) Source # end :: Lens' (LineSegment d p r) (EndCore (LineSegment d p r) :+ EndExtra (LineSegment d p r)) Source # | |
HasEnd (PolyLine d p r) Source # | |
class HasStart t where Source #
Instances
HasStart (Interval a r) Source # | |
HasStart (HalfLine d r) Source # | |
HasStart (LineSegment d p r) Source # | |
Defined in Data.Geometry.LineSegment.Internal type StartCore (LineSegment d p r) Source # type StartExtra (LineSegment d p r) Source # start :: Lens' (LineSegment d p r) (StartCore (LineSegment d p r) :+ StartExtra (LineSegment d p r)) Source # | |
HasStart (PolyLine d p r) Source # | |
data Interval a r where Source #
An Interval is essentially a Range
but with possible payload
We can think of an interval being defined as:
>>>
data Interval a r = Interval (EndPoint (r :+ a)) (EndPoint (r :+ a))
pattern ClosedInterval :: (r :+ a) -> (r :+ a) -> Interval a r | |
pattern Interval :: EndPoint (r :+ a) -> EndPoint (r :+ a) -> Interval a r | |
pattern OpenInterval :: (r :+ a) -> (r :+ a) -> Interval a r |
Instances
intersectsInterval :: Ord r => r -> Interval a r -> Bool Source #
Test if a value lies in an interval. Note that the difference between inInterval and inRange is that the extra value is *not* used in the comparison with inInterval, whereas it is in inRange.
inInterval :: Ord r => r -> Interval a r -> PointLocationResult Source #
Compute where the given query value is with respect to the interval.
Note that even if the boundary of the interval is open we may return OnBoundary.
shiftLeft' :: Num r => r -> Interval a r -> Interval a r Source #
Shifts the interval to the left by delta
asProperInterval :: Ord r => Interval p r -> Interval p r Source #
Makes sure the start and endpoint are oriented such that the starting value is smaller than the ending value.
flipInterval :: Interval a r -> Interval a r Source #
Flips the start and endpoint of the interval.
toLineSegment :: (Monoid p, Num r, Arity d) => Line d r -> LineSegment d p r Source #
Directly convert a line into a Closed line segment.
onSegment :: (Ord r, Fractional r, Arity d) => Point d r -> LineSegment d p r -> Bool Source #
Test if a point lies on a line segment.
As a user, you should typically just use intersects
instead.
onSegment2 :: (Ord r, Num r) => Point 2 r -> LineSegment 2 p r -> Bool Source #
Test if a point lies on a line segment.
>>>
(Point2 1 0) `onSegment2` (ClosedLineSegment (origin :+ ()) (Point2 2 0 :+ ()))
True>>>
(Point2 1 1) `onSegment2` (ClosedLineSegment (origin :+ ()) (Point2 2 0 :+ ()))
False>>>
(Point2 5 0) `onSegment2` (ClosedLineSegment (origin :+ ()) (Point2 2 0 :+ ()))
False>>>
(Point2 (-1) 0) `onSegment2` (ClosedLineSegment (origin :+ ()) (Point2 2 0 :+ ()))
False>>>
(Point2 1 1) `onSegment2` (ClosedLineSegment (origin :+ ()) (Point2 3 3 :+ ()))
True>>>
(Point2 2 0) `onSegment2` (ClosedLineSegment (origin :+ ()) (Point2 2 0 :+ ()))
True>>>
origin `onSegment2` (ClosedLineSegment (origin :+ ()) (Point2 2 0 :+ ()))
True
orderedEndPoints :: Ord r => LineSegment 2 p r -> (Point 2 r :+ p, Point 2 r :+ p) Source #
The left and right end point (or left below right if they have equal x-coords)
segmentLength :: (Arity d, Floating r) => LineSegment d p r -> r Source #
Length of the line segment
sqSegmentLength :: (Arity d, Num r) => LineSegment d p r -> r Source #
Squared length of a line segment.
sqDistanceToSeg :: (Arity d, Fractional r, Ord r) => Point d r -> LineSegment d p r -> r Source #
Deprecated: use squaredEuclideanDistTo instead
Squared distance from the point to the Segment s. The same remark as for
the sqDistanceToSegArg
applies here.
sqDistanceToSegArg :: (Arity d, Fractional r, Ord r) => Point d r -> LineSegment d p r -> (r, Point d r) Source #
Squared distance from the point to the Segment s, and the point on s realizing it.
Note that if the segment is *open*, the closest point returned may be one of the (open) end points, even though technically the end point does not lie on the segment. (The true closest point then lies arbitrarily close to the end point).
>>>
:{
let ls = OpenLineSegment (Point2 0 0 :+ ()) (Point2 1 0 :+ ()) p = Point2 2 0 in snd (sqDistanceToSegArg p ls) == Point2 1 0 :} True
flipSegment :: LineSegment d p r -> LineSegment d p r Source #
flips the start and end point of the segment
interpolate :: (Fractional r, Arity d) => r -> LineSegment d p r -> Point d r Source #
Linearly interpolate the two endpoints with a value in the range [0,1]
>>>
interpolate 0.5 $ ClosedLineSegment (ext $ origin) (ext $ Point2 10.0 10.0)
Point2 5.0 5.0>>>
interpolate 0.1 $ ClosedLineSegment (ext $ origin) (ext $ Point2 10.0 10.0)
Point2 1.0 1.0>>>
interpolate 0 $ ClosedLineSegment (ext $ origin) (ext $ Point2 10.0 10.0)
Point2 0.0 0.0>>>
interpolate 1 $ ClosedLineSegment (ext $ origin) (ext $ Point2 10.0 10.0)
Point2 10.0 10.0
validSegment :: (Eq r, Arity d) => EndPoint (Point d r :+ p) -> EndPoint (Point d r :+ p) -> Maybe (LineSegment d p r) Source #
smart constructor that creates a valid segment, i.e. it validates that the endpoints are disjoint.
sampleLineSegment :: (Arity d, RandomGen g, Random r) => Rand g (LineSegment d () r) Source #
Compute a random line segmeent
ordAtX :: (Fractional r, Ord r) => r -> LineSegment 2 p r -> LineSegment 2 p r -> Ordering Source #
Given an x-coordinate, compare the segments based on the y-coordinate of the intersection with the horizontal line through y
ordAtY :: (Fractional r, Ord r) => r -> LineSegment 2 p r -> LineSegment 2 p r -> Ordering Source #
Given a y-coordinate, compare the segments based on the x-coordinate of the intersection with the horizontal line through y
xCoordAt :: (Fractional r, Ord r) => r -> LineSegment 2 p r -> r Source #
Given a y coord and a line segment that intersects the horizontal line through y, compute the x-coordinate of this intersection point.
note that we will pretend that the line segment is closed, even if it is not
yCoordAt :: (Fractional r, Ord r) => r -> LineSegment 2 p r -> r Source #
Given an x-coordinate and a line segment that intersects the vertical line through x, compute the y-coordinate of this intersection point.
note that we will pretend that the line segment is closed, even if it is not