hgeometry 0.11.0.0 → 0.12.0.0
raw patch · 153 files changed
+8262/−6694 lines, 153 filesdep +deepseq-genericsdep +directorydep +filepathdep ~MonadRandomdep ~QuickCheckdep ~basenew-component:exe:planargraphPVP ok
version bump matches the API change (PVP)
Dependencies added: deepseq-generics, directory, filepath, hgeometry, nonempty-vector, optparse-applicative, reanimate, reanimate-svg, tasty-bench, vector-algorithms, vector-circular
Dependency ranges changed: MonadRandom, QuickCheck, base, bytestring, containers, deepseq, dlist, fixed-vector, hashable, hgeometry-combinatorial, lens, linear, mtl, quickcheck-instances, semigroupoids, semigroups, text, vector, vinyl
API changes (from Hackage documentation)
- Algorithms.Geometry.DelaunayTriangulation.DivideAndConquer: delaunayTriangulation' :: (Ord r, Fractional r) => BinLeafTree Size (Point 2 r :+ p) -> Mapping p r -> (Adj, ConvexPolygon (p :+ VertexID) r)
- Algorithms.Geometry.DelaunayTriangulation.DivideAndConquer: delete :: VertexID -> VertexID -> Adj -> Adj
- Algorithms.Geometry.DelaunayTriangulation.DivideAndConquer: firsts :: ConvexPolygon (p :+ VertexID) r -> IntMap VertexID
- Algorithms.Geometry.DelaunayTriangulation.DivideAndConquer: focus' :: CList a -> a
- Algorithms.Geometry.DelaunayTriangulation.DivideAndConquer: fromHull :: Ord r => Mapping p r -> ConvexPolygon (p :+ q) r -> Adj
- Algorithms.Geometry.DelaunayTriangulation.DivideAndConquer: insert :: (Num r, Ord r) => VertexID -> VertexID -> Merge p r ()
- Algorithms.Geometry.DelaunayTriangulation.DivideAndConquer: insert' :: (Num r, Ord r) => VertexID -> VertexID -> Mapping p r -> Adj -> Adj
- Algorithms.Geometry.DelaunayTriangulation.DivideAndConquer: isLeftOf :: (Ord r, Num r) => VertexID -> (VertexID, VertexID) -> Merge p r Bool
- Algorithms.Geometry.DelaunayTriangulation.DivideAndConquer: isRightOf :: (Ord r, Num r) => VertexID -> (VertexID, VertexID) -> Merge p r Bool
- Algorithms.Geometry.DelaunayTriangulation.DivideAndConquer: lookup' :: Ord k => Map k a -> k -> a
- Algorithms.Geometry.DelaunayTriangulation.DivideAndConquer: lookup'' :: Int -> IntMap a -> a
- Algorithms.Geometry.DelaunayTriangulation.DivideAndConquer: merge :: (Ord r, Fractional r) => Adj -> Adj -> LineSegment 2 (p :+ VertexID) r -> LineSegment 2 (p :+ VertexID) r -> Mapping p r -> Firsts -> Adj
- Algorithms.Geometry.DelaunayTriangulation.DivideAndConquer: moveUp :: (Ord r, Fractional r) => (VertexID, VertexID) -> VertexID -> VertexID -> Merge p r ()
- Algorithms.Geometry.DelaunayTriangulation.DivideAndConquer: nub' :: Eq a => NonEmpty (a :+ b) -> NonEmpty (a :+ b)
- Algorithms.Geometry.DelaunayTriangulation.DivideAndConquer: pred' :: CList a -> CList a
- Algorithms.Geometry.DelaunayTriangulation.DivideAndConquer: qTest :: (Ord r, Fractional r) => VertexID -> VertexID -> Vertex -> Vertex -> Merge p r Bool
- Algorithms.Geometry.DelaunayTriangulation.DivideAndConquer: rotateL :: (Ord r, Fractional r) => VertexID -> VertexID -> Vertex -> Merge p r (Vertex, Bool)
- Algorithms.Geometry.DelaunayTriangulation.DivideAndConquer: rotateL' :: (Ord r, Fractional r) => VertexID -> VertexID -> Vertex -> Vertex -> Merge p r Vertex
- Algorithms.Geometry.DelaunayTriangulation.DivideAndConquer: rotateR :: (Ord r, Fractional r) => VertexID -> VertexID -> Vertex -> Merge p r (Vertex, Bool)
- Algorithms.Geometry.DelaunayTriangulation.DivideAndConquer: rotateR' :: (Ord r, Fractional r) => VertexID -> VertexID -> Vertex -> Vertex -> Merge p r Vertex
- Algorithms.Geometry.DelaunayTriangulation.DivideAndConquer: rotateTo :: Eq a => a -> CList a -> CList a
- Algorithms.Geometry.DelaunayTriangulation.DivideAndConquer: rotateToFirst :: VertexID -> Firsts -> Merge p r ()
- Algorithms.Geometry.DelaunayTriangulation.DivideAndConquer: size' :: BinLeafTree Size a -> Size
- Algorithms.Geometry.DelaunayTriangulation.DivideAndConquer: succ' :: CList a -> CList a
- Algorithms.Geometry.DelaunayTriangulation.DivideAndConquer: type Firsts = IntMap VertexID
- Algorithms.Geometry.DelaunayTriangulation.DivideAndConquer: type Merge p r = StateT Adj (Reader (Mapping p r, Firsts))
- Algorithms.Geometry.DelaunayTriangulation.DivideAndConquer: withID :: (c :+ e) -> e' -> c :+ (e :+ e')
- Algorithms.Geometry.DelaunayTriangulation.Naive: sortAround' :: (Num r, Ord r) => Mapping p r -> VertexID -> [VertexID] -> [VertexID]
- Algorithms.Geometry.DelaunayTriangulation.Types: ST :: !a -> !b -> !c -> ST a b c
- Algorithms.Geometry.DelaunayTriangulation.Types: [fst'] :: ST a b c -> !a
- Algorithms.Geometry.DelaunayTriangulation.Types: [snd'] :: ST a b c -> !b
- Algorithms.Geometry.DelaunayTriangulation.Types: [trd'] :: ST a b c -> !c
- Algorithms.Geometry.DelaunayTriangulation.Types: data ST a b c
- Algorithms.Geometry.DelaunayTriangulation.Types: showDT :: (Show p, Show r) => Triangulation p r -> IO ()
- Algorithms.Geometry.DelaunayTriangulation.Types: tEdges :: Triangulation p r -> [(VertexID, VertexID)]
- Algorithms.Geometry.DelaunayTriangulation.Types: triangulationEdges :: Triangulation p r -> [(Point 2 r :+ p, Point 2 r :+ p)]
- Algorithms.Geometry.DelaunayTriangulation.Types: type ArcID = Int
- Algorithms.Geometry.DelaunayTriangulation.Types: type ST' a = ST (Map (VertexID, VertexID) ArcID) ArcID a
- Algorithms.Geometry.EuclideanMST.EuclideanMST: data MSTW
- Algorithms.Geometry.EuclideanMST.EuclideanMST: euclideanMST :: (Ord r, Fractional r) => NonEmpty (Point 2 r :+ p) -> Tree (Point 2 r :+ p)
- Algorithms.Geometry.LineSegmentIntersection.BentleyOttmann: End :: !s -> EventType s
- Algorithms.Geometry.LineSegmentIntersection.BentleyOttmann: Event :: !Point 2 r -> !EventType (LineSegment 2 p r) -> Event p r
- Algorithms.Geometry.LineSegmentIntersection.BentleyOttmann: Intersection :: EventType s
- Algorithms.Geometry.LineSegmentIntersection.BentleyOttmann: Start :: !NonEmpty s -> EventType s
- Algorithms.Geometry.LineSegmentIntersection.BentleyOttmann: [eventPoint] :: Event p r -> !Point 2 r
- Algorithms.Geometry.LineSegmentIntersection.BentleyOttmann: [eventType] :: Event p r -> !EventType (LineSegment 2 p r)
- Algorithms.Geometry.LineSegmentIntersection.BentleyOttmann: asEventPts :: Ord r => LineSegment 2 p r -> [Event p r]
- Algorithms.Geometry.LineSegmentIntersection.BentleyOttmann: data Event p r
- Algorithms.Geometry.LineSegmentIntersection.BentleyOttmann: data EventType s
- Algorithms.Geometry.LineSegmentIntersection.BentleyOttmann: endsAt :: Ord r => Point 2 r -> LineSegment 2 p r -> Bool
- Algorithms.Geometry.LineSegmentIntersection.BentleyOttmann: extractContains :: (Fractional r, Ord r) => Point 2 r -> StatusStructure p r -> (StatusStructure p r, [LineSegment 2 p r], StatusStructure p r)
- Algorithms.Geometry.LineSegmentIntersection.BentleyOttmann: findNewEvent :: (Ord r, Fractional r) => Point 2 r -> LineSegment 2 p r -> LineSegment 2 p r -> Maybe (Event p r)
- Algorithms.Geometry.LineSegmentIntersection.BentleyOttmann: groupStarts :: Eq r => [Event p r] -> [Event p r]
- Algorithms.Geometry.LineSegmentIntersection.BentleyOttmann: handle :: forall r p. (Ord r, Fractional r) => Event p r -> EventQueue p r -> StatusStructure p r -> [IntersectionPoint p r]
- Algorithms.Geometry.LineSegmentIntersection.BentleyOttmann: isClosedStart :: Eq r => Point 2 r -> LineSegment 2 p r -> Bool
- Algorithms.Geometry.LineSegmentIntersection.BentleyOttmann: merge :: Ord r => [IntersectionPoint p r] -> Intersections p r
- Algorithms.Geometry.LineSegmentIntersection.BentleyOttmann: ordPoints :: Ord r => Point 2 r -> Point 2 r -> Ordering
- Algorithms.Geometry.LineSegmentIntersection.BentleyOttmann: rightEndpoint :: Ord r => LineSegment 2 p r -> r
- Algorithms.Geometry.LineSegmentIntersection.BentleyOttmann: startSegs :: Event p r -> [LineSegment 2 p r]
- Algorithms.Geometry.LineSegmentIntersection.BentleyOttmann: sweep :: (Ord r, Fractional r) => EventQueue p r -> StatusStructure p r -> [IntersectionPoint p r]
- Algorithms.Geometry.LineSegmentIntersection.BentleyOttmann: toStatusStruct :: (Fractional r, Ord r) => Point 2 r -> [LineSegment 2 p r] -> StatusStructure p r
- Algorithms.Geometry.LineSegmentIntersection.BentleyOttmann: type EventQueue p r = Set (Event p r)
- Algorithms.Geometry.LineSegmentIntersection.BentleyOttmann: type StatusStructure p r = Set (LineSegment 2 p r)
- Algorithms.Geometry.LineSegmentIntersection.Naive: addTo :: Ord r => Point 2 r -> LineSegment 2 p r -> Intersections p r -> Intersections p r
- Algorithms.Geometry.LineSegmentIntersection.Naive: collect :: (Ord r, Fractional r) => (LineSegment 2 p r, LineSegment 2 p r) -> Intersections p r -> Intersections p r
- Algorithms.Geometry.LineSegmentIntersection.Naive: handlePoint :: Ord r => LineSegment 2 p r -> LineSegment 2 p r -> Point 2 r -> Intersections p r -> Intersections p r
- Algorithms.Geometry.LineSegmentIntersection.Naive: isEndPointOf :: Eq r => Point 2 r -> LineSegment 2 p r -> Bool
- Algorithms.Geometry.LineSegmentIntersection.Naive: pairs :: [a] -> [(a, a)]
- Algorithms.Geometry.LineSegmentIntersection.Types: Associated :: Set' (LineSegment 2 p r) -> Set' (LineSegment 2 p r) -> Associated p r
- Algorithms.Geometry.LineSegmentIntersection.Types: IntersectionPoint :: !Point 2 r -> !Associated p r -> IntersectionPoint p r
- Algorithms.Geometry.LineSegmentIntersection.Types: [_associatedSegs] :: IntersectionPoint p r -> !Associated p r
- Algorithms.Geometry.LineSegmentIntersection.Types: [_endPointOf] :: Associated p r -> Set' (LineSegment 2 p r)
- Algorithms.Geometry.LineSegmentIntersection.Types: [_interiorTo] :: Associated p r -> Set' (LineSegment 2 p r)
- Algorithms.Geometry.LineSegmentIntersection.Types: [_intersectionPoint] :: IntersectionPoint p r -> !Point 2 r
- Algorithms.Geometry.LineSegmentIntersection.Types: associated :: Ord r => [LineSegment 2 p r] -> [LineSegment 2 p r] -> Associated p r
- Algorithms.Geometry.LineSegmentIntersection.Types: associatedSegs :: forall p_a1HAK r_a1HAL p_a1HUq. Lens (IntersectionPoint p_a1HAK r_a1HAL) (IntersectionPoint p_a1HUq r_a1HAL) (Associated p_a1HAK r_a1HAL) (Associated p_a1HUq r_a1HAL)
- Algorithms.Geometry.LineSegmentIntersection.Types: data Associated p r
- Algorithms.Geometry.LineSegmentIntersection.Types: data IntersectionPoint p r
- Algorithms.Geometry.LineSegmentIntersection.Types: endPointOf :: Associated p r -> [LineSegment 2 p r]
- Algorithms.Geometry.LineSegmentIntersection.Types: endPoints' :: (HasEnd s, HasStart s) => s -> (StartCore s, EndCore s)
- Algorithms.Geometry.LineSegmentIntersection.Types: instance (Control.DeepSeq.NFData p, Control.DeepSeq.NFData r) => Control.DeepSeq.NFData (Algorithms.Geometry.LineSegmentIntersection.Types.Associated p r)
- Algorithms.Geometry.LineSegmentIntersection.Types: instance (GHC.Classes.Eq p, GHC.Classes.Eq r) => GHC.Classes.Eq (Algorithms.Geometry.LineSegmentIntersection.Types.Associated p r)
- Algorithms.Geometry.LineSegmentIntersection.Types: instance (GHC.Classes.Eq r, GHC.Classes.Eq p) => GHC.Classes.Eq (Algorithms.Geometry.LineSegmentIntersection.Types.IntersectionPoint p r)
- Algorithms.Geometry.LineSegmentIntersection.Types: instance (GHC.Show.Show r, GHC.Show.Show p) => GHC.Show.Show (Algorithms.Geometry.LineSegmentIntersection.Types.Associated p r)
- Algorithms.Geometry.LineSegmentIntersection.Types: instance (GHC.Show.Show r, GHC.Show.Show p) => GHC.Show.Show (Algorithms.Geometry.LineSegmentIntersection.Types.IntersectionPoint p r)
- Algorithms.Geometry.LineSegmentIntersection.Types: instance GHC.Classes.Ord r => GHC.Base.Monoid (Algorithms.Geometry.LineSegmentIntersection.Types.Associated p r)
- Algorithms.Geometry.LineSegmentIntersection.Types: instance GHC.Classes.Ord r => GHC.Base.Semigroup (Algorithms.Geometry.LineSegmentIntersection.Types.Associated p r)
- Algorithms.Geometry.LineSegmentIntersection.Types: instance GHC.Generics.Generic (Algorithms.Geometry.LineSegmentIntersection.Types.Associated p r)
- Algorithms.Geometry.LineSegmentIntersection.Types: interiorTo :: Associated p r -> [LineSegment 2 p r]
- Algorithms.Geometry.LineSegmentIntersection.Types: intersectionPoint :: forall p_a1HAK r_a1HAL. Lens' (IntersectionPoint p_a1HAK r_a1HAL) (Point 2 r_a1HAL)
- Algorithms.Geometry.LineSegmentIntersection.Types: isEndPointIntersection :: Associated p r -> Bool
- Algorithms.Geometry.LineSegmentIntersection.Types: type Compare a = a -> a -> Ordering
- Algorithms.Geometry.LineSegmentIntersection.Types: type Intersections p r = Map (Point 2 r) (Associated p r)
- Algorithms.Geometry.LineSegmentIntersection.Types: type Set' l = Map (Point (Dimension l) (NumType l), Point (Dimension l) (NumType l)) (NonEmpty l)
- Algorithms.Geometry.PolygonTriangulation.TriangulateMonotone: L :: LR
- Algorithms.Geometry.PolygonTriangulation.TriangulateMonotone: R :: LR
- Algorithms.Geometry.PolygonTriangulation.TriangulateMonotone: chainOf :: P p r -> LR
- Algorithms.Geometry.PolygonTriangulation.TriangulateMonotone: data LR
- Algorithms.Geometry.PolygonTriangulation.TriangulateMonotone: isInside :: (Ord r, Num r) => P p r -> (P p r, P p r) -> Bool
- Algorithms.Geometry.PolygonTriangulation.TriangulateMonotone: mergeBy :: (a -> a -> Ordering) -> [a] -> [a] -> [a]
- Algorithms.Geometry.PolygonTriangulation.TriangulateMonotone: process :: (Ord r, Num r) => P p r -> Stack (P p r) -> SP (Stack (P p r)) [LineSegment 2 p r]
- Algorithms.Geometry.PolygonTriangulation.TriangulateMonotone: seg :: P p r -> P p r -> LineSegment 2 p r
- Algorithms.Geometry.PolygonTriangulation.TriangulateMonotone: splitPolygon :: Ord r => MonotonePolygon p r -> ([Point 2 r :+ (LR :+ p)], [Point 2 r :+ (LR :+ p)])
- Algorithms.Geometry.PolygonTriangulation.TriangulateMonotone: testPoly5 :: SimplePolygon () Rational
- Algorithms.Geometry.PolygonTriangulation.TriangulateMonotone: toVtx :: P p r -> Point 2 r :+ p
- Algorithms.Geometry.PolygonTriangulation.TriangulateMonotone: type P p r = Point 2 r :+ (LR :+ p)
- Algorithms.Geometry.PolygonTriangulation.TriangulateMonotone: type Stack a = [a]
- Algorithms.Geometry.SmallestEnclosingBall.Types: DiskResult :: Disk () r -> TwoOrThree (Point 2 r :+ p) -> DiskResult p r
- Algorithms.Geometry.SmallestEnclosingBall.Types: Three :: !a -> !a -> !a -> TwoOrThree a
- Algorithms.Geometry.SmallestEnclosingBall.Types: Two :: !a -> !a -> TwoOrThree a
- Algorithms.Geometry.SmallestEnclosingBall.Types: [_definingPoints] :: DiskResult p r -> TwoOrThree (Point 2 r :+ p)
- Algorithms.Geometry.SmallestEnclosingBall.Types: [_enclosingDisk] :: DiskResult p r -> Disk () r
- Algorithms.Geometry.SmallestEnclosingBall.Types: data DiskResult p r
- Algorithms.Geometry.SmallestEnclosingBall.Types: data TwoOrThree a
- Algorithms.Geometry.SmallestEnclosingBall.Types: definingPoints :: forall p_a2SvR r_a2SvS p_a2SOG. Lens (DiskResult p_a2SvR r_a2SvS) (DiskResult p_a2SOG r_a2SvS) (TwoOrThree ((:+) (Point 2 r_a2SvS) p_a2SvR)) (TwoOrThree ((:+) (Point 2 r_a2SvS) p_a2SOG))
- Algorithms.Geometry.SmallestEnclosingBall.Types: enclosingDisk :: forall p_a2SvR r_a2SvS. Lens' (DiskResult p_a2SvR r_a2SvS) (Disk () r_a2SvS)
- Algorithms.Geometry.SmallestEnclosingBall.Types: fromList :: [a] -> Either String (TwoOrThree a)
- Algorithms.Geometry.SmallestEnclosingBall.Types: instance (GHC.Classes.Eq r, GHC.Classes.Eq p) => GHC.Classes.Eq (Algorithms.Geometry.SmallestEnclosingBall.Types.DiskResult p r)
- Algorithms.Geometry.SmallestEnclosingBall.Types: instance (GHC.Show.Show r, GHC.Show.Show p) => GHC.Show.Show (Algorithms.Geometry.SmallestEnclosingBall.Types.DiskResult p r)
- Algorithms.Geometry.SmallestEnclosingBall.Types: instance Data.Foldable.Foldable Algorithms.Geometry.SmallestEnclosingBall.Types.TwoOrThree
- Algorithms.Geometry.SmallestEnclosingBall.Types: instance GHC.Base.Functor Algorithms.Geometry.SmallestEnclosingBall.Types.TwoOrThree
- Algorithms.Geometry.SmallestEnclosingBall.Types: instance GHC.Classes.Eq a => GHC.Classes.Eq (Algorithms.Geometry.SmallestEnclosingBall.Types.TwoOrThree a)
- Algorithms.Geometry.SmallestEnclosingBall.Types: instance GHC.Classes.Ord a => GHC.Classes.Ord (Algorithms.Geometry.SmallestEnclosingBall.Types.TwoOrThree a)
- Algorithms.Geometry.SmallestEnclosingBall.Types: instance GHC.Read.Read a => GHC.Read.Read (Algorithms.Geometry.SmallestEnclosingBall.Types.TwoOrThree a)
- Algorithms.Geometry.SmallestEnclosingBall.Types: instance GHC.Show.Show a => GHC.Show.Show (Algorithms.Geometry.SmallestEnclosingBall.Types.TwoOrThree a)
- Algorithms.Geometry.WellSeparatedPairDecomposition.Types: instance (Data.Geometry.Vector.VectorFamily.Arity d, GHC.Classes.Eq r, GHC.Classes.Eq a) => GHC.Classes.Eq (Algorithms.Geometry.WellSeparatedPairDecomposition.Types.NodeData d r a)
- Algorithms.Geometry.WellSeparatedPairDecomposition.Types: instance (Data.Geometry.Vector.VectorFamily.Arity d, GHC.Classes.Eq r, GHC.Classes.Eq p) => GHC.Classes.Eq (Algorithms.Geometry.WellSeparatedPairDecomposition.Types.FindAndCompact d r p)
- Algorithms.Geometry.WellSeparatedPairDecomposition.Types: instance (Data.Geometry.Vector.VectorFamily.Arity d, GHC.Show.Show r, GHC.Show.Show a) => GHC.Show.Show (Algorithms.Geometry.WellSeparatedPairDecomposition.Types.NodeData d r a)
- Algorithms.Geometry.WellSeparatedPairDecomposition.Types: instance (Data.Geometry.Vector.VectorFamily.Arity d, GHC.Show.Show r, GHC.Show.Show p) => GHC.Show.Show (Algorithms.Geometry.WellSeparatedPairDecomposition.Types.FindAndCompact d r p)
- Algorithms.Geometry.WellSeparatedPairDecomposition.Types: instance Data.Foldable.Foldable (Algorithms.Geometry.WellSeparatedPairDecomposition.Types.NodeData d r)
- Algorithms.Geometry.WellSeparatedPairDecomposition.Types: instance Data.Traversable.Traversable (Algorithms.Geometry.WellSeparatedPairDecomposition.Types.NodeData d r)
- Algorithms.Geometry.WellSeparatedPairDecomposition.Types: instance GHC.Base.Functor (Algorithms.Geometry.WellSeparatedPairDecomposition.Types.NodeData d r)
- Algorithms.Geometry.WellSeparatedPairDecomposition.Types: instance GHC.Base.Semigroup v => Data.Measured.Class.Measured v (Algorithms.Geometry.WellSeparatedPairDecomposition.Types.NodeData d r v)
- Algorithms.Geometry.WellSeparatedPairDecomposition.Types: instance GHC.Classes.Eq Algorithms.Geometry.WellSeparatedPairDecomposition.Types.Level
- Algorithms.Geometry.WellSeparatedPairDecomposition.Types: instance GHC.Classes.Eq Algorithms.Geometry.WellSeparatedPairDecomposition.Types.ShortSide
- Algorithms.Geometry.WellSeparatedPairDecomposition.Types: instance GHC.Classes.Ord Algorithms.Geometry.WellSeparatedPairDecomposition.Types.Level
- Algorithms.Geometry.WellSeparatedPairDecomposition.Types: instance GHC.Show.Show Algorithms.Geometry.WellSeparatedPairDecomposition.Types.Level
- Algorithms.Geometry.WellSeparatedPairDecomposition.Types: instance GHC.Show.Show Algorithms.Geometry.WellSeparatedPairDecomposition.Types.ShortSide
- Algorithms.Geometry.WellSeparatedPairDecomposition.WSPD: areWellSeparated :: (Arity d, Arity (d + 1), Fractional r, Ord r) => r -> SplitTree d p r a -> SplitTree d p r a -> Bool
- Algorithms.Geometry.WellSeparatedPairDecomposition.WSPD: areWellSeparated' :: (Floating r, Ord r, Arity d) => r -> SplitTree d p r a -> SplitTree d p r a -> Bool
- Algorithms.Geometry.WellSeparatedPairDecomposition.WSPD: assignLevel :: (c :+ (Idx :+ p)) -> Level -> RST s ()
- Algorithms.Geometry.WellSeparatedPairDecomposition.WSPD: assignLevels :: (Fractional r, Ord r, Arity d, Show r, Show p) => Int -> Int -> Vector d (PointSeq d (Idx :+ p) r) -> Level -> [Level] -> RST s (NonEmpty Level)
- Algorithms.Geometry.WellSeparatedPairDecomposition.WSPD: bbOf :: Ord r => SplitTree d p r a -> Box d () r
- Algorithms.Geometry.WellSeparatedPairDecomposition.WSPD: boxBox :: (Fractional r, Ord r, Arity d, Arity (d + 1)) => r -> Box d p r -> Box d p r -> Bool
- Algorithms.Geometry.WellSeparatedPairDecomposition.WSPD: boxBox1 :: (Floating r, Ord r, Arity d) => r -> Box d p r -> Box d p r -> Bool
- Algorithms.Geometry.WellSeparatedPairDecomposition.WSPD: children' :: BinLeafTree v a -> [BinLeafTree v a]
- Algorithms.Geometry.WellSeparatedPairDecomposition.WSPD: compactEnds :: Arity d => Vector d (PointSeq d (Idx :+ p) r) -> RST s (Vector d (PointSeq d (Idx :+ p) r))
- Algorithms.Geometry.WellSeparatedPairDecomposition.WSPD: compactEnds' :: PointSeq d (Idx :+ p) r -> RST s (PointSeq d (Idx :+ p) r)
- Algorithms.Geometry.WellSeparatedPairDecomposition.WSPD: distributePoints :: (Arity d, Show r, Show p) => Int -> Vector (Maybe Level) -> Vector d (PointSeq d (Idx :+ p) r) -> Vector (Vector d (PointSeq d (Idx :+ p) r))
- Algorithms.Geometry.WellSeparatedPairDecomposition.WSPD: distributePoints' :: Int -> Vector (Maybe Level) -> PointSeq d (Idx :+ p) r -> Vector (PointSeq d (Idx :+ p) r)
- Algorithms.Geometry.WellSeparatedPairDecomposition.WSPD: dropIdx :: (core :+ (t :+ extra)) -> core :+ extra
- Algorithms.Geometry.WellSeparatedPairDecomposition.WSPD: extends :: Arity d => Vector d (PointSeq d p r) -> Vector d (Range r)
- Algorithms.Geometry.WellSeparatedPairDecomposition.WSPD: fairSplitTree :: (Fractional r, Ord r, Arity d, 1 <= d, Show r, Show p) => NonEmpty (Point d r :+ p) -> SplitTree d p r ()
- Algorithms.Geometry.WellSeparatedPairDecomposition.WSPD: fairSplitTree' :: (Fractional r, Ord r, Arity d, 1 <= d, Show r, Show p) => Int -> Vector d (PointSeq d (Idx :+ p) r) -> BinLeafTree Int (Point d r :+ p)
- Algorithms.Geometry.WellSeparatedPairDecomposition.WSPD: findAndCompact :: (Ord r, Arity d, Show r, Show p) => Int -> PointSeq d (Idx :+ p) r -> r -> RST s (PointSeq d (Idx :+ p) r, PointSeq d (Idx :+ p) r)
- Algorithms.Geometry.WellSeparatedPairDecomposition.WSPD: findPairs :: (Floating r, Ord r, Arity d, Arity (d + 1)) => r -> SplitTree d p r a -> SplitTree d p r a -> [WSP d p r a]
- Algorithms.Geometry.WellSeparatedPairDecomposition.WSPD: fromSeqUnsafe :: () => Seq a -> LSeq n a
- Algorithms.Geometry.WellSeparatedPairDecomposition.WSPD: hasLevel :: (c :+ (Idx :+ p)) -> RST s Bool
- Algorithms.Geometry.WellSeparatedPairDecomposition.WSPD: ix' :: (Arity d, KnownNat d) => Int -> Lens' (Vector d a) a
- Algorithms.Geometry.WellSeparatedPairDecomposition.WSPD: levelOf :: (c :+ (Idx :+ p)) -> RST s (Maybe Level)
- Algorithms.Geometry.WellSeparatedPairDecomposition.WSPD: maxWidth :: (Arity d, Num r) => SplitTree d p r a -> r
- Algorithms.Geometry.WellSeparatedPairDecomposition.WSPD: reIndexPoints :: (Arity d, 1 <= d) => Vector d (PointSeq d (Idx :+ p) r) -> Vector d (PointSeq d (Idx :+ p) r)
- Algorithms.Geometry.WellSeparatedPairDecomposition.WSPD: transpose :: Arity d => Vector d (Vector a) -> Vector (Vector d a)
- Algorithms.Geometry.WellSeparatedPairDecomposition.WSPD: type RST s = ReaderT (MVector s (Maybe Level)) (ST s)
- Algorithms.Geometry.WellSeparatedPairDecomposition.WSPD: wellSeparatedPairs :: (Floating r, Ord r, Arity d, Arity (d + 1)) => r -> SplitTree d p r a -> [WSP d p r a]
- Algorithms.Geometry.WellSeparatedPairDecomposition.WSPD: widestDimension :: (Num r, Ord r, Arity d) => Vector d (PointSeq d p r) -> Int
- Algorithms.Geometry.WellSeparatedPairDecomposition.WSPD: widths :: (Num r, Arity d) => Vector d (PointSeq d p r) -> Vector d r
- Data.Geometry: asSimplePolygon :: Polygon t p r -> SimplePolygon p r
- Data.Geometry: readVec :: forall d r. (Arity d, Read r) => ReadP (Vector d r)
- Data.Geometry.Ball: instance (GHC.Classes.Ord r, GHC.Float.Floating r) => Data.Intersection.IsIntersectableWith (Data.Geometry.LineSegment.LineSegment 2 p r) (Data.Geometry.Ball.Circle q r)
- Data.Geometry.Directions: _East :: Prism' CardinalDirection ()
- Data.Geometry.Directions: _North :: Prism' CardinalDirection ()
- Data.Geometry.Directions: _NorthEast :: Prism' InterCardinalDirection ()
- Data.Geometry.Directions: _NorthWest :: Prism' InterCardinalDirection ()
- Data.Geometry.Directions: _South :: Prism' CardinalDirection ()
- Data.Geometry.Directions: _SouthEast :: Prism' InterCardinalDirection ()
- Data.Geometry.Directions: _SouthWest :: Prism' InterCardinalDirection ()
- Data.Geometry.Directions: _West :: Prism' CardinalDirection ()
- Data.Geometry.HalfLine: [_halfLineDirection] :: HalfLine d r -> Vector d r
- Data.Geometry.HalfLine: [_startPoint] :: HalfLine d r -> Point d r
- Data.Geometry.HalfLine: onHalfLine :: (Ord r, Fractional r, Arity d) => Point d r -> HalfLine d r -> Bool
- Data.Geometry.LineSegment: instance (Data.Geometry.Vector.VectorFamily.Arity d, Control.DeepSeq.NFData r, Control.DeepSeq.NFData p) => Control.DeepSeq.NFData (Data.Geometry.LineSegment.LineSegment d p r)
- Data.Geometry.LineSegment: instance (GHC.Classes.Eq r, GHC.Classes.Eq p, Data.Geometry.Vector.VectorFamily.Arity d) => GHC.Classes.Eq (Data.Geometry.LineSegment.LineSegment d p r)
- Data.Geometry.LineSegment: instance (GHC.Classes.Ord r, GHC.Real.Fractional r) => Data.Intersection.IsIntersectableWith (Data.Geometry.LineSegment.LineSegment 2 p r) (Data.Geometry.Line.Internal.Line 2 r)
- Data.Geometry.LineSegment: instance (GHC.Classes.Ord r, GHC.Real.Fractional r) => Data.Intersection.IsIntersectableWith (Data.Geometry.LineSegment.LineSegment 2 p r) (Data.Geometry.LineSegment.LineSegment 2 p r)
- Data.Geometry.LineSegment: instance (GHC.Num.Num r, Data.Geometry.Vector.VectorFamily.Arity d) => Data.Geometry.Line.Internal.HasSupportingLine (Data.Geometry.LineSegment.LineSegment d p r)
- Data.Geometry.LineSegment: instance (GHC.Real.Fractional r, Data.Geometry.Vector.VectorFamily.Arity d, Data.Geometry.Vector.VectorFamily.Arity (d GHC.TypeNats.+ 1)) => Data.Geometry.Transformation.IsTransformable (Data.Geometry.LineSegment.LineSegment d p r)
- Data.Geometry.LineSegment: instance (GHC.Show.Show r, GHC.Show.Show p, Data.Geometry.Vector.VectorFamily.Arity d) => GHC.Show.Show (Data.Geometry.LineSegment.LineSegment d p r)
- Data.Geometry.LineSegment: instance (Test.QuickCheck.Arbitrary.Arbitrary r, Test.QuickCheck.Arbitrary.Arbitrary p, Data.Geometry.Vector.VectorFamily.Arity d) => Test.QuickCheck.Arbitrary.Arbitrary (Data.Geometry.LineSegment.LineSegment d p r)
- Data.Geometry.LineSegment: instance Data.Geometry.Interval.HasEnd (Data.Geometry.LineSegment.LineSegment d p r)
- Data.Geometry.LineSegment: instance Data.Geometry.Interval.HasStart (Data.Geometry.LineSegment.LineSegment d p r)
- Data.Geometry.LineSegment: instance Data.Geometry.Point.Internal.PointFunctor (Data.Geometry.LineSegment.LineSegment d p)
- Data.Geometry.LineSegment: instance Data.Geometry.Vector.VectorFamily.Arity d => Data.Bifunctor.Bifunctor (Data.Geometry.LineSegment.LineSegment d)
- Data.Geometry.LineSegment: instance Data.Geometry.Vector.VectorFamily.Arity d => Data.Geometry.Box.Internal.IsBoxable (Data.Geometry.LineSegment.LineSegment d p r)
- Data.Geometry.LineSegment: instance Data.Geometry.Vector.VectorFamily.Arity d => GHC.Base.Functor (Data.Geometry.LineSegment.LineSegment d p)
- Data.Geometry.LineSegment: onSegment :: (Ord r, Fractional r, Arity d) => Point d r -> LineSegment d p r -> Bool
- Data.Geometry.LineSegment: pattern Range' :: forall a. () => () => a -> a -> Range a
- Data.Geometry.PlanarSubdivision.Basic: data Dart (s :: k) :: forall k. () => k -> Type
- Data.Geometry.PlanarSubdivision.Basic: newtype FaceId (s :: k) (w :: World) :: forall k. () => k -> World -> Type
- Data.Geometry.Point: asAPoint :: AsAPoint p => Lens (p d r) (p d' r') (Point d r) (Point d' r')
- Data.Geometry.Point: class AsAPoint p
- Data.Geometry.Point: vector' :: AsAPoint p => Lens (p d r) (p d r') (Vector d r) (Vector d r')
- Data.Geometry.Polygon: asSimplePolygon :: Polygon t p r -> SimplePolygon p r
- Data.Geometry.RangeTree: instance (1 GHC.TypeNats.<= d, i GHC.TypeNats.<= d, Data.Geometry.RangeTree.Query (i GHC.TypeNats.- 1) d, Data.Geometry.Vector.VectorFamily.Arity d, i Data.Type.Equality.~ 2) => Data.Geometry.RangeTree.Query 2 d
- Data.Geometry.RangeTree: instance forall k1 k2 r p (d :: GHC.Types.Nat) (i :: k2) (v :: k1). (GHC.Classes.Eq r, GHC.Classes.Eq p, Data.Geometry.Vector.VectorFamily.Arity d) => GHC.Classes.Eq (Data.Geometry.RangeTree.Leaf i d v p r)
- Data.Geometry.RangeTree: instance forall k1 k2 r p (d :: GHC.Types.Nat) (i :: k2) (v :: k1). (GHC.Show.Show r, GHC.Show.Show p, Data.Geometry.Vector.VectorFamily.Arity d) => GHC.Show.Show (Data.Geometry.RangeTree.Leaf i d v p r)
- Data.Geometry.Slab: instance (GHC.Real.Fractional r, GHC.Classes.Ord r, Data.Geometry.Slab.HasBoundingLines o) => Data.Intersection.IsIntersectableWith (Data.Geometry.LineSegment.LineSegment 2 a r) (Data.Geometry.Slab.Slab o a r)
- Data.Geometry.SubLine: testz :: SubLine 2 () Rational Rational
- Data.Geometry.Vector.VectorFamily: instance (Data.Geometry.Vector.VectorFamily.Arity d, GHC.Show.Show r) => GHC.Show.Show (Data.Geometry.Vector.VectorFamily.Vector d r)
- Data.Geometry.Vector.VectorFamily: instance Data.Geometry.Vector.VectorFamily.Arity d => Control.Lens.Indexed.FoldableWithIndex GHC.Types.Int (Data.Geometry.Vector.VectorFamily.Vector d)
- Data.Geometry.Vector.VectorFamily: instance Data.Geometry.Vector.VectorFamily.Arity d => Control.Lens.Indexed.FunctorWithIndex GHC.Types.Int (Data.Geometry.Vector.VectorFamily.Vector d)
- Data.Geometry.Vector.VectorFamily: instance Data.Geometry.Vector.VectorFamily.Arity d => Control.Lens.Indexed.TraversableWithIndex GHC.Types.Int (Data.Geometry.Vector.VectorFamily.Vector d)
- Data.Geometry.Vector.VectorFamily: readVec :: forall d r. (Arity d, Read r) => ReadP (Vector d r)
- Data.Geometry.Vector.VectorFamilyPeano: [SS] :: !SingPeano d -> SingPeano (S d)
- Data.Geometry.Vector.VectorFamilyPeano: [SZ] :: SingPeano Z
- Data.Geometry.Vector.VectorFamilyPeano: [_unVF] :: VectorFamily -> VectorFamilyF d r
- Data.Geometry.Vector.VectorFamilyPeano: class ImplicitPeano (d :: PeanoNum)
- Data.Geometry.Vector.VectorFamilyPeano: data SingPeano (d :: PeanoNum)
- Data.Geometry.Vector.VectorFamilyPeano: destruct :: (ImplicitArity d, ImplicitArity (S d)) => VectorFamily (S d) r -> (r, VectorFamily d r)
- Data.Geometry.Vector.VectorFamilyPeano: elem0 :: Int -> Traversal' (VectorFamily Z r) r
- Data.Geometry.Vector.VectorFamilyPeano: elem1 :: Int -> Traversal' (VectorFamily One r) r
- Data.Geometry.Vector.VectorFamilyPeano: elem2 :: Int -> Traversal' (VectorFamily Two r) r
- Data.Geometry.Vector.VectorFamilyPeano: elem3 :: Int -> Traversal' (VectorFamily Three r) r
- Data.Geometry.Vector.VectorFamilyPeano: elem4 :: Int -> Traversal' (VectorFamily Four r) r
- Data.Geometry.Vector.VectorFamilyPeano: elemD :: Arity (FromPeano (Many d)) => Int -> Traversal' (VectorFamily (Many d) r) r
- Data.Geometry.Vector.VectorFamilyPeano: element' :: forall d r. ImplicitArity d => Int -> Traversal' (VectorFamily d r) r
- Data.Geometry.Vector.VectorFamilyPeano: implicitPeano :: ImplicitPeano d => SingPeano d
- Data.Geometry.Vector.VectorFamilyPeano: type Four = S Three
- Data.Geometry.Vector.VectorFamilyPeano: type Many d = S (S (S (S (S d))))
- Data.Geometry.Vector.VectorFamilyPeano: type One = S Z
- Data.Geometry.Vector.VectorFamilyPeano: type Three = S Two
- Data.Geometry.Vector.VectorFamilyPeano: unVF :: Lens (VectorFamily d r) (VectorFamily d t) (VectorFamilyF d r) (VectorFamilyF d t)
- Data.Geometry.Vector.VectorFamilyPeano: vectorFromList :: ImplicitArity d => [r] -> Maybe (VectorFamily d r)
- Data.Geometry.Vector.VectorFamilyPeano: vectorFromListUnsafe :: ImplicitArity d => [r] -> VectorFamily d r
- Data.PlaneGraph: data Dart (s :: k) :: forall k. () => k -> Type
- Data.PlaneGraph: newtype FaceId (s :: k) (w :: World) :: forall k. () => k -> World -> Type
- Data.PlaneGraph.Core: data Dart (s :: k) :: forall k. () => k -> Type
- Data.PlaneGraph.Core: newtype FaceId (s :: k) (w :: World) :: forall k. () => k -> World -> Type
+ Algorithms.Geometry.ClosestPair: closestPair :: (Ord r, Num r) => LSeq 2 (Point 2 r :+ p) -> Two (Point 2 r :+ p)
+ Algorithms.Geometry.ConvexHull: convexHull :: (Ord r, Num r) => NonEmpty (Point 2 r :+ p) -> ConvexPolygon p r
+ Algorithms.Geometry.DelaunayTriangulation.Naive: sortAroundMapping :: (Num r, Ord r) => Mapping p r -> VertexID -> [VertexID] -> [VertexID]
+ Algorithms.Geometry.DelaunayTriangulation.Types: edgesAsPoints :: Triangulation p r -> [(Point 2 r :+ p, Point 2 r :+ p)]
+ Algorithms.Geometry.DelaunayTriangulation.Types: edgesAsVertices :: Triangulation p r -> [(VertexID, VertexID)]
+ Algorithms.Geometry.Diameter: diameter :: (Ord r, Floating r) => [Point 2 r :+ p] -> r
+ Algorithms.Geometry.Diameter: diametralPair :: (Ord r, Num r) => [Point 2 r :+ p] -> Maybe (Point 2 r :+ p, Point 2 r :+ p)
+ Algorithms.Geometry.Diameter.ConvexHull: diameter :: (Ord r, Floating r) => [Point 2 r :+ p] -> r
+ Algorithms.Geometry.Diameter.ConvexHull: diametralPair :: (Ord r, Num r) => [Point 2 r :+ p] -> Maybe (Point 2 r :+ p, Point 2 r :+ p)
+ Algorithms.Geometry.EuclideanMST: euclideanMST :: (Ord r, Fractional r) => NonEmpty (Point 2 r :+ p) -> Tree (Point 2 r :+ p)
+ Algorithms.Geometry.LineSegmentIntersection: Associated :: Set' (LineSegment 2 p r) -> Set' (LineSegment 2 p r) -> Associated p r
+ Algorithms.Geometry.LineSegmentIntersection: IntersectionPoint :: !Point 2 r -> !Associated p r -> IntersectionPoint p r
+ Algorithms.Geometry.LineSegmentIntersection: [_associatedSegs] :: IntersectionPoint p r -> !Associated p r
+ Algorithms.Geometry.LineSegmentIntersection: [_endPointOf] :: Associated p r -> Set' (LineSegment 2 p r)
+ Algorithms.Geometry.LineSegmentIntersection: [_interiorTo] :: Associated p r -> Set' (LineSegment 2 p r)
+ Algorithms.Geometry.LineSegmentIntersection: [_intersectionPoint] :: IntersectionPoint p r -> !Point 2 r
+ Algorithms.Geometry.LineSegmentIntersection: associated :: Ord r => [LineSegment 2 p r] -> [LineSegment 2 p r] -> Associated p r
+ Algorithms.Geometry.LineSegmentIntersection: data Associated p r
+ Algorithms.Geometry.LineSegmentIntersection: data IntersectionPoint p r
+ Algorithms.Geometry.LineSegmentIntersection: isEndPointIntersection :: Associated p r -> Bool
+ Algorithms.Geometry.LineSegmentIntersection: type Compare a = a -> a -> Ordering
+ Algorithms.Geometry.LineSegmentIntersection: type Intersections p r = Map (Point 2 r) (Associated p r)
+ Algorithms.Geometry.LineSegmentIntersection.BooleanSweep: hasIntersections :: (Ord r, Num r) => [LineSegment 2 p r] -> Bool
+ Algorithms.Geometry.LineSegmentIntersection.BooleanSweep: segmentsOverlap :: (Num r, Ord r) => LineSegment 2 p r -> LineSegment 2 p r -> Bool
+ Algorithms.Geometry.PolygonTriangulation.EarClip: earClip :: (Num r, Ord r) => SimplePolygon p r -> [(Int, Int, Int)]
+ Algorithms.Geometry.PolygonTriangulation.EarClip: earClipHashed :: Real r => SimplePolygon p r -> [(Int, Int, Int)]
+ Algorithms.Geometry.PolygonTriangulation.EarClip: earClipRandom :: (Num r, Ord r) => SimplePolygon p r -> [(Int, Int, Int)]
+ Algorithms.Geometry.PolygonTriangulation.EarClip: earClipRandomHashed :: Real r => SimplePolygon p r -> [(Int, Int, Int)]
+ Algorithms.Geometry.PolygonTriangulation.EarClip: zHash :: V2 Word -> Word
+ Algorithms.Geometry.PolygonTriangulation.EarClip: zUnHash :: Word -> V2 Word
+ Algorithms.Geometry.SSSP: instance Data.FingerTree.Measured (Algorithms.Geometry.SSSP.MinMax r) (Algorithms.Geometry.SSSP.Index r)
+ Algorithms.Geometry.SSSP: instance GHC.Base.Monoid (Algorithms.Geometry.SSSP.MinMax r)
+ Algorithms.Geometry.SSSP: instance GHC.Base.Semigroup (Algorithms.Geometry.SSSP.MinMax r)
+ Algorithms.Geometry.SSSP: instance GHC.Classes.Eq (Algorithms.Geometry.SSSP.Index r)
+ Algorithms.Geometry.SSSP: instance GHC.Show.Show (Algorithms.Geometry.SSSP.Dual r)
+ Algorithms.Geometry.SSSP: instance GHC.Show.Show (Algorithms.Geometry.SSSP.DualTree r)
+ Algorithms.Geometry.SSSP: instance GHC.Show.Show (Algorithms.Geometry.SSSP.Funnel r)
+ Algorithms.Geometry.SSSP: instance GHC.Show.Show (Algorithms.Geometry.SSSP.Index r)
+ Algorithms.Geometry.SSSP: instance GHC.Show.Show (Algorithms.Geometry.SSSP.MinMax r)
+ Algorithms.Geometry.SSSP: instance GHC.Show.Show Algorithms.Geometry.SSSP.SplitDirection
+ Algorithms.Geometry.SSSP: sssp :: (Ord r, Fractional r) => PlaneGraph s Int PolygonEdgeType PolygonFaceData r -> SSSP
+ Algorithms.Geometry.SSSP: triangulate :: (Ord r, Fractional r) => SimplePolygon p r -> PlaneGraph s Int PolygonEdgeType PolygonFaceData r
+ Algorithms.Geometry.SSSP: type SSSP = Vector Int
+ Algorithms.Geometry.SSSP: visibilityDual :: forall s r. (Ord r, Fractional r) => PlaneGraph s Int PolygonEdgeType PolygonFaceData r -> Dual r
+ Algorithms.Geometry.SSSP: visibilityFinger :: forall r. (Fractional r, Ord r, Show r) => Dual r -> [Either (Int, Int, Int) (Point 2 r)]
+ Algorithms.Geometry.SSSP: visibilitySensitive :: forall s r. (Ord r, Fractional r, Show r) => PlaneGraph s Int PolygonEdgeType PolygonFaceData r -> SimplePolygon () r
+ Algorithms.Geometry.SSSP.Naive: sssp :: (Real r, Fractional r) => SimplePolygon p r -> SSSP
+ Algorithms.Geometry.SSSP.Naive: sssp' :: (Real r, Fractional r) => SimplePolygon p r -> Vector SSSP
+ Algorithms.Geometry.SmallestEnclosingBall: DiskResult :: Disk () r -> TwoOrThree (Point 2 r :+ p) -> DiskResult p r
+ Algorithms.Geometry.SmallestEnclosingBall: Three :: !a -> !a -> !a -> TwoOrThree a
+ Algorithms.Geometry.SmallestEnclosingBall: Two :: !a -> !a -> TwoOrThree a
+ Algorithms.Geometry.SmallestEnclosingBall: [_definingPoints] :: DiskResult p r -> TwoOrThree (Point 2 r :+ p)
+ Algorithms.Geometry.SmallestEnclosingBall: [_enclosingDisk] :: DiskResult p r -> Disk () r
+ Algorithms.Geometry.SmallestEnclosingBall: data DiskResult p r
+ Algorithms.Geometry.SmallestEnclosingBall: data TwoOrThree a
+ Algorithms.Geometry.SmallestEnclosingBall: definingPoints :: forall p_a2IBQ r_a2IBR p_a2IUw. Lens (DiskResult p_a2IBQ r_a2IBR) (DiskResult p_a2IUw r_a2IBR) (TwoOrThree ((:+) (Point 2 r_a2IBR) p_a2IBQ)) (TwoOrThree ((:+) (Point 2 r_a2IBR) p_a2IUw))
+ Algorithms.Geometry.SmallestEnclosingBall: enclosingDisk :: forall p_a2IBQ r_a2IBR. Lens' (DiskResult p_a2IBQ r_a2IBR) (Disk () r_a2IBR)
+ Algorithms.Geometry.SmallestEnclosingBall: twoOrThreeFromList :: [a] -> Either String (TwoOrThree a)
+ Algorithms.Geometry.VisibilityPolygon.Lee: compareAroundEndPoint :: forall p r e. (Ord r, Fractional r) => Point 2 r -> (LineSegment 2 p r :+ e) -> (LineSegment 2 p r :+ e) -> Ordering
+ Algorithms.Geometry.VisibilityPolygon.Lee: instance (GHC.Show.Show r, GHC.Show.Show p, GHC.Show.Show e) => GHC.Show.Show (Algorithms.Geometry.VisibilityPolygon.Lee.Event p e r)
+ Algorithms.Geometry.VisibilityPolygon.Lee: instance GHC.Classes.Eq a => GHC.Classes.Eq (Algorithms.Geometry.VisibilityPolygon.Lee.Action a)
+ Algorithms.Geometry.VisibilityPolygon.Lee: instance GHC.Classes.Ord a => GHC.Classes.Ord (Algorithms.Geometry.VisibilityPolygon.Lee.Action a)
+ Algorithms.Geometry.VisibilityPolygon.Lee: instance GHC.Show.Show a => GHC.Show.Show (Algorithms.Geometry.VisibilityPolygon.Lee.Action a)
+ Algorithms.Geometry.VisibilityPolygon.Lee: type Definer p e r = Either p (Point 2 r :+ p, LineSegment 2 p r :+ e)
+ Algorithms.Geometry.VisibilityPolygon.Lee: type StarShapedPolygon p r = SimplePolygon p r
+ Algorithms.Geometry.VisibilityPolygon.Lee: type VisibilityPolygon p e r = StarShapedPolygon (Definer p e r) r
+ Algorithms.Geometry.VisibilityPolygon.Lee: visibilityPolygon :: forall p t r. (Ord r, Fractional r) => Point 2 r -> Polygon t p r -> StarShapedPolygon (Definer p () r) r
+ Algorithms.Geometry.VisibilityPolygon.Lee: visibilitySweep :: forall p r e. (Ord r, Fractional r) => Vector 2 r -> Maybe (Point 2 r) -> Point 2 r -> [LineSegment 2 p r :+ e] -> [Point 2 r :+ Definer p e r]
+ Algorithms.Geometry.WSPD: Level :: Int -> Maybe Int -> Level
+ Algorithms.Geometry.WSPD: NodeData :: !Int -> !Box d () r -> !a -> NodeData d r a
+ Algorithms.Geometry.WSPD: [_unLevel] :: Level -> Int
+ Algorithms.Geometry.WSPD: [_widestDim] :: Level -> Maybe Int
+ Algorithms.Geometry.WSPD: data Level
+ Algorithms.Geometry.WSPD: data NodeData d r a
+ Algorithms.Geometry.WSPD: distributePoints :: (Arity d, Show r, Show p) => Int -> Vector (Maybe Level) -> Vector d (PointSeq d (Idx :+ p) r) -> Vector (Vector d (PointSeq d (Idx :+ p) r))
+ Algorithms.Geometry.WSPD: distributePoints' :: Int -> Vector (Maybe Level) -> PointSeq d (Idx :+ p) r -> Vector (PointSeq d (Idx :+ p) r)
+ Algorithms.Geometry.WSPD: fairSplitTree :: (Fractional r, Ord r, Arity d, 1 <= d, Show r, Show p) => NonEmpty (Point d r :+ p) -> SplitTree d p r ()
+ Algorithms.Geometry.WSPD: nodeData :: forall d_a2zOP r_a2zOQ a_a2zOR a_a2zTy. Lens (NodeData d_a2zOP r_a2zOQ a_a2zOR) (NodeData d_a2zOP r_a2zOQ a_a2zTy) a_a2zOR a_a2zTy
+ Algorithms.Geometry.WSPD: reIndexPoints :: (Arity d, 1 <= d) => Vector d (PointSeq d (Idx :+ p) r) -> Vector d (PointSeq d (Idx :+ p) r)
+ Algorithms.Geometry.WSPD: type SplitTree d p r a = BinLeafTree (NodeData d r a) (Point d r :+ p)
+ Algorithms.Geometry.WSPD: type WSP d p r a = (PointSet d p r a, PointSet d p r a)
+ Algorithms.Geometry.WSPD: wellSeparatedPairs :: (Floating r, Ord r, Arity d, Arity (d + 1)) => r -> SplitTree d p r a -> [WSP d p r a]
+ Data.Geometry: findRotateTo :: ((Point 2 r :+ p) -> Bool) -> SimplePolygon p r -> Maybe (SimplePolygon p r)
+ Data.Geometry: fromCircularVector :: forall p r. (Eq r, Num r) => CircularVector (Point 2 r :+ p) -> SimplePolygon p r
+ Data.Geometry: isSimple :: (Ord r, Fractional r) => Polygon p t r -> Bool
+ Data.Geometry: maximumVertexBy :: ((Point 2 r :+ p) -> (Point 2 r :+ p) -> Ordering) -> Polygon t p r -> Point 2 r :+ p
+ Data.Geometry: minimumVertexBy :: ((Point 2 r :+ p) -> (Point 2 r :+ p) -> Ordering) -> Polygon t p r -> Point 2 r :+ p
+ Data.Geometry: outerBoundaryVector :: forall t p r. Getter (Polygon t p r) (CircularVector (Point 2 r :+ p))
+ Data.Geometry: rotateLeft :: Int -> SimplePolygon p r -> SimplePolygon p r
+ Data.Geometry: rotateRight :: Int -> SimplePolygon p r -> SimplePolygon p r
+ Data.Geometry: sameDirection :: (Eq r, Num r, Arity d) => Vector d r -> Vector d r -> Bool
+ Data.Geometry: simpleFromCircularVector :: forall p r. (Ord r, Fractional r) => CircularVector (Point 2 r :+ p) -> SimplePolygon p r
+ Data.Geometry: simpleFromPoints :: forall p r. (Ord r, Fractional r) => [Point 2 r :+ p] -> SimplePolygon p r
+ Data.Geometry: size :: Polygon t p r -> Int
+ Data.Geometry: toPoints :: Polygon t p r -> [Point 2 r :+ p]
+ Data.Geometry: toVector :: Polygon t p r -> Vector (Point 2 r :+ p)
+ Data.Geometry: unsafeFromCircularVector :: CircularVector (Point 2 r :+ p) -> SimplePolygon p r
+ Data.Geometry: unsafeFromPoints :: [Point 2 r :+ p] -> SimplePolygon p r
+ Data.Geometry: unsafeFromVector :: Vector (Point 2 r :+ p) -> SimplePolygon p r
+ Data.Geometry: unsafeOuterBoundaryVector :: forall t p r. Lens' (Polygon t p r) (CircularVector (Point 2 r :+ p))
+ Data.Geometry.Ball: instance (GHC.Classes.Ord r, GHC.Float.Floating r) => Data.Intersection.IsIntersectableWith (Data.Geometry.LineSegment.Internal.LineSegment 2 p r) (Data.Geometry.Ball.Circle q r)
+ Data.Geometry.Box.Internal: insideBox :: (Arity d, Ord r) => Point d r -> Box d p r -> Bool
+ Data.Geometry.HalfLine: instance (GHC.Classes.Eq r, GHC.Real.Fractional r) => GHC.Classes.Eq (Data.Geometry.HalfLine.HalfLine 2 r)
+ Data.Geometry.HalfLine: instance (GHC.Classes.Ord r, GHC.Real.Fractional r) => Data.Intersection.IsIntersectableWith (Data.Geometry.HalfLine.HalfLine 2 r) (Data.Geometry.Boundary.Boundary (Data.Geometry.Box.Internal.Rectangle p r))
+ Data.Geometry.HalfLine: instance (GHC.Classes.Ord r, GHC.Real.Fractional r) => Data.Intersection.IsIntersectableWith (Data.Geometry.HalfLine.HalfLine 2 r) (Data.Geometry.Box.Internal.Rectangle p r)
+ Data.Geometry.HalfLine: instance (GHC.Classes.Ord r, GHC.Real.Fractional r) => Data.Intersection.IsIntersectableWith (Data.Geometry.HalfLine.HalfLine 2 r) (Data.Geometry.HalfLine.HalfLine 2 r)
+ Data.Geometry.HalfLine: instance (GHC.Classes.Ord r, GHC.Real.Fractional r) => Data.Intersection.IsIntersectableWith (Data.Geometry.HalfLine.HalfLine 2 r) (Data.Geometry.Line.Internal.Line 2 r)
+ Data.Geometry.HalfLine: instance (GHC.Classes.Ord r, GHC.Real.Fractional r) => Data.Intersection.IsIntersectableWith (Data.Geometry.LineSegment.Internal.LineSegment 2 () r) (Data.Geometry.HalfLine.HalfLine 2 r)
+ Data.Geometry.HalfLine: instance (GHC.Classes.Ord r, GHC.Real.Fractional r, Data.Geometry.Vector.VectorFamily.Arity d) => Data.Intersection.IsIntersectableWith (Data.Geometry.Point.Internal.Point d r) (Data.Geometry.HalfLine.HalfLine d r)
+ Data.Geometry.Line.Internal: liesBelow :: (Ord r, Num r) => Point 2 r -> Line 2 r -> Bool
+ Data.Geometry.LineSegment: pattern ClosedRange :: a -> a -> Range a
+ Data.Geometry.LineSegment: pattern OpenRange :: a -> a -> Range a
+ Data.Geometry.LineSegment: pattern Range' :: a -> a -> Range a
+ Data.Geometry.LineSegment: sampleLineSegment :: (Arity d, RandomGen g, Random r) => Rand g (LineSegment d () r)
+ Data.Geometry.LineSegment: sqSegmentLength :: (Arity d, Num r) => LineSegment d p r -> r
+ Data.Geometry.LineSegment: toRange :: Interval a r -> Range (r :+ a)
+ Data.Geometry.LineSegment.Internal: Closed :: !a -> EndPoint a
+ Data.Geometry.LineSegment.Internal: Open :: !a -> EndPoint a
+ Data.Geometry.LineSegment.Internal: Range :: !EndPoint a -> !EndPoint a -> Range a
+ Data.Geometry.LineSegment.Internal: [_lower] :: Range a -> !EndPoint a
+ Data.Geometry.LineSegment.Internal: [_upper] :: Range a -> !EndPoint a
+ Data.Geometry.LineSegment.Internal: _Range :: Iso' (Interval a r) (Range (r :+ a))
+ Data.Geometry.LineSegment.Internal: _SubLine :: (Num r, Arity d) => Iso' (LineSegment d p r) (SubLine d p r r)
+ Data.Geometry.LineSegment.Internal: asProperInterval :: Ord r => Interval p r -> Interval p r
+ Data.Geometry.LineSegment.Internal: clampTo :: Ord r => Range r -> r -> r
+ Data.Geometry.LineSegment.Internal: class HasEnd t where {
+ Data.Geometry.LineSegment.Internal: class HasStart t where {
+ Data.Geometry.LineSegment.Internal: clipLower :: Ord a => EndPoint a -> Range a -> Maybe (Range a)
+ Data.Geometry.LineSegment.Internal: clipUpper :: Ord a => EndPoint a -> Range a -> Maybe (Range a)
+ Data.Geometry.LineSegment.Internal: covers :: Ord a => Range a -> Range a -> Bool
+ Data.Geometry.LineSegment.Internal: data EndPoint a
+ Data.Geometry.LineSegment.Internal: data Interval a r
+ Data.Geometry.LineSegment.Internal: data LineSegment d p r
+ Data.Geometry.LineSegment.Internal: data Range a
+ Data.Geometry.LineSegment.Internal: end :: HasEnd t => Lens' t (EndCore t :+ EndExtra t)
+ Data.Geometry.LineSegment.Internal: endPoints :: Traversal (LineSegment d p r) (LineSegment d' q s) (Point d r :+ p) (Point d' s :+ q)
+ Data.Geometry.LineSegment.Internal: flipInterval :: Interval a r -> Interval a r
+ Data.Geometry.LineSegment.Internal: flipSegment :: LineSegment d p r -> LineSegment d p r
+ Data.Geometry.LineSegment.Internal: fromRange :: Range (r :+ a) -> Interval a r
+ Data.Geometry.LineSegment.Internal: inInterval :: Ord r => r -> Interval a r -> Bool
+ Data.Geometry.LineSegment.Internal: inRange :: Ord a => a -> Range a -> Bool
+ Data.Geometry.LineSegment.Internal: instance (Data.Geometry.Vector.VectorFamily.Arity d, Control.DeepSeq.NFData r, Control.DeepSeq.NFData p) => Control.DeepSeq.NFData (Data.Geometry.LineSegment.Internal.LineSegment d p r)
+ Data.Geometry.LineSegment.Internal: instance (GHC.Classes.Eq r, GHC.Classes.Eq p, Data.Geometry.Vector.VectorFamily.Arity d) => GHC.Classes.Eq (Data.Geometry.LineSegment.Internal.LineSegment d p r)
+ Data.Geometry.LineSegment.Internal: instance (GHC.Classes.Ord r, GHC.Num.Num r) => Data.Intersection.IsIntersectableWith (Data.Geometry.Point.Internal.Point 2 r) (Data.Geometry.LineSegment.Internal.LineSegment 2 p r)
+ Data.Geometry.LineSegment.Internal: instance (GHC.Classes.Ord r, GHC.Real.Fractional r) => Data.Intersection.IsIntersectableWith (Data.Geometry.LineSegment.Internal.LineSegment 2 p r) (Data.Geometry.Line.Internal.Line 2 r)
+ Data.Geometry.LineSegment.Internal: instance (GHC.Classes.Ord r, GHC.Real.Fractional r) => Data.Intersection.IsIntersectableWith (Data.Geometry.LineSegment.Internal.LineSegment 2 p r) (Data.Geometry.LineSegment.Internal.LineSegment 2 p r)
+ Data.Geometry.LineSegment.Internal: instance (GHC.Classes.Ord r, GHC.Real.Fractional r, Data.Geometry.Vector.VectorFamily.Arity d) => Data.Intersection.IsIntersectableWith (Data.Geometry.Point.Internal.Point d r) (Data.Geometry.LineSegment.Internal.LineSegment d p r)
+ Data.Geometry.LineSegment.Internal: instance (GHC.Num.Num r, Data.Geometry.Vector.VectorFamily.Arity d) => Data.Geometry.Line.Internal.HasSupportingLine (Data.Geometry.LineSegment.Internal.LineSegment d p r)
+ Data.Geometry.LineSegment.Internal: instance (GHC.Read.Read r, GHC.Read.Read p, Data.Geometry.Vector.VectorFamily.Arity d) => GHC.Read.Read (Data.Geometry.LineSegment.Internal.LineSegment d p r)
+ Data.Geometry.LineSegment.Internal: instance (GHC.Real.Fractional r, Data.Geometry.Vector.VectorFamily.Arity d, Data.Geometry.Vector.VectorFamily.Arity (d GHC.TypeNats.+ 1)) => Data.Geometry.Transformation.IsTransformable (Data.Geometry.LineSegment.Internal.LineSegment d p r)
+ Data.Geometry.LineSegment.Internal: instance (GHC.Show.Show r, GHC.Show.Show p, Data.Geometry.Vector.VectorFamily.Arity d) => GHC.Show.Show (Data.Geometry.LineSegment.Internal.LineSegment d p r)
+ Data.Geometry.LineSegment.Internal: instance (Test.QuickCheck.Arbitrary.Arbitrary r, Test.QuickCheck.Arbitrary.Arbitrary p, GHC.Classes.Eq r, Data.Geometry.Vector.VectorFamily.Arity d) => Test.QuickCheck.Arbitrary.Arbitrary (Data.Geometry.LineSegment.Internal.LineSegment d p r)
+ Data.Geometry.LineSegment.Internal: instance Data.Geometry.Interval.HasEnd (Data.Geometry.LineSegment.Internal.LineSegment d p r)
+ Data.Geometry.LineSegment.Internal: instance Data.Geometry.Interval.HasStart (Data.Geometry.LineSegment.Internal.LineSegment d p r)
+ Data.Geometry.LineSegment.Internal: instance Data.Geometry.Point.Internal.PointFunctor (Data.Geometry.LineSegment.Internal.LineSegment d p)
+ Data.Geometry.LineSegment.Internal: instance Data.Geometry.Vector.VectorFamily.Arity d => Data.Bifunctor.Bifunctor (Data.Geometry.LineSegment.Internal.LineSegment d)
+ Data.Geometry.LineSegment.Internal: instance Data.Geometry.Vector.VectorFamily.Arity d => Data.Geometry.Box.Internal.IsBoxable (Data.Geometry.LineSegment.Internal.LineSegment d p r)
+ Data.Geometry.LineSegment.Internal: instance Data.Geometry.Vector.VectorFamily.Arity d => GHC.Base.Functor (Data.Geometry.LineSegment.Internal.LineSegment d p)
+ Data.Geometry.LineSegment.Internal: interpolate :: (Fractional r, Arity d) => r -> LineSegment d p r -> Point d r
+ Data.Geometry.LineSegment.Internal: isClosed :: EndPoint a -> Bool
+ Data.Geometry.LineSegment.Internal: isOpen :: EndPoint a -> Bool
+ Data.Geometry.LineSegment.Internal: isValid :: Ord a => Range a -> Bool
+ Data.Geometry.LineSegment.Internal: lower :: Lens' (Range a) (EndPoint a)
+ Data.Geometry.LineSegment.Internal: onSegment :: (Ord r, Fractional r, Arity d) => Point d r -> LineSegment d p r -> Bool
+ Data.Geometry.LineSegment.Internal: onSegment2 :: (Ord r, Num r) => Point 2 r -> LineSegment 2 p r -> Bool
+ Data.Geometry.LineSegment.Internal: orderedEndPoints :: Ord r => LineSegment 2 p r -> (Point 2 r :+ p, Point 2 r :+ p)
+ Data.Geometry.LineSegment.Internal: pattern ClosedInterval :: (r :+ a) -> (r :+ a) -> Interval a r
+ Data.Geometry.LineSegment.Internal: pattern ClosedLineSegment :: (Point d r :+ p) -> (Point d r :+ p) -> LineSegment d p r
+ Data.Geometry.LineSegment.Internal: pattern ClosedRange :: a -> a -> Range a
+ Data.Geometry.LineSegment.Internal: pattern Interval :: EndPoint (r :+ a) -> EndPoint (r :+ a) -> Interval a r
+ Data.Geometry.LineSegment.Internal: pattern LineSegment :: EndPoint (Point d r :+ p) -> EndPoint (Point d r :+ p) -> LineSegment d p r
+ Data.Geometry.LineSegment.Internal: pattern LineSegment' :: (Point d r :+ p) -> (Point d r :+ p) -> LineSegment d p r
+ Data.Geometry.LineSegment.Internal: pattern OpenInterval :: (r :+ a) -> (r :+ a) -> Interval a r
+ Data.Geometry.LineSegment.Internal: pattern OpenLineSegment :: (Point d r :+ p) -> (Point d r :+ p) -> LineSegment d p r
+ Data.Geometry.LineSegment.Internal: pattern OpenRange :: a -> a -> Range a
+ Data.Geometry.LineSegment.Internal: pattern Range' :: a -> a -> Range a
+ Data.Geometry.LineSegment.Internal: prettyShow :: Show a => Range a -> String
+ Data.Geometry.LineSegment.Internal: sampleLineSegment :: (Arity d, RandomGen g, Random r) => Rand g (LineSegment d () r)
+ Data.Geometry.LineSegment.Internal: segmentLength :: (Arity d, Floating r) => LineSegment d p r -> r
+ Data.Geometry.LineSegment.Internal: shiftLeft :: Num r => r -> Range r -> Range r
+ Data.Geometry.LineSegment.Internal: shiftLeft' :: Num r => r -> Interval a r -> Interval a r
+ Data.Geometry.LineSegment.Internal: shiftRight :: Num r => r -> Range r -> Range r
+ Data.Geometry.LineSegment.Internal: sqDistanceToSeg :: (Arity d, Fractional r, Ord r) => Point d r -> LineSegment d p r -> r
+ Data.Geometry.LineSegment.Internal: sqDistanceToSegArg :: (Arity d, Fractional r, Ord r) => Point d r -> LineSegment d p r -> (r, Point d r)
+ Data.Geometry.LineSegment.Internal: sqSegmentLength :: (Arity d, Num r) => LineSegment d p r -> r
+ Data.Geometry.LineSegment.Internal: start :: HasStart t => Lens' t (StartCore t :+ StartExtra t)
+ Data.Geometry.LineSegment.Internal: toLineSegment :: (Monoid p, Num r, Arity d) => Line d r -> LineSegment d p r
+ Data.Geometry.LineSegment.Internal: toRange :: Interval a r -> Range (r :+ a)
+ Data.Geometry.LineSegment.Internal: type family StartExtra t;
+ Data.Geometry.LineSegment.Internal: unEndPoint :: Lens (EndPoint a) (EndPoint b) a b
+ Data.Geometry.LineSegment.Internal: upper :: Lens' (Range a) (EndPoint a)
+ Data.Geometry.LineSegment.Internal: validSegment :: (Eq r, Arity d) => EndPoint (Point d r :+ p) -> EndPoint (Point d r :+ p) -> Maybe (LineSegment d p r)
+ Data.Geometry.LineSegment.Internal: }
+ Data.Geometry.PlanarSubdivision.Basic: data Dart (s :: k)
+ Data.Geometry.PlanarSubdivision.Basic: data PlanarGraph (s :: k) (w :: World) v e f
+ Data.Geometry.PlanarSubdivision.Basic: newtype FaceId (s :: k) (w :: World)
+ Data.Geometry.PlanarSubdivision.Basic: newtype VertexId (s :: k) (w :: World)
+ Data.Geometry.Point: ccwCmpAround' :: (Num r, Ord r) => (Point 2 r :+ qc) -> (Point 2 r :+ p) -> (Point 2 r :+ q) -> Ordering
+ Data.Geometry.Point: ccwCmpAroundWith' :: (Ord r, Num r) => Vector 2 r -> (Point 2 r :+ c) -> (Point 2 r :+ a) -> (Point 2 r :+ b) -> Ordering
+ Data.Geometry.Point: cmpByDistanceTo' :: (Ord r, Num r, Arity d) => (Point d r :+ c) -> (Point d r :+ p) -> (Point d r :+ q) -> Ordering
+ Data.Geometry.Point: cwCmpAround' :: (Num r, Ord r) => (Point 2 r :+ qc) -> (Point 2 r :+ p) -> (Point 2 r :+ q) -> Ordering
+ Data.Geometry.Point: cwCmpAroundWith' :: (Ord r, Num r) => Vector 2 r -> (Point 2 r :+ a) -> (Point 2 r :+ b) -> (Point 2 r :+ c) -> Ordering
+ Data.Geometry.Point: isCoLinear :: (Eq r, Num r) => Point 2 r -> Point 2 r -> Point 2 r -> Bool
+ Data.Geometry.Point: sortAround' :: (Ord r, Num r) => (Point 2 r :+ q) -> [Point 2 r :+ p] -> [Point 2 r :+ p]
+ Data.Geometry.PointLocation.PersistentSweep: In :: InOut
+ Data.Geometry.PointLocation.PersistentSweep: Out :: InOut
+ Data.Geometry.PointLocation.PersistentSweep: PointLocationDS :: VerticalRayShootingStructure v (Dart s) r -> PlanarSubdivision s v e f r -> FaceId' s -> PointLocationDS s v e f r
+ Data.Geometry.PointLocation.PersistentSweep: dartAbove :: (Ord r, Fractional r) => Point 2 r -> PointLocationDS s v e f r -> Maybe (Dart s)
+ Data.Geometry.PointLocation.PersistentSweep: dartAboveOrOn :: (Ord r, Fractional r) => Point 2 r -> PointLocationDS s v e f r -> Maybe (Dart s)
+ Data.Geometry.PointLocation.PersistentSweep: data InOut
+ Data.Geometry.PointLocation.PersistentSweep: data PointLocationDS s v e f r
+ Data.Geometry.PointLocation.PersistentSweep: edgeOnOrAbove :: (Ord r, Fractional r) => Point 2 r -> InPolygonDS v r -> Maybe (LineSegment 2 (SP Int v) r)
+ Data.Geometry.PointLocation.PersistentSweep: faceContaining :: (Ord r, Fractional r) => Point 2 r -> PointLocationDS s v e f r -> f
+ Data.Geometry.PointLocation.PersistentSweep: faceIdContaining :: (Ord r, Fractional r) => Point 2 r -> PointLocationDS s v e f r -> FaceId' s
+ Data.Geometry.PointLocation.PersistentSweep: inPolygonDS :: (Fractional r, Ord r) => SimplePolygon v r -> InPolygonDS v r
+ Data.Geometry.PointLocation.PersistentSweep: instance Data.Foldable.Foldable Data.Geometry.PointLocation.PersistentSweep.OneOrTwo
+ Data.Geometry.PointLocation.PersistentSweep: instance Data.Traversable.Traversable Data.Geometry.PointLocation.PersistentSweep.OneOrTwo
+ Data.Geometry.PointLocation.PersistentSweep: instance GHC.Base.Functor Data.Geometry.PointLocation.PersistentSweep.OneOrTwo
+ Data.Geometry.PointLocation.PersistentSweep: instance GHC.Classes.Eq Data.Geometry.PointLocation.PersistentSweep.InOut
+ Data.Geometry.PointLocation.PersistentSweep: instance GHC.Classes.Eq a => GHC.Classes.Eq (Data.Geometry.PointLocation.PersistentSweep.OneOrTwo a)
+ Data.Geometry.PointLocation.PersistentSweep: instance GHC.Classes.Ord a => GHC.Classes.Ord (Data.Geometry.PointLocation.PersistentSweep.OneOrTwo a)
+ Data.Geometry.PointLocation.PersistentSweep: instance GHC.Read.Read a => GHC.Read.Read (Data.Geometry.PointLocation.PersistentSweep.OneOrTwo a)
+ Data.Geometry.PointLocation.PersistentSweep: instance GHC.Show.Show Data.Geometry.PointLocation.PersistentSweep.InOut
+ Data.Geometry.PointLocation.PersistentSweep: instance GHC.Show.Show a => GHC.Show.Show (Data.Geometry.PointLocation.PersistentSweep.OneOrTwo a)
+ Data.Geometry.PointLocation.PersistentSweep: instance forall k (s :: k) v e f r. (GHC.Classes.Eq r, GHC.Classes.Eq v, GHC.Classes.Eq e, GHC.Classes.Eq f) => GHC.Classes.Eq (Data.Geometry.PointLocation.PersistentSweep.PointLocationDS s v e f r)
+ Data.Geometry.PointLocation.PersistentSweep: instance forall k (s :: k) v e f r. (GHC.Show.Show r, GHC.Show.Show v, GHC.Show.Show e, GHC.Show.Show f) => GHC.Show.Show (Data.Geometry.PointLocation.PersistentSweep.PointLocationDS s v e f r)
+ Data.Geometry.PointLocation.PersistentSweep: outerFace :: forall k_a3jMS (s_a3jMD :: k_a3jMS) v_a3jME e_a3jMF f_a3jMG r_a3jMH. Getter (PointLocationDS (s_a3jMD :: k_a3jMS) v_a3jME e_a3jMF f_a3jMG r_a3jMH) (FaceId' s_a3jMD)
+ Data.Geometry.PointLocation.PersistentSweep: pointInPolygon :: (Ord r, Fractional r) => Point 2 r -> InPolygonDS v r -> InOut
+ Data.Geometry.PointLocation.PersistentSweep: pointLocationDS :: (Ord r, Fractional r) => PlanarSubdivision s v e f r -> PointLocationDS s v e f r
+ Data.Geometry.PointLocation.PersistentSweep: subdivision :: forall k_a3jMS (s_a3jMD :: k_a3jMS) v_a3jME e_a3jMF f_a3jMG r_a3jMH. Getter (PointLocationDS (s_a3jMD :: k_a3jMS) v_a3jME e_a3jMF f_a3jMG r_a3jMH) (PlanarSubdivision s_a3jMD v_a3jME e_a3jMF f_a3jMG r_a3jMH)
+ Data.Geometry.PointLocation.PersistentSweep: type InPolygonDS v r = PointLocationDS Dummy (SP Int v) () InOut r
+ Data.Geometry.PointLocation.PersistentSweep: verticalRayShootingStructure :: forall k_a3jMS (s_a3jMD :: k_a3jMS) v_a3jME e_a3jMF f_a3jMG r_a3jMH. Getter (PointLocationDS (s_a3jMD :: k_a3jMS) v_a3jME e_a3jMF f_a3jMG r_a3jMH) (VerticalRayShootingStructure v_a3jME (Dart s_a3jMD) r_a3jMH)
+ Data.Geometry.PolyLine: instance Data.Geometry.Interval.HasEnd (Data.Geometry.PolyLine.PolyLine d p r)
+ Data.Geometry.PolyLine: instance Data.Geometry.Interval.HasStart (Data.Geometry.PolyLine.PolyLine d p r)
+ Data.Geometry.Polygon: findRotateTo :: ((Point 2 r :+ p) -> Bool) -> SimplePolygon p r -> Maybe (SimplePolygon p r)
+ Data.Geometry.Polygon: fromCircularVector :: forall p r. (Eq r, Num r) => CircularVector (Point 2 r :+ p) -> SimplePolygon p r
+ Data.Geometry.Polygon: instance (GHC.Real.Fractional r, GHC.Classes.Ord r) => Data.Intersection.IsIntersectableWith (Data.Geometry.Point.Internal.Point 2 r) (Data.Geometry.Polygon.Core.Polygon t p r)
+ Data.Geometry.Polygon: isSimple :: (Ord r, Fractional r) => Polygon p t r -> Bool
+ Data.Geometry.Polygon: maximumVertexBy :: ((Point 2 r :+ p) -> (Point 2 r :+ p) -> Ordering) -> Polygon t p r -> Point 2 r :+ p
+ Data.Geometry.Polygon: minimumVertexBy :: ((Point 2 r :+ p) -> (Point 2 r :+ p) -> Ordering) -> Polygon t p r -> Point 2 r :+ p
+ Data.Geometry.Polygon: outerBoundaryVector :: forall t p r. Getter (Polygon t p r) (CircularVector (Point 2 r :+ p))
+ Data.Geometry.Polygon: rotateLeft :: Int -> SimplePolygon p r -> SimplePolygon p r
+ Data.Geometry.Polygon: rotateRight :: Int -> SimplePolygon p r -> SimplePolygon p r
+ Data.Geometry.Polygon: simpleFromCircularVector :: forall p r. (Ord r, Fractional r) => CircularVector (Point 2 r :+ p) -> SimplePolygon p r
+ Data.Geometry.Polygon: simpleFromPoints :: forall p r. (Ord r, Fractional r) => [Point 2 r :+ p] -> SimplePolygon p r
+ Data.Geometry.Polygon: size :: Polygon t p r -> Int
+ Data.Geometry.Polygon: toPoints :: Polygon t p r -> [Point 2 r :+ p]
+ Data.Geometry.Polygon: toVector :: Polygon t p r -> Vector (Point 2 r :+ p)
+ Data.Geometry.Polygon: unsafeFromCircularVector :: CircularVector (Point 2 r :+ p) -> SimplePolygon p r
+ Data.Geometry.Polygon: unsafeFromPoints :: [Point 2 r :+ p] -> SimplePolygon p r
+ Data.Geometry.Polygon: unsafeFromVector :: Vector (Point 2 r :+ p) -> SimplePolygon p r
+ Data.Geometry.Polygon: unsafeOuterBoundaryVector :: forall t p r. Lens' (Polygon t p r) (CircularVector (Point 2 r :+ p))
+ Data.Geometry.Polygon.Convex: convexPolygon :: forall t p r. (Ord r, Num r, Show r, Show p) => Polygon t p r -> ConvexPolygon p r
+ Data.Geometry.Polygon.Convex: diameter :: (Ord r, Floating r) => ConvexPolygon p r -> r
+ Data.Geometry.Polygon.Convex: diametralIndexPair :: (Ord r, Num r) => ConvexPolygon p r -> (Int, Int)
+ Data.Geometry.Polygon.Convex: diametralPair :: (Ord r, Num r) => ConvexPolygon p r -> (Point 2 r :+ p, Point 2 r :+ p)
+ Data.Geometry.Polygon.Convex: inConvex :: forall p r. (Fractional r, Ord r) => Point 2 r -> ConvexPolygon p r -> PointLocationResult
+ Data.Geometry.Polygon.Convex: isConvex :: (Ord r, Num r) => SimplePolygon p r -> Bool
+ Data.Geometry.Polygon.Convex: randomConvex :: RandomGen g => Int -> Int -> Rand g (ConvexPolygon () Rational)
+ Data.Geometry.Polygon.Convex: verifyConvex :: (Ord r, Num r) => ConvexPolygon p r -> Bool
+ Data.Geometry.Polygon.Inflate: Arc :: Point 2 r -> (Point 2 r, Point 2 r) -> Arc r
+ Data.Geometry.Polygon.Inflate: [arcCenter] :: Arc r -> Point 2 r
+ Data.Geometry.Polygon.Inflate: [arcEdge] :: Arc r -> (Point 2 r, Point 2 r)
+ Data.Geometry.Polygon.Inflate: data Arc r
+ Data.Geometry.Polygon.Inflate: inflate :: (Real r, Fractional r) => Double -> SimplePolygon () r -> SimplePolygon (Arc r) r
+ Data.Geometry.Polygon.Inflate: instance GHC.Show.Show r => GHC.Show.Show (Data.Geometry.Polygon.Inflate.Arc r)
+ Data.Geometry.Polygon.Monotone: isMonotone :: (Fractional r, Ord r) => Vector 2 r -> SimplePolygon p r -> Bool
+ Data.Geometry.Polygon.Monotone: monotoneFrom :: (Ord r, Num r) => Vector 2 r -> [Point 2 r] -> SimplePolygon () r
+ Data.Geometry.Polygon.Monotone: randomMonotone :: (RandomGen g, Random r, Ord r, Num r) => Int -> Rand g (SimplePolygon () r)
+ Data.Geometry.Polygon.Monotone: randomMonotoneDirected :: (RandomGen g, Random r, Ord r, Num r) => Int -> Vector 2 r -> Rand g (SimplePolygon () r)
+ Data.Geometry.Polygon.Monotone: randomNonZeroVector :: (RandomGen g, Random r, Eq r, Num r) => Rand g (Vector 2 r)
+ Data.Geometry.RangeTree: instance (1 GHC.TypeNats.<= d, i GHC.TypeNats.<= d, Data.Geometry.RangeTree.Query (i GHC.TypeNats.- 1) d, Data.Geometry.Vector.VectorFamily.Arity d, i GHC.Types.~ 2) => Data.Geometry.RangeTree.Query 2 d
+ Data.Geometry.RangeTree: instance forall k1 k2 r p (d :: GHC.Types.Nat) (i :: k1) (v :: k2). (GHC.Classes.Eq r, GHC.Classes.Eq p, Data.Geometry.Vector.VectorFamily.Arity d) => GHC.Classes.Eq (Data.Geometry.RangeTree.Leaf i d v p r)
+ Data.Geometry.RangeTree: instance forall k1 k2 r p (d :: GHC.Types.Nat) (i :: k1) (v :: k2). (GHC.Show.Show r, GHC.Show.Show p, Data.Geometry.Vector.VectorFamily.Arity d) => GHC.Show.Show (Data.Geometry.RangeTree.Leaf i d v p r)
+ Data.Geometry.Slab: instance (GHC.Real.Fractional r, GHC.Classes.Ord r, Data.Geometry.Slab.HasBoundingLines o) => Data.Intersection.IsIntersectableWith (Data.Geometry.LineSegment.Internal.LineSegment 2 a r) (Data.Geometry.Slab.Slab o a r)
+ Data.Geometry.Triangle: inTriangleRelaxed :: (Ord r, Num r) => Point 2 r -> Triangle 2 p r -> PointLocationResult
+ Data.Geometry.Triangle: instance (Data.Geometry.Vector.VectorFamily.Arity d, GHC.Classes.Ord r) => Data.Geometry.Box.Internal.IsBoxable (Data.Geometry.Triangle.Triangle d p r)
+ Data.Geometry.Triangle: onTriangleRelaxed :: (Ord r, Num r) => Point 2 r -> Triangle 2 p r -> Bool
+ Data.Geometry.Vector: instance Data.Geometry.Vector.VectorFamily.Arity d => Test.QuickCheck.Arbitrary.Arbitrary1 (Data.Geometry.Vector.VectorFamily.Vector d)
+ Data.Geometry.Vector: sameDirection :: (Eq r, Num r, Arity d) => Vector d r -> Vector d r -> Bool
+ Data.Geometry.Vector.VectorFamily: instance (GHC.Show.Show r, Data.Geometry.Vector.VectorFamily.Arity d) => GHC.Show.Show (Data.Geometry.Vector.VectorFamily.Vector d r)
+ Data.Geometry.Vector.VectorFamily: instance Data.Geometry.Vector.VectorFamily.Arity d => Data.Functor.Classes.Eq1 (Data.Geometry.Vector.VectorFamily.Vector d)
+ Data.Geometry.Vector.VectorFamily: instance Data.Geometry.Vector.VectorFamily.Arity d => Data.Functor.Classes.Read1 (Data.Geometry.Vector.VectorFamily.Vector d)
+ Data.Geometry.Vector.VectorFamily: instance Data.Geometry.Vector.VectorFamily.Arity d => Data.Functor.Classes.Show1 (Data.Geometry.Vector.VectorFamily.Vector d)
+ Data.Geometry.Vector.VectorFamily: instance Data.Geometry.Vector.VectorFamily.Arity d => WithIndex.FoldableWithIndex GHC.Types.Int (Data.Geometry.Vector.VectorFamily.Vector d)
+ Data.Geometry.Vector.VectorFamily: instance Data.Geometry.Vector.VectorFamily.Arity d => WithIndex.FunctorWithIndex GHC.Types.Int (Data.Geometry.Vector.VectorFamily.Vector d)
+ Data.Geometry.Vector.VectorFamily: instance Data.Geometry.Vector.VectorFamily.Arity d => WithIndex.TraversableWithIndex GHC.Types.Int (Data.Geometry.Vector.VectorFamily.Vector d)
+ Data.Geometry.Vector.VectorFamilyPeano: instance Data.Geometry.Vector.VectorFamilyPeano.ImplicitArity d => Data.Functor.Classes.Eq1 (Data.Geometry.Vector.VectorFamilyPeano.VectorFamily d)
+ Data.Geometry.Vector.VectorFixed: instance Data.Vector.Fixed.Cont.Arity d => Data.Functor.Classes.Eq1 (Data.Geometry.Vector.VectorFixed.Vector d)
+ Data.Geometry.VerticalRayShooting.PersistentSweep: VerticalRayShootingStructure :: r -> Vector (r :+ StatusStructure p e r) -> VerticalRayShootingStructure p e r
+ Data.Geometry.VerticalRayShooting.PersistentSweep: data VerticalRayShootingStructure p e r
+ Data.Geometry.VerticalRayShooting.PersistentSweep: findSlab :: Ord r => Point 2 r -> VerticalRayShootingStructure p e r -> Maybe (StatusStructure p e r)
+ Data.Geometry.VerticalRayShooting.PersistentSweep: instance (GHC.Classes.Eq r, GHC.Classes.Eq p, GHC.Classes.Eq e) => GHC.Classes.Eq (Data.Geometry.VerticalRayShooting.PersistentSweep.VerticalRayShootingStructure p e r)
+ Data.Geometry.VerticalRayShooting.PersistentSweep: instance (GHC.Show.Show r, GHC.Show.Show p, GHC.Show.Show e) => GHC.Show.Show (Data.Geometry.VerticalRayShooting.PersistentSweep.VerticalRayShootingStructure p e r)
+ Data.Geometry.VerticalRayShooting.PersistentSweep: instance GHC.Classes.Eq a => GHC.Classes.Eq (Data.Geometry.VerticalRayShooting.PersistentSweep.Action a)
+ Data.Geometry.VerticalRayShooting.PersistentSweep: instance GHC.Show.Show a => GHC.Show.Show (Data.Geometry.VerticalRayShooting.PersistentSweep.Action a)
+ Data.Geometry.VerticalRayShooting.PersistentSweep: leftMost :: forall p_a2Sdd e_a2Sde r_a2Sdf. Getter (VerticalRayShootingStructure p_a2Sdd e_a2Sde r_a2Sdf) r_a2Sdf
+ Data.Geometry.VerticalRayShooting.PersistentSweep: lookupAbove :: (Ord r, Num r) => Point 2 r -> StatusStructure p e r -> Maybe (LineSegment 2 p r :+ e)
+ Data.Geometry.VerticalRayShooting.PersistentSweep: lookupAboveOrOn :: (Ord r, Num r) => Point 2 r -> StatusStructure p e r -> Maybe (LineSegment 2 p r :+ e)
+ Data.Geometry.VerticalRayShooting.PersistentSweep: ordAt :: (Fractional r, Ord r) => r -> Compare (LineSegment 2 p r :+ e)
+ Data.Geometry.VerticalRayShooting.PersistentSweep: searchInSlab :: Num r => (Line 2 r -> Bool) -> StatusStructure p e r -> Maybe (LineSegment 2 p r :+ e)
+ Data.Geometry.VerticalRayShooting.PersistentSweep: segmentAbove :: (Ord r, Num r) => Point 2 r -> VerticalRayShootingStructure p e r -> Maybe (LineSegment 2 p r :+ e)
+ Data.Geometry.VerticalRayShooting.PersistentSweep: segmentAboveOrOn :: (Ord r, Num r) => Point 2 r -> VerticalRayShootingStructure p e r -> Maybe (LineSegment 2 p r :+ e)
+ Data.Geometry.VerticalRayShooting.PersistentSweep: sweepStruct :: forall p_a2Sdd e_a2Sde r_a2Sdf. Getter (VerticalRayShootingStructure p_a2Sdd e_a2Sde r_a2Sdf) (Vector ((:+) r_a2Sdf (StatusStructure p_a2Sdd e_a2Sde r_a2Sdf)))
+ Data.Geometry.VerticalRayShooting.PersistentSweep: type StatusStructure p e r = Set (LineSegment 2 p r :+ e)
+ Data.Geometry.VerticalRayShooting.PersistentSweep: verticalRayShootingStructure :: (Ord r, Fractional r, Foldable1 t) => t (LineSegment 2 p r :+ e) -> VerticalRayShootingStructure p e r
+ Data.Geometry.VerticalRayShooting.PersistentSweep: yCoordAt :: (Fractional r, Ord r) => r -> (LineSegment 2 p r :+ e) -> r
+ Data.PlaneGraph: data Dart (s :: k)
+ Data.PlaneGraph: data PlanarGraph (s :: k) (w :: World) v e f
+ Data.PlaneGraph: newtype FaceId (s :: k) (w :: World)
+ Data.PlaneGraph: newtype VertexId (s :: k) (w :: World)
+ Data.PlaneGraph.Core: data Dart (s :: k)
+ Data.PlaneGraph.Core: data PlanarGraph (s :: k) (w :: World) v e f
+ Data.PlaneGraph.Core: newtype FaceId (s :: k) (w :: World)
+ Data.PlaneGraph.Core: newtype VertexId (s :: k) (w :: World)
- Algorithms.Geometry.DelaunayTriangulation.Types: neighbours :: forall p_a3yrK r_a3yrL. Lens' (Triangulation p_a3yrK r_a3yrL) (Vector (CList VertexID))
+ Algorithms.Geometry.DelaunayTriangulation.Types: neighbours :: Lens' (Triangulation p r) (Vector (CList VertexID))
- Algorithms.Geometry.DelaunayTriangulation.Types: positions :: forall p_a3yrK r_a3yrL p_a3ywF. Lens (Triangulation p_a3yrK r_a3yrL) (Triangulation p_a3ywF r_a3yrL) (Vector ((:+) (Point 2 r_a3yrL) p_a3yrK)) (Vector ((:+) (Point 2 r_a3yrL) p_a3ywF))
+ Algorithms.Geometry.DelaunayTriangulation.Types: positions :: Lens (Triangulation p1 r) (Triangulation p2 r) (Vector (Point 2 r :+ p1)) (Vector (Point 2 r :+ p2))
- Algorithms.Geometry.DelaunayTriangulation.Types: vertexIds :: forall p_a3yrK r_a3yrL. Lens' (Triangulation p_a3yrK r_a3yrL) (Map (Point 2 r_a3yrL) VertexID)
+ Algorithms.Geometry.DelaunayTriangulation.Types: vertexIds :: Lens' (Triangulation p r) (Map (Point 2 r) VertexID)
- Algorithms.Geometry.LinearProgramming.Types: _NoSolution :: forall d_a2O97 r_a2O98. Prism' (LPSolution d_a2O97 r_a2O98) ()
+ Algorithms.Geometry.LinearProgramming.Types: _NoSolution :: forall d_a2Eg4 r_a2Eg5. Prism' (LPSolution d_a2Eg4 r_a2Eg5) ()
- Algorithms.Geometry.LinearProgramming.Types: _Single :: forall d_a2O97 r_a2O98. Prism' (LPSolution d_a2O97 r_a2O98) (Point d_a2O97 r_a2O98)
+ Algorithms.Geometry.LinearProgramming.Types: _Single :: forall d_a2Eg4 r_a2Eg5. Prism' (LPSolution d_a2Eg4 r_a2Eg5) (Point d_a2Eg4 r_a2Eg5)
- Algorithms.Geometry.LinearProgramming.Types: _UnBounded :: forall d_a2O97 r_a2O98. Prism' (LPSolution d_a2O97 r_a2O98) (HalfLine d_a2O97 r_a2O98)
+ Algorithms.Geometry.LinearProgramming.Types: _UnBounded :: forall d_a2Eg4 r_a2Eg5. Prism' (LPSolution d_a2Eg4 r_a2Eg5) (HalfLine d_a2Eg4 r_a2Eg5)
- Algorithms.Geometry.LinearProgramming.Types: constraints :: forall d_a2Oaq r_a2Oar. Lens' (LinearProgram d_a2Oaq r_a2Oar) [HalfSpace d_a2Oaq r_a2Oar]
+ Algorithms.Geometry.LinearProgramming.Types: constraints :: forall d_a2Ehg r_a2Ehh. Lens' (LinearProgram d_a2Ehg r_a2Ehh) [HalfSpace d_a2Ehg r_a2Ehh]
- Algorithms.Geometry.LinearProgramming.Types: objective :: forall d_a2Oaq r_a2Oar. Lens' (LinearProgram d_a2Oaq r_a2Oar) (Vector d_a2Oaq r_a2Oar)
+ Algorithms.Geometry.LinearProgramming.Types: objective :: forall d_a2Ehg r_a2Ehh. Lens' (LinearProgram d_a2Ehg r_a2Ehh) (Vector d_a2Ehg r_a2Ehh)
- Algorithms.Geometry.WellSeparatedPairDecomposition.Types: bBox :: forall d_a2JkP r_a2JkQ a_a2JkR d_a2JpH r_a2JpI. Lens (NodeData d_a2JkP r_a2JkQ a_a2JkR) (NodeData d_a2JpH r_a2JpI a_a2JkR) (Box d_a2JkP () r_a2JkQ) (Box d_a2JpH () r_a2JpI)
+ Algorithms.Geometry.WellSeparatedPairDecomposition.Types: bBox :: forall d_a2zOP r_a2zOQ a_a2zOR d_a2zTw r_a2zTx. Lens (NodeData d_a2zOP r_a2zOQ a_a2zOR) (NodeData d_a2zTw r_a2zTx a_a2zOR) (Box d_a2zOP () r_a2zOQ) (Box d_a2zTw () r_a2zTx)
- Algorithms.Geometry.WellSeparatedPairDecomposition.Types: leftPart :: forall d_a2JBS r_a2JBT p_a2JBU. Lens' (FindAndCompact d_a2JBS r_a2JBT p_a2JBU) (Seq ((:+) (Point d_a2JBS r_a2JBT) p_a2JBU))
+ Algorithms.Geometry.WellSeparatedPairDecomposition.Types: leftPart :: forall d_a2A5J r_a2A5K p_a2A5L. Lens' (FindAndCompact d_a2A5J r_a2A5K p_a2A5L) (Seq ((:+) (Point d_a2A5J r_a2A5K) p_a2A5L))
- Algorithms.Geometry.WellSeparatedPairDecomposition.Types: nodeData :: forall d_a2JkP r_a2JkQ a_a2JkR a_a2JpJ. Lens (NodeData d_a2JkP r_a2JkQ a_a2JkR) (NodeData d_a2JkP r_a2JkQ a_a2JpJ) a_a2JkR a_a2JpJ
+ Algorithms.Geometry.WellSeparatedPairDecomposition.Types: nodeData :: forall d_a2zOP r_a2zOQ a_a2zOR a_a2zTy. Lens (NodeData d_a2zOP r_a2zOQ a_a2zOR) (NodeData d_a2zOP r_a2zOQ a_a2zTy) a_a2zOR a_a2zTy
- Algorithms.Geometry.WellSeparatedPairDecomposition.Types: rightPart :: forall d_a2JBS r_a2JBT p_a2JBU. Lens' (FindAndCompact d_a2JBS r_a2JBT p_a2JBU) (Seq ((:+) (Point d_a2JBS r_a2JBT) p_a2JBU))
+ Algorithms.Geometry.WellSeparatedPairDecomposition.Types: rightPart :: forall d_a2A5J r_a2A5K p_a2A5L. Lens' (FindAndCompact d_a2A5J r_a2A5K p_a2A5L) (Seq ((:+) (Point d_a2A5J r_a2A5K) p_a2A5L))
- Algorithms.Geometry.WellSeparatedPairDecomposition.Types: shortSide :: forall d_a2JBS r_a2JBT p_a2JBU. Lens' (FindAndCompact d_a2JBS r_a2JBT p_a2JBU) ShortSide
+ Algorithms.Geometry.WellSeparatedPairDecomposition.Types: shortSide :: forall d_a2A5J r_a2A5K p_a2A5L. Lens' (FindAndCompact d_a2A5J r_a2A5K p_a2A5L) ShortSide
- Algorithms.Geometry.WellSeparatedPairDecomposition.Types: splitDim :: forall d_a2JkP r_a2JkQ a_a2JkR. Lens' (NodeData d_a2JkP r_a2JkQ a_a2JkR) Int
+ Algorithms.Geometry.WellSeparatedPairDecomposition.Types: splitDim :: forall d_a2zOP r_a2zOQ a_a2zOR. Lens' (NodeData d_a2zOP r_a2zOQ a_a2zOR) Int
- Data.Geometry: C :: C
+ Data.Geometry: C :: C (n :: Nat)
- Data.Geometry: MKVector :: VectorFamily (Peano d) r -> Vector
+ Data.Geometry: MKVector :: VectorFamily (Peano d) r -> Vector (d :: Nat) (r :: *)
- Data.Geometry: [MultiPolygon] :: CSeq (Point 2 r :+ p) -> [Polygon Simple p r] -> Polygon Multi p r
+ Data.Geometry: [MultiPolygon] :: SimplePolygon p r -> [SimplePolygon p r] -> MultiPolygon p r
- Data.Geometry: [SimplePolygon] :: CSeq (Point 2 r :+ p) -> Polygon Simple p r
+ Data.Geometry: [SimplePolygon] :: Vertices (Point 2 r :+ p) -> SimplePolygon p r
- Data.Geometry: [_unV] :: Vector -> VectorFamily (Peano d) r
+ Data.Geometry: [_unV] :: Vector (d :: Nat) (r :: *) -> VectorFamily (Peano d) r
- Data.Geometry: _MultiPolygon :: Prism' (Polygon Multi p r) (CSeq (Point 2 r :+ p), [Polygon Simple p r])
+ Data.Geometry: _MultiPolygon :: Prism' (Polygon Multi p r) (Polygon Simple p r, [Polygon Simple p r])
- Data.Geometry: _SimplePolygon :: Prism' (Polygon Simple p r) (CSeq (Point 2 r :+ p))
+ Data.Geometry: _SimplePolygon :: Prism' (Polygon Simple p r) (Vertices (Point 2 r :+ p))
- Data.Geometry: infixl 6 ^-^
+ Data.Geometry: infixl 6 ^+^
- Data.Geometry: isCounterClockwise :: (Eq r, Fractional r) => Polygon t p r -> Bool
+ Data.Geometry: isCounterClockwise :: (Eq r, Num r) => Polygon t p r -> Bool
- Data.Geometry: onBoundary :: (Fractional r, Ord r) => Point 2 r -> Polygon t p r -> Bool
+ Data.Geometry: onBoundary :: (Num r, Ord r) => Point 2 r -> Polygon t p r -> Bool
- Data.Geometry: outerBoundary :: forall t p r. Lens' (Polygon t p r) (CSeq (Point 2 r :+ p))
+ Data.Geometry: outerBoundary :: forall t p r. Lens' (Polygon t p r) (SimplePolygon p r)
- Data.Geometry: outerBoundaryEdges :: Polygon t p r -> CSeq (LineSegment 2 p r)
+ Data.Geometry: outerBoundaryEdges :: Polygon t p r -> CircularVector (LineSegment 2 p r)
- Data.Geometry: outerVertex :: Int -> Lens' (Polygon t p r) (Point 2 r :+ p)
+ Data.Geometry: outerVertex :: Int -> Getter (Polygon t p r) (Point 2 r :+ p)
- Data.Geometry: points :: forall d_a22fG p_a22fH r_a22fI d_a22hP p_a22hQ r_a22hR. Iso (PolyLine d_a22fG p_a22fH r_a22fI) (PolyLine d_a22hP p_a22hQ r_a22hR) (LSeq 2 ((:+) (Point d_a22fG r_a22fI) p_a22fH)) (LSeq 2 ((:+) (Point d_a22hP r_a22hR) p_a22hQ))
+ Data.Geometry: points :: Iso (PolyLine d1 p1 r1) (PolyLine d2 p2 r2) (LSeq 2 (Point d1 r1 :+ p1)) (LSeq 2 (Point d2 r2 :+ p2))
- Data.Geometry: toClockwiseOrder :: (Eq r, Fractional r) => Polygon t p r -> Polygon t p r
+ Data.Geometry: toClockwiseOrder :: (Eq r, Num r) => Polygon t p r -> Polygon t p r
- Data.Geometry: toClockwiseOrder' :: (Eq r, Fractional r) => Polygon t p r -> Polygon t p r
+ Data.Geometry: toClockwiseOrder' :: (Eq r, Num r) => Polygon t p r -> Polygon t p r
- Data.Geometry: toCounterClockWiseOrder :: (Eq r, Fractional r) => Polygon t p r -> Polygon t p r
+ Data.Geometry: toCounterClockWiseOrder :: (Eq r, Num r) => Polygon t p r -> Polygon t p r
- Data.Geometry: toCounterClockWiseOrder' :: (Eq r, Fractional r) => Polygon t p r -> Polygon t p r
+ Data.Geometry: toCounterClockWiseOrder' :: (Eq r, Num r) => Polygon t p r -> Polygon t p r
- Data.Geometry: unV :: Lens (Vector d r) (Vector d s) (VectorFamily (Peano d) r) (VectorFamily (Peano d) s)
+ Data.Geometry: unV :: Iso (Vector d r) (Vector d s) (VectorFamily (Peano d) r) (VectorFamily (Peano d) s)
- Data.Geometry.Arrangement: boundedArea :: forall s_a3nHW l_a3nHX v_a3nHY e_a3nHZ f_a3nI0 r_a3nI1. Lens' (Arrangement s_a3nHW l_a3nHX v_a3nHY e_a3nHZ f_a3nI0 r_a3nI1) (Rectangle () r_a3nI1)
+ Data.Geometry.Arrangement: boundedArea :: forall k_a3n3p (s_a3n2V :: k_a3n3p) l_a3n2W v_a3n2X e_a3n2Y f_a3n2Z r_a3n30. Lens' (Arrangement (s_a3n2V :: k_a3n3p) l_a3n2W v_a3n2X e_a3n2Y f_a3n2Z r_a3n30) (Rectangle () r_a3n30)
- Data.Geometry.Arrangement: inputLines :: forall s_a3nHW l_a3nHX v_a3nHY e_a3nHZ f_a3nI0 r_a3nI1. Lens' (Arrangement s_a3nHW l_a3nHX v_a3nHY e_a3nHZ f_a3nI0 r_a3nI1) (Vector ((:+) (Line 2 r_a3nI1) l_a3nHX))
+ Data.Geometry.Arrangement: inputLines :: forall k_a3n3p (s_a3n2V :: k_a3n3p) l_a3n2W v_a3n2X e_a3n2Y f_a3n2Z r_a3n30. Lens' (Arrangement (s_a3n2V :: k_a3n3p) l_a3n2W v_a3n2X e_a3n2Y f_a3n2Z r_a3n30) (Vector ((:+) (Line 2 r_a3n30) l_a3n2W))
- Data.Geometry.Arrangement: subdivision :: forall s_a3nHW l_a3nHX v_a3nHY e_a3nHZ f_a3nI0 r_a3nI1 v_a3nPK e_a3nPL f_a3nPM. Lens (Arrangement s_a3nHW l_a3nHX v_a3nHY e_a3nHZ f_a3nI0 r_a3nI1) (Arrangement s_a3nHW l_a3nHX v_a3nPK e_a3nPL f_a3nPM r_a3nI1) (PlanarSubdivision s_a3nHW v_a3nHY e_a3nHZ f_a3nI0 r_a3nI1) (PlanarSubdivision s_a3nHW v_a3nPK e_a3nPL f_a3nPM r_a3nI1)
+ Data.Geometry.Arrangement: subdivision :: forall k_a3n3p (s_a3n2V :: k_a3n3p) l_a3n2W v_a3n2X e_a3n2Y f_a3n2Z r_a3n30 v_a3naC e_a3naD f_a3naE. Lens (Arrangement (s_a3n2V :: k_a3n3p) l_a3n2W v_a3n2X e_a3n2Y f_a3n2Z r_a3n30) (Arrangement (s_a3n2V :: k_a3n3p) l_a3n2W v_a3naC e_a3naD f_a3naE r_a3n30) (PlanarSubdivision s_a3n2V v_a3n2X e_a3n2Y f_a3n2Z r_a3n30) (PlanarSubdivision s_a3n2V v_a3naC e_a3naD f_a3naE r_a3n30)
- Data.Geometry.Arrangement: unboundedIntersections :: forall s_a3nHW l_a3nHX v_a3nHY e_a3nHZ f_a3nI0 r_a3nI1. Lens' (Arrangement s_a3nHW l_a3nHX v_a3nHY e_a3nHZ f_a3nI0 r_a3nI1) (ArrangementBoundary s_a3nHW l_a3nHX r_a3nI1)
+ Data.Geometry.Arrangement: unboundedIntersections :: forall k_a3n3p (s_a3n2V :: k_a3n3p) l_a3n2W v_a3n2X e_a3n2Y f_a3n2Z r_a3n30. Lens' (Arrangement (s_a3n2V :: k_a3n3p) l_a3n2W v_a3n2X e_a3n2Y f_a3n2Z r_a3n30) (ArrangementBoundary s_a3n2V l_a3n2W r_a3n30)
- Data.Geometry.Arrangement.Internal: boundedArea :: forall s_a3nHW l_a3nHX v_a3nHY e_a3nHZ f_a3nI0 r_a3nI1. Lens' (Arrangement s_a3nHW l_a3nHX v_a3nHY e_a3nHZ f_a3nI0 r_a3nI1) (Rectangle () r_a3nI1)
+ Data.Geometry.Arrangement.Internal: boundedArea :: forall k_a3n3p (s_a3n2V :: k_a3n3p) l_a3n2W v_a3n2X e_a3n2Y f_a3n2Z r_a3n30. Lens' (Arrangement (s_a3n2V :: k_a3n3p) l_a3n2W v_a3n2X e_a3n2Y f_a3n2Z r_a3n30) (Rectangle () r_a3n30)
- Data.Geometry.Arrangement.Internal: inputLines :: forall s_a3nHW l_a3nHX v_a3nHY e_a3nHZ f_a3nI0 r_a3nI1. Lens' (Arrangement s_a3nHW l_a3nHX v_a3nHY e_a3nHZ f_a3nI0 r_a3nI1) (Vector ((:+) (Line 2 r_a3nI1) l_a3nHX))
+ Data.Geometry.Arrangement.Internal: inputLines :: forall k_a3n3p (s_a3n2V :: k_a3n3p) l_a3n2W v_a3n2X e_a3n2Y f_a3n2Z r_a3n30. Lens' (Arrangement (s_a3n2V :: k_a3n3p) l_a3n2W v_a3n2X e_a3n2Y f_a3n2Z r_a3n30) (Vector ((:+) (Line 2 r_a3n30) l_a3n2W))
- Data.Geometry.Arrangement.Internal: subdivision :: forall s_a3nHW l_a3nHX v_a3nHY e_a3nHZ f_a3nI0 r_a3nI1 v_a3nPK e_a3nPL f_a3nPM. Lens (Arrangement s_a3nHW l_a3nHX v_a3nHY e_a3nHZ f_a3nI0 r_a3nI1) (Arrangement s_a3nHW l_a3nHX v_a3nPK e_a3nPL f_a3nPM r_a3nI1) (PlanarSubdivision s_a3nHW v_a3nHY e_a3nHZ f_a3nI0 r_a3nI1) (PlanarSubdivision s_a3nHW v_a3nPK e_a3nPL f_a3nPM r_a3nI1)
+ Data.Geometry.Arrangement.Internal: subdivision :: forall k_a3n3p (s_a3n2V :: k_a3n3p) l_a3n2W v_a3n2X e_a3n2Y f_a3n2Z r_a3n30 v_a3naC e_a3naD f_a3naE. Lens (Arrangement (s_a3n2V :: k_a3n3p) l_a3n2W v_a3n2X e_a3n2Y f_a3n2Z r_a3n30) (Arrangement (s_a3n2V :: k_a3n3p) l_a3n2W v_a3naC e_a3naD f_a3naE r_a3n30) (PlanarSubdivision s_a3n2V v_a3n2X e_a3n2Y f_a3n2Z r_a3n30) (PlanarSubdivision s_a3n2V v_a3naC e_a3naD f_a3naE r_a3n30)
- Data.Geometry.Arrangement.Internal: unboundedIntersections :: forall s_a3nHW l_a3nHX v_a3nHY e_a3nHZ f_a3nI0 r_a3nI1. Lens' (Arrangement s_a3nHW l_a3nHX v_a3nHY e_a3nHZ f_a3nI0 r_a3nI1) (ArrangementBoundary s_a3nHW l_a3nHX r_a3nI1)
+ Data.Geometry.Arrangement.Internal: unboundedIntersections :: forall k_a3n3p (s_a3n2V :: k_a3n3p) l_a3n2W v_a3n2X e_a3n2Y f_a3n2Z r_a3n30. Lens' (Arrangement (s_a3n2V :: k_a3n3p) l_a3n2W v_a3n2X e_a3n2Y f_a3n2Z r_a3n30) (ArrangementBoundary s_a3n2V l_a3n2W r_a3n30)
- Data.Geometry.Ball: center :: forall d_a2mAY p_a2mAZ r_a2mB0 d_a2mDG p_a2mDH. Lens (Ball d_a2mAY p_a2mAZ r_a2mB0) (Ball d_a2mDG p_a2mDH r_a2mB0) ((:+) (Point d_a2mAY r_a2mB0) p_a2mAZ) ((:+) (Point d_a2mDG r_a2mB0) p_a2mDH)
+ Data.Geometry.Ball: center :: forall d_a2auB p_a2auC r_a2auD d_a2axf p_a2axg. Lens (Ball d_a2auB p_a2auC r_a2auD) (Ball d_a2axf p_a2axg r_a2auD) ((:+) (Point d_a2auB r_a2auD) p_a2auC) ((:+) (Point d_a2axf r_a2auD) p_a2axg)
- Data.Geometry.Ball: squaredRadius :: forall d_a2mAY p_a2mAZ r_a2mB0. Lens' (Ball d_a2mAY p_a2mAZ r_a2mB0) r_a2mB0
+ Data.Geometry.Ball: squaredRadius :: forall d_a2auB p_a2auC r_a2auD. Lens' (Ball d_a2auB p_a2auC r_a2auD) r_a2auD
- Data.Geometry.BezierSpline: controlPoints :: forall n_a2jaG d_a2jaH r_a2jaI n_a2jbq d_a2jbr r_a2jbs. Iso (BezierSpline n_a2jaG d_a2jaH r_a2jaI) (BezierSpline n_a2jbq d_a2jbr r_a2jbs) (LSeq ((+) 1 n_a2jaG) (Point d_a2jaH r_a2jaI)) (LSeq ((+) 1 n_a2jbq) (Point d_a2jbr r_a2jbs))
+ Data.Geometry.BezierSpline: controlPoints :: Iso (BezierSpline n1 d1 r1) (BezierSpline n2 d2 r2) (LSeq (1 + n1) (Point d1 r1)) (LSeq (1 + n2) (Point d2 r2))
- Data.Geometry.Box.Corners: northEast :: forall a_a1OzZ. Lens' (Corners a_a1OzZ) a_a1OzZ
+ Data.Geometry.Box.Corners: northEast :: forall a_a1CJS. Lens' (Corners a_a1CJS) a_a1CJS
- Data.Geometry.Box.Corners: northWest :: forall a_a1OzZ. Lens' (Corners a_a1OzZ) a_a1OzZ
+ Data.Geometry.Box.Corners: northWest :: forall a_a1CJS. Lens' (Corners a_a1CJS) a_a1CJS
- Data.Geometry.Box.Corners: southEast :: forall a_a1OzZ. Lens' (Corners a_a1OzZ) a_a1OzZ
+ Data.Geometry.Box.Corners: southEast :: forall a_a1CJS. Lens' (Corners a_a1CJS) a_a1CJS
- Data.Geometry.Box.Corners: southWest :: forall a_a1OzZ. Lens' (Corners a_a1OzZ) a_a1OzZ
+ Data.Geometry.Box.Corners: southWest :: forall a_a1CJS. Lens' (Corners a_a1CJS) a_a1CJS
- Data.Geometry.Box.Internal: cwMax :: forall a_a1xgn a_a1xxm. Iso (CWMax a_a1xgn) (CWMax a_a1xxm) a_a1xgn a_a1xxm
+ Data.Geometry.Box.Internal: cwMax :: forall a_a1jRy a_a1k8H. Iso (CWMax a_a1jRy) (CWMax a_a1k8H) a_a1jRy a_a1k8H
- Data.Geometry.Box.Internal: cwMin :: forall a_a1x1y a_a1xgh. Iso (CWMin a_a1x1y) (CWMin a_a1xgh) a_a1x1y a_a1xgh
+ Data.Geometry.Box.Internal: cwMin :: forall a_a1jCx a_a1jRs. Iso (CWMin a_a1jCx) (CWMin a_a1jRs) a_a1jCx a_a1jRs
- Data.Geometry.Box.Internal: maxP :: forall d_a1xxt p_a1xxu r_a1xxv. Lens' (Box d_a1xxt p_a1xxu r_a1xxv) ((:+) (CWMax (Point d_a1xxt r_a1xxv)) p_a1xxu)
+ Data.Geometry.Box.Internal: maxP :: forall d_a1k8O p_a1k8P r_a1k8Q. Lens' (Box d_a1k8O p_a1k8P r_a1k8Q) ((:+) (CWMax (Point d_a1k8O r_a1k8Q)) p_a1k8P)
- Data.Geometry.Box.Internal: minP :: forall d_a1xxt p_a1xxu r_a1xxv. Lens' (Box d_a1xxt p_a1xxu r_a1xxv) ((:+) (CWMin (Point d_a1xxt r_a1xxv)) p_a1xxu)
+ Data.Geometry.Box.Internal: minP :: forall d_a1k8O p_a1k8P r_a1k8Q. Lens' (Box d_a1k8O p_a1k8P r_a1k8Q) ((:+) (CWMin (Point d_a1k8O r_a1k8Q)) p_a1k8P)
- Data.Geometry.Box.Sides: east :: forall a_a1R1A. Lens' (Sides a_a1R1A) a_a1R1A
+ Data.Geometry.Box.Sides: east :: forall a_a1Fa7. Lens' (Sides a_a1Fa7) a_a1Fa7
- Data.Geometry.Box.Sides: north :: forall a_a1R1A. Lens' (Sides a_a1R1A) a_a1R1A
+ Data.Geometry.Box.Sides: north :: forall a_a1Fa7. Lens' (Sides a_a1Fa7) a_a1Fa7
- Data.Geometry.Box.Sides: south :: forall a_a1R1A. Lens' (Sides a_a1R1A) a_a1R1A
+ Data.Geometry.Box.Sides: south :: forall a_a1Fa7. Lens' (Sides a_a1Fa7) a_a1Fa7
- Data.Geometry.Box.Sides: west :: forall a_a1R1A. Lens' (Sides a_a1R1A) a_a1R1A
+ Data.Geometry.Box.Sides: west :: forall a_a1Fa7. Lens' (Sides a_a1Fa7) a_a1Fa7
- Data.Geometry.Ellipse: affineTransformation :: forall r_a2FNO r_a2GfJ. Iso (Ellipse r_a2FNO) (Ellipse r_a2GfJ) (Transformation 2 r_a2FNO) (Transformation 2 r_a2GfJ)
+ Data.Geometry.Ellipse: affineTransformation :: forall r_a2wmL r_a2wPr. Iso (Ellipse r_a2wmL) (Ellipse r_a2wPr) (Transformation 2 r_a2wmL) (Transformation 2 r_a2wPr)
- Data.Geometry.HalfLine: halfLineDirection :: forall d_a2dr4 r_a2dr5. Lens' (HalfLine d_a2dr4 r_a2dr5) (Vector d_a2dr4 r_a2dr5)
+ Data.Geometry.HalfLine: halfLineDirection :: forall d_a22jd r_a22je. Lens' (HalfLine d_a22jd r_a22je) (Vector d_a22jd r_a22je)
- Data.Geometry.HalfLine: startPoint :: forall d_a2dr4 r_a2dr5. Lens' (HalfLine d_a2dr4 r_a2dr5) (Point d_a2dr4 r_a2dr5)
+ Data.Geometry.HalfLine: startPoint :: forall d_a22jd r_a22je. Lens' (HalfLine d_a22jd r_a22je) (Point d_a22jd r_a22je)
- Data.Geometry.HalfSpace: boundingPlane :: forall d_a2fS6 r_a2fS7 d_a2fU3 r_a2fU4. Iso (HalfSpace d_a2fS6 r_a2fS7) (HalfSpace d_a2fU3 r_a2fU4) (HyperPlane d_a2fS6 r_a2fS7) (HyperPlane d_a2fU3 r_a2fU4)
+ Data.Geometry.HalfSpace: boundingPlane :: forall d_a27iP r_a27iQ d_a27kI r_a27kJ. Iso (HalfSpace d_a27iP r_a27iQ) (HalfSpace d_a27kI r_a27kJ) (HyperPlane d_a27iP r_a27iQ) (HyperPlane d_a27kI r_a27kJ)
- Data.Geometry.HyperPlane: HyperPlane :: !Point d r -> !Vector d r -> HyperPlane
+ Data.Geometry.HyperPlane: HyperPlane :: !Point d r -> !Vector d r -> HyperPlane (d :: Nat) (r :: *)
- Data.Geometry.HyperPlane: [_inPlane] :: HyperPlane -> !Point d r
+ Data.Geometry.HyperPlane: [_inPlane] :: HyperPlane (d :: Nat) (r :: *) -> !Point d r
- Data.Geometry.HyperPlane: [_normalVec] :: HyperPlane -> !Vector d r
+ Data.Geometry.HyperPlane: [_normalVec] :: HyperPlane (d :: Nat) (r :: *) -> !Vector d r
- Data.Geometry.HyperPlane: inPlane :: forall d_a2alM r_a2alN. Lens' (HyperPlane d_a2alM r_a2alN) (Point d_a2alM r_a2alN)
+ Data.Geometry.HyperPlane: inPlane :: forall d_a1Yoc r_a1Yod. Lens' (HyperPlane d_a1Yoc r_a1Yod) (Point d_a1Yoc r_a1Yod)
- Data.Geometry.HyperPlane: normalVec :: forall d_a2alM r_a2alN. Lens' (HyperPlane d_a2alM r_a2alN) (Vector d_a2alM r_a2alN)
+ Data.Geometry.HyperPlane: normalVec :: forall d_a1Yoc r_a1Yod. Lens' (HyperPlane d_a1Yoc r_a1Yod) (Vector d_a1Yoc r_a1Yod)
- Data.Geometry.Interval: _Range :: Lens' (Interval a r) (Range (r :+ a))
+ Data.Geometry.Interval: _Range :: Iso' (Interval a r) (Range (r :+ a))
- Data.Geometry.Interval.Util: unL :: forall r_avvf r_awrF. Iso (L r_avvf) (L r_awrF) (EndPoint r_avvf) (EndPoint r_awrF)
+ Data.Geometry.Interval.Util: unL :: forall r_algX r_alKv. Iso (L r_algX) (L r_alKv) (EndPoint r_algX) (EndPoint r_alKv)
- Data.Geometry.Interval.Util: unR :: forall r_awrL r_awGg. Iso (R r_awrL) (R r_awGg) (EndPoint r_awrL) (EndPoint r_awGg)
+ Data.Geometry.Interval.Util: unR :: forall r_alKB r_alXu. Iso (R r_alKB) (R r_alXu) (EndPoint r_alKB) (EndPoint r_alXu)
- Data.Geometry.IntervalTree: intervalsLeft :: forall i_aAf8 r_aAf9. Lens' (NodeData i_aAf8 r_aAf9) (Map (L r_aAf9) [i_aAf8])
+ Data.Geometry.IntervalTree: intervalsLeft :: forall i_aoYQ r_aoYR. Lens' (NodeData i_aoYQ r_aoYR) (Map (L r_aoYR) [i_aoYQ])
- Data.Geometry.IntervalTree: intervalsRight :: forall i_aAf8 r_aAf9. Lens' (NodeData i_aAf8 r_aAf9) (Map (R r_aAf9) [i_aAf8])
+ Data.Geometry.IntervalTree: intervalsRight :: forall i_aoYQ r_aoYR. Lens' (NodeData i_aoYQ r_aoYR) (Map (R r_aoYR) [i_aoYQ])
- Data.Geometry.IntervalTree: splitPoint :: forall i_aAf8 r_aAf9. Lens' (NodeData i_aAf8 r_aAf9) r_aAf9
+ Data.Geometry.IntervalTree: splitPoint :: forall i_aoYQ r_aoYR. Lens' (NodeData i_aoYQ r_aoYR) r_aoYR
- Data.Geometry.IntervalTree: unIntervalTree :: forall i_aAor r_aAos i_aAvA r_aAvB. Iso (IntervalTree i_aAor r_aAos) (IntervalTree i_aAvA r_aAvB) (BinaryTree (NodeData i_aAor r_aAos)) (BinaryTree (NodeData i_aAvA r_aAvB))
+ Data.Geometry.IntervalTree: unIntervalTree :: forall i_ap7S r_ap7T i_apeQ r_apeR. Iso (IntervalTree i_ap7S r_ap7T) (IntervalTree i_apeQ r_apeR) (BinaryTree (NodeData i_ap7S r_ap7T)) (BinaryTree (NodeData i_apeQ r_apeR))
- Data.Geometry.KDTree: Coord :: Int -> Coord
+ Data.Geometry.KDTree: Coord :: Int -> Coord (d :: Nat)
- Data.Geometry.KDTree: [unCoord] :: Coord -> Int
+ Data.Geometry.KDTree: [unCoord] :: Coord (d :: Nat) -> Int
- Data.Geometry.Line.Internal: anchorPoint :: forall d_a1nxr r_a1nxs. Lens' (Line d_a1nxr r_a1nxs) (Point d_a1nxr r_a1nxs)
+ Data.Geometry.Line.Internal: anchorPoint :: Lens' (Line d r) (Point d r)
- Data.Geometry.Line.Internal: direction :: forall d_a1nxr r_a1nxs. Lens' (Line d_a1nxr r_a1nxs) (Vector d_a1nxr r_a1nxs)
+ Data.Geometry.Line.Internal: direction :: Lens' (Line d r) (Vector d r)
- Data.Geometry.LineSegment: _Range :: Lens' (Interval a r) (Range (r :+ a))
+ Data.Geometry.LineSegment: _Range :: Iso' (Interval a r) (Range (r :+ a))
- Data.Geometry.LineSegment: isClosed :: () => EndPoint a -> Bool
+ Data.Geometry.LineSegment: isClosed :: EndPoint a -> Bool
- Data.Geometry.LineSegment: isOpen :: () => EndPoint a -> Bool
+ Data.Geometry.LineSegment: isOpen :: EndPoint a -> Bool
- Data.Geometry.LineSegment: lower :: () => Lens' (Range a) (EndPoint a)
+ Data.Geometry.LineSegment: lower :: Lens' (Range a) (EndPoint a)
- Data.Geometry.LineSegment: unEndPoint :: () => Lens (EndPoint a) (EndPoint b) a b
+ Data.Geometry.LineSegment: unEndPoint :: Lens (EndPoint a) (EndPoint b) a b
- Data.Geometry.LineSegment: upper :: () => Lens' (Range a) (EndPoint a)
+ Data.Geometry.LineSegment: upper :: Lens' (Range a) (EndPoint a)
- Data.Geometry.PlanarSubdivision.Basic: FaceId :: VertexId s (DualOf w) -> FaceId
+ Data.Geometry.PlanarSubdivision.Basic: FaceId :: VertexId s (DualOf w) -> FaceId (s :: k) (w :: World)
- Data.Geometry.PlanarSubdivision.Basic: VertexId :: Int -> VertexId
+ Data.Geometry.PlanarSubdivision.Basic: VertexId :: Int -> VertexId (s :: k) (w :: World)
- Data.Geometry.PlanarSubdivision.Basic: [_unFaceId] :: FaceId -> VertexId s (DualOf w)
+ Data.Geometry.PlanarSubdivision.Basic: [_unFaceId] :: FaceId (s :: k) (w :: World) -> VertexId s (DualOf w)
- Data.Geometry.PlanarSubdivision.Basic: [_unVertexId] :: VertexId -> Int
+ Data.Geometry.PlanarSubdivision.Basic: [_unVertexId] :: VertexId (s :: k) (w :: World) -> Int
- Data.Geometry.PlanarSubdivision.Basic: components :: forall s_a3eQC v_a3eQD e_a3eQE f_a3eQF r_a3eQG r_a3f3S. Lens (PlanarSubdivision s_a3eQC v_a3eQD e_a3eQE f_a3eQF r_a3eQG) (PlanarSubdivision s_a3eQC v_a3eQD e_a3eQE f_a3eQF r_a3f3S) (Vector (Component s_a3eQC r_a3eQG)) (Vector (Component s_a3eQC r_a3f3S))
+ Data.Geometry.PlanarSubdivision.Basic: components :: forall k_a3b3y (s_a3b2U :: k_a3b3y) v_a3b2V e_a3b2W f_a3b2X r_a3b2Y r_a3bg3. Lens (PlanarSubdivision (s_a3b2U :: k_a3b3y) v_a3b2V e_a3b2W f_a3b2X r_a3b2Y) (PlanarSubdivision (s_a3b2U :: k_a3b3y) v_a3b2V e_a3b2W f_a3b2X r_a3bg3) (Vector (Component s_a3b2U r_a3b2Y)) (Vector (Component s_a3b2U r_a3bg3))
- Data.Geometry.PlanarSubdivision.Basic: dual :: () => Getter (PlanarGraph s w v e f) (PlanarGraph s (DualOf w) f e v)
+ Data.Geometry.PlanarSubdivision.Basic: dual :: forall k (s :: k) (w :: World) v e f. Getter (PlanarGraph s w v e f) (PlanarGraph s (DualOf w) f e v)
- Data.Geometry.PlanarSubdivision.Basic: fData :: forall h_a38zf f_a38zg f_a39pF. Lens (FaceData h_a38zf f_a38zg) (FaceData h_a38zf f_a39pF) f_a38zg f_a39pF
+ Data.Geometry.PlanarSubdivision.Basic: fData :: forall h_a34Us f_a34Ut f_a35Gs. Lens (FaceData h_a34Us f_a34Ut) (FaceData h_a34Us f_a35Gs) f_a34Ut f_a35Gs
- Data.Geometry.PlanarSubdivision.Basic: holes :: forall h_a38zf f_a38zg h_a39pG. Lens (FaceData h_a38zf f_a38zg) (FaceData h_a39pG f_a38zg) (Seq h_a38zf) (Seq h_a39pG)
+ Data.Geometry.PlanarSubdivision.Basic: holes :: forall h_a34Us f_a34Ut h_a35Gt. Lens (FaceData h_a34Us f_a34Ut) (FaceData h_a35Gt f_a34Ut) (Seq h_a34Us) (Seq h_a35Gt)
- Data.Geometry.PlanarSubdivision.Basic: location :: forall r_a30z8 v_a30z9 r_a30NV. Lens (VertexData r_a30z8 v_a30z9) (VertexData r_a30NV v_a30z9) (Point 2 r_a30z8) (Point 2 r_a30NV)
+ Data.Geometry.PlanarSubdivision.Basic: location :: forall r_a2Xgg v_a2Xgh r_a2XuU. Lens (VertexData r_a2Xgg v_a2Xgh) (VertexData r_a2XuU v_a2Xgh) (Point 2 r_a2Xgg) (Point 2 r_a2XuU)
- Data.Geometry.PlanarSubdivision.Basic: rawDartData :: forall s_a3eQC v_a3eQD e_a3eQE f_a3eQF r_a3eQG e_a3f3T. Lens (PlanarSubdivision s_a3eQC v_a3eQD e_a3eQE f_a3eQF r_a3eQG) (PlanarSubdivision s_a3eQC v_a3eQD e_a3f3T f_a3eQF r_a3eQG) (Vector (Raw s_a3eQC (Dart (Wrap s_a3eQC)) e_a3eQE)) (Vector (Raw s_a3eQC (Dart (Wrap s_a3eQC)) e_a3f3T))
+ Data.Geometry.PlanarSubdivision.Basic: rawDartData :: forall k_a3b3y (s_a3b2U :: k_a3b3y) v_a3b2V e_a3b2W f_a3b2X r_a3b2Y e_a3bg4. Lens (PlanarSubdivision (s_a3b2U :: k_a3b3y) v_a3b2V e_a3b2W f_a3b2X r_a3b2Y) (PlanarSubdivision (s_a3b2U :: k_a3b3y) v_a3b2V e_a3bg4 f_a3b2X r_a3b2Y) (Vector (Raw s_a3b2U (Dart (Wrap s_a3b2U)) e_a3b2W)) (Vector (Raw s_a3b2U (Dart (Wrap s_a3b2U)) e_a3bg4))
- Data.Geometry.PlanarSubdivision.Basic: rawFaceData :: forall s_a3eQC v_a3eQD e_a3eQE f_a3eQF r_a3eQG f_a3f3U. Lens (PlanarSubdivision s_a3eQC v_a3eQD e_a3eQE f_a3eQF r_a3eQG) (PlanarSubdivision s_a3eQC v_a3eQD e_a3eQE f_a3f3U r_a3eQG) (Vector (RawFace s_a3eQC f_a3eQF)) (Vector (RawFace s_a3eQC f_a3f3U))
+ Data.Geometry.PlanarSubdivision.Basic: rawFaceData :: forall k_a3b3y (s_a3b2U :: k_a3b3y) v_a3b2V e_a3b2W f_a3b2X r_a3b2Y f_a3bg5. Lens (PlanarSubdivision (s_a3b2U :: k_a3b3y) v_a3b2V e_a3b2W f_a3b2X r_a3b2Y) (PlanarSubdivision (s_a3b2U :: k_a3b3y) v_a3b2V e_a3b2W f_a3bg5 r_a3b2Y) (Vector (RawFace s_a3b2U f_a3b2X)) (Vector (RawFace s_a3b2U f_a3bg5))
- Data.Geometry.PlanarSubdivision.Basic: rawVertexData :: forall s_a3eQC v_a3eQD e_a3eQE f_a3eQF r_a3eQG v_a3f3V. Lens (PlanarSubdivision s_a3eQC v_a3eQD e_a3eQE f_a3eQF r_a3eQG) (PlanarSubdivision s_a3eQC v_a3f3V e_a3eQE f_a3eQF r_a3eQG) (Vector (Raw s_a3eQC (VertexId' (Wrap s_a3eQC)) v_a3eQD)) (Vector (Raw s_a3eQC (VertexId' (Wrap s_a3eQC)) v_a3f3V))
+ Data.Geometry.PlanarSubdivision.Basic: rawVertexData :: forall k_a3b3y (s_a3b2U :: k_a3b3y) v_a3b2V e_a3b2W f_a3b2X r_a3b2Y v_a3bg6. Lens (PlanarSubdivision (s_a3b2U :: k_a3b3y) v_a3b2V e_a3b2W f_a3b2X r_a3b2Y) (PlanarSubdivision (s_a3b2U :: k_a3b3y) v_a3bg6 e_a3b2W f_a3b2X r_a3b2Y) (Vector (Raw s_a3b2U (VertexId' (Wrap s_a3b2U)) v_a3b2V)) (Vector (Raw s_a3b2U (VertexId' (Wrap s_a3b2U)) v_a3bg6))
- Data.Geometry.PlanarSubdivision.Basic: twin :: () => Dart s -> Dart s
+ Data.Geometry.PlanarSubdivision.Basic: twin :: forall k (s :: k). Dart s -> Dart s
- Data.Geometry.PlanarSubdivision.Basic: type FaceId' (s :: k) = FaceId s Primal
+ Data.Geometry.PlanarSubdivision.Basic: type FaceId' (s :: k) = FaceId s 'Primal
- Data.Geometry.PlanarSubdivision.Basic: type VertexId' (s :: k) = VertexId s Primal
+ Data.Geometry.PlanarSubdivision.Basic: type VertexId' (s :: k) = VertexId s 'Primal
- Data.Geometry.PlanarSubdivision.Basic: type family DataOf g i :: Type;
+ Data.Geometry.PlanarSubdivision.Basic: type family DataOf g i;
- Data.Geometry.PlanarSubdivision.Basic: vData :: forall r_a30z8 v_a30z9 v_a30NW. Lens (VertexData r_a30z8 v_a30z9) (VertexData r_a30z8 v_a30NW) v_a30z9 v_a30NW
+ Data.Geometry.PlanarSubdivision.Basic: vData :: forall r_a2Xgg v_a2Xgh v_a2XuV. Lens (VertexData r_a2Xgg v_a2Xgh) (VertexData r_a2Xgg v_a2XuV) v_a2Xgh v_a2XuV
- Data.Geometry.PlanarSubdivision.Raw: fData :: forall h_a38zf f_a38zg f_a39pF. Lens (FaceData h_a38zf f_a38zg) (FaceData h_a38zf f_a39pF) f_a38zg f_a39pF
+ Data.Geometry.PlanarSubdivision.Raw: fData :: forall h_a34Us f_a34Ut f_a35Gs. Lens (FaceData h_a34Us f_a34Ut) (FaceData h_a34Us f_a35Gs) f_a34Ut f_a35Gs
- Data.Geometry.PlanarSubdivision.Raw: faceDataVal :: forall s_a39pV f_a39pW f_a39FC. Lens (RawFace s_a39pV f_a39pW) (RawFace s_a39pV f_a39FC) (FaceData (Dart s_a39pV) f_a39pW) (FaceData (Dart s_a39pV) f_a39FC)
+ Data.Geometry.PlanarSubdivision.Raw: faceDataVal :: forall k_a35Hm (s_a35GI :: k_a35Hm) f_a35GJ f_a35Wq. Lens (RawFace (s_a35GI :: k_a35Hm) f_a35GJ) (RawFace (s_a35GI :: k_a35Hm) f_a35Wq) (FaceData (Dart s_a35GI) f_a35GJ) (FaceData (Dart s_a35GI) f_a35Wq)
- Data.Geometry.PlanarSubdivision.Raw: faceIdx :: forall s_a39pV f_a39pW. Lens' (RawFace s_a39pV f_a39pW) (Maybe (ComponentId s_a39pV, FaceId' (Wrap s_a39pV)))
+ Data.Geometry.PlanarSubdivision.Raw: faceIdx :: forall k_a35Hm (s_a35GI :: k_a35Hm) f_a35GJ. Lens' (RawFace (s_a35GI :: k_a35Hm) f_a35GJ) (Maybe (ComponentId s_a35GI, FaceId' (Wrap s_a35GI)))
- Data.Geometry.PlanarSubdivision.Raw: holes :: forall h_a38zf f_a38zg h_a39pG. Lens (FaceData h_a38zf f_a38zg) (FaceData h_a39pG f_a38zg) (Seq h_a38zf) (Seq h_a39pG)
+ Data.Geometry.PlanarSubdivision.Raw: holes :: forall h_a34Us f_a34Ut h_a35Gt. Lens (FaceData h_a34Us f_a34Ut) (FaceData h_a35Gt f_a34Ut) (Seq h_a34Us) (Seq h_a35Gt)
- Data.Geometry.Point: ccwCmpAround :: (Num r, Ord r) => (Point 2 r :+ qc) -> (Point 2 r :+ p) -> (Point 2 r :+ q) -> Ordering
+ Data.Geometry.Point: ccwCmpAround :: (Num r, Ord r) => Point 2 r -> Point 2 r -> Point 2 r -> Ordering
- Data.Geometry.Point: ccwCmpAroundWith :: (Ord r, Num r) => Vector 2 r -> (Point 2 r :+ c) -> (Point 2 r :+ a) -> (Point 2 r :+ b) -> Ordering
+ Data.Geometry.Point: ccwCmpAroundWith :: (Ord r, Num r) => Vector 2 r -> Point 2 r -> Point 2 r -> Point 2 r -> Ordering
- Data.Geometry.Point: cmpByDistanceTo :: (Ord r, Num r, Arity d) => (Point d r :+ c) -> (Point d r :+ p) -> (Point d r :+ q) -> Ordering
+ Data.Geometry.Point: cmpByDistanceTo :: (Ord r, Num r, Arity d) => Point d r -> Point d r -> Point d r -> Ordering
- Data.Geometry.Point: cwCmpAround :: (Num r, Ord r) => (Point 2 r :+ qc) -> (Point 2 r :+ p) -> (Point 2 r :+ q) -> Ordering
+ Data.Geometry.Point: cwCmpAround :: (Num r, Ord r) => Point 2 r -> Point 2 r -> Point 2 r -> Ordering
- Data.Geometry.Point: cwCmpAroundWith :: (Ord r, Num r) => Vector 2 r -> (Point 2 r :+ a) -> (Point 2 r :+ b) -> (Point 2 r :+ c) -> Ordering
+ Data.Geometry.Point: cwCmpAroundWith :: (Ord r, Num r) => Vector 2 r -> Point 2 r -> Point 2 r -> Point 2 r -> Ordering
- Data.Geometry.Point: sortAround :: (Ord r, Num r) => (Point 2 r :+ q) -> [Point 2 r :+ p] -> [Point 2 r :+ p]
+ Data.Geometry.Point: sortAround :: (Ord r, Num r) => Point 2 r -> [Point 2 r] -> [Point 2 r]
- Data.Geometry.Point: vector :: Lens' (Point d r) (Vector d r)
+ Data.Geometry.Point: vector :: Lens (Point d r) (Point d r') (Vector d r) (Vector d r')
- Data.Geometry.PolyLine: points :: forall d_a22fG p_a22fH r_a22fI d_a22hP p_a22hQ r_a22hR. Iso (PolyLine d_a22fG p_a22fH r_a22fI) (PolyLine d_a22hP p_a22hQ r_a22hR) (LSeq 2 ((:+) (Point d_a22fG r_a22fI) p_a22fH)) (LSeq 2 ((:+) (Point d_a22hP r_a22hR) p_a22hQ))
+ Data.Geometry.PolyLine: points :: Iso (PolyLine d1 p1 r1) (PolyLine d2 p2 r2) (LSeq 2 (Point d1 r1 :+ p1)) (LSeq 2 (Point d2 r2 :+ p2))
- Data.Geometry.Polygon: [MultiPolygon] :: CSeq (Point 2 r :+ p) -> [Polygon Simple p r] -> Polygon Multi p r
+ Data.Geometry.Polygon: [MultiPolygon] :: SimplePolygon p r -> [SimplePolygon p r] -> MultiPolygon p r
- Data.Geometry.Polygon: [SimplePolygon] :: CSeq (Point 2 r :+ p) -> Polygon Simple p r
+ Data.Geometry.Polygon: [SimplePolygon] :: Vertices (Point 2 r :+ p) -> SimplePolygon p r
- Data.Geometry.Polygon: _MultiPolygon :: Prism' (Polygon Multi p r) (CSeq (Point 2 r :+ p), [Polygon Simple p r])
+ Data.Geometry.Polygon: _MultiPolygon :: Prism' (Polygon Multi p r) (Polygon Simple p r, [Polygon Simple p r])
- Data.Geometry.Polygon: _SimplePolygon :: Prism' (Polygon Simple p r) (CSeq (Point 2 r :+ p))
+ Data.Geometry.Polygon: _SimplePolygon :: Prism' (Polygon Simple p r) (Vertices (Point 2 r :+ p))
- Data.Geometry.Polygon: fromPoints :: [Point 2 r :+ p] -> SimplePolygon p r
+ Data.Geometry.Polygon: fromPoints :: forall p r. (Eq r, Num r) => [Point 2 r :+ p] -> SimplePolygon p r
- Data.Geometry.Polygon: isCounterClockwise :: (Eq r, Fractional r) => Polygon t p r -> Bool
+ Data.Geometry.Polygon: isCounterClockwise :: (Eq r, Num r) => Polygon t p r -> Bool
- Data.Geometry.Polygon: onBoundary :: (Fractional r, Ord r) => Point 2 r -> Polygon t p r -> Bool
+ Data.Geometry.Polygon: onBoundary :: (Num r, Ord r) => Point 2 r -> Polygon t p r -> Bool
- Data.Geometry.Polygon: outerBoundary :: forall t p r. Lens' (Polygon t p r) (CSeq (Point 2 r :+ p))
+ Data.Geometry.Polygon: outerBoundary :: forall t p r. Lens' (Polygon t p r) (SimplePolygon p r)
- Data.Geometry.Polygon: outerBoundaryEdges :: Polygon t p r -> CSeq (LineSegment 2 p r)
+ Data.Geometry.Polygon: outerBoundaryEdges :: Polygon t p r -> CircularVector (LineSegment 2 p r)
- Data.Geometry.Polygon: outerVertex :: Int -> Lens' (Polygon t p r) (Point 2 r :+ p)
+ Data.Geometry.Polygon: outerVertex :: Int -> Getter (Polygon t p r) (Point 2 r :+ p)
- Data.Geometry.Polygon: toClockwiseOrder :: (Eq r, Fractional r) => Polygon t p r -> Polygon t p r
+ Data.Geometry.Polygon: toClockwiseOrder :: (Eq r, Num r) => Polygon t p r -> Polygon t p r
- Data.Geometry.Polygon: toClockwiseOrder' :: (Eq r, Fractional r) => Polygon t p r -> Polygon t p r
+ Data.Geometry.Polygon: toClockwiseOrder' :: (Eq r, Num r) => Polygon t p r -> Polygon t p r
- Data.Geometry.Polygon: toCounterClockWiseOrder :: (Eq r, Fractional r) => Polygon t p r -> Polygon t p r
+ Data.Geometry.Polygon: toCounterClockWiseOrder :: (Eq r, Num r) => Polygon t p r -> Polygon t p r
- Data.Geometry.Polygon: toCounterClockWiseOrder' :: (Eq r, Fractional r) => Polygon t p r -> Polygon t p r
+ Data.Geometry.Polygon: toCounterClockWiseOrder' :: (Eq r, Num r) => Polygon t p r -> Polygon t p r
- Data.Geometry.Polygon.Convex: bottomMost :: Ord r => CSeq (Point 2 r :+ p) -> CSeq (Point 2 r :+ p)
+ Data.Geometry.Polygon.Convex: bottomMost :: Ord r => CircularVector (Point 2 r :+ p) -> CircularVector (Point 2 r :+ p)
- Data.Geometry.Polygon.Convex: simplePolygon :: forall p_a2BxI r_a2BxJ p_a2BCl r_a2BCm. Iso (ConvexPolygon p_a2BxI r_a2BxJ) (ConvexPolygon p_a2BCl r_a2BCm) (SimplePolygon p_a2BxI r_a2BxJ) (SimplePolygon p_a2BCl r_a2BCm)
+ Data.Geometry.Polygon.Convex: simplePolygon :: Iso (ConvexPolygon p1 r1) (ConvexPolygon p2 r2) (SimplePolygon p1 r1) (SimplePolygon p2 r2)
- Data.Geometry.QuadTree: startingCell :: forall v_a1ZtD p_a1ZtE r_a1ZtF r_a1ZFG. Lens (QuadTree v_a1ZtD p_a1ZtE r_a1ZtF) (QuadTree v_a1ZtD p_a1ZtE r_a1ZFG) (Cell r_a1ZtF) (Cell r_a1ZFG)
+ Data.Geometry.QuadTree: startingCell :: forall v_a1NHL p_a1NHM r_a1NHN r_a1NTS. Lens (QuadTree v_a1NHL p_a1NHM r_a1NHN) (QuadTree v_a1NHL p_a1NHM r_a1NTS) (Cell r_a1NHN) (Cell r_a1NTS)
- Data.Geometry.QuadTree: tree :: forall v_a1ZtD p_a1ZtE r_a1ZtF v_a1ZFH p_a1ZFI. Lens (QuadTree v_a1ZtD p_a1ZtE r_a1ZtF) (QuadTree v_a1ZFH p_a1ZFI r_a1ZtF) (Tree v_a1ZtD p_a1ZtE) (Tree v_a1ZFH p_a1ZFI)
+ Data.Geometry.QuadTree: tree :: forall v_a1NHL p_a1NHM r_a1NHN v_a1NTT p_a1NTU. Lens (QuadTree v_a1NHL p_a1NHM r_a1NHN) (QuadTree v_a1NTT p_a1NTU r_a1NHN) (Tree v_a1NHL p_a1NHM) (Tree v_a1NTT p_a1NTU)
- Data.Geometry.QuadTree.Cell: cellWidthIndex :: forall r_a1TUJ. Lens' (Cell r_a1TUJ) WidthIndex
+ Data.Geometry.QuadTree.Cell: cellWidthIndex :: forall r_a1I3f. Lens' (Cell r_a1I3f) WidthIndex
- Data.Geometry.QuadTree.Cell: lowerLeft :: forall r_a1TUJ r_a1U5N. Lens (Cell r_a1TUJ) (Cell r_a1U5N) (Point 2 r_a1TUJ) (Point 2 r_a1U5N)
+ Data.Geometry.QuadTree.Cell: lowerLeft :: forall r_a1I3f r_a1Iee. Lens (Cell r_a1I3f) (Cell r_a1Iee) (Point 2 r_a1I3f) (Point 2 r_a1Iee)
- Data.Geometry.QuadTree.Split: _No :: forall i_a1X9q v_a1X9r p_a1X9s p_a1XfS. Prism (Split i_a1X9q v_a1X9r p_a1XfS) (Split i_a1X9q v_a1X9r p_a1X9s) p_a1XfS p_a1X9s
+ Data.Geometry.QuadTree.Split: _No :: forall i_a1Lqt v_a1Lqu p_a1LwK p_a1Lqv. Prism (Split i_a1Lqt v_a1Lqu p_a1LwK) (Split i_a1Lqt v_a1Lqu p_a1Lqv) p_a1LwK p_a1Lqv
- Data.Geometry.QuadTree.Split: _Yes :: forall i_a1X9q v_a1X9r p_a1X9s i_a1XfY v_a1XfZ. Prism (Split i_a1XfY v_a1XfZ p_a1X9s) (Split i_a1X9q v_a1X9r p_a1X9s) (v_a1XfZ, Quadrants i_a1XfY) (v_a1X9r, Quadrants i_a1X9q)
+ Data.Geometry.QuadTree.Split: _Yes :: forall i_a1LwQ v_a1LwR p_a1Lqv i_a1Lqt v_a1Lqu. Prism (Split i_a1LwQ v_a1LwR p_a1Lqv) (Split i_a1Lqt v_a1Lqu p_a1Lqv) (v_a1LwR, Quadrants i_a1LwQ) (v_a1Lqu, Quadrants i_a1Lqt)
- Data.Geometry.QuadTree.Tree: _Leaf :: forall v_a1YaG p_a1YaH. Prism' (Tree v_a1YaG p_a1YaH) p_a1YaH
+ Data.Geometry.QuadTree.Tree: _Leaf :: forall v_a1Mqj p_a1Mqk. Prism' (Tree v_a1Mqj p_a1Mqk) p_a1Mqk
- Data.Geometry.QuadTree.Tree: _Node :: forall v_a1YaG p_a1YaH v_a1Yei. Prism (Tree v_a1Yei p_a1YaH) (Tree v_a1YaG p_a1YaH) (v_a1Yei, Quadrants (Tree v_a1Yei p_a1YaH)) (v_a1YaG, Quadrants (Tree v_a1YaG p_a1YaH))
+ Data.Geometry.QuadTree.Tree: _Node :: forall v_a1MtI p_a1Mqk v_a1Mqj. Prism (Tree v_a1MtI p_a1Mqk) (Tree v_a1Mqj p_a1Mqk) (v_a1MtI, Quadrants (Tree v_a1MtI p_a1Mqk)) (v_a1Mqj, Quadrants (Tree v_a1Mqj p_a1Mqk))
- Data.Geometry.SegmentTree.Generic: assoc :: forall v_aEbu r_aEbv v_aEiG. Lens (NodeData v_aEbu r_aEbv) (NodeData v_aEiG r_aEbv) v_aEbu v_aEiG
+ Data.Geometry.SegmentTree.Generic: assoc :: forall v_atWp r_atWq v_au3o. Lens (NodeData v_atWp r_atWq) (NodeData v_au3o r_atWq) v_atWp v_au3o
- Data.Geometry.SegmentTree.Generic: atomicRange :: forall v_aEj6 r_aEj7 r_aEwY. Lens (LeafData v_aEj6 r_aEj7) (LeafData v_aEj6 r_aEwY) (AtomicRange r_aEj7) (AtomicRange r_aEwY)
+ Data.Geometry.SegmentTree.Generic: atomicRange :: forall v_au3O r_au3P r_auhl. Lens (LeafData v_au3O r_au3P) (LeafData v_au3O r_auhl) (AtomicRange r_au3P) (AtomicRange r_auhl)
- Data.Geometry.SegmentTree.Generic: leafAssoc :: forall v_aEj6 r_aEj7 v_aEwZ. Lens (LeafData v_aEj6 r_aEj7) (LeafData v_aEwZ r_aEj7) v_aEj6 v_aEwZ
+ Data.Geometry.SegmentTree.Generic: leafAssoc :: forall v_au3O r_au3P v_auhm. Lens (LeafData v_au3O r_au3P) (LeafData v_auhm r_au3P) v_au3O v_auhm
- Data.Geometry.SegmentTree.Generic: range :: forall v_aEbu r_aEbv. Lens' (NodeData v_aEbu r_aEbv) (Range r_aEbv)
+ Data.Geometry.SegmentTree.Generic: range :: forall v_atWp r_atWq. Lens' (NodeData v_atWp r_atWq) (Range r_atWq)
- Data.Geometry.SegmentTree.Generic: splitPoint :: forall v_aEbu r_aEbv. Lens' (NodeData v_aEbu r_aEbv) (EndPoint r_aEbv)
+ Data.Geometry.SegmentTree.Generic: splitPoint :: forall v_atWp r_atWq. Lens' (NodeData v_atWp r_atWq) (EndPoint r_atWq)
- Data.Geometry.SegmentTree.Generic: unSegmentTree :: forall v_aExd r_aExe v_aEFc r_aEFd. Iso (SegmentTree v_aExd r_aExe) (SegmentTree v_aEFc r_aEFd) (BinLeafTree (NodeData v_aExd r_aExe) (LeafData v_aExd r_aExe)) (BinLeafTree (NodeData v_aEFc r_aEFd) (LeafData v_aEFc r_aEFd))
+ Data.Geometry.SegmentTree.Generic: unSegmentTree :: forall v_auhA r_auhB v_aupp r_aupq. Iso (SegmentTree v_auhA r_auhB) (SegmentTree v_aupp r_aupq) (BinLeafTree (NodeData v_auhA r_auhB) (LeafData v_auhA r_auhB)) (BinLeafTree (NodeData v_aupp r_aupq) (LeafData v_aupp r_aupq))
- Data.Geometry.Slab: Slab :: Interval a r -> Slab a r
+ Data.Geometry.Slab: Slab :: Interval a r -> Slab (o :: Orthogonal) a r
- Data.Geometry.Slab: [_unSlab] :: Slab a r -> Interval a r
+ Data.Geometry.Slab: [_unSlab] :: Slab (o :: Orthogonal) a r -> Interval a r
- Data.Geometry.Slab: unSlab :: forall o_a26XO a_a26XP r_a26XQ o_a273z a_a273A r_a273B. Iso (Slab o_a26XO a_a26XP r_a26XQ) (Slab o_a273z a_a273A r_a273B) (Interval a_a26XP r_a26XQ) (Interval a_a273A r_a273B)
+ Data.Geometry.Slab: unSlab :: forall o_a1ViD a_a1ViE r_a1ViF o_a1Vof a_a1Vog r_a1Voh. Iso (Slab o_a1ViD a_a1ViE r_a1ViF) (Slab o_a1Vof a_a1Vog r_a1Voh) (Interval a_a1ViE r_a1ViF) (Interval a_a1Vog r_a1Voh)
- Data.Geometry.SubLine: line :: forall d_a1t6F p_a1t6G s_a1t6H r_a1t6I d_a1t7z r_a1t7A. Lens (SubLine d_a1t6F p_a1t6G s_a1t6H r_a1t6I) (SubLine d_a1t7z p_a1t6G s_a1t6H r_a1t7A) (Line d_a1t6F r_a1t6I) (Line d_a1t7z r_a1t7A)
+ Data.Geometry.SubLine: line :: Lens (SubLine d1 p s r1) (SubLine d2 p s r2) (Line d1 r1) (Line d2 r2)
- Data.Geometry.SubLine: subRange :: forall d_a1t6F p_a1t6G s_a1t6H r_a1t6I p_a1t7B s_a1t7C. Lens (SubLine d_a1t6F p_a1t6G s_a1t6H r_a1t6I) (SubLine d_a1t6F p_a1t7B s_a1t7C r_a1t6I) (Interval p_a1t6G s_a1t6H) (Interval p_a1t7B s_a1t7C)
+ Data.Geometry.SubLine: subRange :: Lens (SubLine d p1 s1 r) (SubLine d p2 s2 r) (Interval p1 s1) (Interval p2 s2)
- Data.Geometry.Vector: C :: C
+ Data.Geometry.Vector: C :: C (n :: Nat)
- Data.Geometry.Vector.VectorFamily: MKVector :: VectorFamily (Peano d) r -> Vector
+ Data.Geometry.Vector.VectorFamily: MKVector :: VectorFamily (Peano d) r -> Vector (d :: Nat) (r :: *)
- Data.Geometry.Vector.VectorFamily: [_unV] :: Vector -> VectorFamily (Peano d) r
+ Data.Geometry.Vector.VectorFamily: [_unV] :: Vector (d :: Nat) (r :: *) -> VectorFamily (Peano d) r
- Data.Geometry.Vector.VectorFamily: unV :: Lens (Vector d r) (Vector d s) (VectorFamily (Peano d) r) (VectorFamily (Peano d) s)
+ Data.Geometry.Vector.VectorFamily: unV :: Iso (Vector d r) (Vector d s) (VectorFamily (Peano d) r) (VectorFamily (Peano d) s)
- Data.Geometry.Vector.VectorFamilyPeano: VectorFamily :: VectorFamilyF d r -> VectorFamily
+ Data.Geometry.Vector.VectorFamilyPeano: VectorFamily :: VectorFamilyF d r -> VectorFamily (d :: PeanoNum) (r :: *)
- Data.Geometry.Vector.VectorFamilyPeano: type family VectorFamilyF (d :: PeanoNum) :: * -> *
+ Data.Geometry.Vector.VectorFamilyPeano: type family FromPeano (d :: PeanoNum) :: Nat
- Data.Geometry.Vector.VectorFixed: C :: C
+ Data.Geometry.Vector.VectorFixed: C :: C (n :: Nat)
- Data.Geometry.Vector.VectorFixed: Vector :: Vec d r -> Vector
+ Data.Geometry.Vector.VectorFixed: Vector :: Vec d r -> Vector (d :: Nat) (r :: *)
- Data.Geometry.Vector.VectorFixed: [_unV] :: Vector -> Vec d r
+ Data.Geometry.Vector.VectorFixed: [_unV] :: Vector (d :: Nat) (r :: *) -> Vec d r
- Data.PlaneGraph: FaceId :: VertexId s (DualOf w) -> FaceId
+ Data.PlaneGraph: FaceId :: VertexId s (DualOf w) -> FaceId (s :: k) (w :: World)
- Data.PlaneGraph: VertexId :: Int -> VertexId
+ Data.PlaneGraph: VertexId :: Int -> VertexId (s :: k) (w :: World)
- Data.PlaneGraph: [_unFaceId] :: FaceId -> VertexId s (DualOf w)
+ Data.PlaneGraph: [_unFaceId] :: FaceId (s :: k) (w :: World) -> VertexId s (DualOf w)
- Data.PlaneGraph: [_unVertexId] :: VertexId -> Int
+ Data.PlaneGraph: [_unVertexId] :: VertexId (s :: k) (w :: World) -> Int
- Data.PlaneGraph: dual :: () => Getter (PlanarGraph s w v e f) (PlanarGraph s (DualOf w) f e v)
+ Data.PlaneGraph: dual :: forall k (s :: k) (w :: World) v e f. Getter (PlanarGraph s w v e f) (PlanarGraph s (DualOf w) f e v)
- Data.PlaneGraph: graph :: forall s_a30Ob v_a30Oc e_a30Od f_a30Oe r_a30Of s_a30ZX v_a30ZY e_a30ZZ f_a3100 r_a3101. Iso (PlaneGraph s_a30Ob v_a30Oc e_a30Od f_a30Oe r_a30Of) (PlaneGraph s_a30ZX v_a30ZY e_a30ZZ f_a3100 r_a3101) (PlanarGraph s_a30Ob 'Primal (VertexData r_a30Of v_a30Oc) e_a30Od f_a30Oe) (PlanarGraph s_a30ZX 'Primal (VertexData r_a3101 v_a30ZY) e_a30ZZ f_a3100)
+ Data.PlaneGraph: graph :: forall k_a2XvW (s_a2Xva :: k_a2XvW) v_a2Xvb e_a2Xvc f_a2Xvd r_a2Xve k_a2XGe (s_a2XG9 :: k_a2XGe) v_a2XGa e_a2XGb f_a2XGc r_a2XGd. Iso (PlaneGraph (s_a2Xva :: k_a2XvW) v_a2Xvb e_a2Xvc f_a2Xvd r_a2Xve) (PlaneGraph (s_a2XG9 :: k_a2XGe) v_a2XGa e_a2XGb f_a2XGc r_a2XGd) (PlanarGraph s_a2Xva 'Primal (VertexData r_a2Xve v_a2Xvb) e_a2Xvc f_a2Xvd) (PlanarGraph s_a2XG9 'Primal (VertexData r_a2XGd v_a2XGa) e_a2XGb f_a2XGc)
- Data.PlaneGraph: location :: forall r_a30z8 v_a30z9 r_a30NV. Lens (VertexData r_a30z8 v_a30z9) (VertexData r_a30NV v_a30z9) (Point 2 r_a30z8) (Point 2 r_a30NV)
+ Data.PlaneGraph: location :: forall r_a2Xgg v_a2Xgh r_a2XuU. Lens (VertexData r_a2Xgg v_a2Xgh) (VertexData r_a2XuU v_a2Xgh) (Point 2 r_a2Xgg) (Point 2 r_a2XuU)
- Data.PlaneGraph: twin :: () => Dart s -> Dart s
+ Data.PlaneGraph: twin :: forall k (s :: k). Dart s -> Dart s
- Data.PlaneGraph: type FaceId' (s :: k) = FaceId s Primal
+ Data.PlaneGraph: type FaceId' (s :: k) = FaceId s 'Primal
- Data.PlaneGraph: type VertexId' (s :: k) = VertexId s Primal
+ Data.PlaneGraph: type VertexId' (s :: k) = VertexId s 'Primal
- Data.PlaneGraph: type family DataOf g i :: Type;
+ Data.PlaneGraph: type family DataOf g i;
- Data.PlaneGraph: vData :: forall r_a30z8 v_a30z9 v_a30NW. Lens (VertexData r_a30z8 v_a30z9) (VertexData r_a30z8 v_a30NW) v_a30z9 v_a30NW
+ Data.PlaneGraph: vData :: forall r_a2Xgg v_a2Xgh v_a2XuV. Lens (VertexData r_a2Xgg v_a2Xgh) (VertexData r_a2Xgg v_a2XuV) v_a2Xgh v_a2XuV
- Data.PlaneGraph.Core: FaceId :: VertexId s (DualOf w) -> FaceId
+ Data.PlaneGraph.Core: FaceId :: VertexId s (DualOf w) -> FaceId (s :: k) (w :: World)
- Data.PlaneGraph.Core: VertexId :: Int -> VertexId
+ Data.PlaneGraph.Core: VertexId :: Int -> VertexId (s :: k) (w :: World)
- Data.PlaneGraph.Core: [_unFaceId] :: FaceId -> VertexId s (DualOf w)
+ Data.PlaneGraph.Core: [_unFaceId] :: FaceId (s :: k) (w :: World) -> VertexId s (DualOf w)
- Data.PlaneGraph.Core: [_unVertexId] :: VertexId -> Int
+ Data.PlaneGraph.Core: [_unVertexId] :: VertexId (s :: k) (w :: World) -> Int
- Data.PlaneGraph.Core: dual :: () => Getter (PlanarGraph s w v e f) (PlanarGraph s (DualOf w) f e v)
+ Data.PlaneGraph.Core: dual :: forall k (s :: k) (w :: World) v e f. Getter (PlanarGraph s w v e f) (PlanarGraph s (DualOf w) f e v)
- Data.PlaneGraph.Core: fromAdjacencyLists :: (Foldable h, Functor h) => [(VertexId s w, h (VertexId s w))] -> PlanarGraph s w () () ()
+ Data.PlaneGraph.Core: fromAdjacencyLists :: forall k (s :: k) (w :: World) h. (Foldable h, Functor h) => [(VertexId s w, h (VertexId s w))] -> PlanarGraph s w () () ()
- Data.PlaneGraph.Core: graph :: forall s_a30Ob v_a30Oc e_a30Od f_a30Oe r_a30Of s_a30ZX v_a30ZY e_a30ZZ f_a3100 r_a3101. Iso (PlaneGraph s_a30Ob v_a30Oc e_a30Od f_a30Oe r_a30Of) (PlaneGraph s_a30ZX v_a30ZY e_a30ZZ f_a3100 r_a3101) (PlanarGraph s_a30Ob 'Primal (VertexData r_a30Of v_a30Oc) e_a30Od f_a30Oe) (PlanarGraph s_a30ZX 'Primal (VertexData r_a3101 v_a30ZY) e_a30ZZ f_a3100)
+ Data.PlaneGraph.Core: graph :: forall k_a2XvW (s_a2Xva :: k_a2XvW) v_a2Xvb e_a2Xvc f_a2Xvd r_a2Xve k_a2XGe (s_a2XG9 :: k_a2XGe) v_a2XGa e_a2XGb f_a2XGc r_a2XGd. Iso (PlaneGraph (s_a2Xva :: k_a2XvW) v_a2Xvb e_a2Xvc f_a2Xvd r_a2Xve) (PlaneGraph (s_a2XG9 :: k_a2XGe) v_a2XGa e_a2XGb f_a2XGc r_a2XGd) (PlanarGraph s_a2Xva 'Primal (VertexData r_a2Xve v_a2Xvb) e_a2Xvc f_a2Xvd) (PlanarGraph s_a2XG9 'Primal (VertexData r_a2XGd v_a2XGa) e_a2XGb f_a2XGc)
- Data.PlaneGraph.Core: location :: forall r_a30z8 v_a30z9 r_a30NV. Lens (VertexData r_a30z8 v_a30z9) (VertexData r_a30NV v_a30z9) (Point 2 r_a30z8) (Point 2 r_a30NV)
+ Data.PlaneGraph.Core: location :: forall r_a2Xgg v_a2Xgh r_a2XuU. Lens (VertexData r_a2Xgg v_a2Xgh) (VertexData r_a2XuU v_a2Xgh) (Point 2 r_a2Xgg) (Point 2 r_a2XuU)
- Data.PlaneGraph.Core: twin :: () => Dart s -> Dart s
+ Data.PlaneGraph.Core: twin :: forall k (s :: k). Dart s -> Dart s
- Data.PlaneGraph.Core: type FaceId' (s :: k) = FaceId s Primal
+ Data.PlaneGraph.Core: type FaceId' (s :: k) = FaceId s 'Primal
- Data.PlaneGraph.Core: type VertexId' (s :: k) = VertexId s Primal
+ Data.PlaneGraph.Core: type VertexId' (s :: k) = VertexId s 'Primal
- Data.PlaneGraph.Core: type family DataOf g i :: Type;
+ Data.PlaneGraph.Core: type family DataOf g i;
- Data.PlaneGraph.Core: vData :: forall r_a30z8 v_a30z9 v_a30NW. Lens (VertexData r_a30z8 v_a30z9) (VertexData r_a30z8 v_a30NW) v_a30z9 v_a30NW
+ Data.PlaneGraph.Core: vData :: forall r_a2Xgg v_a2Xgh v_a2XuV. Lens (VertexData r_a2Xgg v_a2Xgh) (VertexData r_a2Xgg v_a2XuV) v_a2Xgh v_a2XuV
- Graphics.Camera: cameraPosition :: forall r_a3ATc. Lens' (Camera r_a3ATc) (Point 3 r_a3ATc)
+ Graphics.Camera: cameraPosition :: Lens' (Camera r) (Point 3 r)
- Graphics.Camera: farDist :: forall r_a3ATc. Lens' (Camera r_a3ATc) r_a3ATc
+ Graphics.Camera: farDist :: Lens' (Camera r) r
- Graphics.Camera: nearDist :: forall r_a3ATc. Lens' (Camera r_a3ATc) r_a3ATc
+ Graphics.Camera: nearDist :: Lens' (Camera r) r
- Graphics.Camera: rawCameraNormal :: forall r_a3ATc. Lens' (Camera r_a3ATc) (Vector 3 r_a3ATc)
+ Graphics.Camera: rawCameraNormal :: Lens' (Camera r) (Vector 3 r)
- Graphics.Camera: rawViewUp :: forall r_a3ATc. Lens' (Camera r_a3ATc) (Vector 3 r_a3ATc)
+ Graphics.Camera: rawViewUp :: Lens' (Camera r) (Vector 3 r)
- Graphics.Camera: screenDimensions :: forall r_a3ATc. Lens' (Camera r_a3ATc) (Vector 2 r_a3ATc)
+ Graphics.Camera: screenDimensions :: Lens' (Camera r) (Vector 2 r)
- Graphics.Camera: viewPlaneDepth :: forall r_a3ATc. Lens' (Camera r_a3ATc) r_a3ATc
+ Graphics.Camera: viewPlaneDepth :: Lens' (Camera r) r
Files
- README.md +46/−39
- benchmark/Algorithms/Geometry/ClosestPair/Bench.hs +36/−0
- benchmark/Algorithms/Geometry/ConvexHull/Bench.hs +65/−0
- benchmark/Algorithms/Geometry/ConvexHull/GrahamFam.hs +103/−0
- benchmark/Algorithms/Geometry/ConvexHull/GrahamFam6.hs +103/−0
- benchmark/Algorithms/Geometry/ConvexHull/GrahamFamPeano.hs +107/−0
- benchmark/Algorithms/Geometry/ConvexHull/GrahamFixed.hs +104/−0
- benchmark/Algorithms/Geometry/ConvexHull/GrahamV2.hs +95/−0
- benchmark/Algorithms/Geometry/LineSegmentIntersection/Bench.hs +50/−0
- benchmark/Algorithms/Geometry/LineSegmentIntersection/BentleyOttmannOld.hs +236/−0
- benchmark/Algorithms/Geometry/PolygonTriangulation/Bench.hs +64/−0
- benchmark/Algorithms/Geometry/PolygonTriangulation/MakeMonotoneOld.hs +312/−0
- benchmark/Benchmark/Util.hs +7/−0
- benchmark/Benchmarks.hs +10/−0
- benchmark/Data/Geometry/IntervalTreeBench.hs +75/−0
- benchmark/Data/Geometry/Vector/VectorFamily6.hs +257/−0
- changelog.org +26/−0
- doctests.hs +1/−1
- hgeometry.cabal +141/−27
- planargraph.hs +136/−0
- src/Algorithms/Geometry/ClosestPair.hs +14/−0
- src/Algorithms/Geometry/ClosestPair/DivideAndConquer.hs +3/−3
- src/Algorithms/Geometry/ConvexHull.hs +10/−0
- src/Algorithms/Geometry/ConvexHull/DivideAndConquer.hs +4/−4
- src/Algorithms/Geometry/ConvexHull/GrahamScan.hs +13/−3
- src/Algorithms/Geometry/ConvexHull/JarvisMarch.hs +12/−6
- src/Algorithms/Geometry/ConvexHull/Naive.hs +16/−11
- src/Algorithms/Geometry/ConvexHull/QuickHull.hs +12/−5
- src/Algorithms/Geometry/DelaunayTriangulation/DivideAndConquer.hs +44/−34
- src/Algorithms/Geometry/DelaunayTriangulation/Naive.hs +13/−7
- src/Algorithms/Geometry/DelaunayTriangulation/Types.hs +45/−19
- src/Algorithms/Geometry/Diameter.hs +13/−0
- src/Algorithms/Geometry/Diameter/ConvexHull.hs +35/−0
- src/Algorithms/Geometry/Diameter/Naive.hs +10/−0
- src/Algorithms/Geometry/EuclideanMST.hs +47/−0
- src/Algorithms/Geometry/EuclideanMST/EuclideanMST.hs +5/−35
- src/Algorithms/Geometry/FrechetDistance/Discrete.hs +7/−0
- src/Algorithms/Geometry/InPolygon.hs +155/−0
- src/Algorithms/Geometry/LineSegmentIntersection.hs +18/−1
- src/Algorithms/Geometry/LineSegmentIntersection/BentleyOttmann.hs +13/−7
- src/Algorithms/Geometry/LineSegmentIntersection/BooleanSweep.hs +171/−0
- src/Algorithms/Geometry/LineSegmentIntersection/Naive.hs +8/−4
- src/Algorithms/Geometry/LineSegmentIntersection/Types.hs +7/−0
- src/Algorithms/Geometry/LinearProgramming/LP2DRIC.hs +23/−20
- src/Algorithms/Geometry/LowerEnvelope/DualCH.hs +7/−0
- src/Algorithms/Geometry/PolyLineSimplification/DouglasPeucker.hs +8/−1
- src/Algorithms/Geometry/PolygonTriangulation/EarClip.hs +525/−0
- src/Algorithms/Geometry/PolygonTriangulation/MakeMonotone.hs +29/−22
- src/Algorithms/Geometry/PolygonTriangulation/Triangulate.hs +7/−1
- src/Algorithms/Geometry/PolygonTriangulation/TriangulateMonotone.hs +46/−25
- src/Algorithms/Geometry/PolygonTriangulation/Types.hs +8/−0
- src/Algorithms/Geometry/RedBlueSeparator/RIC.hs +2/−2
- src/Algorithms/Geometry/SSSP.hs +454/−0
- src/Algorithms/Geometry/SSSP/Naive.hs +90/−0
- src/Algorithms/Geometry/SmallestEnclosingBall.hs +20/−0
- src/Algorithms/Geometry/SmallestEnclosingBall/Naive.hs +7/−5
- src/Algorithms/Geometry/SmallestEnclosingBall/RIC.hs +4/−6
- src/Algorithms/Geometry/SmallestEnclosingBall/Types.hs +5/−5
- src/Algorithms/Geometry/SoS.hs +0/−6
- src/Algorithms/Geometry/SoS/AsPoint.hs +2/−4
- src/Algorithms/Geometry/SoS/Expr.hs +2/−1
- src/Algorithms/Geometry/SoS/Orientation.hs +2/−2
- src/Algorithms/Geometry/SoS/Sign.hs +1/−0
- src/Algorithms/Geometry/SoS/Symbolic.hs +11/−4
- src/Algorithms/Geometry/VisibilityPolygon/Lee.hs +537/−0
- src/Algorithms/Geometry/WSPD.hs +474/−0
- src/Algorithms/Geometry/WSPD/Types.hs +85/−0
- src/Algorithms/Geometry/WellSeparatedPairDecomposition/Types.hs +7/−71
- src/Algorithms/Geometry/WellSeparatedPairDecomposition/WSPD.hs +5/−448
- src/Data/Geometry.hs +1/−1
- src/Data/Geometry/Arrangement/Internal.hs +19/−18
- src/Data/Geometry/Ball.hs +11/−9
- src/Data/Geometry/BezierSpline.hs +15/−5
- src/Data/Geometry/Boundary.hs +7/−0
- src/Data/Geometry/Box/Corners.hs +10/−2
- src/Data/Geometry/Box/Internal.hs +21/−5
- src/Data/Geometry/Box/Sides.hs +7/−0
- src/Data/Geometry/Directions.hs +13/−6
- src/Data/Geometry/Duality.hs +7/−0
- src/Data/Geometry/Ellipse.hs +8/−1
- src/Data/Geometry/HalfLine.hs +118/−64
- src/Data/Geometry/HalfSpace.hs +7/−7
- src/Data/Geometry/HyperPlane.hs +10/−3
- src/Data/Geometry/Interval.hs +28/−21
- src/Data/Geometry/Interval/Util.hs +8/−0
- src/Data/Geometry/IntervalTree.hs +9/−2
- src/Data/Geometry/KDTree.hs +18/−12
- src/Data/Geometry/Line.hs +9/−9
- src/Data/Geometry/Line/Internal.hs +32/−11
- src/Data/Geometry/LineSegment.hs +15/−299
- src/Data/Geometry/LineSegment/Internal.hs +406/−0
- src/Data/Geometry/Matrix.hs +30/−14
- src/Data/Geometry/PlanarSubdivision.hs +8/−9
- src/Data/Geometry/PlanarSubdivision/Basic.hs +9/−7
- src/Data/Geometry/PlanarSubdivision/Merge.hs +11/−9
- src/Data/Geometry/PlanarSubdivision/Raw.hs +1/−1
- src/Data/Geometry/Point.hs +10/−10
- src/Data/Geometry/Point/Class.hs +25/−7
- src/Data/Geometry/Point/Internal.hs +72/−58
- src/Data/Geometry/Point/Orientation/Degenerate.hs +94/−18
- src/Data/Geometry/Point/Quadrants.hs +7/−14
- src/Data/Geometry/PointLocation.hs +12/−0
- src/Data/Geometry/PointLocation/PersistentSweep.hs +177/−0
- src/Data/Geometry/PolyLine.hs +24/−6
- src/Data/Geometry/Polygon.hs +88/−26
- src/Data/Geometry/Polygon/Convex.hs +376/−70
- src/Data/Geometry/Polygon/Core.hs +522/−281
- src/Data/Geometry/Polygon/Extremes.hs +5/−6
- src/Data/Geometry/Polygon/Inflate.hs +142/−0
- src/Data/Geometry/Polygon/Monotone.hs +118/−0
- src/Data/Geometry/PrioritySearchTree.hs +2/−2
- src/Data/Geometry/Properties.hs +0/−1
- src/Data/Geometry/QuadTree.hs +9/−1
- src/Data/Geometry/QuadTree/Cell.hs +9/−2
- src/Data/Geometry/QuadTree/Quadrants.hs +7/−0
- src/Data/Geometry/QuadTree/Split.hs +12/−4
- src/Data/Geometry/QuadTree/Tree.hs +7/−0
- src/Data/Geometry/RangeTree.hs +7/−2
- src/Data/Geometry/RangeTree/Generic.hs +7/−2
- src/Data/Geometry/RangeTree/Measure.hs +8/−0
- src/Data/Geometry/SegmentTree.hs +7/−0
- src/Data/Geometry/SegmentTree/Generic.hs +1/−1
- src/Data/Geometry/Slab.hs +28/−21
- src/Data/Geometry/SubLine.hs +50/−24
- src/Data/Geometry/Transformation.hs +51/−3
- src/Data/Geometry/Triangle.hs +57/−36
- src/Data/Geometry/Vector.hs +49/−13
- src/Data/Geometry/Vector/VectorFamily.hs +74/−35
- src/Data/Geometry/Vector/VectorFamilyPeano.hs +33/−10
- src/Data/Geometry/Vector/VectorFixed.hs +15/−2
- src/Data/Geometry/VerticalRayShooting.hs +12/−0
- src/Data/Geometry/VerticalRayShooting/PersistentSweep.hs +230/−0
- src/Data/PlaneGraph.hs +0/−2
- src/Data/PlaneGraph/Core.hs +32/−35
- src/Data/PlaneGraph/IO.hs +2/−3
- src/Graphics/Camera.hs +33/−5
- test/Algorithms/Geometry/LineSegmentIntersection/manual.ipe +0/−324
- test/Algorithms/Geometry/LineSegmentIntersection/selfIntersections.ipe +0/−313
- test/Algorithms/Geometry/LinearProgramming/manual.ipe +0/−370
- test/Algorithms/Geometry/LowerEnvelope/manual.ipe +0/−299
- test/Algorithms/Geometry/PolygonTriangulation/monotone.ipe +0/−364
- test/Algorithms/Geometry/PolygonTriangulation/simplepolygon6.ipe +0/−297
- test/Algorithms/Geometry/RedBlueSeparator/manual.ipe +0/−355
- test/Algorithms/Geometry/SmallestEnclosingDisk/manual.ipe +0/−369
- test/Data/Geometry/Polygon/Convex/convexTests.ipe +0/−308
- test/Data/Geometry/Polygon/star_shaped.ipe +0/−339
- test/Data/Geometry/arrangement.ipe +0/−296
- test/Data/Geometry/arrangement.ipe.out.ipe +0/−247
- test/Data/Geometry/pointInPolygon.ipe +0/−311
- test/Data/Geometry/pointInTriangle.ipe +0/−310
- test/Data/PlaneGraph/myPlaneGraph.yaml +0/−90
- test/Data/PlaneGraph/small.yaml +0/−58
- test/Data/PlaneGraph/testsegs.png binary
README.md view
@@ -1,8 +1,9 @@ HGeometry ========= -[](https://travis-ci.org/noinia/hgeometry)-[](https://hackage.haskell.org/package/hgeometry)++[](https://hackage.haskell.org/package/hgeometry)+[](https://noinia.github.io/hgeometry/doc/) HGeometry is a library for computing with geometric objects in Haskell. It defines basic geometric types and primitives, and it@@ -34,19 +35,23 @@ HGeometry is split into a few smaller packages. In particular: -- hgeometry-combinatorial : defines some non-geometric+- hgeometry : defines the actual geometric data types, data+ structures, and algorithms,+- hgeometry-combinatorial : defines the non-geometric (i.e. combinatorial) data types, data structures, and algorithms.+ - hgeometry-ipe : defines functions for working with [ipe](http://ipe.otfried.org) files. - hgeometry-svg : defines functions for working with svg files.-- hgeometry-interactive : defines functions for building an+- hgeometry-web : defines functions for building an interactive viewer using [miso](https://haskell-miso.org).-- hgeometry : defines the actual geometric data types, data- structures, and algorithms.+- hgeometry-interactive : defines functions for building an+ interactive viewer using+ [reflex-sdl2](https://hackage.haskell.org/package/reflex-sdl2). -In addition there is a [hgeometry-examples](hgeometry-examples)-package that defines some example applications, and a hgometry-test-package that contains all testcases. The latter is to work around a-bug in cabal.+In addition there are [hgeometry-examples](hgeometry-examples) and+[hgeometry-showcase](hgeometry-showcase) packages that define some+example applications, and a hgometry-test package that contains all+testcases. The latter is to work around a bug in cabal. Available Geometric Algorithms ------------------------------@@ -56,25 +61,28 @@ implements some more advanced geometric algorithms. In particuar, the following algorithms are currently available: -* two \(O(n \log n)\) time algorithms for convex hull in- $\mathbb{R}^2$: the typical Graham scan, and a divide and conquer algorithm,-* an \(O(n)\) expected time algorithm for smallest enclosing disk in $\mathbb{R}^$2,+* two *O(n log n)* time algorithms for convex hull in+ ℝ²: the typical Graham scan, and a divide and conquer algorithm,+* an *O(n)* expected time algorithm for smallest enclosing disk in ℝ², * the well-known Douglas Peucker polyline line simplification algorithm,-* an \(O(n \log n)\) time algorithm for computing the Delaunay triangulation-(using divide and conquer).-* an \(O(n \log n)\) time algorithm for computing the Euclidean Minimum Spanning-Tree (EMST), based on computing the Delaunay Triangulation.-* an \(O(\log^2 n)\) time algorithm to find extremal points and tangents on/to a- convex polygon.-* An optimal \(O(n+m)\) time algorithm to compute the Minkowski sum of two convex-polygons.-* An \(O(1/\varepsilon^dn\log n)\) time algorithm for constructing a Well-Separated pair- decomposition.-* The classic (optimal) \(O(n\log n)\) time divide and conquer algorithm to- compute the closest pair among a set of \(n\) points in \(\mathbb{R}^2\).-* An \(O(nm)\) time algorithm to compute the discrete Fr\'echet- distance of two sequences of points (curves) of length \(n\) and- \(m\), respectively.+* an *O(n log n)* time algorithm for computing the Delaunay triangulation+(using divide and conquer),+* an *O(n log n)* time algorithm for computing the Euclidean Minimum Spanning+Tree (EMST), based on computing the Delaunay Triangulation,+* an *O(log n)* time algorithm to find extremal points and tangents on/to a+ convex polygon,+* an optimal *O(n+m)* time algorithm to compute the Minkowski sum of two convex+polygons,+* an *O(1/εᵈn log n)* time algorithm for constructing a Well-Separated pair+ decomposition,+* the classic (optimal) *O(n log n)* time divide and conquer algorithm to+ compute the closest pair among a set of *n* points in ℝ²,+* an *O(nm)* time algorithm to compute the discrete Fréchet+ distance of two sequences of points (curves) of length *n* and+ *m*, respectively.+* an *O(n)* time single-source shortest path algorithm on triangulated polygons.+* an *O(n log n)* time algorithm for generating random convex polygons.+* an *O(n)* time algorithm for finding the convex hull of a simple polygon. Available Geometric Data Structures -----------------------------------@@ -85,11 +93,13 @@ * A one dimensional Segment Tree. The base tree is static. * A one dimensional Interval Tree. The base tree is static. * A KD-Tree. The base tree is static.+* An *O(n log n)* size planar point location data structure supporting+ *O(log n)* queries. There is also support for working with planar subdivisions. As a result, [hgeometry-combinatorial] also includes a data structure for working with planar graphs. In particular, it has an `EdgeOracle` data-structure, that can be built in \(O(n)\) time that can test if the+structure, that can be built in *O(n)* time that can test if the planar graph contains an edge in constant time. @@ -101,8 +111,8 @@ i.e. because of floating point errors one may get completely wrong results. Hence, I *strongly* advise against using `Double` or `Float` for these types. In several algorithms it is sufficient if the type `r` is-`Fractional`. Hence, you can use an exact number type such as `Rational`.-+`Fractional`. Hence, you can use an exact number type such as+`Data.RealNumber.Rational` or `Data.Ratio.Rational`. Working with additional data ----------------------------@@ -119,14 +129,11 @@ To still allow for some extensibility our types will use the Ext (:+) type, as defined in the hgeometry-combinatorial package. For example,-our `Polygon` data type, has an extra type parameter `p` that allows-the vertices of the polygon to cary some extra information of type `p`-(for example a color, a size, or whatever).+our `LineSegment` data type, has an extra type parameter `p` that+allows the vertices of the line segment to carry some extra+information of type `p` (for example a color, a size, or+whatever). Polylines, Polylygons, Boxes, etc have similar such+parameters. -```haskell-data Polygon (t :: PolygonType) p r where- SimplePolygon :: C.CSeq (Point 2 r :+ p) -> Polygon Simple p r- MultiPolygon :: C.CSeq (Point 2 r :+ p) -> [Polygon Simple p r] -> Polygon Multi p r-``` In all places this extra data is accessable by the (:+) type in Data.Ext, which is essentially just a pair.
+ benchmark/Algorithms/Geometry/ClosestPair/Bench.hs view
@@ -0,0 +1,36 @@+module Algorithms.Geometry.ClosestPair.Bench where++import qualified Algorithms.Geometry.ClosestPair.DivideAndConquer as DivideAndConquer+import qualified Algorithms.Geometry.ClosestPair.Naive as Naive++import Control.Monad.Random+import Data.Ext+import Data.Geometry.Point+import Data.Hashable+import Data.LSeq (LSeq)+import qualified Data.LSeq as LSeq+import Test.Tasty.Bench++--------------------------------------------------------------------------------++genPts :: (Ord r, Random r, RandomGen g)+ => Int -> Rand g (LSeq 2 (Point 2 r :+ ()))+genPts n | n >= 2 = LSeq.promise . LSeq.fromList <$> replicateM n (fmap ext getRandom)+ | otherwise = error "genPts: Need at least 2 points"++gen :: StdGen+gen = mkStdGen (hash "closest pair")++-- | Benchmark computing the closest pair+benchmark :: Benchmark+benchmark = bgroup "ClosestPair"+ [ bgroup (show n) (build $ evalRand (genPts @Int n) gen)+ | n <- sizes'+ ]+ where+ sizes' = [500]++ build pts = [ bench "sort" $ nf LSeq.unstableSort pts+ , bench "Div&Conq" $ nf DivideAndConquer.closestPair pts+ , bench "Naive" $ nf Naive.closestPair pts+ ]
+ benchmark/Algorithms/Geometry/ConvexHull/Bench.hs view
@@ -0,0 +1,65 @@+module Algorithms.Geometry.ConvexHull.Bench (benchmark) where++import qualified Algorithms.Geometry.ConvexHull.DivideAndConquer as DivideAndConquer+import qualified Algorithms.Geometry.ConvexHull.GrahamScan as GrahamScan+import qualified Algorithms.Geometry.ConvexHull.JarvisMarch as JarvisMarch+import qualified Algorithms.Geometry.ConvexHull.QuickHull as QuickHull++import Control.Monad.Random+import Data.Double.Approximate+import Data.Ext+import Data.Geometry.Point+import Data.Hashable+import Data.List.NonEmpty (NonEmpty (..))+import qualified Data.List.NonEmpty as NonEmpty+import Data.RealNumber.Rational+import Test.Tasty.Bench++type R = RealNumber 5++--------------------------------------------------------------------------------++genPts :: (Ord r, Random r, RandomGen g)+ => Int -> Rand g (NonEmpty (Point 2 r :+ ()))+genPts n = NonEmpty.fromList <$> replicateM n (fmap ext getRandom)++-- genPts' :: (Ord r, Random r, RandomGen g) => Int+-- -> Rand g ( NonEmpty (Point 2 r :+ ())+-- , NonEmpty (Point 2 r Multi.:+ '[])+-- )+-- genPts' n = (\pts -> (pts, fmap (\ ~(c :+ _) -> Multi.ext c) pts)+-- ) <$> genPts n++gen :: StdGen+gen = mkStdGen (hash "convex hull")++-- | Benchmark building the convexHull+benchmark :: Benchmark+benchmark = bgroup "ConvexHull" $+ [ bgroup ("1e"++show i ++ "/RealNumber") (convexHullFractional $ evalRand (genPts @R n) gen)+ | i <- [3, 4::Int]+ , let n = 10^i+ ] +++ [ bgroup ("1e"++show i ++ "/Int") (convexHullNum $ evalRand (genPts @Int n) gen)+ | i <- [4, 5::Int]+ , let n = 10^i+ ] +++ [ bgroup ("1e"++show i ++ "/SafeDouble") (convexHullFractional $ evalRand (genPts @SafeDouble n) gen)+ | i <- [4, 5::Int]+ , let n = 10^i+ ] +++ [ bgroup ("1e"++show i ++ "/Double") (convexHullFractional $ evalRand (genPts @Double n) gen)+ | i <- [4, 5::Int]+ , let n = 10^i ]+ where+ convexHullFractional pts =+ [ bench "GrahamScan" $ nf GrahamScan.convexHull pts+ , bench "DivideAndConquer" $ nf DivideAndConquer.convexHull pts+ , bench "QuickHull" $ nf QuickHull.convexHull pts+ , bench "JarvisMarch" $ nf JarvisMarch.convexHull pts+ ]+ convexHullNum pts =+ [ bench "GrahamScan" $ nf GrahamScan.convexHull pts+ , bench "DivideAndConquer" $ nf DivideAndConquer.convexHull pts+ , bench "JarvisMarch" $ nf JarvisMarch.convexHull pts+ ]
+ benchmark/Algorithms/Geometry/ConvexHull/GrahamFam.hs view
@@ -0,0 +1,103 @@+{-# LANGUAGE UndecidableInstances #-}+module Algorithms.Geometry.ConvexHull.GrahamFam( convexHull+ , upperHull+ , lowerHull, fromP+ ) where++import Control.DeepSeq+import Control.Lens ((^.))+import Data.Ext+import Data.Geometry.Point+import qualified Data.Geometry.Vector.VectorFamily as VF+import Data.List.NonEmpty (NonEmpty(..))+import qualified Data.List.NonEmpty as NonEmpty+import Data.Monoid+import GHC.TypeLits+++newtype MyPoint d r = MyPoint (VF.Vector d r)++deriving instance (VF.Arity d, Eq r) => Eq (MyPoint d r)+deriving instance (VF.Arity d, Ord r) => Ord (MyPoint d r)+deriving instance (VF.Arity d, Show r) => Show (MyPoint d r)+deriving instance (NFData (VF.Vector d r)) => NFData (MyPoint d r)++pattern MyPoint2 x y = MyPoint (VF.Vector2 x y)+++-- instance (NFData r, Arity d) => NFData (MyPoint d r) where+-- rnf (MyPoint x y) = rnf (x,y)+-- rnf (MyP p) = rnf p++toP :: MyPoint 2 r :+ e -> Point 2 r :+ e+toP (MyPoint2 x y :+ e) = Point2 x y :+ e++fromP :: Point 2 r :+ e -> MyPoint 2 r :+ e+fromP (Point2 x y :+ e) = MyPoint2 x y :+ e+++subt :: Num r => MyPoint 2 r -> MyPoint 2 r -> MyPoint 2 r+(MyPoint2 x y) `subt` (MyPoint2 a b) = MyPoint2 (x-a) (y-b)++newtype ConvexPolygon p r = ConvexPolygon [Point 2 r :+ p] deriving (Show,Eq,NFData)++-- | \(O(n \log n)\) time ConvexHull using Graham-Scan. The resulting polygon is+-- given in clockwise order.+convexHull :: (Ord r, Num r)+ => NonEmpty (MyPoint 2 r :+ p) -> ConvexPolygon p r+convexHull (p :| []) = ConvexPolygon $ [toP p]+convexHull ps = let ps' = NonEmpty.toList . NonEmpty.sortBy incXdecY $ ps+ uh = NonEmpty.tail . hull' $ ps'+ lh = NonEmpty.tail . hull' $ reverse ps'+ in ConvexPolygon . map toP . reverse $ lh ++ uh++upperHull :: (Ord r, Num r) => NonEmpty (MyPoint 2 r :+ p) -> NonEmpty (MyPoint 2 r :+ p)+upperHull = hull id+++lowerHull :: (Ord r, Num r) => NonEmpty (MyPoint 2 r :+ p) -> NonEmpty (MyPoint 2 r :+ p)+lowerHull = hull reverse+++-- | Helper function so that that can compute both the upper or the lower hull, depending+-- on the function f+hull :: (Ord r, Num r)+ => ([MyPoint 2 r :+ p] -> [MyPoint 2 r :+ p])+ -> NonEmpty (MyPoint 2 r :+ p) -> NonEmpty (MyPoint 2 r :+ p)+hull _ h@(_ :| []) = h+hull f pts = hull' . f+ . NonEmpty.toList . NonEmpty.sortBy incXdecY $ pts++incXdecY :: Ord r => (MyPoint 2 r) :+ p -> (MyPoint 2 r) :+ q -> Ordering+incXdecY (MyPoint2 px py :+ _) (MyPoint2 qx qy :+ _) =+ compare px qx <> compare qy py+++-- | Precondition: The list of input points is sorted+hull' :: (Ord r, Num r) => [MyPoint 2 r :+ p] -> NonEmpty (MyPoint 2 r :+ p)+hull' (a:b:ps) = NonEmpty.fromList $ hull'' [b,a] ps+ where+ hull'' h [] = h+ hull'' h (p:ps') = hull'' (cleanMiddle (p:h)) ps'++ cleanMiddle h@[_,_] = h+ cleanMiddle h@(z:y:x:rest)+ | rightTurn (x^.core) (y^.core) (z^.core) = h+ | otherwise = cleanMiddle (z:x:rest)+ cleanMiddle _ = error "cleanMiddle: too few points"++rightTurn :: (Ord r, Num r) => MyPoint 2 r -> MyPoint 2 r -> MyPoint 2 r -> Bool+rightTurn a b c = ccwP a b c == CW++++ccwP :: (Ord r, Num r) => MyPoint 2 r -> MyPoint 2 r -> MyPoint 2 r -> CCW+ccwP p q r = case z `compare` 0 of+ LT -> CW+ GT -> CCW+ EQ -> CoLinear+ where++ MyPoint2 ux uy = q `subt` p+ MyPoint2 vx vy = r `subt` p+ z = ux * vy - uy * vx
+ benchmark/Algorithms/Geometry/ConvexHull/GrahamFam6.hs view
@@ -0,0 +1,103 @@+{-# LANGUAGE UndecidableInstances #-}+module Algorithms.Geometry.ConvexHull.GrahamFam6( convexHull+ , upperHull+ , lowerHull, fromP+ ) where++import Control.DeepSeq+import Control.Lens ((^.))+import Data.Ext+import Data.Geometry.Point+import qualified Data.Geometry.Vector.VectorFamily6 as VF+import Data.List.NonEmpty (NonEmpty(..))+import qualified Data.List.NonEmpty as NonEmpty+import Data.Monoid+import GHC.TypeLits+++newtype MyPoint d r = MyPoint (VF.Vector d r)++deriving instance (VF.Arity d, Eq r) => Eq (MyPoint d r)+deriving instance (VF.Arity d, Ord r) => Ord (MyPoint d r)+deriving instance (VF.Arity d, Show r) => Show (MyPoint d r)+deriving instance (NFData (VF.Vector d r)) => NFData (MyPoint d r)++pattern MyPoint2 x y = MyPoint (VF.Vector2 x y)+++-- instance (NFData r, Arity d) => NFData (MyPoint d r) where+-- rnf (MyPoint x y) = rnf (x,y)+-- rnf (MyP p) = rnf p++toP :: MyPoint 2 r :+ e -> Point 2 r :+ e+toP (MyPoint2 x y :+ e) = Point2 x y :+ e++fromP :: Point 2 r :+ e -> MyPoint 2 r :+ e+fromP (Point2 x y :+ e) = MyPoint2 x y :+ e+++subt :: Num r => MyPoint 2 r -> MyPoint 2 r -> MyPoint 2 r+(MyPoint2 x y) `subt` (MyPoint2 a b) = MyPoint2 (x-a) (y-b)++newtype ConvexPolygon p r = ConvexPolygon [Point 2 r :+ p] deriving (Show,Eq,NFData)++-- | \(O(n \log n)\) time ConvexHull using Graham-Scan. The resulting polygon is+-- given in clockwise order.+convexHull :: (Ord r, Num r)+ => NonEmpty (MyPoint 2 r :+ p) -> ConvexPolygon p r+convexHull (p :| []) = ConvexPolygon $ [toP p]+convexHull ps = let ps' = NonEmpty.toList . NonEmpty.sortBy incXdecY $ ps+ uh = NonEmpty.tail . hull' $ ps'+ lh = NonEmpty.tail . hull' $ reverse ps'+ in ConvexPolygon . map toP . reverse $ lh ++ uh++upperHull :: (Ord r, Num r) => NonEmpty (MyPoint 2 r :+ p) -> NonEmpty (MyPoint 2 r :+ p)+upperHull = hull id+++lowerHull :: (Ord r, Num r) => NonEmpty (MyPoint 2 r :+ p) -> NonEmpty (MyPoint 2 r :+ p)+lowerHull = hull reverse+++-- | Helper function so that that can compute both the upper or the lower hull, depending+-- on the function f+hull :: (Ord r, Num r)+ => ([MyPoint 2 r :+ p] -> [MyPoint 2 r :+ p])+ -> NonEmpty (MyPoint 2 r :+ p) -> NonEmpty (MyPoint 2 r :+ p)+hull _ h@(_ :| []) = h+hull f pts = hull' . f+ . NonEmpty.toList . NonEmpty.sortBy incXdecY $ pts++incXdecY :: Ord r => (MyPoint 2 r) :+ p -> (MyPoint 2 r) :+ q -> Ordering+incXdecY (MyPoint2 px py :+ _) (MyPoint2 qx qy :+ _) =+ compare px qx <> compare qy py+++-- | Precondition: The list of input points is sorted+hull' :: (Ord r, Num r) => [MyPoint 2 r :+ p] -> NonEmpty (MyPoint 2 r :+ p)+hull' (a:b:ps) = NonEmpty.fromList $ hull'' [b,a] ps+ where+ hull'' h [] = h+ hull'' h (p:ps') = hull'' (cleanMiddle (p:h)) ps'++ cleanMiddle h@[_,_] = h+ cleanMiddle h@(z:y:x:rest)+ | rightTurn (x^.core) (y^.core) (z^.core) = h+ | otherwise = cleanMiddle (z:x:rest)+ cleanMiddle _ = error "cleanMiddle: too few points"++rightTurn :: (Ord r, Num r) => MyPoint 2 r -> MyPoint 2 r -> MyPoint 2 r -> Bool+rightTurn a b c = ccwP a b c == CW++++ccwP :: (Ord r, Num r) => MyPoint 2 r -> MyPoint 2 r -> MyPoint 2 r -> CCW+ccwP p q r = case z `compare` 0 of+ LT -> CW+ GT -> CCW+ EQ -> CoLinear+ where++ MyPoint2 ux uy = q `subt` p+ MyPoint2 vx vy = r `subt` p+ z = ux * vy - uy * vx
+ benchmark/Algorithms/Geometry/ConvexHull/GrahamFamPeano.hs view
@@ -0,0 +1,107 @@+{-# LANGUAGE UndecidableInstances #-}+module Algorithms.Geometry.ConvexHull.GrahamFamPeano( convexHull+ , upperHull+ , lowerHull, fromP+ ) where++import Control.DeepSeq+import Control.Lens ((^.))+import Data.Ext+import Data.Geometry.Point+import qualified Data.Vector.Fixed.Cont as V+import qualified Data.Geometry.Vector.VectorFamilyPeano as VF+import Data.List.NonEmpty (NonEmpty(..))+import qualified Data.List.NonEmpty as NonEmpty+import Data.Monoid+import GHC.TypeLits+import qualified Linear.V2 as V2+++newtype MyPoint d r = MyPoint (VF.VectorFamily d r)++deriving instance (VF.ImplicitArity d, Eq r) => Eq (MyPoint d r)+deriving instance (VF.ImplicitArity d, Ord r) => Ord (MyPoint d r)+deriving instance (VF.ImplicitArity d, Show r) => Show (MyPoint d r)+deriving instance (NFData (VF.VectorFamily d r)) => NFData (MyPoint d r)++pattern Vector2 x y = VF.VectorFamily (V2.V2 x y)++pattern MyPoint2 x y = MyPoint (Vector2 x y)+++-- instance (NFData r, Arity d) => NFData (MyPoint d r) where+-- rnf (MyPoint x y) = rnf (x,y)+-- rnf (MyP p) = rnf p++toP :: MyPoint VF.Two r :+ e -> Point 2 r :+ e+toP (MyPoint2 x y :+ e) = Point2 x y :+ e++fromP :: Point 2 r :+ e -> MyPoint VF.Two r :+ e+fromP (Point2 x y :+ e) = MyPoint2 x y :+ e+++subt :: Num r => MyPoint VF.Two r -> MyPoint VF.Two r -> MyPoint VF.Two r+(MyPoint2 x y) `subt` (MyPoint2 a b) = MyPoint2 (x-a) (y-b)++newtype ConvexPolygon p r = ConvexPolygon [Point 2 r :+ p] deriving (Show,Eq,NFData)++-- | \(O(n \log n)\) time ConvexHull using Graham-Scan. The resulting polygon is+-- given in clockwise order.+convexHull :: (Ord r, Num r)+ => NonEmpty (MyPoint VF.Two r :+ p) -> ConvexPolygon p r+convexHull (p :| []) = ConvexPolygon $ [toP p]+convexHull ps = let ps' = NonEmpty.toList . NonEmpty.sortBy incXdecY $ ps+ uh = NonEmpty.tail . hull' $ ps'+ lh = NonEmpty.tail . hull' $ reverse ps'+ in ConvexPolygon . map toP . reverse $ lh ++ uh++upperHull :: (Ord r, Num r) => NonEmpty (MyPoint VF.Two r :+ p) -> NonEmpty (MyPoint VF.Two r :+ p)+upperHull = hull id+++lowerHull :: (Ord r, Num r) => NonEmpty (MyPoint VF.Two r :+ p) -> NonEmpty (MyPoint VF.Two r :+ p)+lowerHull = hull reverse+++-- | Helper function so that that can compute both the upper or the lower hull, depending+-- on the function f+hull :: (Ord r, Num r)+ => ([MyPoint VF.Two r :+ p] -> [MyPoint VF.Two r :+ p])+ -> NonEmpty (MyPoint VF.Two r :+ p) -> NonEmpty (MyPoint VF.Two r :+ p)+hull _ h@(_ :| []) = h+hull f pts = hull' . f+ . NonEmpty.toList . NonEmpty.sortBy incXdecY $ pts++incXdecY :: Ord r => (MyPoint VF.Two r) :+ p -> (MyPoint VF.Two r) :+ q -> Ordering+incXdecY (MyPoint2 px py :+ _) (MyPoint2 qx qy :+ _) =+ compare px qx <> compare qy py+++-- | Precondition: The list of input points is sorted+hull' :: (Ord r, Num r) => [MyPoint VF.Two r :+ p] -> NonEmpty (MyPoint VF.Two r :+ p)+hull' (a:b:ps) = NonEmpty.fromList $ hull'' [b,a] ps+ where+ hull'' h [] = h+ hull'' h (p:ps') = hull'' (cleanMiddle (p:h)) ps'++ cleanMiddle h@[_,_] = h+ cleanMiddle h@(z:y:x:rest)+ | rightTurn (x^.core) (y^.core) (z^.core) = h+ | otherwise = cleanMiddle (z:x:rest)+ cleanMiddle _ = error "cleanMiddle: too few points"++rightTurn :: (Ord r, Num r) => MyPoint VF.Two r -> MyPoint VF.Two r -> MyPoint VF.Two r -> Bool+rightTurn a b c = ccwP a b c == CW++++ccwP :: (Ord r, Num r) => MyPoint VF.Two r -> MyPoint VF.Two r -> MyPoint VF.Two r -> CCW+ccwP p q r = case z `compare` 0 of+ LT -> CW+ GT -> CCW+ EQ -> CoLinear+ where++ MyPoint2 ux uy = q `subt` p+ MyPoint2 vx vy = r `subt` p+ z = ux * vy - uy * vx
+ benchmark/Algorithms/Geometry/ConvexHull/GrahamFixed.hs view
@@ -0,0 +1,104 @@+{-# LANGUAGE UndecidableInstances #-}+module Algorithms.Geometry.ConvexHull.GrahamFixed( convexHull+ , upperHull+ , lowerHull, fromP+ ) where++import Control.DeepSeq+import Control.Lens ((^.))+import Data.Ext+import Data.Geometry.Point+import Data.Vector.Fixed (Arity)+import qualified Data.Geometry.Vector.VectorFixed as VF+import Data.List.NonEmpty (NonEmpty(..))+import qualified Data.List.NonEmpty as NonEmpty+import Data.Monoid+import GHC.TypeLits+++newtype MyPoint d r = MyPoint (VF.Vector d r)++deriving instance (Arity d, Eq r) => Eq (MyPoint d r)+deriving instance (Arity d, Ord r) => Ord (MyPoint d r)+deriving instance (Arity d, Show r) => Show (MyPoint d r)+deriving instance (NFData (VF.Vector d r)) => NFData (MyPoint d r)++pattern MyPoint2 x y = MyPoint (VF.Vector2 x y)+++-- instance (NFData r, Arity d) => NFData (MyPoint d r) where+-- rnf (MyPoint x y) = rnf (x,y)+-- rnf (MyP p) = rnf p++toP :: MyPoint 2 r :+ e -> Point 2 r :+ e+toP (MyPoint2 x y :+ e) = Point2 x y :+ e++fromP :: Point 2 r :+ e -> MyPoint 2 r :+ e+fromP (Point2 x y :+ e) = MyPoint2 x y :+ e+++subt :: Num r => MyPoint 2 r -> MyPoint 2 r -> MyPoint 2 r+(MyPoint2 x y) `subt` (MyPoint2 a b) = MyPoint2 (x-a) (y-b)++newtype ConvexPolygon p r = ConvexPolygon [Point 2 r :+ p] deriving (Show,Eq,NFData)++-- | \(O(n \log n)\) time ConvexHull using Graham-Scan. The resulting polygon is+-- given in clockwise order.+convexHull :: (Ord r, Num r)+ => NonEmpty (MyPoint 2 r :+ p) -> ConvexPolygon p r+convexHull (p :| []) = ConvexPolygon $ [toP p]+convexHull ps = let ps' = NonEmpty.toList . NonEmpty.sortBy incXdecY $ ps+ uh = NonEmpty.tail . hull' $ ps'+ lh = NonEmpty.tail . hull' $ reverse ps'+ in ConvexPolygon . map toP . reverse $ lh ++ uh++upperHull :: (Ord r, Num r) => NonEmpty (MyPoint 2 r :+ p) -> NonEmpty (MyPoint 2 r :+ p)+upperHull = hull id+++lowerHull :: (Ord r, Num r) => NonEmpty (MyPoint 2 r :+ p) -> NonEmpty (MyPoint 2 r :+ p)+lowerHull = hull reverse+++-- | Helper function so that that can compute both the upper or the lower hull, depending+-- on the function f+hull :: (Ord r, Num r)+ => ([MyPoint 2 r :+ p] -> [MyPoint 2 r :+ p])+ -> NonEmpty (MyPoint 2 r :+ p) -> NonEmpty (MyPoint 2 r :+ p)+hull _ h@(_ :| []) = h+hull f pts = hull' . f+ . NonEmpty.toList . NonEmpty.sortBy incXdecY $ pts++incXdecY :: Ord r => (MyPoint 2 r) :+ p -> (MyPoint 2 r) :+ q -> Ordering+incXdecY (MyPoint2 px py :+ _) (MyPoint2 qx qy :+ _) =+ compare px qx <> compare qy py+++-- | Precondition: The list of input points is sorted+hull' :: (Ord r, Num r) => [MyPoint 2 r :+ p] -> NonEmpty (MyPoint 2 r :+ p)+hull' (a:b:ps) = NonEmpty.fromList $ hull'' [b,a] ps+ where+ hull'' h [] = h+ hull'' h (p:ps') = hull'' (cleanMiddle (p:h)) ps'++ cleanMiddle h@[_,_] = h+ cleanMiddle h@(z:y:x:rest)+ | rightTurn (x^.core) (y^.core) (z^.core) = h+ | otherwise = cleanMiddle (z:x:rest)+ cleanMiddle _ = error "cleanMiddle: too few points"++rightTurn :: (Ord r, Num r) => MyPoint 2 r -> MyPoint 2 r -> MyPoint 2 r -> Bool+rightTurn a b c = ccwP a b c == CW++++ccwP :: (Ord r, Num r) => MyPoint 2 r -> MyPoint 2 r -> MyPoint 2 r -> CCW+ccwP p q r = case z `compare` 0 of+ LT -> CW+ GT -> CCW+ EQ -> CoLinear+ where++ MyPoint2 ux uy = q `subt` p+ MyPoint2 vx vy = r `subt` p+ z = ux * vy - uy * vx
+ benchmark/Algorithms/Geometry/ConvexHull/GrahamV2.hs view
@@ -0,0 +1,95 @@+{-# Language DeriveGeneric #-}+module Algorithms.Geometry.ConvexHull.GrahamV2( convexHull+ , upperHull+ , lowerHull, fromP+ ) where+++import Control.DeepSeq+import Control.Lens ((^.))+import Data.Ext+import Data.Geometry.Point+import Data.List.NonEmpty (NonEmpty(..))+import qualified Data.List.NonEmpty as NonEmpty+import Data.Monoid+import GHC.Generics+import qualified Linear.V2 as V2++++newtype MyPoint r = MKPoint (V2.V2 r) deriving (Show,Eq,Ord,Generic)+-- data MyPoint r = MyPoint !r !r deriving (Show,Eq,Ord,Generic)++pattern MyPoint x y = MKPoint (V2.V2 x y)++instance NFData r => NFData (MyPoint r)+++toP (MyPoint x y :+ e) = Point2 x y :+ e+fromP (Point2 x y :+ e) = MyPoint x y :+ e++(MyPoint x y) `subt` (MyPoint a b) = MyPoint (x-a) (y-b)+++newtype ConvexPolygon p r = ConvexPolygon [Point 2 r :+ p] deriving (Show,Eq,NFData)++-- | \(O(n \log n)\) time ConvexHull using Graham-Scan. The resulting polygon is+-- given in clockwise order.+convexHull :: (Ord r, Num r)+ => NonEmpty (MyPoint r :+ p) -> ConvexPolygon p r+convexHull (p :| []) = ConvexPolygon $ [toP p]+convexHull ps = let ps' = NonEmpty.toList . NonEmpty.sortBy incXdecY $ ps+ uh = NonEmpty.tail . hull' $ ps'+ lh = NonEmpty.tail . hull' $ reverse ps'+ in ConvexPolygon . map toP . reverse $ lh ++ uh++upperHull :: (Ord r, Num r) => NonEmpty (MyPoint r :+ p) -> NonEmpty (MyPoint r :+ p)+upperHull = hull id+++lowerHull :: (Ord r, Num r) => NonEmpty (MyPoint r :+ p) -> NonEmpty (MyPoint r :+ p)+lowerHull = hull reverse+++-- | Helper function so that that can compute both the upper or the lower hull, depending+-- on the function f+hull :: (Ord r, Num r)+ => ([MyPoint r :+ p] -> [MyPoint r :+ p])+ -> NonEmpty (MyPoint r :+ p) -> NonEmpty (MyPoint r :+ p)+hull _ h@(_ :| []) = h+hull f pts = hull' . f+ . NonEmpty.toList . NonEmpty.sortBy incXdecY $ pts++incXdecY :: Ord r => (MyPoint r) :+ p -> (MyPoint r) :+ q -> Ordering+incXdecY (MyPoint px py :+ _) (MyPoint qx qy :+ _) =+ compare px qx <> compare qy py+++-- | Precondition: The list of input points is sorted+hull' :: (Ord r, Num r) => [MyPoint r :+ p] -> NonEmpty (MyPoint r :+ p)+hull' (a:b:ps) = NonEmpty.fromList $ hull'' [b,a] ps+ where+ hull'' h [] = h+ hull'' h (p:ps') = hull'' (cleanMiddle (p:h)) ps'++ cleanMiddle h@[_,_] = h+ cleanMiddle h@(z:y:x:rest)+ | rightTurn (x^.core) (y^.core) (z^.core) = h+ | otherwise = cleanMiddle (z:x:rest)+ cleanMiddle _ = error "cleanMiddle: too few points"++rightTurn :: (Ord r, Num r) => MyPoint r -> MyPoint r -> MyPoint r -> Bool+rightTurn a b c = ccwP a b c == CW++++ccwP :: (Ord r, Num r) => MyPoint r -> MyPoint r -> MyPoint r -> CCW+ccwP p q r = case z `compare` 0 of+ LT -> CW+ GT -> CCW+ EQ -> CoLinear+ where++ MyPoint ux uy = q `subt` p+ MyPoint vx vy = r `subt` p+ z = ux * vy - uy * vx
+ benchmark/Algorithms/Geometry/LineSegmentIntersection/Bench.hs view
@@ -0,0 +1,50 @@+module Algorithms.Geometry.LineSegmentIntersection.Bench (benchmark) where++import qualified Algorithms.Geometry.LineSegmentIntersection.BentleyOttmann as BONew+import qualified Algorithms.Geometry.LineSegmentIntersection.BentleyOttmannOld as BOOld++import Control.DeepSeq+import Control.Lens+import Control.Monad.Random+import Data.Ext+import Data.Geometry.LineSegment+import Data.Geometry.Point+import Data.Hashable+import qualified Data.List as List+import Data.RealNumber.Rational+import Test.Tasty.Bench++--------------------------------------------------------------------------------++type R = RealNumber 5++benchmark :: Benchmark+benchmark = bgroup "LineSegmentIntersection"+ [ benchBuild (evalRand (genPts @R 100) gen)+ ]++gen :: StdGen+gen = mkStdGen (hash "line segment intersection")++--------------------------------------------------------------------------------++genPts :: (Ord r, Random r, RandomGen g)+ => Int -> Rand g [LineSegment 2 () r]+genPts n = replicateM n sampleLineSegment++-- | Benchmark computing the closest pair+benchBuild :: (Ord r, Fractional r, NFData r) => [LineSegment 2 () r] -> Benchmark+benchBuild ss = bgroup "LineSegs" [ bgroup (show n) (build $ take n ss)+ | n <- sizes' ss+ ]+ where+ sizes' xs = [length xs]+ -- let n = length pts in [ n*i `div` 100 | i <- [10,20,25,50,75,100]]++ build segs = [ bench "sort" $ nf sort' segs+ , bench "Old" $ nf BOOld.intersections segs+ , bench "New" $ nf BONew.intersections segs+ ]++sort' :: Ord r => [LineSegment 2 () r] -> [Point 2 r]+sort' = List.sort . concatMap (\s -> s^..endPoints.core)
+ benchmark/Algorithms/Geometry/LineSegmentIntersection/BentleyOttmannOld.hs view
@@ -0,0 +1,236 @@+{-# LANGUAGE ScopedTypeVariables #-}+--------------------------------------------------------------------------------+-- |+-- Module : Algorithms.Geometry.LineSegmentIntersection.BentleyOttmann+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+--+-- The \(O((n+k)\log n)\) time line segment intersection algorithm by Bentley+-- and Ottmann.+--+--------------------------------------------------------------------------------+module Algorithms.Geometry.LineSegmentIntersection.BentleyOttmannOld where++import Algorithms.Geometry.LineSegmentIntersection+import Control.Lens hiding (contains)+import Data.Ext+import qualified Data.Foldable as F+import Data.Geometry.Interval+import Data.Geometry.LineSegment+import Data.Geometry.Point+import Data.Geometry.Properties+import qualified Data.List as L+import Data.List.NonEmpty (NonEmpty(..))+import qualified Data.List.NonEmpty as NonEmpty+import qualified Data.Map as M+import Data.Maybe+import Data.Ord (Down(..), comparing)+import qualified Data.OrdSeq as SS -- status struct+import qualified Data.Set as EQ -- event queue+import Data.Vinyl+import Data.Vinyl.CoRec++--------------------------------------------------------------------------------++-- | Compute all intersections+--+-- \(O((n+k)\log n)\), where \(k\) is the number of intersections.+intersections :: (Ord r, Fractional r)+ => [LineSegment 2 p r] -> Intersections p r+intersections ss = merge $ sweep pts mempty+ where+ pts = EQ.fromAscList . groupStarts . L.sort . concatMap asEventPts $ ss++-- | Computes all intersection points p s.t. p lies in the interior of at least+-- one of the segments.+--+-- \(O((n+k)\log n)\), where \(k\) is the number of intersections.+interiorIntersections :: (Ord r, Fractional r)+ => [LineSegment 2 p r] -> Intersections p r+interiorIntersections = M.filter (not . isEndPointIntersection) . intersections++-- | Computes the event points for a given line segment+asEventPts :: Ord r => LineSegment 2 p r -> [Event p r]+asEventPts s = let [p,q] = L.sortBy ordPoints [s^.start.core,s^.end.core]+ in [Event p (Start $ s :| []), Event q (End s)]++-- | Group the segments with the intersection points+merge :: Ord r => [IntersectionPoint p r] -> Intersections p r+merge = foldr (\(IntersectionPoint p a) -> M.insertWith (<>) p a) M.empty++-- | Group the startpoints such that segments with the same start point+-- correspond to one event.+groupStarts :: Eq r => [Event p r] -> [Event p r]+groupStarts [] = []+groupStarts (Event p (Start s) : es) = Event p (Start ss) : groupStarts rest+ where+ (ss',rest) = L.span sameStart es+ -- sort the segs on lower endpoint+ ss = let (x:|xs) = s in x :| (xs ++ concatMap startSegs ss')++ sameStart (Event q (Start _)) = p == q+ sameStart _ = False+groupStarts (e : es) = e : groupStarts es++--------------------------------------------------------------------------------+-- * Data type for Events++-- | Type of segment+data EventType s = Start !(NonEmpty s)| Intersection | End !s deriving (Show)++instance Eq (EventType s) where+ a == b = a `compare` b == EQ++instance Ord (EventType s) where+ (Start _) `compare` (Start _) = EQ+ (Start _) `compare` _ = LT+ Intersection `compare` (Start _) = GT+ Intersection `compare` Intersection = EQ+ Intersection `compare` (End _) = LT+ (End _) `compare` (End _) = EQ+ (End _) `compare` _ = GT++-- | The actual event consists of a point and its type+data Event p r = Event { eventPoint :: !(Point 2 r)+ , eventType :: !(EventType (LineSegment 2 p r))+ } deriving (Show,Eq)++instance Ord r => Ord (Event p r) where+ -- decreasing on the y-coord, then increasing on x-coord, and increasing on event-type+ (Event p s) `compare` (Event q t) = case ordPoints p q of+ EQ -> s `compare` t+ x -> x++-- | An ordering that is decreasing on y, increasing on x+ordPoints :: Ord r => Point 2 r -> Point 2 r -> Ordering+ordPoints a b = let f p = (Down $ p^.yCoord, p^.xCoord) in comparing f a b++-- | Get the segments that start at the given event point+startSegs :: Event p r -> [LineSegment 2 p r]+startSegs e = case eventType e of+ Start ss -> NonEmpty.toList ss+ _ -> []++--------------------------------------------------------------------------------++-- | Compare based on the x-coordinate of the intersection with the horizontal+-- line through y+ordAt :: (Fractional r, Ord r) => r -> Compare (LineSegment 2 p r)+ordAt y = comparing (xCoordAt y)++-- | 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+xCoordAt :: (Fractional r, Ord r) => r -> LineSegment 2 p r -> r+xCoordAt y (LineSegment' (Point2 px py :+ _) (Point2 qx qy :+ _))+ | py == qy = px `max` qx -- s is horizontal, and since it by the+ -- precondition it intersects the sweep+ -- line, we return the x-coord of the+ -- rightmost endpoint.+ | otherwise = px + alpha * (qx - px)+ where+ alpha = (y - py) / (qy - py)++--------------------------------------------------------------------------------+-- * The Main Sweep++type EventQueue p r = EQ.Set (Event p r)+type StatusStructure p r = SS.OrdSeq (LineSegment 2 p r)++-- | Run the sweep handling all events+sweep :: (Ord r, Fractional r)+ => EventQueue p r -> StatusStructure p r -> [IntersectionPoint p r]+sweep eq ss = case EQ.minView eq of+ Nothing -> []+ Just (e,eq') -> handle e eq' ss++isClosedStart :: Eq r => Point 2 r -> LineSegment 2 p r -> Bool+isClosedStart p (LineSegment s e)+ | p == s^.unEndPoint.core = isClosed s+ | otherwise = isClosed e++-- | Handle an event point+handle :: forall r p. (Ord r, Fractional r)+ => Event p r -> EventQueue p r -> StatusStructure p r+ -> [IntersectionPoint p r]+handle e@(eventPoint -> p) eq ss = toReport <> sweep eq' ss'+ where+ starts = startSegs e+ (before,contains',after) = extractContains p ss+ (ends,contains) = L.partition (endsAt p) contains'+ -- starting segments, exluding those that have an open starting point+ starts' = filter (isClosedStart p) starts+ toReport = case starts' ++ contains' of+ (_:_:_) -> [IntersectionPoint p $ associated (starts' <> ends) contains]+ _ -> []++ -- new status structure+ ss' = before <> newSegs <> after+ newSegs = toStatusStruct p $ starts ++ contains++ -- the new eeventqueue+ eq' = foldr EQ.insert eq es+ -- the new events:+ es | F.null newSegs = maybeToList $ app (findNewEvent p) sl sr+ | otherwise = let s' = fst <$> SS.minView newSegs+ s'' = fst <$> SS.maxView newSegs+ in catMaybes [ app (findNewEvent p) sl s'+ , app (findNewEvent p) s'' sr+ ]+ sl = fst <$> SS.maxView before+ sr = fst <$> SS.minView after++ app f x y = do { x' <- x ; y' <- y ; f x' y'}++-- | split the status structure, extracting the segments that contain p.+-- the result is (before,contains,after)+extractContains :: (Fractional r, Ord r)+ => Point 2 r -> StatusStructure p r+ -> (StatusStructure p r, [LineSegment 2 p r], StatusStructure p r)+extractContains p ss = (before, F.toList $ mid1 <> mid2, after)+ where+ (before, mid1, after') = SS.splitOn (xCoordAt $ p^.yCoord) (p^.xCoord) ss+ -- Make sure to also select the horizontal segments containing p+ (mid2, after) = SS.splitMonotonic (not . intersects p) after'++-- | Given a point and the linesegements that contain it. Create a piece of+-- status structure for it.+toStatusStruct :: (Fractional r, Ord r)+ => Point 2 r -> [LineSegment 2 p r] -> StatusStructure p r+toStatusStruct p xs = ss <> hors+ -- ss { SS.nav = ordAtNav $ p^.yCoord } `SS.join` hors+ where+ (hors',rest) = L.partition isHorizontal xs+ ss = SS.fromListBy (ordAt $ maxY xs) rest+ hors = SS.fromListBy (comparing rightEndpoint) hors'++ isHorizontal s = s^.start.core.yCoord == s^.end.core.yCoord++ -- find the y coord of the first interesting thing below the sweep at y+ maxY = maximum . filter (< p^.yCoord)+ . concatMap (\s -> [s^.start.core.yCoord,s^.end.core.yCoord])++-- | Get the right endpoint of a segment+rightEndpoint :: Ord r => LineSegment 2 p r -> r+rightEndpoint s = (s^.start.core.xCoord) `max` (s^.end.core.xCoord)++-- | Test if a segment ends at p+endsAt :: Ord r => Point 2 r -> LineSegment 2 p r -> Bool+endsAt p (LineSegment' a b) = all (\q -> ordPoints (q^.core) p /= GT) [a,b]++--------------------------------------------------------------------------------+-- * Finding New events++-- | Find all events+findNewEvent :: (Ord r, Fractional r)+ => Point 2 r -> LineSegment 2 p r -> LineSegment 2 p r+ -> Maybe (Event p r)+findNewEvent p l r = match (l `intersect` r) $+ (H $ \NoIntersection -> Nothing)+ :& (H $ \q -> if ordPoints q p == GT then Just (Event q Intersection)+ else Nothing)+ :& (H $ \_ -> Nothing) -- full segment intersectsions are handled+ -- at insertion time+ :& RNil
+ benchmark/Algorithms/Geometry/PolygonTriangulation/Bench.hs view
@@ -0,0 +1,64 @@+module Algorithms.Geometry.PolygonTriangulation.Bench where+{-+import Algorithms.Geometry.LineSegmentIntersection (hasSelfIntersections)+import qualified Algorithms.Geometry.PolygonTriangulation.MakeMonotone as New+import qualified Algorithms.Geometry.PolygonTriangulation.MakeMonotoneOld as Old+import Benchmark.Util+import Control.DeepSeq+import Control.Lens+import Data.Ext+import Test.Tasty.Bench+import qualified Data.Foldable as F+import Data.Geometry.Ipe+import Data.Geometry.LineSegment+import Data.Geometry.Polygon+import Data.Geometry.PlanarSubdivision+import Data.Geometry.Point+import qualified Data.LSeq as LSeq+import qualified Data.List as List+import Data.Proxy+import Test.QuickCheck++--------------------------------------------------------------------------------++data PX = PX++main :: IO ()+main = do+ polies <- getPolies "/home/frank/tmp/antarctica.ipe"+ defaultMain [ benchBuild polies ]++getPolies inFile = do+ ePage <- readSinglePageFile inFile+ case ePage of+ Left err -> error $ show err+ Right (page :: IpePage Rational) -> pure $ runPage page+ where+ runPage page =+ let polies = page^..content.to flattenGroups.traverse._withAttrs _IpePath _asSimplePolygon+ in filter (not . hasSelfIntersections . (^.core)) polies+++process f polies = let subdivs = map (\(pg :+ _) -> f (Identity PX) pg) polies+ in concatMap (\ps -> map (^._2.core) . F.toList . edgeSegments $ ps) subdivs++-- benchmark :: Benchmark+-- benchmark = bgroup "MakeMonotoneBench"+-- [ env (genPts (Proxy :: Proxy Rational) 100) benchBuild+-- ]++--------------------------------------------------------------------------------++-- | Benchmark computing the closest pair+benchBuild :: (Ord r, Fractional r, NFData r) => [Polygon t () r :+ p] -> Benchmark+benchBuild ss = bgroup "MakeMonotone" [ bgroup (show n) (build $ take n ss)+ | n <- sizes' ss+ ]+ where+ sizes' xs = [length xs]+ -- let n = length pts in [ n*i `div` 100 | i <- [10,20,25,50,75,100]]++ build ps = [ bench "Old" $ nf (process Old.makeMonotone) ps+ , bench "New" $ nf (process New.makeMonotone) ps+ ]+-}
+ benchmark/Algorithms/Geometry/PolygonTriangulation/MakeMonotoneOld.hs view
@@ -0,0 +1,312 @@+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TemplateHaskell #-}+module Algorithms.Geometry.PolygonTriangulation.MakeMonotoneOld where++import Algorithms.Geometry.LineSegmentIntersection.BentleyOttmann (ordAt, xCoordAt)+import Algorithms.Geometry.PolygonTriangulation.Types++import Control.Lens+import Control.Monad (forM_, when)+import Control.Monad.Reader+import Control.Monad.State.Strict+import Control.Monad.Writer (WriterT, execWriterT, tell)+import Data.Bifunctor+import Data.CircularSeq (rotateL, rotateR, zip3LWith)+import qualified Data.DList as DList+import Data.Ext+import qualified Data.Foldable as F+import Data.Geometry.LineSegment+import Data.Geometry.PlanarSubdivision.Basic+import Data.Geometry.Point+import Data.Geometry.Polygon+import qualified Data.IntMap as IntMap+import qualified Data.List.NonEmpty as NonEmpty+import Data.Ord (Down (..), comparing)+import Data.OrdSeq (OrdSeq)+import qualified Data.OrdSeq as SS+import Data.Util+import qualified Data.Vector as V+import qualified Data.Vector.Circular as CV+import qualified Data.Vector.Mutable as MV+++----------------------------------------------------------------------------------++data VertexType = Start | Merge | Split | End | Regular deriving (Show,Read,Eq)+++-- How about the hole vertices?++-- | assigns a vertex type to each vertex+--+-- pre: the polygon is given in CCW order+--+-- running time: \(O(n)\).+classifyVertices :: (Num r, Ord r)+ => Polygon t p r+ -> Polygon t (p :+ VertexType) r+classifyVertices p@SimplePolygon{} = classifyVertices' p+classifyVertices (MultiPolygon vs h) = MultiPolygon vs' h'+ where+ vs' = classifyVertices' vs+ h' = map (first (&extra %~ onHole) . classifyVertices') h++ -- the roles on hole vertices are slightly different+ onHole Start = Split+ onHole Merge = End+ onHole Split = Start+ onHole End = Merge+ onHole Regular = Regular++-- | assigns a vertex type to each vertex+--+-- pre: the polygon is given in CCW order+--+-- running time: \(O(n)\).+classifyVertices' :: (Num r, Ord r)+ => SimplePolygon p r+ -> SimplePolygon (p :+ VertexType) r+classifyVertices' poly =+ -- SimplePolygon $ zip3LWith f (rotateL vs) vs (rotateR vs)+ unsafeFromCircularVector $ CV.zipWith3 f (CV.rotateLeft 1 vs) vs (CV.rotateRight 1 vs)+ where+ vs = poly ^. outerBoundaryVector+ -- is the angle larger than > 180 degrees+ largeInteriorAngle p c n = case ccw (p^.core) (c^.core) (n^.core) of+ CCW -> False+ CW -> True+ _ -> error "classifyVertices -> largeInteriorAngle: colinear points"++ f p c n = c&extra %~ (:+ vt)+ where+ vt = case (p `cmpSweep` c, n `cmpSweep` c, largeInteriorAngle p c n) of+ (LT, LT, False) -> Start+ (LT, LT, True) -> Split+ (GT, GT, False) -> End+ (GT, GT, True) -> Merge+ _ -> Regular++++-- | p < q = p.y < q.y || p.y == q.y && p.x > q.y+cmpSweep :: Ord r => Point 2 r :+ e -> Point 2 r :+ e -> Ordering+p `cmpSweep` q =+ comparing (^.core.yCoord) p q <> comparing (Down . (^.core.xCoord)) p q+++--------------------------------------------------------------------------------++type Event r = Point 2 r :+ (Two (LineSegment 2 Int r))++data StatusStruct r = SS { _statusStruct :: !(SS.OrdSeq (LineSegment 2 Int r))+ , _helper :: !(IntMap.IntMap Int)+ -- ^ for every e_i, the id of the helper vertex+ } deriving (Show)+makeLenses ''StatusStruct++ix' :: Int -> Lens' (V.Vector a) a+ix' i = singular (ix i)++-- | Given a polygon, find a set of non-intersecting diagonals that partition+-- the polygon into y-monotone pieces.+--+-- running time: \(O(n\log n)\)+computeDiagonals :: forall t r p. (Fractional r, Ord r)+ => Polygon t p r -> [LineSegment 2 p r]+computeDiagonals p' = map f . sweep+ . NonEmpty.sortBy (flip cmpSweep)+ . polygonVertices . withIncidentEdges+ . first (^._1) $ pg+ where+ -- remaps to get the p value rather than the vertexId+ f = first (\i -> vertexInfo^.ix' i._2)++ pg :: Polygon t (SP Int (p :+ VertexType)) r+ pg = numberVertices . classifyVertices . toCounterClockWiseOrder $ p'+ vertexInfo :: V.Vector (STR (Point 2 r) p VertexType)+ vertexInfo = let vs = polygonVertices pg+ n = F.length vs+ in V.create $ do+ v <- MV.new n+ forM_ vs $ \(pt :+ SP i (p :+ vt)) ->+ MV.write v i (STR pt p vt)+ return v++ initialSS = SS mempty mempty++ sweep es = flip runReader vertexInfo $ evalStateT (sweep' es) initialSS+ sweep' es = DList.toList <$> execWriterT (sweep'' es)++ sweep'' :: NonEmpty.NonEmpty (Event r) -> Sweep p r ()+ sweep'' = mapM_ handle++-- | Computes a set of diagionals that decompose the polygon into y-monotone+-- pieces.+--+-- running time: \(O(n\log n)\)+makeMonotone :: (Fractional r, Ord r)+ => proxy s -> Polygon t p r+ -> PlanarSubdivision s p PolygonEdgeType PolygonFaceData r+makeMonotone px pg = let (e:es) = listEdges pg+ in constructSubdivision px e es (computeDiagonals pg)++type Sweep p r = WriterT (DList.DList (LineSegment 2 Int r))+ (StateT (StatusStruct r)+ (Reader (V.Vector (VertexInfo p r))))++type VertexInfo p r = STR (Point 2 r) p VertexType+++tell' :: LineSegment 2 Int r -> Sweep p r ()+tell' = tell . DList.singleton++getIdx :: Event r -> Int+getIdx = view (extra._1.end.extra)++getVertexType :: Int -> Sweep p r VertexType+getVertexType v = asks (^.ix' v._3)++getEventType :: Event r -> Sweep p r VertexType+getEventType = getVertexType . getIdx++handle :: (Fractional r, Ord r) => Event r -> Sweep p r ()+handle e = let i = getIdx e in getEventType e >>= \case+ Start -> handleStart i e+ End -> handleEnd i e+ Split -> handleSplit i e+ Merge -> handleMerge i e+ Regular | isLeftVertex i e -> handleRegularL i e+ | otherwise -> handleRegularR i e+++insertAt :: (Ord r, Fractional r) => Point 2 r -> LineSegment 2 q r+ -> OrdSeq (LineSegment 2 q r) -> OrdSeq (LineSegment 2 q r)+insertAt v = SS.insertBy (ordAt $ v^.yCoord)++deleteAt :: (Fractional r, Ord r) => Point 2 r -> LineSegment 2 p r+ -> OrdSeq (LineSegment 2 p r) -> OrdSeq (LineSegment 2 p r)+deleteAt v = SS.deleteAllBy (ordAt $ v^.yCoord)+++handleStart :: (Fractional r, Ord r)+ => Int -> Event r -> Sweep p r ()+handleStart i (v :+ adj) = modify $ \(SS t h) ->+ SS (insertAt v (adj^._2) t)+ (IntMap.insert i i h)++handleEnd :: (Fractional r, Ord r)+ => Int -> Event r -> Sweep p r ()+handleEnd i (v :+ adj) = do let iPred = adj^._1.start.extra -- i-1+ -- lookup p's helper; if it is a merge vertex+ -- we insert a new segment+ tellIfMerge i v iPred+ -- delete e_{i-1} from the status struct+ modify $ \ss ->+ ss&statusStruct %~ deleteAt v (adj^._1)++-- | Adds edge (i,j) if e_j's helper is a merge vertex+tellIfMerge :: Int -> Point 2 r -> Int -> Sweep p r ()+tellIfMerge i v j = do SP u ut <- getHelper j+ when (ut == Merge) (tell' $ ClosedLineSegment (v :+ i) u)++-- | Get the helper of edge i, and its vertex type+getHelper :: Int -> Sweep p r (SP (Point 2 r :+ Int) VertexType)+getHelper i = do ui <- gets (^?!helper.ix i)+ STR u _ ut <- asks (^.ix' ui)+ pure $ SP (u :+ ui) ut+++lookupLE :: (Ord r, Fractional r)+ => Point 2 r -> OrdSeq (LineSegment 2 Int r)+ -> Maybe (LineSegment 2 Int r)+lookupLE v s = let (l,m,_) = SS.splitOn (xCoordAt $ v^.yCoord) (v^.xCoord) s+ in SS.lookupMax (l <> m)+++handleSplit :: (Fractional r, Ord r) => Int -> Event r -> Sweep p r ()+handleSplit i (v :+ adj) = do ej <- gets $ \ss -> ss^?!statusStruct.to (lookupLE v)._Just+ let j = ej^.start.extra+ SP u _ <- getHelper j+ -- update the status struct:+ -- insert the new edge into the status Struct and+ -- set the helper of e_j to be v_i+ modify $ \(SS t h) ->+ SS (insertAt v (adj^._2) t)+ (IntMap.insert i i . IntMap.insert j i $ h)+ -- return the diagonal+ tell' $ ClosedLineSegment (v :+ i) u++handleMerge :: (Fractional r, Ord r) => Int -> Event r -> Sweep p r ()+handleMerge i (v :+ adj) = do let ePred = adj^._1.start.extra -- i-1+ tellIfMerge i v ePred+ -- delete e_{i-1} from the status struct+ modify $ \ss -> ss&statusStruct %~ deleteAt v (adj^._1)+ connectToLeft i v++-- | finds the edge j to the left of v_i, and connect v_i to it if the helper+-- of j is a merge vertex+connectToLeft :: (Fractional r, Ord r) => Int -> Point 2 r -> Sweep p r ()+connectToLeft i v = do ej <- gets $ \ss -> ss^?!statusStruct.to (lookupLE v)._Just+ let j = ej^.start.extra+ tellIfMerge i v j+ modify $ \ss -> ss&helper %~ IntMap.insert j i++-- | returns True if v the interior of the polygon is to the right of v+isLeftVertex :: Ord r => Int -> Event r -> Bool+isLeftVertex i (v :+ adj) = case (adj^._1.start) `cmpSweep` (v :+ i) of+ GT -> True+ _ -> False+ -- if the predecessor occurs before the sweep, this must be a left vertex++handleRegularL :: (Fractional r, Ord r) => Int -> Event r -> Sweep p r ()+handleRegularL i (v :+ adj) = do let ePred = adj^._1.start.extra -- i-1+ tellIfMerge i v ePred+ -- delete e_{i-1} from the status struct+ modify $ \ss ->+ ss&statusStruct %~ deleteAt v (adj^._1)+ -- insert a e_i in the status struct, and set its helper+ -- to be v_i+ modify $ \(SS t h) ->+ SS (insertAt v (adj^._2) t)+ (IntMap.insert i i h)++handleRegularR :: (Fractional r, Ord r) => Int -> Event r -> Sweep p r ()+handleRegularR i (v :+ _) = connectToLeft i v+++++--------------------------------------------------------------------------------+++-- testPolygon :: SimplePolygon Int Rational+-- testPolygon = fromPoints [ Point2 20 20 :+ 1+-- , Point2 18 19 :+ 2+-- , Point2 16 25 :+ 3+-- , Point2 13 23 :+ 4+-- , Point2 10 24 :+ 5+-- , Point2 6 22 :+ 6+-- , Point2 8 21 :+ 7+-- , Point2 7 18 :+ 8+-- , Point2 2 19 :+ 9+-- , Point2 1 10 :+ 10+-- , Point2 3 5 :+ 11+-- , Point2 11 7 :+ 12+-- , Point2 15 1 :+ 13+-- , Point2 12 15 :+ 14+-- , Point2 15 12 :+ 15+-- ]++-- vertexTypes = [Start,Merge,Start,Merge,Start,Regular,Regular,Merge,Start,Regular,End,Split,End,Split,End]+++-- loadT = do pgs <- readAllFrom "/Users/frank/tmp/testPoly.ipe"+-- :: IO [SimplePolygon () Rational :+ IpeAttributes Path Rational]+-- mapM_ print pgs+-- let diags = map (computeDiagonals . (^.core)) pgs+-- f = asIpeGroup . map (asIpeObject' mempty)+-- out = [ asIpeGroup $ map (\(pg :+ a) -> asIpeObject pg a) pgs+-- , asIpeGroup $ map f diags+-- ]+-- outFile = "/Users/frank/tmp/out.ipe"+-- writeIpeFile outFile . singlePageFromContent $ out
+ benchmark/Benchmark/Util.hs view
@@ -0,0 +1,7 @@+module Benchmark.Util where++++-- | Generates different size benchmarks+sizes :: Foldable f => f a -> [Int]+sizes xs = let n = length xs in (\i -> n*i `div` 100) <$> [5,10..100]
+ benchmark/Benchmarks.hs view
@@ -0,0 +1,10 @@+module Main where++import qualified Algorithms.Geometry.ClosestPair.Bench as CP+import qualified Algorithms.Geometry.LineSegmentIntersection.Bench as Line+-- import qualified Algorithms.Geometry.PolygonTriangulation.Bench as M+import qualified Algorithms.Geometry.ConvexHull.Bench as M+import Test.Tasty.Bench++main :: IO ()+main = defaultMain [ CP.benchmark, M.benchmark, Line.benchmark ]
+ benchmark/Data/Geometry/IntervalTreeBench.hs view
@@ -0,0 +1,75 @@+module Data.Geometry.IntervalTreeBench where++import Benchmark.Util+import Control.DeepSeq+import Control.Lens+import Test.Tasty.Bench+import Data.Ext+import Data.Geometry.Interval+import qualified Data.Geometry.IntervalTree as IT+import Data.Geometry.SegmentTree (I(..))+import qualified Data.Geometry.SegmentTree as SegTree+import qualified Data.List.NonEmpty as NonEmpty+import Debug.Trace+import Test.QuickCheck++--------------------------------------------------------------------------------++main :: IO ()+main = defaultMain [ intervalBench ]++intervalBench :: Benchmark+intervalBench = bgroup "IntervalTree"+ [ -- env (genIntervals (I (5 :: Int)) 1000) benchBuild+ -- env (genIntervals (I (5 :: Int)) 100) benchQueryIT+ ]++--------------------------------------------------------------------------------++-- | generates n random intervals+genIntervals :: (Ord r, Arbitrary r)+ => proxy r -> Int -> IO [Interval () r]+genIntervals _ n | n <= 0 = error "genIntervals: need n > 0"+ | otherwise = generate (vectorOf n arbitrary)++genQueries :: (Ord r, Arbitrary r)+ => proxy r -> Int -> IO [r]+genQueries _ n | n <= 0 = error "genQueries: need n > 0"+ | otherwise = generate (vectorOf n arbitrary)+++-- genQuerySetup :: (Ord r, Arbitrary r)+-- => proxy r -> Int -> IO (Int,IT.IntervalTree (I (Interval () r)) r, [r])+-- genQuerySetup p n = (\is qs -> (n, IT.fromIntervals . fmap I $ is, qs))+-- <$> genIntervals p n+-- <*> genQueries p n+++-- | Benchmark building the interval tree+benchBuild :: (Ord r, NFData r) => [Interval () r] -> Benchmark+benchBuild is = bgroup "build" [ bench (show n) $ nf IT.fromIntervals (take n is')+ | n <- sizes is+ ]+ where+ is' = I <$> is++-- benchQueryIT :: (Ord r, Arbitrary r, NFData r) => [Interval () r] -> Benchmark+-- benchQueryIT is = bgroup "queries"+-- [ env (setup' n) (\(t,qs) ->+-- bench ("queries on size" ++ show n) $ whnf (queryAll t) qs)+-- | n <- sizes is+-- ]+-- where+-- is' = I <$> is+-- r = is^.to head.start.core+-- setup' n = traceShow "setup" $ setup n++-- setup n = (IT.fromIntervals (take n is'),) <$> genQueries (I r) 100000+-- queryAll t = map (flip IT.search t)+++-- benchQueryIT :: Ord r+-- => (Int, IT.IntervalTree (I (Interval () r)) r, [r]) -> Benchmark+-- benchQueryIT (n,t,qs) = bgroup "queries" [ bench "query" $ whnf (flip IT.search t) q+-- | q <- qs+-- ]
+ benchmark/Data/Geometry/Vector/VectorFamily6.hs view
@@ -0,0 +1,257 @@+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE UndecidableInstances #-}+module Data.Geometry.Vector.VectorFamily6 where++import Control.Applicative (liftA2)+import Control.DeepSeq+import Control.Lens hiding (element)+-- import Data.Aeson (ToJSON(..),FromJSON(..))+import qualified Data.Foldable as F+import qualified Data.Geometry.Vector.VectorFixed as FV+import Data.Maybe (fromMaybe)+import Data.Proxy+import Data.Traversable (foldMapDefault,fmapDefault)+import qualified Data.Vector.Fixed as V+import Data.Vector.Fixed.Cont (Peano(..), PeanoNum(..), Fun(..))+import GHC.TypeLits+import Linear.Affine (Affine(..))+import Linear.Metric+import qualified Linear.V2 as L2+import qualified Linear.V3 as L3+import qualified Linear.V4 as L4+import Linear.Vector++--------------------------------------------------------------------------------+-- * d dimensional Vectors+++type One = S Z+type Two = S One+type Three = S Two+type Four = S Three+type Many d = S (S (S (S (S d))))+++type family FromPeano (d :: PeanoNum) :: Nat where+ FromPeano Z = 0+ FromPeano (S d) = 1 + FromPeano d+++data SingPeano (d :: PeanoNum) where+ SZ :: SingPeano Z+ SS :: !(SingPeano d) -> SingPeano (S d)++class ImplicitPeano (d :: PeanoNum) where+ implicitPeano :: SingPeano d+instance ImplicitPeano Z where+ implicitPeano = SZ+instance ImplicitPeano d => ImplicitPeano (S d) where+ implicitPeano = SS implicitPeano++-- | Mapping between the implementation type, and the actual implementation.+type family VectorFamilyF (d :: PeanoNum) :: * -> * where+ VectorFamilyF Z = Const ()+ VectorFamilyF One = Identity+ VectorFamilyF Two = L2.V2+ VectorFamilyF Three = L3.V3+ VectorFamilyF Four = L4.V4+ VectorFamilyF (Many d) = FV.Vector (FromPeano (Many d))+++-- | Datatype representing d dimensional vectors. The default implementation is+-- based n VectorFixed. However, for small vectors we automatically select a+-- more efficient representation.+newtype VectorFamily (d :: PeanoNum) (r :: *) =+ VectorFamily { _unVF :: VectorFamilyF d r }++type ImplicitArity d = (ImplicitPeano d, V.Arity (FromPeano d))++++instance (Eq r, ImplicitArity d) => Eq (VectorFamily d r) where+ (VectorFamily u) == (VectorFamily v) = case (implicitPeano :: SingPeano d) of+ SZ -> u == v+ (SS SZ) -> u == v+ (SS (SS SZ)) -> u == v+ (SS (SS (SS SZ))) -> u == v+ (SS (SS (SS (SS SZ)))) -> u == v+ (SS (SS (SS (SS (SS _))))) -> u == v+ {-# INLINE (==) #-}++instance (Ord r, ImplicitArity d) => Ord (VectorFamily d r) where+ (VectorFamily u) `compare` (VectorFamily v) = case (implicitPeano :: SingPeano d) of+ SZ -> u `compare` v+ (SS SZ) -> u `compare` v+ (SS (SS SZ)) -> u `compare` v+ (SS (SS (SS SZ))) -> u `compare` v+ (SS (SS (SS (SS SZ)))) -> u `compare` v+ (SS (SS (SS (SS (SS _))))) -> u `compare` v+ {-# INLINE compare #-}+++instance ImplicitArity d => Functor (VectorFamily d) where+ fmap f = VectorFamily . g f . _unVF+ where g = case (implicitPeano :: SingPeano d) of+ SZ -> fmap+ (SS SZ) -> fmap+ (SS (SS SZ)) -> fmap+ (SS (SS (SS SZ))) -> fmap+ (SS (SS (SS (SS SZ)))) -> fmap+ (SS (SS (SS (SS (SS _))))) -> fmap+ {-# INLINE fmap #-}+++instance ImplicitArity d => Foldable (VectorFamily d) where+ foldMap f = g f . _unVF+ where g = case (implicitPeano :: SingPeano d) of+ SZ -> foldMap+ (SS SZ) -> foldMap+ (SS (SS SZ)) -> foldMap+ (SS (SS (SS SZ))) -> foldMap+ (SS (SS (SS (SS SZ)))) -> foldMap+ (SS (SS (SS (SS (SS _))))) -> foldMap+ {-# INLINE foldMap #-}++instance ImplicitArity d => Traversable (VectorFamily d) where+ traverse f = fmap VectorFamily . g f . _unVF+ where g = case (implicitPeano :: SingPeano d) of+ SZ -> traverse+ (SS SZ) -> traverse+ (SS (SS SZ)) -> traverse+ (SS (SS (SS SZ))) -> traverse+ (SS (SS (SS (SS SZ)))) -> traverse+ (SS (SS (SS (SS (SS _))))) -> traverse+ {-# INLINE traverse #-}++instance ImplicitArity d => Applicative (VectorFamily d) where+ pure = VectorFamily . case (implicitPeano :: SingPeano d) of+ SZ -> pure+ (SS SZ) -> pure+ (SS (SS SZ)) -> pure+ (SS (SS (SS SZ))) -> pure+ (SS (SS (SS (SS SZ)))) -> pure+ (SS (SS (SS (SS (SS _))))) -> pure+ {-# INLINE pure #-}+ liftA2 f (VectorFamily u) (VectorFamily v) = VectorFamily $+ case (implicitPeano :: SingPeano d) of+ SZ -> liftA2 f u v+ (SS SZ) -> liftA2 f u v+ (SS (SS SZ)) -> liftA2 f u v+ (SS (SS (SS SZ))) -> liftA2 f u v+ (SS (SS (SS (SS SZ)))) -> liftA2 f u v+ (SS (SS (SS (SS (SS _))))) -> liftA2 f u v+ {-# INLINE liftA2 #-}+++++type instance V.Dim (VectorFamily d) = FromPeano d+++++instance ImplicitArity d => V.Vector (VectorFamily d) r where+ construct = fmap VectorFamily $ case (implicitPeano :: SingPeano d) of+ SZ -> Fun $ Const ()+ (SS SZ) -> V.construct+ (SS (SS SZ)) -> Fun L2.V2+ (SS (SS (SS SZ))) -> Fun L3.V3+ (SS (SS (SS (SS SZ)))) -> Fun L4.V4+ (SS (SS (SS (SS (SS _))))) -> V.construct+ {-# INLINE construct #-}+ inspect (VectorFamily v) ff@(Fun f) = case (implicitPeano :: SingPeano d) of+ SZ -> f+ (SS SZ) -> V.inspect v ff+ (SS (SS SZ)) -> let (L2.V2 x y) = v in f x y+ (SS (SS (SS SZ))) -> let (L3.V3 x y z) = v in f x y z+ (SS (SS (SS (SS SZ)))) -> let (L4.V4 x y z w) = v in f x y z w+ (SS (SS (SS (SS (SS _))))) -> V.inspect v ff+ {-# INLINE inspect #-}+ -- basicIndex (VectorFamily v) i = case (implicitPeano :: SingPeano d) of+ -- SZ -> err+ -- (SS SZ) -> if i == 0 then runIdentity v else err+ -- (SS (SS SZ)) -> let (L2.V2 x y) = v in f x y+ -- (SS (SS (SS SZ))) -> let (L3.V3 x y z) = v in f x y z+ -- (SS (SS (SS (SS SZ)))) -> let (L4.V4 x y z w) = v in f x y z w+ -- (SS (SS (SS (SS (SS _))))) -> V.basicIndex v i+ -- where+ -- err = error "VectorFamily: basicIndex out of range"+ -- {-# INLINE basicIndex #-}+++instance (ImplicitArity d, Show r) => Show (VectorFamily d r) where+ show v = mconcat [ "Vector", show $ F.length v , " "+ , show $ F.toList v ]++deriving instance (NFData (VectorFamilyF d r)) => NFData (VectorFamily d r)+++type instance Index (VectorFamily d r) = Int+type instance IxValue (VectorFamily d r) = r++--------------------------------------------------------------------------------+++newtype Vector (d :: Nat) (r :: *) = MKVector { _unV :: VectorFamily (Peano d) r }++type instance V.Dim (Vector d) = d+++type instance Index (Vector d r) = Int+type instance IxValue (Vector d r) = r++type Arity d = ImplicitArity (Peano d)++deriving instance (Eq r, Arity d) => Eq (Vector d r)+deriving instance (Ord r, Arity d) => Ord (Vector d r)++deriving instance Arity d => Functor (Vector d)+deriving instance Arity d => Foldable (Vector d)+deriving instance Arity d => Traversable (Vector d)++instance (Arity d, Show r) => Show (Vector d r) where+ show v = mconcat [ "Vector", show $ F.length v , " "+ , show $ F.toList v ]+++deriving instance (NFData (VectorFamily (Peano d) r)) => NFData (Vector d r)+++++--------------------------------------------------------------------------------+-- * Convenience "constructors"++pattern Vector :: VectorFamilyF (Peano d) r -> Vector d r+pattern Vector v = MKVector (VectorFamily v)++pattern Vector1 :: r -> Vector 1 r+pattern Vector1 x = (Vector (Identity x))++pattern Vector2 :: r -> r -> Vector 2 r+pattern Vector2 x y = (Vector (L2.V2 x y))++pattern Vector3 :: r -> r -> r -> Vector 3 r+pattern Vector3 x y z = (Vector (L3.V3 x y z))++pattern Vector4 :: r -> r -> r -> r -> Vector 4 r+pattern Vector4 x y z w = (Vector (L4.V4 x y z w))++--------------------------------------------------------------------------------++-- -- destruct :: (Vec d r, Vec (d + 1) r, 1 <= (d + 1))+-- -- => Vector (d + 1) r -> (r, Vector d r)+-- -- destruct (Vector v) = (V.head v, Vector $ V.tail v)+++-- -- -- vectorFromList :: Arity d => [a] -> Maybe (Vector d a)+-- -- vectorFromList = fmap Vector . V.fromListM++-- -- vectorFromListUnsafe :: V.Arity d => [a] -> Vector d a+-- -- vectorFromListUnsafe = Vector . V.fromList++ --------------------------------------------------------------------------------++-- | Cross product of two three-dimensional vectors+cross :: Num r => Vector 3 r -> Vector 3 r -> Vector 3 r+(Vector u) `cross` (Vector v) = Vector $ u `L3.cross` v
changelog.org view
@@ -2,6 +2,32 @@ * Changelog +** 0.12++- New website: https://hgeometry.org/+- Switch polygon implementation from a circular seq to a circular vector.+- Hide polygon implementation details.+- Enforce CCW polygon order by default.+- Fix bug in Data.Geometry.Polygon.Convex.extremes/maxInDirection.+- Fix bug in pointInPolygon in case of degenerate situations.+- Fix Read/Show instances for Point and Polygon such that 'read.show = id'.+- Improved numerical robustness.+- Random generation of monotone polygons. Thanks to @1ndy.+- Random and uniform generation of convex polygons.+- More IsIntersectableWith instances+- Updated Show/Read instances for LineSegments+- New algorithm: Visibility polygon in O(n log n) time.+- New algorithm: Earclip triangulation in O(n^2) time worst case, O(n)+ time expected case.+- New algorithm: Single-source shortest path in O(n) time.+- New algorithm: Planar point locator in O(log n) time.+- New algorithm: Point set diameter in O(n log n) time.+- New algorithm: Convex hull of a polygon in O(n) time.+- New algorithm: Diameter of a convex polygon in O(n) time.+- New algorithm: Check if a point lies inside a convex polygon in O(n)+ time.+- New algorithm: Discrete Frechet distance in O(n^2) time.+ ** 0.11 - Removed Functor instance from Triangle and replaced it with Bifunctor/Bifoldable/Bitraversable
doctests.hs view
@@ -29,7 +29,6 @@ , "DeriveFunctor" , "DeriveFoldable" , "DeriveTraversable"- , "AutoDeriveTypeable" , "DeriveGeneric" , "FlexibleInstances" , "FlexibleContexts"@@ -70,4 +69,5 @@ , "Algorithms.Geometry.ConvexHull.JarvisMarch" , "Algorithms.Geometry.SoS.Orientation"+ , "Algorithms.Geometry.InPolygon" ]
hgeometry.cabal view
@@ -1,5 +1,5 @@ name: hgeometry-version: 0.11.0.0+version: 0.12.0.0 synopsis: Geometric Algorithms, Data structures, and Data types. description: HGeometry provides some basic geometry types, and geometric algorithms and@@ -19,28 +19,6 @@ category: Geometry build-type: Simple -data-files: test/Algorithms/Geometry/LineSegmentIntersection/manual.ipe- test/Algorithms/Geometry/LineSegmentIntersection/selfIntersections.ipe- test/Algorithms/Geometry/LowerEnvelope/manual.ipe- test/Algorithms/Geometry/PolygonTriangulation/monotone.ipe- test/Algorithms/Geometry/PolygonTriangulation/simplepolygon6.ipe- test/Algorithms/Geometry/SmallestEnclosingDisk/manual.ipe- test/Algorithms/Geometry/LinearProgramming/manual.ipe- test/Algorithms/Geometry/RedBlueSeparator/manual.ipe- test/Data/Geometry/pointInPolygon.ipe- test/Data/Geometry/pointInTriangle.ipe- test/Data/Geometry/Polygon/star_shaped.ipe- test/Data/Geometry/Polygon/Convex/convexTests.ipe- test/Data/Geometry/arrangement.ipe- test/Data/Geometry/arrangement.ipe.out.ipe- test/Data/PlaneGraph/myPlaneGraph.yaml- test/Data/PlaneGraph/small.yaml- test/Data/PlaneGraph/testsegs.png-- -- in the future (cabal >=2.4) we can use- -- examples/**/*.in- -- examples/**/*.out- extra-source-files: README.md changelog.org @@ -52,6 +30,10 @@ type: git location: https://github.com/noinia/hgeometry +flag planargraph+ default: False+ manual: True+ library ghc-options: -O2 -Wall -fno-warn-unticked-promoted-constructors -fno-warn-type-defaults @@ -84,6 +66,7 @@ Data.Geometry.Line Data.Geometry.Line.Internal Data.Geometry.LineSegment+ Data.Geometry.LineSegment.Internal Data.Geometry.SubLine Data.Geometry.HalfLine Data.Geometry.PolyLine@@ -101,7 +84,9 @@ Data.Geometry.Ellipse Data.Geometry.Polygon+ Data.Geometry.Polygon.Inflate Data.Geometry.Polygon.Convex+ Data.Geometry.Polygon.Monotone Data.Geometry.BezierSpline @@ -132,10 +117,16 @@ Data.Geometry.QuadTree.Split Data.Geometry.QuadTree.Tree + Data.Geometry.PointLocation+ Data.Geometry.PointLocation.PersistentSweep + Data.Geometry.VerticalRayShooting+ Data.Geometry.VerticalRayShooting.PersistentSweep+ -- * Algorithms -- * Geometric Algorithms+ Algorithms.Geometry.ConvexHull Algorithms.Geometry.ConvexHull.GrahamScan Algorithms.Geometry.ConvexHull.DivideAndConquer Algorithms.Geometry.ConvexHull.QuickHull@@ -144,7 +135,7 @@ Algorithms.Geometry.LowerEnvelope.DualCH - Algorithms.Geometry.SmallestEnclosingBall.Types+ Algorithms.Geometry.SmallestEnclosingBall Algorithms.Geometry.SmallestEnclosingBall.RIC Algorithms.Geometry.SmallestEnclosingBall.Naive @@ -154,12 +145,16 @@ Algorithms.Geometry.PolyLineSimplification.DouglasPeucker + Algorithms.Geometry.EuclideanMST Algorithms.Geometry.EuclideanMST.EuclideanMST + Algorithms.Geometry.WSPD Algorithms.Geometry.WellSeparatedPairDecomposition.WSPD Algorithms.Geometry.WellSeparatedPairDecomposition.Types + Algorithms.Geometry.Diameter Algorithms.Geometry.Diameter.Naive+ Algorithms.Geometry.Diameter.ConvexHull -- Algorithms.Geometry.Sweep @@ -167,14 +162,16 @@ Algorithms.Geometry.PolygonTriangulation.Triangulate Algorithms.Geometry.PolygonTriangulation.MakeMonotone Algorithms.Geometry.PolygonTriangulation.TriangulateMonotone+ Algorithms.Geometry.PolygonTriangulation.EarClip Algorithms.Geometry.LineSegmentIntersection Algorithms.Geometry.LineSegmentIntersection.Naive Algorithms.Geometry.LineSegmentIntersection.BentleyOttmann- Algorithms.Geometry.LineSegmentIntersection.Types+ Algorithms.Geometry.LineSegmentIntersection.BooleanSweep -- Algorithms.Geometry.HiddenSurfaceRemoval.HiddenSurfaceRemoval + Algorithms.Geometry.ClosestPair Algorithms.Geometry.ClosestPair.Naive Algorithms.Geometry.ClosestPair.DivideAndConquer @@ -185,6 +182,9 @@ Algorithms.Geometry.FrechetDistance.Discrete + Algorithms.Geometry.VisibilityPolygon.Lee+ Algorithms.Geometry.SSSP+ Algorithms.Geometry.SSSP.Naive -- * Embedded Planar Graphs Data.PlaneGraph@@ -202,8 +202,13 @@ -- * Implementation Internals of Polygons Data.Geometry.Polygon.Core Data.Geometry.Polygon.Extremes+ Algorithms.Geometry.InPolygon + Algorithms.Geometry.LineSegmentIntersection.Types+ Algorithms.Geometry.SmallestEnclosingBall.Types + Algorithms.Geometry.WSPD.Types+ Data.Geometry.Point.Internal Data.Geometry.Point.Orientation Data.Geometry.Point.Quadrants@@ -222,7 +227,7 @@ -- other-extensions: build-depends: base >= 4.11 && < 5- , hgeometry-combinatorial >= 0.11.0.0+ , hgeometry-combinatorial >= 0.12.0.0 , bifunctors >= 4.1 , bytestring >= 0.10@@ -251,9 +256,12 @@ -- , ghc-typelits-natnormalise >= 0.6 -- , ghc-typelits-knownnat >= 0.6 - , vector >= 0.11+ , vector >= 0.11 && < 0.12.2.0 , data-clist >= 0.1.2.3+ , vector-circular >= 0.1.2+ , nonempty-vector >= 0.2.0.0 , text >= 1.1.1.0+ , vector-algorithms , aeson >= 1.0 , yaml >= 0.8@@ -304,5 +312,111 @@ , doctest >= 0.8 , doctest-discover , QuickCheck+ , quickcheck-instances default-language: Haskell2010++benchmark benchmarks++ hs-source-dirs: benchmark++ main-is: Benchmarks.hs+ type: exitcode-stdio-1.0++ other-modules: Benchmark.Util+ Algorithms.Geometry.ConvexHull.Bench+ Algorithms.Geometry.ConvexHull.GrahamV2+ Algorithms.Geometry.ConvexHull.GrahamFam+ Algorithms.Geometry.ConvexHull.GrahamFamPeano+ Algorithms.Geometry.ConvexHull.GrahamFixed+ Data.Geometry.Vector.VectorFamily6+ Algorithms.Geometry.ConvexHull.GrahamFam6+ Data.Geometry.IntervalTreeBench+ -- Demo.ExpectedPairwiseDistance+ -- Demo.TriangulateWorld+ -- WSPDBench+ Algorithms.Geometry.ClosestPair.Bench++ Algorithms.Geometry.LineSegmentIntersection.Bench+ Algorithms.Geometry.LineSegmentIntersection.BentleyOttmannOld++ Algorithms.Geometry.PolygonTriangulation.Bench+ Algorithms.Geometry.PolygonTriangulation.MakeMonotoneOld+++ build-depends:+ base+ , tasty-bench+ , fixed-vector+ , linear+ , semigroups+ , deepseq+ , deepseq-generics+ , hgeometry+ , hgeometry-combinatorial+ , lens+ , semigroupoids+ , QuickCheck+ , bytestring+ , containers+ , optparse-applicative+ , vinyl+ , vector+ , dlist+ , mtl+ , vector-circular+ , MonadRandom+ , hashable+++ ghc-options: -Wall -O2 -rtsopts -fno-warn-unticked-promoted-constructors++ default-language: Haskell2010++ default-extensions: TypeFamilies+ , GADTs+ , KindSignatures+ , DataKinds+ , TypeOperators+ , ConstraintKinds+ , PolyKinds+ , RankNTypes+ , TypeApplications+ , ScopedTypeVariables++ , PatternSynonyms+ , ViewPatterns+ , LambdaCase+ , TupleSections+++ , StandaloneDeriving+ , GeneralizedNewtypeDeriving+ , DeriveFunctor+ , DeriveFoldable+ , DeriveTraversable++ , FlexibleInstances+ , FlexibleContexts+ , MultiParamTypeClasses++executable planargraph+ main-is: planargraph.hs+ if flag(planargraph)+ buildable: True+ else+ buildable: False+ default-language: Haskell2010+ build-depends: base,+ vector,+ vector-circular,+ linear,+ text,+ hashable,+ lens,+ directory,+ filepath,+ hgeometry,+ hgeometry-combinatorial,+ reanimate,+ reanimate-svg
+ planargraph.hs view
@@ -0,0 +1,136 @@+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE RecordWildCards #-}+module Main where++import Data.PlanarGraph.Immutable+import qualified Data.PlanarGraph.Mutable as Mut++import Control.Lens ()+import Control.Monad.ST+import Data.Ext+import Data.Foldable as F+import Data.Geometry.Point+import Data.Geometry.Polygon+import Data.STRef+import Data.Hashable+import qualified Data.Text as T+import qualified Data.Vector as V+import qualified Data.Vector.Circular as CV+import Graphics.SvgTree (Number (..))+import Linear.Metric+import Linear.V2+import Linear.Vector+import Reanimate+import Reanimate.Animation+import System.Directory+import System.FilePath+import Debug.Trace++graphs :: [PlanarGraph]+graphs =+ [ pgFromFaces [[0..2]]+ , pgFromFaces [[1,2,3]]+ , pgFromFaces [[0..3]]+ , pgFromFaces [[0..3],[4,3,2,1]]+ , let pg = pgFromFaces [[0..3]]+ in pgMutate pg $ \pg' -> do+ let he0 = Mut.halfEdgeFromId 0 pg'+ he4 = Mut.halfEdgeFromId 4 pg'+ _newEdge <- Mut.pgConnectVertices he0 he4+ return ()+ , pgFromFaces [[0,4,1],[0,1,2],[4,3,1],[4,5,3],[3,5,2],[2,5,0]]+ ]++main :: IO ()+-- main = reanimate $ staticFrame (1/60) (fst test2)+main = do+ forM_ graphs savePlanarGraphSVG++-- test1 = renderPlanarGraph (pgFromFaces [[0..2]])+-- test2 = renderPlanarGraph (pgFromFaces [[0..3],[4,3,2,1]])++savePlanarGraphSVG :: PlanarGraph -> IO ()+savePlanarGraphSVG pg = do+ writeFile fileName svgOutput+ writeFile compactName compactOutput+ where+ svgOutput = renderSvg (Just $ Num 300) (Just $ Num 300) svg+ compactOutput = renderSvg (Just $ Num 300) (Just $ Num 300) compactSvg+ fileName = "planargraph-" ++ show (hash pg) <.> "svg"+ compactName = "planargraph-" ++ show (hash pg) <.> "compact" <.> "svg"+ defOpts = RenderOptions { disableHalfEdges = False }+ compactOpts = RenderOptions { disableHalfEdges = True }+ svg = renderPlanarGraph defOpts pg+ compactSvg = renderPlanarGraph compactOpts pg++data RenderOptions = RenderOptions+ { disableHalfEdges :: Bool }++renderPlanarGraph :: RenderOptions -> PlanarGraph -> SVG+renderPlanarGraph RenderOptions{..} pg = svg+ where+ vs = tutteEmbedding pg+ faces = pgFaces pg+ svg =+ withViewBox (screenBottom, screenBottom, screenHeight, screenHeight) $+ mkGroup+ [ mkBackground bgColor+ , mkGroup+ [ translate (x*scaleFactor) (y*scaleFactor) $+ mkGroup+ [ label+ , withFillOpacity 0 $ withStrokeColor "black" $ withStrokeWidth strokeWidth $+ -- mkRect (strokeWidth+svgWidth label*1.5) (strokeWidth+svgHeight label*1.5)+ translate 0 (-(svgHeight label+0.1)/2) $+ center $ mkLine (0,0) (svgWidth label*1.2,0)+ ]+ | face <- faces+ , let boundary = faceBoundary face pg+ poly = simpleFromPoints $ map ext+ [ Point2 x y+ | vId <- boundary+ , let V2 x y = vs V.! vertexId vId+ ]+ Point2 x y = centroid poly+ label = scale 0.5 $ center $ latex (T.pack $ show $ faceId face)+ ]+ , mkGroup+ [ mkGroup $+ [ withStrokeColor "black" $+ mkLine (tipX*scaleFactor, tipY*scaleFactor) (tailX*scaleFactor, tailY*scaleFactor)+ ] ++ if disableHalfEdges+ then []+ else + [ translate (halfX*scaleFactor + angY) (halfY*scaleFactor - angX) $+ labelTwin+ , translate (halfX*scaleFactor - angY) (halfY*scaleFactor + angX) $+ labelEdge+ ]+ | edge <- pgEdges pg+ , let (tip, tail) = edgeHalfEdges edge+ V2 tipX tipY = vs V.! vertexId (halfEdgeVertex tip pg)+ V2 tailX tailY = vs V.! vertexId (halfEdgeVertex tail pg)+ (halfX,halfY) = (tipX + (tailX-tipX)/2, tipY + (tailY-tipY)/2)+ labelEdge = scale 0.4 $ center $ latex (T.pack $ show $ halfEdgeId tip)+ labelTwin = scale 0.4 $ center $ latex (T.pack $ show $ halfEdgeId tail)+ V2 angX angY = signorm (V2 tipX tipY - V2 tailX tailY) ^* 0.3+ ]+ , mkGroup+ [ translate (x*scaleFactor) (y*scaleFactor) $+ mkGroup+ [ withFillOpacity 1 $ withFillColor "white" $ withStrokeColor "black" $+ mkCircle 0.3+ , label ]+ | v <- map vertexId $ pgVertices pg+ , let V2 x y = vs V.! v+ label = scaleToWidth 0.2 $ center $ latex (T.pack $ show v)+ ]+ ]++strokeWidth = defaultStrokeWidth*0.5++bgColor :: String+bgColor = "white"++scaleFactor :: Double+scaleFactor = screenTop*0.8
+ src/Algorithms/Geometry/ClosestPair.hs view
@@ -0,0 +1,14 @@+--------------------------------------------------------------------------------+-- |+-- Module : Algorithms.Geometry.ClosestPair+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+--+-- \(O(n\log n)\) time algorithm to compute the+-- closest pair among a set of \(n\) points in \(\mathbb{R}^2\).+--+--------------------------------------------------------------------------------+module Algorithms.Geometry.ClosestPair( closestPair ) where++import Algorithms.Geometry.ClosestPair.DivideAndConquer
src/Algorithms/Geometry/ClosestPair/DivideAndConquer.hs view
@@ -36,7 +36,7 @@ -- | Classical divide and conquer algorithm to compute the closest pair among -- \(n\) points. ----- running time: \(O(n)\)+-- running time: \(O(n \log n)\) closestPair :: (Ord r, Num r) => LSeq 2 (Point 2 r :+ p) -> Two (Point 2 r :+ p) closestPair = f . divideAndConquer1 mkCCP . toNonEmpty . LSeq.unstableSortBy (comparing (^.core))@@ -100,8 +100,8 @@ -> CP (Point 2 r :+ p) r run cp'' r ls = runWhile cp'' ls- (\cp l -> (ValT $ sqVertDist r l) < getDist cp) -- r and l inverted- -- by design+ (\cp l -> ValT (sqVertDist r l) < getDist cp) -- r and l inverted+ -- by design (\cp l -> minBy getDist cp (ValT $ SP (Two l r) (dist l r))) where dist (p :+ _) (q :+ _) = squaredEuclideanDist p q
+ src/Algorithms/Geometry/ConvexHull.hs view
@@ -0,0 +1,10 @@+--------------------------------------------------------------------------------+-- |+-- Module : Algorithms.Geometry.ConvexHull+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+--------------------------------------------------------------------------------+module Algorithms.Geometry.ConvexHull( convexHull ) where++import Algorithms.Geometry.ConvexHull.GrahamScan
src/Algorithms/Geometry/ConvexHull/DivideAndConquer.hs view
@@ -28,10 +28,10 @@ -- | \(O(n \log n)\) time ConvexHull using divide and conquer. The resulting polygon is -- given in clockwise order. convexHull :: (Ord r, Num r) => NonEmpty (Point 2 r :+ p) -> ConvexPolygon p r-convexHull (p :| []) = ConvexPolygon . fromPoints $ [p]+convexHull (p :| []) = ConvexPolygon . unsafeFromPoints $ [p] convexHull pts = combine . (upperHull' &&& lowerHull') . NonEmpty.sortBy incXdecY $ pts where- combine (l:|uh,_:|lh) = ConvexPolygon . fromPoints $ l : uh <> reverse (init lh)+ combine (l:|uh,_:|lh) = ConvexPolygon . unsafeFromPoints $ l : uh <> reverse (init lh) ---------------------------------------- -- * Computing a lower hull@@ -72,10 +72,10 @@ hull :: (NonEmpty p -> NonEmpty p -> Two (p :+ [p])) -> NonEmpty p -> NonEmpty p -> NonEmpty p hull tangent lh rh = let Two (l :+ lh') (r :+ rh') = tangent (NonEmpty.reverse lh) rh- in NonEmpty.fromList $ (reverse lh') <> [l,r] <> rh'+ in NonEmpty.fromList $ reverse lh' <> [l,r] <> rh' -------------------------------------------------------------------------------- -incXdecY :: Ord r => (Point 2 r) :+ p -> (Point 2 r) :+ q -> Ordering+incXdecY :: Ord r => Point 2 r :+ p -> Point 2 r :+ q -> Ordering incXdecY (Point2 px py :+ _) (Point2 qx qy :+ _) = compare px qx <> compare qy py
src/Algorithms/Geometry/ConvexHull/GrahamScan.hs view
@@ -1,3 +1,10 @@+--------------------------------------------------------------------------------+-- |+-- Module : Algorithms.Geometry.ConvexHull.GrahamScan+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+-------------------------------------------------------------------------------- module Algorithms.Geometry.ConvexHull.GrahamScan( convexHull , upperHull, upperHull' , lowerHull, lowerHull'@@ -18,11 +25,11 @@ -- given in clockwise order. convexHull :: (Ord r, Num r) => NonEmpty (Point 2 r :+ p) -> ConvexPolygon p r-convexHull (p :| []) = ConvexPolygon . fromPoints $ [p]+convexHull (p :| []) = ConvexPolygon . unsafeFromPoints $ [p] convexHull ps = let ps' = NonEmpty.toList . NonEmpty.sortBy incXdecY $ ps uh = NonEmpty.tail . hull' $ ps' lh = NonEmpty.tail . hull' $ reverse ps'- in ConvexPolygon . fromPoints . reverse $ lh ++ uh+ in ConvexPolygon . unsafeFromPoints . reverse $ lh ++ uh -- | Computes the upper hull. The upper hull is given from left to right. --@@ -83,7 +90,7 @@ hull f pts = hull' . f . NonEmpty.toList . NonEmpty.sortBy incXdecY $ pts -incXdecY :: Ord r => (Point 2 r) :+ p -> (Point 2 r) :+ q -> Ordering+incXdecY :: Ord r => Point 2 r :+ p -> Point 2 r :+ q -> Ordering incXdecY (Point2 px py :+ _) (Point2 qx qy :+ _) = compare px qx <> compare qy py @@ -126,6 +133,9 @@ | rightTurn (x^.core) (y^.core) (z^.core) = h | otherwise = cleanMiddle (z:x:rest) cleanMiddle _ = error "cleanMiddle: too few points"+hull' _ = error+ "Algorithms.Geometry.ConvexHull.GrahamScan.hull' requires a list with at least \+ \two elements." rightTurn :: (Ord r, Num r) => Point 2 r -> Point 2 r -> Point 2 r -> Bool rightTurn a b c = ccw a b c == CW
src/Algorithms/Geometry/ConvexHull/JarvisMarch.hs view
@@ -1,3 +1,10 @@+--------------------------------------------------------------------------------+-- |+-- Module : Algorithms.Geometry.ConvexHull.JarvisMarch+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+-------------------------------------------------------------------------------- module Algorithms.Geometry.ConvexHull.JarvisMarch( convexHull @@ -8,7 +15,6 @@ import Control.Lens ((^.)) import Data.Bifunctor-import Data.Either (either) import Data.Ext import Data.Foldable import Data.Geometry.Point@@ -30,8 +36,8 @@ -- and \(h\) is the complexity of the hull. convexHull :: (Ord r, Num r) => NonEmpty (Point 2 r :+ p) -> ConvexPolygon p r-convexHull (p :| []) = ConvexPolygon . fromPoints $ [p]-convexHull pts = ConvexPolygon . fromPoints $ uh <> reverse lh+convexHull (p :| []) = ConvexPolygon . unsafeFromPoints $ [p]+convexHull pts = ConvexPolygon . unsafeFromPoints $ uh <> reverse lh where lh = case NonEmpty.nonEmpty (NonEmpty.init $ lowerHull pts) of Nothing -> []@@ -93,13 +99,13 @@ -- with minimum slope w.r.t. the given point. steepestCcwFrom :: (Ord r, Num r) => (Point 2 r :+ a) -> NonEmpty (Point 2 r :+ b) -> Point 2 r :+ b-steepestCcwFrom p = List.minimumBy (ccwCmpAroundWith (Vector2 0 (-1)) p)+steepestCcwFrom p = List.minimumBy (ccwCmpAroundWith' (Vector2 0 (-1)) p) -- | Find the next point in clockwise order, i.e. the point -- with maximum slope w.r.t. the given point. steepestCwFrom :: (Ord r, Num r) => (Point 2 r :+ a) -> NonEmpty (Point 2 r :+ b) -> Point 2 r :+ b-steepestCwFrom p = List.minimumBy (cwCmpAroundWith (Vector2 0 1) p)+steepestCwFrom p = List.minimumBy (cwCmpAroundWith' (Vector2 0 1) p) repeatedly :: (a -> a -> Ordering) -> (a -> NonEmpty a -> a) -> a -> [a] -> NonEmpty a repeatedly cmp f = go@@ -126,7 +132,7 @@ where go (x :| xs) = case NonEmpty.nonEmpty xs of Nothing -> b x- Just xs' -> x `f` (go xs')+ Just xs' -> x `f` go xs' -- | extracts all minima from the list. The result consists of the -- list of minima, and all remaining points. Both lists are returned
src/Algorithms/Geometry/ConvexHull/Naive.hs view
@@ -1,3 +1,10 @@+--------------------------------------------------------------------------------+-- |+-- Module : Algorithms.Geometry.ConvexHull.Naive+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+-------------------------------------------------------------------------------- module Algorithms.Geometry.ConvexHull.Naive( ConvexHull , lowerHull', lowerHullAll @@ -14,10 +21,9 @@ import Data.Geometry.Triangle import Data.Geometry.Vector import Data.Intersection(intersects)-import qualified Data.List as List import Data.List.NonEmpty (NonEmpty(..))-import qualified Data.List.NonEmpty as NonEmpty-import Data.Maybe (listToMaybe, isNothing)+import Data.List (find)+import Data.Maybe (isNothing) import Data.Util -------------------------------------------------------------------------------- @@ -50,15 +56,14 @@ -killOverlapping :: (Ord r, Fractional r) => [Triangle 3 p r] -> [Triangle 3 p r]-killOverlapping = foldr keepIfNotOverlaps []+_killOverlapping :: (Ord r, Fractional r) => [Triangle 3 p r] -> [Triangle 3 p r]+_killOverlapping = foldr keepIfNotOverlaps [] where keepIfNotOverlaps t ts | any (t `overlaps`) ts = ts | otherwise = t:ts --t1@(Triangle p q r) `overlaps` t2@(Triangle a b c) = upperHalfSpaceOf t1 == upperHalfSpaceOf t2- && False+overlaps :: (Fractional r, Ord r) => Triangle 3 p1 r -> Triangle 3 p2 r -> Bool+t1 `overlaps` t2 = upperHalfSpaceOf t1 == upperHalfSpaceOf t2 && False @@ -72,10 +77,10 @@ -- Nothing -- >>> let t = (Triangle (ext origin) (ext $ Point3 1 0 0) (ext $ Point3 0 1 0)) -- >>> isValidTriangle t [ext $ Point3 5 5 (-10)]--- Just (Point3 [5,5,-10] :+ ())+-- Just (Point3 5 5 (-10) :+ ()) isValidTriangle :: (Num r, Ord r) => Triangle 3 p r -> [Point 3 r :+ q] -> Maybe (Point 3 r :+ q)-isValidTriangle t = listToMaybe . filter (\a -> not $ (a^.core) `intersects` h)+isValidTriangle t = find (\a -> not $ (a^.core) `intersects` h) where h = upperHalfSpaceOf t @@ -83,7 +88,7 @@ -- | Computes the halfspace above the triangle. -- -- >>> upperHalfSpaceOf (Triangle (ext $ origin) (ext $ Point3 10 0 0) (ext $ Point3 0 10 0))--- HalfSpace {_boundingPlane = HyperPlane {_inPlane = Point3 [0,0,0], _normalVec = Vector3 [0,0,100]}}+-- HalfSpace {_boundingPlane = HyperPlane {_inPlane = Point3 0 0 0, _normalVec = Vector3 0 0 100}} upperHalfSpaceOf :: (Ord r, Num r) => Triangle 3 p r -> HalfSpace 3 r upperHalfSpaceOf (Triangle p q r) = HalfSpace h where
src/Algorithms/Geometry/ConvexHull/QuickHull.hs view
@@ -1,6 +1,13 @@+--------------------------------------------------------------------------------+-- |+-- Module : Algorithms.Geometry.ConvexHull.QuickHull+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+-------------------------------------------------------------------------------- module Algorithms.Geometry.ConvexHull.QuickHull( convexHull ) where -import Control.Lens ((^.),(&),(.~))+import Control.Lens ((^.)) import Data.Ext import qualified Data.Foldable as F import Data.Geometry.Line@@ -26,9 +33,9 @@ -- running time: \(O(n^2)\) convexHull :: (Ord r, Fractional r, Show r, Show p) => NonEmpty (Point 2 r :+ p) -> ConvexPolygon p r-convexHull (p :| []) = ConvexPolygon . fromPoints $ [p]-convexHull ps = ConvexPolygon . fromPoints- $ [l] <> hull l r above <> [r] <> (reverse $ hull l r below)+convexHull (p :| []) = ConvexPolygon . unsafeFromPoints $ [p]+convexHull ps = ConvexPolygon . unsafeFromPoints+ $ [l] <> hull l r above <> [r] <> reverse (hull l r below) where STR l r mids = findExtremes ps m = lineThrough (l^.core) (r^.core)@@ -59,7 +66,7 @@ -- in STR l r [p | p <- F.toList pts, p /=. l, p /=. r] -incXdecY :: Ord r => (Point 2 r) :+ p -> (Point 2 r) :+ q -> Ordering+incXdecY :: Ord r => Point 2 r :+ p -> Point 2 r :+ q -> Ordering incXdecY (Point2 px py :+ _) (Point2 qx qy :+ _) = compare px qx <> compare qy py
src/Algorithms/Geometry/DelaunayTriangulation/DivideAndConquer.hs view
@@ -1,30 +1,40 @@ {-# LANGUAGE ScopedTypeVariables #-}-module Algorithms.Geometry.DelaunayTriangulation.DivideAndConquer where+--------------------------------------------------------------------------------+-- |+-- Module : Algorithms.Geometry.DelaunayTriangulation.DivideAndConquer+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+--------------------------------------------------------------------------------+module Algorithms.Geometry.DelaunayTriangulation.DivideAndConquer+ (+ -- * Divide & Conqueror Delaunay Triangulation+ delaunayTriangulation+ ) where -import Algorithms.Geometry.ConvexHull.GrahamScan as GS+import Algorithms.Geometry.ConvexHull.GrahamScan as GS import Algorithms.Geometry.DelaunayTriangulation.Types import Control.Lens import Control.Monad.Reader import Control.Monad.State import Data.BinaryTree-import qualified Data.CircularList as CL-import qualified Data.CircularList.Util as CU-import qualified Data.CircularSeq as CS+import qualified Data.CircularList as CL+import qualified Data.CircularList.Util as CU import Data.Ext-import qualified Data.Foldable as F-import Data.Function (on)-import Data.Geometry hiding (rotateTo)-import Data.Geometry.Ball (disk, insideBall)-import Data.Geometry.Polygon-import Data.Geometry.Polygon.Convex (ConvexPolygon(..), simplePolygon)-import qualified Data.Geometry.Polygon.Convex as Convex-import qualified Data.IntMap.Strict as IM-import qualified Data.List as L-import qualified Data.List.NonEmpty as NonEmpty-import qualified Data.Map as M-import Data.Maybe (fromJust, fromMaybe)+import qualified Data.Foldable as F+import Data.Function (on)+import Data.Geometry hiding (rotateTo)+import Data.Geometry.Ball (disk, insideBall)+import Data.Geometry.Polygon.Convex (ConvexPolygon (..), simplePolygon)+import qualified Data.Geometry.Polygon.Convex as Convex+import qualified Data.IntMap.Strict as IM+import qualified Data.List as L+import qualified Data.List.NonEmpty as NonEmpty+import qualified Data.Map as M+import Data.Maybe (fromJust, fromMaybe) import Data.Measured.Size-import qualified Data.Vector as V+import qualified Data.Vector as V+import qualified Data.Vector.Circular.Util as CV ------------------------------------------------------------------------------- -- * Divide & Conqueror Delaunay Triangulation@@ -42,7 +52,6 @@ -- -- Rotating Right <-> rotate clockwise - -- | Computes the delaunay triangulation of a set of points. -- -- Running time: \(O(n \log n)\)@@ -73,7 +82,7 @@ delaunayTriangulation' pts mapping'@(vtxMap,_) | size' pts == 1 = let (Leaf p) = pts i = lookup' vtxMap (p^.core)- in (IM.singleton i CL.empty, ConvexPolygon $ fromPoints [withID p i])+ in (IM.singleton i CL.empty, ConvexPolygon $ unsafeFromPoints [withID p i]) | size' pts <= 3 = let pts' = NonEmpty.fromList . map (\p -> withID p (lookup' vtxMap (p^.core))) . F.toList $ pts@@ -99,8 +108,8 @@ -- pre: at least two elements fromHull :: Ord r => Mapping p r -> ConvexPolygon (p :+ q) r -> Adj fromHull (vtxMap,_) p = let vs@(u:v:vs') = map (lookup' vtxMap . (^.core))- . F.toList . CS.rightElements- $ p^.simplePolygon.outerBoundary+ . F.toList . CV.rightElements+ $ p^.simplePolygon.outerBoundaryVector es = zipWith3 f vs (tail vs ++ [u]) (vs' ++ [u,v]) f prv c nxt = (c,CL.fromList . L.nub $ [prv, nxt]) in IM.fromList es@@ -138,8 +147,8 @@ | otherwise = do insert l r -- Get the neighbours of r and l along the convex hull- r1 <- pred' . rotateTo l . lookup'' r <$> get- l1 <- succ' . rotateTo r . lookup'' l <$> get+ r1 <- gets (pred' . rotateTo l . lookup'' r)+ l1 <- gets (succ' . rotateTo r . lookup'' l) (r1',a) <- rotateR l r r1 (l1',b) <- rotateL l r l1@@ -152,7 +161,7 @@ moveUp ut l' r' --- | ''rotates'' around r and removes all neighbours of r that violate the+-- | \'rotates\' around r and removes all neighbours of r that violate the -- delaunay condition. Returns the first vertex (as a Neighbour of r) that -- should remain in the Delaunay Triangulation, as well as a boolean A that -- helps deciding if we merge up by rotating left or rotating right (See@@ -199,12 +208,12 @@ -- by the first three points. qTest :: (Ord r, Fractional r) => VertexID -> VertexID -> Vertex -> Vertex -> Merge p r Bool-qTest h i j k = withPtMap . snd . fst <$> ask+qTest h i j k = asks (withPtMap . snd . fst) where withPtMap ptMap = let h' = ptMap V.! h i' = ptMap V.! i- j' = ptMap V.! (focus' j)- k' = ptMap V.! (focus' k)+ j' = ptMap V.! focus' j+ k' = ptMap V.! focus' k in not . maybe True ((k'^.core) `insideBall`) $ disk' h' i' j' disk' p q r = disk (p^.core) (q^.core) (r^.core) @@ -233,8 +242,8 @@ . IM.adjustWithKey (insert'' u) v where -- inserts b into the adjacency list of a- insert'' bi ai = CU.insertOrdBy (cwCmpAround' (ptMap V.! ai) `on` (ptMap V.!)) bi- cwCmpAround' c p q = cwCmpAround c p q <> cmpByDistanceTo c p q+ insert'' bi ai = CU.insertOrdBy (cmp (ptMap V.! ai) `on` (ptMap V.!)) bi+ cmp c p q = cwCmpAround' c p q <> cmpByDistanceTo' c p q -- | Deletes an edge@@ -247,7 +256,7 @@ -- | Lifted version of Convex.IsLeftOf isLeftOf :: (Ord r, Num r) => VertexID -> (VertexID, VertexID) -> Merge p r Bool-p `isLeftOf` (l,r) = withPtMap . snd . fst <$> ask+p `isLeftOf` (l,r) = asks (withPtMap . snd . fst) where withPtMap ptMap = (ptMap V.! p) `isLeftOf'` (ptMap V.! l, ptMap V.! r) a `isLeftOf'` (b,c) = ccw' b c a == CCW@@ -255,7 +264,7 @@ -- | Lifted version of Convex.IsRightOf isRightOf :: (Ord r, Num r) => VertexID -> (VertexID, VertexID) -> Merge p r Bool-p `isRightOf` (l,r) = withPtMap . snd . fst <$> ask+p `isRightOf` (l,r) = asks (withPtMap . snd . fst) where withPtMap ptMap = (ptMap V.! p) `isRightOf'` (ptMap V.! l, ptMap V.! r) a `isRightOf'` (b,c) = ccw' b c a == CW@@ -271,7 +280,7 @@ size' (Leaf _) = 1 size' (Node _ s _) = s --- | an 'unsafe' version of rotateTo that assumes the element to rotate to+-- | an \'unsafe\' version of rotateTo that assumes the element to rotate to -- occurs in the list. rotateTo :: Eq a => a -> CL.CList a -> CL.CList a rotateTo x = fromJust . CL.rotateTo x@@ -284,6 +293,7 @@ succ' :: CL.CList a -> CL.CList a succ' = CL.rotL +-- | Return the focus of the CList, throwing an exception if the list is empty. focus' :: CL.CList a -> a focus' = fromJust . CL.focus @@ -296,4 +306,4 @@ withID p i = p&extra %~ (:+i) lookup'' :: Int -> IM.IntMap a -> a-lookup'' k m = fromJust . IM.lookup k $ m+lookup'' k m = m IM.! k
src/Algorithms/Geometry/DelaunayTriangulation/Naive.hs view
@@ -1,3 +1,10 @@+--------------------------------------------------------------------------------+-- |+-- Module : Algorithms.Geometry.DelaunayTriangulation.Naive+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+-------------------------------------------------------------------------------- module Algorithms.Geometry.DelaunayTriangulation.Naive where import Algorithms.Geometry.DelaunayTriangulation.Types@@ -17,7 +24,7 @@ -------------------------------------------------------------------------------- --- | Naive O(n^4) time implementation of the delaunay triangulation. Simply+-- | Naive \( O(n^4) \) time implementation of the delaunay triangulation. Simply -- tries each triple (p,q,r) and tests if it is delaunay, i.e. if there are no -- other points in the circle defined by p, q, and r. --@@ -52,14 +59,14 @@ addAt v i j = updateAt v i (j:) -- convert to a CList, sorted in CCW order around point u- toCList u = C.fromList . sortAround' m u+ toCList u = C.fromList . sortAroundMapping m u -- | Given a particular point u and a list of points vs, sort the points vs in -- CW order around u.--- running time: O(m log m), where m=|vs| is the number of vertices to sort.-sortAround' :: (Num r, Ord r)+-- running time: \( O(m log m) \), where m=|vs| is the number of vertices to sort.+sortAroundMapping :: (Num r, Ord r) => Mapping p r -> VertexID -> [VertexID] -> [VertexID]-sortAround' (_,ptsV) u vs = reverse . map (^.extra) $ sortAround (f u) (map f vs)+sortAroundMapping (_,ptsV) u vs = reverse . map (^.extra) $ sortAround' (f u) (map f vs) where f v = (ptsV V.! v)&extra .~ v @@ -71,8 +78,7 @@ -- we sort, group, and take the head of the lists --- | Test if the given three points form a triangle in the delaunay triangulation.--- running time: O(n)+-- | \( O(n) \) Test if the given three points form a triangle in the delaunay triangulation. isDelaunay :: (Fractional r, Ord r) => Mapping p r -> VertexID -> VertexID -> VertexID -> Bool isDelaunay (_,ptsV) p q r = case disk (pt p) (pt q) (pt r) of
src/Algorithms/Geometry/DelaunayTriangulation/Types.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE ScopedTypeVariables #-} -------------------------------------------------------------------------------- -- |@@ -10,7 +9,20 @@ -- Defines some geometric types used in the delaunay triangulation -- ---------------------------------------------------------------------------------module Algorithms.Geometry.DelaunayTriangulation.Types where+module Algorithms.Geometry.DelaunayTriangulation.Types+ ( VertexID+ , Vertex+ , Adj+ , Triangulation(..)+ , vertexIds+ , positions+ , neighbours+ , Mapping+ , edgesAsPoints+ , edgesAsVertices+ , toPlanarSubdivision+ , toPlaneGraph+ ) where import Control.Lens import qualified Data.CircularList as C@@ -19,7 +31,7 @@ import Data.Geometry.PlanarSubdivision import qualified Data.IntMap.Strict as IM import qualified Data.Map as M-import qualified Data.Map.Strict as SM+-- import qualified Data.Map.Strict as SM import qualified Data.PlaneGraph as PG import qualified Data.PlanarGraph as PPG import qualified Data.Vector as V@@ -32,12 +44,13 @@ -- : If v on the convex hull, then its first entry in the adj. lists is its CCW -- successor (i.e. its predecessor) on the convex hull --- | Rotating Right <-> rotate clockwise-+-- | Vertex identifier. type VertexID = Int +-- | Rotating Right <-> rotate clockwise type Vertex = C.CList VertexID +-- | Neighbours indexed by VertexID. type Adj = IM.IntMap (C.CList VertexID) -- | Neighbours are stored in clockwise order: i.e. rotating right moves to the@@ -47,35 +60,48 @@ , _neighbours :: V.Vector (C.CList VertexID) } deriving (Show,Eq)-makeLenses ''Triangulation -type instance NumType (Triangulation p r) = r-type instance Dimension (Triangulation p r) = 2+-- | Mapping between triangulated points and their internal VertexID.+vertexIds :: Lens' (Triangulation p r) (M.Map (Point 2 r) VertexID)+vertexIds = lens _vertexIds (\(Triangulation _v p n) v -> Triangulation v p n) +-- | Point positions indexed by VertexID.+positions :: Lens (Triangulation p1 r) (Triangulation p2 r) (V.Vector (Point 2 r :+ p1)) (V.Vector (Point 2 r :+ p2))+positions = lens _positions (\(Triangulation v _p n) p -> Triangulation v p n) -type Mapping p r = (M.Map (Point 2 r) VertexID, V.Vector (Point 2 r :+ p))+-- | Point neighbours indexed by VertexID.+neighbours :: Lens' (Triangulation p r) (V.Vector (C.CList VertexID))+neighbours = lens _neighbours (\(Triangulation v p _n) n -> Triangulation v p n) +type instance NumType (Triangulation p r) = r+type instance Dimension (Triangulation p r) = 2 +-- | Bidirectional mapping between points and VertexIDs.+type Mapping p r = (M.Map (Point 2 r) VertexID, V.Vector (Point 2 r :+ p)) -showDT :: (Show p, Show r) => Triangulation p r -> IO ()-showDT = mapM_ print . triangulationEdges -triangulationEdges :: Triangulation p r -> [(Point 2 r :+ p, Point 2 r :+ p)]-triangulationEdges t = let pts = _positions t- in map (\(u,v) -> (pts V.! u, pts V.! v)) . tEdges $ t +-- showDT :: (Show p, Show r) => Triangulation p r -> IO ()+-- showDT = mapM_ print . edgesAsPoints -tEdges :: Triangulation p r -> [(VertexID,VertexID)]-tEdges = concatMap (\(i,ns) -> map (i,) . filter (> i) . C.toList $ ns)+{- HLINT ignore edgesAsPoints -}+-- | List add edges as point pairs.+edgesAsPoints :: Triangulation p r -> [(Point 2 r :+ p, Point 2 r :+ p)]+edgesAsPoints t = let pts = _positions t+ in map (\(u,v) -> (pts V.! u, pts V.! v)) . edgesAsVertices $ t++-- | List add edges as VertexID pairs.+edgesAsVertices :: Triangulation p r -> [(VertexID,VertexID)]+edgesAsVertices = concatMap (\(i,ns) -> map (i,) . filter (> i) . C.toList $ ns) . zip [0..] . V.toList . _neighbours -------------------------------------------------------------------------------- -data ST a b c = ST { fst' :: !a, snd' :: !b , trd' :: !c}+-- data ST a b c = ST { fst' :: !a, snd' :: !b , trd' :: !c} -type ArcID = Int+-- type ArcID = Int -- | ST' is a strict triple (m,a,x) containing: --@@ -83,7 +109,7 @@ -- u < v, to arcId's. -- - a: the next available unused arcID -- - x: the data value we are interested in computing-type ST' a = ST (SM.Map (VertexID,VertexID) ArcID) ArcID a+-- type ST' a = ST (SM.Map (VertexID,VertexID) ArcID) ArcID a -- | convert the triangulation into a planarsubdivision
+ src/Algorithms/Geometry/Diameter.hs view
@@ -0,0 +1,13 @@+--------------------------------------------------------------------------------+-- |+-- Module : Algorithms.Geometry.Diameter+-- Copyright : (C) David Himmelstrup+-- License : see the LICENSE file+-- Maintainer : Frank Staals, David Himmelstrup+--------------------------------------------------------------------------------+module Algorithms.Geometry.Diameter+ ( diameter+ , diametralPair+ ) where++import Algorithms.Geometry.Diameter.ConvexHull
+ src/Algorithms/Geometry/Diameter/ConvexHull.hs view
@@ -0,0 +1,35 @@+--------------------------------------------------------------------------------+-- |+-- Module : Algorithms.Geometry.Diameter.ConvexHull+-- Copyright : (C) David Himmelstrup+-- License : see the LICENSE file+-- Maintainer : Frank Staals, David Himmelstrup+--------------------------------------------------------------------------------+module Algorithms.Geometry.Diameter.ConvexHull+ ( diameter+ , diametralPair+ ) where++import Algorithms.Geometry.ConvexHull.GrahamScan (convexHull)+import qualified Algorithms.Geometry.Diameter.Naive as Naive+import Control.Lens ((^.))+import Data.Ext (core, type (:+))+import Data.Geometry (Point, euclideanDist)+import qualified Data.Geometry.Polygon.Convex as Convex+import qualified Data.List.NonEmpty as NonEmpty++--------------------------------------------------------------------------------++-- | Computes the Euclidean diameter by first finding the convex hull.+--+-- running time: \(O(n \log n)\)+diameter :: (Ord r, Floating r) => [Point 2 r :+ p] -> r+diameter = maybe 0 (\(p,q) -> euclideanDist (p^.core) (q^.core)) . diametralPair++-- | Computes the Euclidean diameter by first finding the convex hull.+--+-- running time: \(O(n \log n)\)+diametralPair :: (Ord r, Num r)+ => [Point 2 r :+ p] -> Maybe (Point 2 r :+ p, Point 2 r :+ p)+diametralPair lst@(_:_:_:_) = Just . Convex.diametralPair $ convexHull $ NonEmpty.fromList lst+diametralPair lst = Naive.diametralPair lst
src/Algorithms/Geometry/Diameter/Naive.hs view
@@ -1,3 +1,10 @@+--------------------------------------------------------------------------------+-- |+-- Module : Algorithms.Geometry.Diameter.Naive+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+-------------------------------------------------------------------------------- module Algorithms.Geometry.Diameter.Naive where import Control.Lens@@ -7,6 +14,9 @@ -------------------------------------------------------------------------------- +-- | Computes the Euclidean diameter by naively trying all pairs.+--+-- running time: \(O(n^2)\) diameter :: (Ord r, Floating r, Arity d) => [Point d r :+ p] -> r diameter = maybe 0 (\(p,q) -> euclideanDist (p^.core) (q^.core)) . diametralPair
+ src/Algorithms/Geometry/EuclideanMST.hs view
@@ -0,0 +1,47 @@+--------------------------------------------------------------------------------+-- |+-- Module : Algorithms.Geometry.EuclideanMST+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+--+-- \(O(n\log n)\) time algorithm algorithm to compute the Euclidean minimum+-- spanning tree of a set of \(n\) points in \(\mathbb{R}^2\).+--+--------------------------------------------------------------------------------+module Algorithms.Geometry.EuclideanMST ( euclideanMST ) where++import Algorithms.Geometry.DelaunayTriangulation.DivideAndConquer+import Algorithms.Geometry.DelaunayTriangulation.Types+import Algorithms.Graph.MST+import Control.Lens+import Data.Ext+import Data.Geometry+import qualified Data.List.NonEmpty as NonEmpty+import Data.PlaneGraph+import Data.Proxy+import Data.Tree++--------------------------------------------------------------------------------++-- | Computes the Euclidean Minimum Spanning Tree. We compute the Delaunay+-- Triangulation (DT), and then extract the EMST. Hence, the same restrictions+-- apply as for the DT:+--+-- pre: the input is a *SET*, i.e. contains no duplicate points. (If the input+-- does contain duplicate points, the implementation throws them away)+--+-- running time: \(O(n \log n)\)+euclideanMST :: (Ord r, Fractional r)+ => NonEmpty.NonEmpty (Point 2 r :+ p) -> Tree (Point 2 r :+ p)+euclideanMST pts = (\v -> g^.locationOf v :+ g^.dataOf v) <$> t+ where+ -- since we care only about the relative order of the edges we can use the+ -- squared Euclidean distance rather than the Euclidean distance, thus+ -- avoiding the Floating constraint+ g = withEdgeDistances squaredEuclideanDist . toPlaneGraph (Proxy :: Proxy MSTW)+ . delaunayTriangulation $ pts+ t = mst $ g^.graph+++data MSTW
src/Algorithms/Geometry/EuclideanMST/EuclideanMST.hs view
@@ -9,39 +9,9 @@ -- spanning tree of a set of \(n\) points in \(\mathbb{R}^2\). -- ---------------------------------------------------------------------------------module Algorithms.Geometry.EuclideanMST.EuclideanMST where--import Algorithms.Geometry.DelaunayTriangulation.DivideAndConquer-import Algorithms.Geometry.DelaunayTriangulation.Types-import Algorithms.Graph.MST-import Control.Lens-import Data.Ext-import Data.Geometry-import qualified Data.List.NonEmpty as NonEmpty-import Data.PlaneGraph-import Data.Proxy-import Data.Tree-------------------------------------------------------------------------------------- | Computes the Euclidean Minimum Spanning Tree. We compute the Delaunay--- Triangulation (DT), and then extract the EMST. Hence, the same restrictions--- apply as for the DT:------ pre: the input is a *SET*, i.e. contains no duplicate points. (If the input--- does contain duplicate points, the implementation throws them away)------ running time: \(O(n \log n)\)-euclideanMST :: (Ord r, Fractional r)- => NonEmpty.NonEmpty (Point 2 r :+ p) -> Tree (Point 2 r :+ p)-euclideanMST pts = (\v -> g^.locationOf v :+ g^.dataOf v) <$> t- where- -- since we care only about the relative order of the edges we can use the- -- squared Euclidean distance rather than the Euclidean distance, thus- -- avoiding the Floating constraint- g = withEdgeDistances squaredEuclideanDist . toPlaneGraph (Proxy :: Proxy MSTW)- . delaunayTriangulation $ pts- t = mst $ g^.graph-+module Algorithms.Geometry.EuclideanMST.EuclideanMST+ {-# DEPRECATED "This module will be deleted after 2021-06-01. \+ \Use Algorithms.Geometry.EuclideanMST instead." #-}+ ( module Algorithms.Geometry.EuclideanMST ) where -data MSTW+import Algorithms.Geometry.EuclideanMST
src/Algorithms/Geometry/FrechetDistance/Discrete.hs view
@@ -1,3 +1,10 @@+--------------------------------------------------------------------------------+-- |+-- Module : Algorithms.Geometry.FrechetDistance.Discrete+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+-------------------------------------------------------------------------------- module Algorithms.Geometry.FrechetDistance.Discrete( discreteFrechetDistance , discreteFrechetDistanceWith ) where
+ src/Algorithms/Geometry/InPolygon.hs view
@@ -0,0 +1,155 @@+--------------------------------------------------------------------------------+-- |+-- Module : Algorithms.Geometry.InPolygon+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+--+-- Testing if a point lies in a polygon+--+--------------------------------------------------------------------------------+module Algorithms.Geometry.InPolygon+ ( inPolygon+ , insidePolygon+ , onBoundary+ ) where++import Control.Lens++import Data.Ext+import qualified Data.Foldable as F+import Data.Geometry.Boundary+import Data.Geometry.Line+import Data.Geometry.LineSegment+import Data.Geometry.Point+import Data.Geometry.Polygon.Core+import Data.Geometry.Properties++import qualified Data.List.Util as List+import Data.Maybe (mapMaybe)+import Data.Vinyl.CoRec (asA)+--------------------------------------------------------------------------------++{- $setup+>>> import Data.RealNumber.Rational+>>> import Data.Foldable+>>> import Control.Lens.Extras+>>> :{+-- import qualified Data.Vector.Circular as CV+let simplePoly :: SimplePolygon () (RealNumber 10)+ simplePoly = fromPoints . map ext $+ [ Point2 0 0+ , Point2 10 0+ , Point2 10 10+ , Point2 5 15+ , Point2 1 11+ ]+ simpleTriangle :: SimplePolygon () (RealNumber 10)+ simpleTriangle = fromPoints . map ext $+ [ Point2 0 0, Point2 2 0, Point2 1 1]+ multiPoly :: MultiPolygon () (RealNumber 10)+ multiPoly = MultiPolygon+ (fromPoints . map ext $ [Point2 (-1) (-1), Point2 3 (-1), Point2 2 2])+ [simpleTriangle]+:} -}+++-- | \( O(n) \) Test if q lies on the boundary of the polygon.+--+-- >>> Point2 1 1 `onBoundary` simplePoly+-- False+-- >>> Point2 0 0 `onBoundary` simplePoly+-- True+-- >>> Point2 10 0 `onBoundary` simplePoly+-- True+-- >>> Point2 5 13 `onBoundary` simplePoly+-- False+-- >>> Point2 5 10 `onBoundary` simplePoly+-- False+-- >>> Point2 10 5 `onBoundary` simplePoly+-- True+-- >>> Point2 20 5 `onBoundary` simplePoly+-- False+--+-- TODO: testcases multipolygon+onBoundary :: (Num r, Ord r) => Point 2 r -> Polygon t p r -> Bool+q `onBoundary` pg = any (q `intersects`) es+ where+ out = pg^.outerBoundary+ es = concatMap (F.toList . outerBoundaryEdges) $ out : holeList pg++-- | Check if a point lies inside a polygon, on the boundary, or outside of the polygon.+-- Running time: O(n).+--+-- >>> Point2 1 1 `inPolygon` simplePoly+-- Inside+-- >>> Point2 0 0 `inPolygon` simplePoly+-- OnBoundary+-- >>> Point2 10 0 `inPolygon` simplePoly+-- OnBoundary+-- >>> Point2 5 13 `inPolygon` simplePoly+-- Inside+-- >>> Point2 5 10 `inPolygon` simplePoly+-- Inside+-- >>> Point2 10 5 `inPolygon` simplePoly+-- OnBoundary+-- >>> Point2 20 5 `inPolygon` simplePoly+-- Outside+--+-- TODO: Add some testcases with multiPolygons+-- TODO: Add some more onBoundary testcases+inPolygon :: forall t p r. (Fractional r, Ord r)+ => Point 2 r -> Polygon t p r -> PointLocationResult+q `inPolygon` pg+ | q `onBoundary` pg = OnBoundary+ | inHole = Outside+ | otherwise = q `inPolygon'` (pg^.outerBoundary)+ where+ inHole = any (q `insidePolygon`) $ holeList pg++-- | Returns true if the point lies in the polygon+-- pre: point lies inside or outside the polygon, not on its boundary.+inPolygon' :: forall p r. (Fractional r, Ord r)+ => Point 2 r -> SimplePolygon p r+ -> PointLocationResult+q `inPolygon'` pg = if odd . length . mapMaybe intersectionPoint $ ups <> downs+ then Inside else Outside+ where+ -- we don't care about horizontal edges+ (ups',_horizontals,downs') = partitionEdges . listEdges $ pg+ partitionEdges = List.partition3 $ \s -> (s^.end.core.yCoord) `compare` (s^.start.core.yCoord)++ -- upward edges include start, exclude end+ ups = map (\(LineSegment' a b) -> LineSegment (Closed a) (Open b)) ups'+ -- downward edges exclude start, include end+ downs = map (\(LineSegment' a b) -> LineSegment (Open a) (Closed b)) downs'++ -- Given an edge, compute the intersection point (if a point) with+ -- the line through the query point, and test if it lies strictly+ -- right of q.+ --+ -- See http://geomalgorithms.com/a03-_inclusion.html for more information.+ intersectionPoint = F.find (\p -> p^.xCoord > q^.xCoord) . asA @(Point 2 r) . (`intersect` l)+ l = horizontalLine $ q^.yCoord+++-- | Test if a point lies strictly inside the polgyon.+insidePolygon :: (Fractional r, Ord r) => Point 2 r -> Polygon t p r -> Bool+q `insidePolygon` pg = q `inPolygon` pg == Inside+++-- testQ = map (`inPolygon` testPoly) [ Point2 1 1 -- Inside+-- , Point2 0 0 -- OnBoundary+-- , Point2 5 14 -- Inside+-- , Point2 5 10 -- Inside+-- , Point2 10 5 -- OnBoundary+-- , Point2 20 5 -- Outside+-- ]++-- testPoly :: SimplePolygon () Rational+-- testPoly = fromPoints . map ext $ [ Point2 0 0+-- , Point2 10 0+-- , Point2 10 10+-- , Point2 5 15+-- , Point2 1 11+-- ]
src/Algorithms/Geometry/LineSegmentIntersection.hs view
@@ -1,6 +1,23 @@-module Algorithms.Geometry.LineSegmentIntersection where+--------------------------------------------------------------------------------+-- |+-- Module : Algorithms.Geometry.LineSegmentIntersection+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+--------------------------------------------------------------------------------+module Algorithms.Geometry.LineSegmentIntersection+ ( hasInteriorIntersections+ , hasSelfIntersections+ , Intersections+ , Associated(..)+ , IntersectionPoint(..)+ , isEndPointIntersection+ , associated+ , Compare+ ) where import qualified Algorithms.Geometry.LineSegmentIntersection.BentleyOttmann as BO+import Algorithms.Geometry.LineSegmentIntersection.Types import Data.Geometry.LineSegment import Data.Geometry.Polygon
src/Algorithms/Geometry/LineSegmentIntersection/BentleyOttmann.hs view
@@ -10,7 +10,13 @@ -- and Ottmann. -- ---------------------------------------------------------------------------------module Algorithms.Geometry.LineSegmentIntersection.BentleyOttmann where+module Algorithms.Geometry.LineSegmentIntersection.BentleyOttmann+ ( intersections+ , interiorIntersections+ -- FIXME: Move ordAt and xCoordAt to Data.Geometry.LineSegment?+ , ordAt+ , xCoordAt+ ) where import Algorithms.Geometry.LineSegmentIntersection.Types import Control.Lens hiding (contains)@@ -194,7 +200,7 @@ where (before, mid1, after') = SS.splitOn (xCoordAt $ p^.yCoord) (p^.xCoord) ss -- Make sure to also select the horizontal segments containing p- (mid2, after) = SS.spanAntitone (\s -> p `onSegment` s) after'+ (mid2, after) = SS.spanAntitone (intersects p) after' -- | Given a point and the linesegements that contain it. Create a piece of@@ -230,9 +236,9 @@ => Point 2 r -> LineSegment 2 p r -> LineSegment 2 p r -> Maybe (Event p r) findNewEvent p l r = match (l `intersect` r) $- (H $ \NoIntersection -> Nothing)- :& (H $ \q -> if ordPoints q p == GT then Just (Event q Intersection)- else Nothing)- :& (H $ \_ -> Nothing) -- full segment intersectsions are handled- -- at insertion time+ H (const Nothing) -- NoIntersection+ :& H (\q -> if ordPoints q p == GT then Just (Event q Intersection)+ else Nothing)+ :& H (const Nothing) -- full segment intersectsions are handled+ -- at insertion time :& RNil
+ src/Algorithms/Geometry/LineSegmentIntersection/BooleanSweep.hs view
@@ -0,0 +1,171 @@+{-# LANGUAGE ScopedTypeVariables #-}+--------------------------------------------------------------------------------+-- |+-- Module : Algorithms.Geometry.LineSegmentIntersection.BooleanSweep+-- Copyright : (C) Frank Staals, David Himmelstrup+-- License : see the LICENSE file+-- Maintainer : David Himmelstrup+--+-- \( O(n \log n) \) algorithm for determining if any two line segments overlap.+--+-- Shamos and Hoey.+--+--------------------------------------------------------------------------------+module Algorithms.Geometry.LineSegmentIntersection.BooleanSweep+ ( hasIntersections+ , segmentsOverlap+ ) where++import Control.Lens hiding (contains)+import Data.Ext+import Data.Geometry.Interval+import Data.Geometry.Line+import Data.Geometry.LineSegment+import Data.Geometry.Point+import Data.Geometry.Triangle+import qualified Data.List as L+import Data.Maybe+import Data.Ord (Down (..), comparing)+import qualified Data.Set as SS+import qualified Data.Set.Util as SS++-- import Data.RealNumber.Rational+-- import Debug.Trace++--------------------------------------------------------------------------------++-- | Tests if there are any intersections.+--+-- \(O(n\log n)\)+hasIntersections :: (Ord r, Num r)+ => [LineSegment 2 p r] -> Bool+hasIntersections ss = sweep pts SS.empty+ where+ pts = L.sortBy ordEvents . concatMap asEventPts $ ss++-- | Computes the event points for a given line segment+asEventPts :: Ord r => LineSegment 2 p r -> [Event p r]+asEventPts s =+ case ordPoints (s^.start.core) (s^.end.core) of+ LT -> [Insert s, Delete s]+ _ -> let LineSegment a b = s+ s' = LineSegment b a+ in [Insert s', Delete s']++--------------------------------------------------------------------------------+-- * Data type for Events++-- | The actual event consists of a point and its type+data Event p r = Insert (LineSegment 2 p r) | Delete (LineSegment 2 p r)++eventPoint :: Event p r -> Point 2 r+eventPoint (Insert l) = l^.start.core+eventPoint (Delete l) = l^.end.core++-- Sort order:+-- 1. Y-coord. Larger Ys before smaller.+-- 2. X-coord. Smaller Xs before larger.+-- 3. Type: Inserts before deletions+ordEvents :: (Num r, Ord r) => Event p r -> Event p r -> Ordering+ordEvents e1 e2 = ordPoints (eventPoint e1) (eventPoint e2) <> cmpType e1 e2+ where+ cmpType Insert{} Delete{} = LT+ cmpType Delete{} Insert{} = GT+ cmpType _ _ = EQ++-- | An ordering that is decreasing on y, increasing on x+ordPoints :: Ord r => Point 2 r -> Point 2 r -> Ordering+ordPoints a b = let f p = (Down $ p^.yCoord, p^.xCoord) in comparing f a b++--------------------------------------------------------------------------------+-- * The Main Sweep++type StatusStructure p r = SS.Set (LineSegment 2 p r)++-- | Run the sweep handling all events+sweep :: forall r p. (Ord r, Num r)+ => [Event p r] -> StatusStructure p r+ -> Bool+sweep [] _ = False+sweep (Delete l:eq) ss =+ overlaps || sweep eq ss'+ where+ p = l^.end.core+ (before,_contains,after) = splitBeforeAfter p ss+ overlaps = fromMaybe False (segmentsOverlap <$> sl <*> sr)+ sl = SS.lookupMax before+ sr = SS.lookupMin after+ ss' = before `SS.join` after+sweep (Insert l@(LineSegment startPoint _endPoint):eq) ss =+ endOverlap || overlaps || sweep eq ss'+ where+ p = l^.start.core+ (before,contains,after) = splitBeforeAfter p ss+ endOverlap =+ (not (null contains) && isClosed startPoint)+ overlaps = or [ fromMaybe False (segmentsOverlap l <$> sl)+ , fromMaybe False (segmentsOverlap l <$> sr) ]+ sl = SS.lookupMax before+ sr = SS.lookupMin after+ ss' = before `SS.join` SS.singleton l `SS.join` after++-- | split the status structure around p.+-- the result is (before,contains,after)+splitBeforeAfter :: (Num r, Ord r)+ => Point 2 r -> StatusStructure p r+ -> (StatusStructure p r, [LineSegment 2 p r],StatusStructure p r)+splitBeforeAfter p ss = (before, filter (not . endsAt p) $ SS.toList contains, after)+ where+ (before,contains,after) = SS.splitBy cmpLine ss+ cmpLine line+ | isHorizontal line =+ let [_top,bot] = L.sortBy ordPoints [line^.start.core,line^.end.core] in+ (bot^.xCoord) `compare` (p^.xCoord)+ cmpLine line =+ let [top,bot] = L.sortBy ordPoints [line^.start.core,line^.end.core] in+ case ccw bot top p of+ CW -> LT+ CoLinear -> EQ+ CCW -> GT+++isHorizontal :: Eq r => LineSegment 2 p r -> Bool+isHorizontal s = s^.start.core.yCoord == s^.end.core.yCoord++-- | Test if a segment ends at p+endsAt :: Ord r => Point 2 r -> LineSegment 2 p r -> Bool+endsAt p (LineSegment _ b) = fmap (view core) b == Open p++--------------------------------------------------------------------------------+-- * Finding New events++segmentsOverlap :: (Num r, Ord r) => LineSegment 2 p r -> LineSegment 2 p r -> Bool+segmentsOverlap a@(LineSegment aStart aEnd) b =+ (isClosed aStart && (aStart^.unEndPoint.core) `onSegment2` b) ||+ (isClosed aEnd && (aEnd^.unEndPoint.core) `onSegment2` b) ||+ (opposite (ccw' (a^.start) (b^.start) (a^.end)) (ccw' (a^.start) (b^.end) (a^.end)) &&+ not (onTriangleRelaxed (a^.end.core) t1) &&+ not (onTriangleRelaxed (a^.start.core) t2))+ where+ opposite CW CCW = True+ opposite CCW CW = True+ opposite _ _ = False+ t1 = Triangle (a^.start) (b^.start) (b^.end)+ t2 = Triangle (a^.end) (b^.start) (b^.end)++-- Copied from Data.Geometry.LineSegment.Internal. Delete when PR#62 is merged.+onSegment2 :: (Ord r, Num r)+ => Point 2 r -> LineSegment 2 p r -> Bool+p `onSegment2` s@(LineSegment u v) = case ccw' (ext p) (u^.unEndPoint) (v^.unEndPoint) of+ CoLinear -> let su = p `onSide` lu+ sv = p `onSide` lv+ in su /= sv+ && ((su == OnLine) `implies` isClosed u)+ && ((sv == OnLine) `implies` isClosed v)+ _ -> False+ where+ (Line _ w) = perpendicularTo $ supportingLine s+ lu = Line (u^.unEndPoint.core) w+ lv = Line (v^.unEndPoint.core) w++ a `implies` b = b || not a
src/Algorithms/Geometry/LineSegmentIntersection/Naive.hs view
@@ -1,5 +1,9 @@ {-# LANGUAGE ScopedTypeVariables #-}-module Algorithms.Geometry.LineSegmentIntersection.Naive where+-- | Line segment intersections in \(O(n^2)\) by checking+-- all pairs.+module Algorithms.Geometry.LineSegmentIntersection.Naive+ ( intersections+ ) where import Algorithms.Geometry.LineSegmentIntersection.Types import Control.Lens@@ -25,9 +29,9 @@ => (LineSegment 2 p r, LineSegment 2 p r) -> Intersections p r -> Intersections p r collect (s,s') m = match (s `intersect` s') $- (H $ \NoIntersection -> m)- :& (H $ \p -> handlePoint s s' p $ m)- :& (H $ \s'' -> foldr (handlePoint s s') m [s''^.start.core, s''^.end.core])+ H (\NoIntersection -> m)+ :& H (\p -> handlePoint s s' p m)+ :& H (\s'' -> foldr (handlePoint s s') m [s''^.start.core, s''^.end.core]) :& RNil -- | Add s and s' to the map with key p
src/Algorithms/Geometry/LineSegmentIntersection/Types.hs view
@@ -1,4 +1,11 @@ {-# LANGUAGE TemplateHaskell #-}+--------------------------------------------------------------------------------+-- |+-- Module : Algorithms.Geometry.LineSegmentIntersection.Types+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+-------------------------------------------------------------------------------- module Algorithms.Geometry.LineSegmentIntersection.Types where import Control.DeepSeq
src/Algorithms/Geometry/LinearProgramming/LP2DRIC.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE PackageImports #-} -------------------------------------------------------------------------------- -- | -- Module : Algorithms.Geometry.LinearProgramming.LP2DRIC@@ -37,13 +38,13 @@ import Data.Util import Data.Vinyl import Data.Vinyl.CoRec-import System.Random.Shuffle+import "hgeometry-combinatorial" System.Random.Shuffle -------------------------------------------------------------------------------- -- | Solve a linear program-solveLinearProgram :: MonadRandom m => LinearProgram 2 r -> m (LPSolution 2 r)-solveLinearProgram = undefined+_solveLinearProgram :: MonadRandom m => LinearProgram 2 r -> m (LPSolution 2 r)+_solveLinearProgram = undefined -- | Solves a bounded linear program in 2d. Returns Nothing if there is no@@ -115,20 +116,20 @@ => Line 2 r -> [HalfSpace 2 r] -> Maybe [HalfLine 2 r]-collectOn l = sequence . mapMaybe collect . map (l `intersect`)+collectOn l = sequence . mapMaybe (collect . (l `intersect`)) where collect :: Intersection (Line 2 r) (HalfSpace 2 r) -> Maybe (Maybe (HalfLine 2 r)) collect r = match r $- (H $ \NoIntersection -> Just Nothing)- :& (H $ \hl -> Just $ Just hl)- :& (H $ \_ -> Nothing)+ H (const $ Just Nothing) -- NoIntersection+ :& H (Just . Just) -- HalfLine+ :& H (const Nothing) -- Line :& RNil -- | Given a vector v and two points a and b, determine which is smaller in direction v. cmpHalfPlane :: (Ord r, Num r, Arity d) => Vector d r -> Point d r -> Point d r -> Ordering-cmpHalfPlane v a b = case a `inHalfSpace` (HalfSpace $ HyperPlane b $ v) of+cmpHalfPlane v a b = case a `inHalfSpace` HalfSpace (HyperPlane b v) of Inside -> GT OnBoundary -> EQ Outside -> LT@@ -147,7 +148,7 @@ commonIntersection :: (Ord r, Num r, Arity d) => Line d r -> NonEmpty.NonEmpty (HalfLine d r :+ a)- -> Either (Two ((HalfLine d r :+ a)))+ -> Either (Two (HalfLine d r :+ a)) (OneOrTwo (Point d r :+ a)) commonIntersection (Line _ v) hls = case (nh,ph) of (Nothing,Nothing) -> error "absurd; this case cannot occur"@@ -159,7 +160,7 @@ GT -> Right . Right $ Two (extract p) (extract n) where extract = over core (^.startPoint)- (pos,neg) = NonEmpty.partition (\hl -> hl^.core.halfLineDirection == v) $ hls+ (pos,neg) = NonEmpty.partition (\hl -> hl^.core.halfLineDirection == v) hls ph = maximumBy' (cmpHalfPlane' v) pos nh = maximumBy' (flip $ cmpHalfPlane' v) neg @@ -219,7 +220,9 @@ where Just p = asA @(Point 2 r) $ (m1^.boundingPlane._asLine) `intersect` (m2^.boundingPlane._asLine)-+initialize _ = error+ "Algorithms.Geometry.LinearProgramming.LP2DRIC.initialize requires \+ \at least two constraints." --------------------------------------------------------------------------------@@ -234,13 +237,13 @@ -- - \(c \cdot d > 0\), and -- - \(d \cdot n(h) \geq 0\), wherefor every half space \(h\). ---findD :: (Ord r, Fractional r)+_findD :: (Ord r, Fractional r) => LinearProgram 2 r -> Maybe (Vector 2 r)-findD (LinearProgram c hs) = do hls <- collectOn nl hs'- d <- toVec <$> oneDLinearProgramming v nl hls- -- the direction v here does not really matter- if c `dot` d > 0 then pure d- else Nothing+_findD (LinearProgram c hs) = do hls <- collectOn nl hs'+ d <- toVec <$> oneDLinearProgramming v nl hls+ -- the direction v here does not really matter+ if c `dot` d > 0 then pure d+ else Nothing where -- we interpret the points on nl as directions w.r.t the origin nl@(Line _ v) = perpendicularTo (Line (origin .+^ c) c)@@ -248,14 +251,14 @@ -- every halfspace creates an allowed set of directions, modelled by a -- half-line on nl- toHL h = let n = h^.boundingPlane.normalVec+ toHL h = let _n = h^.boundingPlane.normalVec in undefined -- | Either finds an unbounded Haflline, or evidence the two halfspaces that provide -- evidence that no solution exists-findUnBoundedHalfLine :: LinearProgram 2 r -> Either (Two (HalfSpace 2 r)) (HalfLine 2 r)-findUnBoundedHalfLine = undefined -- use findD then find the starting point+_findUnBoundedHalfLine :: LinearProgram 2 r -> Either (Two (HalfSpace 2 r)) (HalfLine 2 r)+_findUnBoundedHalfLine = undefined -- use findD then find the starting point
src/Algorithms/Geometry/LowerEnvelope/DualCH.hs view
@@ -1,4 +1,11 @@ {-# LANGUAGE ScopedTypeVariables #-}+--------------------------------------------------------------------------------+-- |+-- Module : Algorithms.Geometry.LowerEnvelope.DualCH+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+-------------------------------------------------------------------------------- module Algorithms.Geometry.LowerEnvelope.DualCH where import Data.Maybe(fromJust)
src/Algorithms/Geometry/PolyLineSimplification/DouglasPeucker.hs view
@@ -1,3 +1,10 @@+--------------------------------------------------------------------------------+-- |+-- Module : Algorithms.Geometry.PolyLineSimplification.DouglasPeucker+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+-------------------------------------------------------------------------------- module Algorithms.Geometry.PolyLineSimplification.DouglasPeucker where import Control.Lens hiding (only)@@ -18,7 +25,7 @@ -- vertices from pl) s.t. all other vertices are within dist eps to the -- original polyline. ----- Running time: O(n^2) worst case, O(n log n) expected.+-- Running time: \( O(n^2) \) worst case, \( O(n log n) \) expected. douglasPeucker :: (Ord r, Fractional r, Arity d) => r -> PolyLine d p r -> PolyLine d p r douglasPeucker eps pl
+ src/Algorithms/Geometry/PolygonTriangulation/EarClip.hs view
@@ -0,0 +1,525 @@+{-# LANGUAGE RecordWildCards #-}+{-# OPTIONS_GHC -fno-warn-name-shadowing #-}+--------------------------------------------------------------------------------+-- |+-- Module : Algorithms.Geometry.PolygonTriangulation.EarClip+-- Copyright : (C) David Himmelstrup+-- License : see the LICENSE file+-- Maintainer : David Himmelstrup+--+-- Ear clipping triangulation algorithms. The baseline algorithm runs in \( O(n^2) \)+-- but has a low constant factor overhead. The z-order hashed variant runs in+-- \( O(n \log n) \).+--+-- References:+--+-- 1. https://en.wikipedia.org/wiki/Polygon_triangulation#Ear_clipping_method+-- 2. https://en.wikipedia.org/wiki/Z-order_curve+--+--------------------------------------------------------------------------------+module Algorithms.Geometry.PolygonTriangulation.EarClip+ ( earClip+ , earClipRandom+ , earClipHashed+ , earClipRandomHashed+ , zHash+ , zUnHash+ ) where++import Control.Lens ((^.))+import Control.Monad.Identity+import Control.Monad.ST (ST, runST)+import Control.Monad.ST.Unsafe (unsafeInterleaveST)+import Data.Bits+import Data.Ext+import Data.Geometry.Boundary (PointLocationResult (Outside))+import Data.Geometry.Point (Point (Point2), ccw', pattern CCW)+import Data.Geometry.Polygon+import Data.Geometry.Box+import Data.Geometry.Triangle (Triangle (Triangle), inTriangleRelaxed)+import Data.STRef+import Data.Vector (Vector)+import qualified Data.Vector as V+import qualified Data.Vector.Algorithms.Intro as Algo+import qualified Data.Vector.Circular as CV+import qualified Data.Vector.NonEmpty as NE+import qualified Data.Vector.Unboxed as U+import qualified Data.Vector.Unboxed.Mutable as MU+import GHC.Exts (build)+import Linear.V2+import System.Random (mkStdGen, randomR)++{-+ We can check if a vertex is an ear in O(n) time. Checking all vertices will definitely+ yield at least one ear in O(n^2) time. So, finding N ears will take O(n^3) if done naively.++ Keeping a separate list of possible ears will improve matters. For each possible ear,+ we check if the vertex really is an ear or not. If it isn't, it is deleted from the+ list of possible ears. If it /is/ an ear, the vertex is cut and the neighbours are+ added back to the list of possible ears (if they aren't in the list already).++ So, start with a list of N possible ears, and we might add two vertices to the list+ ever time we find an ear. Since there are only N ears to be found, only 2*N vertices+ can be added to the list of possible ears in the worst case scenario. The list is+ therefore bounded to 3*N and finding all ears is therefore O(n^2).++ Note: When checking if a vertex is an ear, it is sufficient to check against+ reflex vertices. Some implementations keep a separate list of reflex+ vertices for this reason but it does increase the constant factor+ overhead. I think it's better to keep the constant factor low for small values+ of N and use the hashed algorithm for larger values of N.+-}+-- | \( O(n^2) \)+--+-- Returns triangular faces using absolute polygon point indices.+earClip :: (Num r, Ord r) => SimplePolygon p r -> [(Int,Int,Int)]+earClip poly = build gen+ where+ vs = NE.toVector $ CV.vector $ poly^.outerBoundaryVector+ gen :: ((Int,Int,Int) -> b -> b) -> b -> b+ gen cons nil = runST $ do+ vertices <- mutListFromVector vs+ possibleEars <- mutListClone vertices+ let worker len focus = do+ prev <- mutListPrev vertices focus+ next <- mutListNext vertices focus+ if len == 3+ then+ return $ cons (prev, focus, next) nil+ else do+ prevEar <- mutListPrev possibleEars focus+ nextEar <- mutListNext possibleEars focus+ isEar <- earCheck vertices prev focus next+ if isEar+ then do+ mutListDelete possibleEars prevEar nextEar+ mutListDelete vertices prev next -- remove ear++ case (prevEar /= prev, nextEar /= next) of+ (True, True) -> do+ mutListInsert possibleEars prevEar nextEar prev+ mutListInsert possibleEars prev nextEar next+ (True, False) -> do+ mutListInsert possibleEars prevEar nextEar prev+ (False, True) -> do+ mutListInsert possibleEars prevEar nextEar next+ (False, False) -> return ()++ cons (prev, focus, next)+ <$> unsafeInterleaveST (worker (len-1) nextEar)+ else do -- not an ear+ mutListDelete possibleEars prevEar nextEar -- remove vertex+ worker len nextEar+ worker (V.length vs) 0++-- | \( O(n^2) \)+--+-- Returns triangular faces using absolute polygon point indices.+earClipRandom :: (Num r, Ord r) => SimplePolygon p r -> [(Int,Int,Int)]+earClipRandom poly = build gen+ where+ vs = NE.toVector $ CV.vector $ poly^.outerBoundaryVector+ gen :: ((Int,Int,Int) -> b -> b) -> b -> b+ gen cons nil = runST $ do+ vertices <- mutListFromVector vs+ possibleEars <- mutListClone vertices+ shuffled <- newShuffled (V.length vs)+ let worker len = do+ focus <- popShuffled shuffled+ prev <- mutListPrev vertices focus+ next <- mutListNext vertices focus+ if len == 3+ then+ return $ cons (prev, focus, next) nil+ else do+ prevEar <- mutListPrev possibleEars focus+ nextEar <- mutListNext possibleEars focus+ isEar <- earCheck vertices prev focus next+ if isEar+ then do+ mutListDelete possibleEars prevEar nextEar+ mutListDelete vertices prev next -- remove ear++ case (prevEar /= prev, nextEar /= next) of+ (True, True) -> do+ pushShuffled shuffled prev+ pushShuffled shuffled next+ mutListInsert possibleEars prevEar nextEar prev+ mutListInsert possibleEars prev nextEar next+ (True, False) -> do+ pushShuffled shuffled prev+ mutListInsert possibleEars prevEar nextEar prev+ (False, True) -> do+ pushShuffled shuffled next+ mutListInsert possibleEars prevEar nextEar next+ (False, False) -> return ()++ cons (prev, focus, next)+ <$> unsafeInterleaveST (worker (len-1))+ else do -- not an ear+ mutListDelete possibleEars prevEar nextEar -- remove vertex+ worker len+ worker (V.length vs)++-- | \( O(n \log n) \) expected time.+--+-- Returns triangular faces using absolute polygon point indices.+earClipHashed :: Real r => SimplePolygon p r -> [(Int,Int,Int)]+earClipHashed poly = build gen+ where+ vs = NE.toVector $ CV.vector $ poly^.outerBoundaryVector+ n = V.length vs+ hasher = zHashGen vs+ zHashVec = U.generate n $ \i -> hasher (V.unsafeIndex vs i ^. core)+ gen :: ((Int,Int,Int) -> b -> b) -> b -> b+ gen cons nil = runST $ do+ vertices <- mutListFromVector vs+ zHashes <- mutListSort zHashVec+ possibleEars <- mutListClone vertices+ let worker len focus = do+ prev <- mutListPrev vertices focus+ next <- mutListNext vertices focus+ if len == 3+ then+ return $ cons (prev, focus, next) nil+ else do+ prevEar <- mutListPrev possibleEars focus+ nextEar <- mutListNext possibleEars focus+ isEar <- earCheckHashed hasher vertices zHashes prev focus next+ if isEar+ then do+ mutListDelete possibleEars prevEar nextEar+ mutListDelete vertices prev next -- remove ear+ mutListDeleteFocus zHashes focus++ case (prevEar /= prev, nextEar /= next) of+ (True, True) -> do+ mutListInsert possibleEars prevEar nextEar prev+ mutListInsert possibleEars prev nextEar next+ (True, False) -> do+ mutListInsert possibleEars prevEar nextEar prev+ (False, True) -> do+ mutListInsert possibleEars prevEar nextEar next+ (False, False) -> return ()++ cons (prev, focus, next)+ <$> unsafeInterleaveST (worker (len-1) nextEar)+ else do -- not an ear+ mutListDelete possibleEars prevEar nextEar -- remove vertex+ worker len nextEar+ worker n 0++-- | \( O(n \log n) \) expected time.+--+-- Returns triangular faces using absolute polygon point indices.+earClipRandomHashed :: Real r => SimplePolygon p r -> [(Int,Int,Int)]+earClipRandomHashed poly = build gen+ where+ vs = NE.toVector $ CV.vector $ poly^.outerBoundaryVector+ n = V.length vs+ hasher = zHashGen vs+ zHashVec = U.generate n $ \i -> hasher (V.unsafeIndex vs i ^. core)+ gen :: ((Int,Int,Int) -> b -> b) -> b -> b+ gen cons nil = runST $ do+ vertices <- mutListFromVector vs+ zHashes <- mutListSort zHashVec+ possibleEars <- mutListClone vertices+ shuffled <- newShuffled (V.length vs)+ let worker len = do+ focus <- popShuffled shuffled+ prev <- mutListPrev vertices focus+ next <- mutListNext vertices focus+ if len == 3+ then+ return $ cons (prev, focus, next) nil+ else do+ prevEar <- mutListPrev possibleEars focus+ nextEar <- mutListNext possibleEars focus+ isEar <- earCheckHashed hasher vertices zHashes prev focus next+ if isEar+ then do+ mutListDelete possibleEars prevEar nextEar+ mutListDelete vertices prev next -- remove ear+ mutListDeleteFocus zHashes focus++ case (prevEar /= prev, nextEar /= next) of+ (True, True) -> do+ pushShuffled shuffled prev+ pushShuffled shuffled next+ mutListInsert possibleEars prevEar nextEar prev+ mutListInsert possibleEars prev nextEar next+ (True, False) -> do+ pushShuffled shuffled prev+ mutListInsert possibleEars prevEar nextEar prev+ (False, True) -> do+ pushShuffled shuffled next+ mutListInsert possibleEars prevEar nextEar next+ (False, False) -> return ()++ cons (prev, focus, next)+ <$> unsafeInterleaveST (worker (len-1))+ else do -- not an ear+ mutListDelete possibleEars prevEar nextEar -- remove vertex+ worker len+ worker n++-------------------------------------------------------------------------------+-- Bounding box++-- Returns (minX, widthX, minY, heightY)+zHashGen :: Real r => V.Vector (Point 2 r :+ p) -> (Point 2 r -> Word)+zHashGen v = zHashPoint bounds+ where+ bounds = (minX, realToFrac (maxX-minX), minY, realToFrac (maxY-minY))+ bb = V.foldl1' (<>) $ V.map boundingBox v+ Point2 minX minY = minPoint bb ^. core+ Point2 maxX maxY = minPoint bb ^. core++-------------------------------------------------------------------------------+-- Z-Order+-- https://en.wikipedia.org/wiki/Z-order_curve++zHashPoint :: Real r => (r,Double,r,Double) -> Point 2 r -> Word+zHashPoint (minX, widthX, minY, heightY) (Point2 x y) =+ zHash (V2 x' y')+ where+ x' = round (realToFrac (x-minX) / widthX * zHashMax)+ y' = round (realToFrac (y-minY) / heightY * zHashMax)++zHashMax :: Double+zHashMax = realToFrac zHashMaxW++zHashMaxW :: Word+zHashMaxW = if finiteBitSize zHashMaxW == 32 then 0xFFFF else 0xFFFFFFFF++-- | O(1) Z-Order hash the first half-world of each coordinate.+zHash :: V2 Word -> Word+zHash (V2 a b) = zHashSingle a .|. (unsafeShiftL (zHashSingle b) 1)++-- | O(1) Reverse z-order hash.+zUnHash :: Word -> V2 Word+zUnHash z =+ V2 (zUnHashSingle z) (zUnHashSingle (unsafeShiftR z 1))++zHashSingle :: Word -> Word+zHashSingle w+ | finiteBitSize w == 32 = zHashSingle32 w+ | otherwise = zHashSingle64 w++zUnHashSingle :: Word -> Word+zUnHashSingle w+ | finiteBitSize w == 32 = zUnHashSingle32 w+ | otherwise = zUnHashSingle64 w++zHashSingle32 :: Word -> Word+zHashSingle32 w = runIdentity $ do+ w <- pure $ w .&. 0x0000FFFF+ w <- pure $ (w .|. unsafeShiftL w 8) .&. 0x00FF00FF+ w <- pure $ (w .|. unsafeShiftL w 4) .&. 0x0F0F0F0F+ w <- pure $ (w .|. unsafeShiftL w 2) .&. 0x33333333+ w <- pure $ (w .|. unsafeShiftL w 1) .&. 0x55555555+ pure w++zUnHashSingle32 :: Word -> Word+zUnHashSingle32 w = runIdentity $ do+ w <- pure $ w .&. 0x55555555+ w <- pure $ (w .|. unsafeShiftR w 1) .&. 0x33333333+ w <- pure $ (w .|. unsafeShiftR w 2) .&. 0x0F0F0F0F+ w <- pure $ (w .|. unsafeShiftR w 4) .&. 0x00FF00FF+ w <- pure $ (w .|. unsafeShiftR w 8) .&. 0x0000FFFF+ pure w++zHashSingle64 :: Word -> Word+zHashSingle64 w = runIdentity $ do+ w <- pure $ w .&. 0x00000000FFFFFFFF+ w <- pure $ (w .|. unsafeShiftL w 16) .&. 0x0000FFFF0000FFFF+ w <- pure $ (w .|. unsafeShiftL w 8) .&. 0x00FF00FF00FF00FF+ w <- pure $ (w .|. unsafeShiftL w 4) .&. 0x0F0F0F0F0F0F0F0F+ w <- pure $ (w .|. unsafeShiftL w 2) .&. 0x3333333333333333+ w <- pure $ (w .|. unsafeShiftL w 1) .&. 0x5555555555555555+ pure w++zUnHashSingle64 :: Word -> Word+zUnHashSingle64 w = runIdentity $ do+ w <- pure $ w .&. 0x5555555555555555+ w <- pure $ (w .|. unsafeShiftR w 1) .&. 0x3333333333333333+ w <- pure $ (w .|. unsafeShiftR w 2) .&. 0x0F0F0F0F0F0F0F0F+ w <- pure $ (w .|. unsafeShiftR w 4) .&. 0x00FF00FF00FF00FF+ w <- pure $ (w .|. unsafeShiftR w 8) .&. 0x0000FFFF0000FFFF+ w <- pure $ (w .|. unsafeShiftR w 16) .&. 0x00000000FFFFFFFF+ pure w++-------------------------------------------------------------------------------+-- Shuffled++data Shuffled s = Shuffled+ { shuffleCount :: STRef s Int+ , shuffleVector :: MU.MVector s Int }++newShuffled :: Int -> ST s (Shuffled s)+newShuffled len = Shuffled <$> newSTRef len <*> U.unsafeThaw (U.enumFromN 0 len)++popShuffled :: Shuffled s -> ST s Int+popShuffled Shuffled{..} = do+ count <- readSTRef shuffleCount+ writeSTRef shuffleCount (count-1)+ let idx = fst $ randomR (0, count-1) (mkStdGen count)+ val <- MU.unsafeRead shuffleVector idx+ MU.unsafeWrite shuffleVector idx =<< MU.unsafeRead shuffleVector (count-1)+ pure val++pushShuffled :: Shuffled s -> Int -> ST s ()+pushShuffled (Shuffled ref vector) val = do+ count <- readSTRef ref+ writeSTRef ref (count+1)+ MU.unsafeWrite vector count val++-------------------------------------------------------------------------------+-- MutList++data MutList s a = MutList+ { mutListIndex :: (Int -> a)+ , mutListNextVec :: MU.MVector s Int+ , mutListPrevVec :: MU.MVector s Int+ }++-- O(n)+mutListFromVector :: Vector a -> ST s (MutList s a)+mutListFromVector vec = MutList (V.unsafeIndex vec)+ <$> do+ arr <- U.unsafeThaw (U.enumFromN 1 (V.length vec))+ MU.unsafeWrite arr (V.length vec-1) 0+ pure arr+ <*> do+ arr <- U.unsafeThaw (U.enumFromN (-1) (V.length vec))+ MU.unsafeWrite arr 0 (V.length vec-1)+ pure arr++mutListClone :: MutList s a -> ST s (MutList s a)+mutListClone (MutList vec nextVec prevVec) = MutList vec+ <$> MU.clone nextVec+ <*> MU.clone prevVec++mutListNext :: MutList s a -> Int -> ST s Int+mutListNext m idx = MU.unsafeRead (mutListNextVec m) idx++mutListPrev :: MutList s a -> Int -> ST s Int+mutListPrev m idx = MU.unsafeRead (mutListPrevVec m) idx++mutListDelete :: MutList s a -> Int -> Int -> ST s ()+mutListDelete m prev next = do+ MU.unsafeWrite (mutListNextVec m) prev next+ MU.unsafeWrite (mutListPrevVec m) next prev++mutListDeleteFocus :: MutList s a -> Int -> ST s ()+mutListDeleteFocus m focus = do+ prev <- mutListPrev m focus+ next <- mutListNext m focus+ unless (prev == -1) $+ MU.unsafeWrite (mutListNextVec m) prev next+ unless (next == -1) $+ MU.unsafeWrite (mutListPrevVec m) next prev++mutListInsert :: MutList s a -> Int -> Int -> Int -> ST s ()+mutListInsert m before after elt = do+ MU.unsafeWrite (mutListNextVec m) before elt -- before.next = elt+ MU.unsafeWrite (mutListNextVec m) elt after -- elt.next = after+ MU.unsafeWrite (mutListPrevVec m) after elt -- after.prev = elt+ MU.unsafeWrite (mutListPrevVec m) elt before -- elt.prev = before++mutListSort :: (Ord a, MU.Unbox a) => U.Vector a -> ST s (MutList s a)+mutListSort vec = do+ sorted <- do+ arr <- U.unsafeThaw $ (U.enumFromN 0 n :: U.Vector Int)+ Algo.sortBy (\a b -> compare (U.unsafeIndex vec a) (U.unsafeIndex vec b)) arr+ U.unsafeFreeze arr++ next <- MU.new n+ prev <- MU.new n+ MU.write next+ (U.unsafeIndex sorted (n-1))+ (-1)+ forM_ [0..n-2] $ \i -> do+ MU.write next+ (U.unsafeIndex sorted i)+ (U.unsafeIndex sorted (i+1))+ MU.write prev+ (U.unsafeIndex sorted 0)+ (-1)+ forM_ [1..n-1] $ \i -> do+ MU.write prev+ (U.unsafeIndex sorted i)+ (U.unsafeIndex sorted (i-1))+ pure $ MutList (U.unsafeIndex vec) next prev+ where+ n = U.length vec++-------------------------------------------------------------------------------+-- Ear checking++-- O(n)+earCheck :: (Num r, Ord r) => MutList s (Point 2 r :+ p) -> Int -> Int -> Int -> ST s Bool+earCheck vertices a b c = do+ let pointA = mutListIndex vertices a+ pointB = mutListIndex vertices b+ pointC = mutListIndex vertices c+ trig = Triangle pointA pointB pointC++ let loop elt | elt == a = pure True+ loop elt = do+ let point = mutListIndex vertices elt ^. core+ case inTriangleRelaxed point trig of+ Outside -> loop =<< mutListNext vertices elt+ _ -> pure False+ if ccw' pointA pointB pointC == CCW+ then loop =<< mutListNext vertices c+ else pure False++-- showBinary :: (Integral a, Show a) => a -> String+-- showBinary i = showIntAtBase 2 intToDigit i ""++earCheckHashed :: Real r => (Point 2 r -> Word) -> MutList s (Point 2 r :+ p) -> MutList s Word -> Int -> Int -> Int -> ST s Bool+earCheckHashed hasher vertices zHashes a b c = do+ let pointA = mutListIndex vertices a+ pointB = mutListIndex vertices b+ pointC = mutListIndex vertices c+ trig = Triangle pointA pointB pointC+ trigBB = boundingBox trig+ lowPt = minPoint trigBB ^. core+ highPt = maxPoint trigBB ^. core+ -- (lowPt, highPt) = triangleBoundingBox trig++ minZ = hasher lowPt+ maxZ = hasher highPt++ let upwards up+ | up == -1 || upZ > maxZ = pure True+ | inTriangleRelaxed pointUp trig /= Outside = pure False+ | otherwise = upwards =<< mutListNext zHashes up+ where+ upZ = mutListIndex zHashes up+ pointUp = mutListIndex vertices up ^. core+ downwards down+ | down == -1 || downZ < minZ = pure True+ | inTriangleRelaxed pointDown trig /= Outside = pure False+ | otherwise = downwards =<< mutListPrev zHashes down+ where+ downZ = mutListIndex zHashes down+ pointDown = mutListIndex vertices down ^. core+ bidirectional up down+ | up == -1 || upZ > maxZ = downwards down+ | down == -1 || downZ < minZ = upwards up+ | up /= a && up /= b && inTriangleRelaxed pointUp trig /= Outside = pure False+ | down /= a && down /= b && inTriangleRelaxed pointDown trig /= Outside = pure False+ | otherwise = do+ up' <- mutListNext zHashes up+ down' <- mutListPrev zHashes down+ bidirectional up' down'+ where+ upZ = mutListIndex zHashes up+ downZ = mutListIndex zHashes down+ pointUp = mutListIndex vertices up ^. core+ pointDown = mutListIndex vertices down ^. core+ if ccw' pointA pointB pointC == CCW+ then bidirectional b b+ else pure False
src/Algorithms/Geometry/PolygonTriangulation/MakeMonotone.hs view
@@ -1,5 +1,12 @@-{-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TemplateHaskell #-}+--------------------------------------------------------------------------------+-- |+-- Module : Algorithms.Geometry.PolygonTriangulation.MakeMonotone+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+-------------------------------------------------------------------------------- module Algorithms.Geometry.PolygonTriangulation.MakeMonotone( makeMonotone , computeDiagonals @@ -8,35 +15,33 @@ , classifyVertices ) where -import Algorithms.Geometry.LineSegmentIntersection.BentleyOttmann ( xCoordAt- , ordAt)-import Algorithms.Geometry.PolygonTriangulation.Types+import Algorithms.Geometry.LineSegmentIntersection.BentleyOttmann (ordAt, xCoordAt)+import Algorithms.Geometry.PolygonTriangulation.Types+ import Control.Lens-import Control.Monad (forM_, when) import Control.Monad.Reader import Control.Monad.State.Strict-import Control.Monad.Writer (WriterT, execWriterT,tell)+import Control.Monad.Writer (WriterT, execWriterT, tell) import Data.Bifunctor-import Data.CircularSeq (rotateL, rotateR, zip3LWith)-import qualified Data.DList as DList+import qualified Data.DList as DList import Data.Ext-import qualified Data.Foldable as F+import qualified Data.Foldable as F import Data.Geometry.LineSegment import Data.Geometry.PlanarSubdivision.Basic import Data.Geometry.Point import Data.Geometry.Polygon-import qualified Data.IntMap as IntMap-import qualified Data.List.NonEmpty as NonEmpty-import Data.Ord (comparing, Down(..))-import qualified Data.Set as SS-import qualified Data.Set.Util as SS+import qualified Data.IntMap as IntMap+import qualified Data.List.NonEmpty as NonEmpty+import Data.Ord (Down (..), comparing)+import qualified Data.Set as SS+import qualified Data.Set.Util as SS import Data.Util-import qualified Data.Vector as V-import qualified Data.Vector.Mutable as MV+import qualified Data.Vector as V+import qualified Data.Vector.Circular as CV+import qualified Data.Vector.Mutable as MV -- import Debug.Trace--- import qualified Data.CircularSeq as CC ---------------------------------------------------------------------------------- data VertexType = Start | Merge | Split | End | Regular deriving (Show,Read,Eq)@@ -49,10 +54,10 @@ classifyVertices :: (Num r, Ord r) => Polygon t p r -> Polygon t (p :+ VertexType) r-classifyVertices p@(SimplePolygon _) = classifyVertices' p+classifyVertices p@SimplePolygon{} = classifyVertices' p classifyVertices (MultiPolygon vs h) = MultiPolygon vs' h' where- (SimplePolygon vs') = classifyVertices' $ SimplePolygon vs+ vs' = classifyVertices' vs h' = map (first (&extra %~ onHole) . classifyVertices') h -- the roles on hole vertices are slightly different@@ -70,9 +75,10 @@ classifyVertices' :: (Num r, Ord r) => SimplePolygon p r -> SimplePolygon (p :+ VertexType) r-classifyVertices' (SimplePolygon vs) =- SimplePolygon $ zip3LWith f (rotateL vs) vs (rotateR vs)+classifyVertices' poly =+ unsafeFromCircularVector $ CV.zipWith3 f (CV.rotateLeft 1 vs) vs (CV.rotateRight 1 vs) where+ vs = poly ^. outerBoundaryVector -- is the angle larger than > 180 degrees largeInteriorAngle p c n = case ccw (p^.core) (c^.core) (n^.core) of CCW -> False@@ -98,7 +104,7 @@ -------------------------------------------------------------------------------- -type Event r = Point 2 r :+ (Two (LineSegment 2 Int r))+type Event r = Point 2 r :+ Two (LineSegment 2 Int r) data StatusStruct r = SS { _statusStruct :: !(SS.Set (LineSegment 2 Int r)) , _helper :: !(IntMap.IntMap Int)@@ -109,6 +115,7 @@ ix' :: Int -> Lens' (V.Vector a) a ix' i = singular (ix i) +{- HLINT ignore computeDiagonals -} -- | Given a polygon, find a set of non-intersecting diagonals that partition -- the polygon into y-monotone pieces. --
src/Algorithms/Geometry/PolygonTriangulation/Triangulate.hs view
@@ -1,3 +1,10 @@+--------------------------------------------------------------------------------+-- |+-- Module : Algorithms.Geometry.PolygonTriangulation.Triangulate+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+-------------------------------------------------------------------------------- module Algorithms.Geometry.PolygonTriangulation.Triangulate where @@ -11,7 +18,6 @@ import Data.Geometry.LineSegment import Data.Geometry.PlanarSubdivision.Basic import Data.Geometry.Polygon-import Data.PlaneGraph (PlaneGraph) --------------------------------------------------------------------------------
src/Algorithms/Geometry/PolygonTriangulation/TriangulateMonotone.hs view
@@ -1,23 +1,45 @@-module Algorithms.Geometry.PolygonTriangulation.TriangulateMonotone where+--------------------------------------------------------------------------------+-- |+-- Module : Algorithms.Geometry.PolygonTriangulation.TriangulateMonotone+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+--------------------------------------------------------------------------------+module Algorithms.Geometry.PolygonTriangulation.TriangulateMonotone+ ( MonotonePolygon+ , triangulate+ , triangulate'+ , computeDiagonals+ -- , LR(..)+ -- , P+ -- , Stack+ -- , chainOf+ -- , toVtx+ -- , seg+ -- , process+ -- , isInside+ -- , mergeBy+ -- , splitPolygon+ ) where +import Algorithms.Geometry.PolygonTriangulation.Types import Control.Lens-import Data.Bifunctor-import qualified Data.CircularSeq as C import Data.Ext-import qualified Data.Foldable as F+import qualified Data.Foldable as F import Data.Geometry.LineSegment+import Data.Geometry.PlanarSubdivision.Basic (PlanarSubdivision, PolygonFaceData) import Data.Geometry.Point import Data.Geometry.Polygon-import qualified Data.List as L-import Data.Ord (comparing, Down(..))+import qualified Data.List as L+import Data.Ord (Down (..), comparing)+import Data.PlaneGraph (PlaneGraph) import Data.Util-import Algorithms.Geometry.PolygonTriangulation.Types-import Data.PlaneGraph (PlaneGraph)-import Data.Geometry.PlanarSubdivision.Basic(PolygonFaceData, PlanarSubdivision)+import qualified Data.Vector.Circular.Util as CV -------------------------------------------------------------------------------- ---+-- | Y-monotone polygon. All straight horizontal lines intersects the polygon+-- no more than twice. type MonotonePolygon p r = SimplePolygon p r data LR = L | R deriving (Show,Eq)@@ -126,19 +148,18 @@ -- running time: \(O(n)\) splitPolygon :: Ord r => MonotonePolygon p r -> ([Point 2 r :+ (LR :+ p)], [Point 2 r :+ (LR :+ p)])-splitPolygon pg = bimap (f L) (f R)- . second reverse+splitPolygon pg = bimap (f L) (f R . reverse) . L.break (\v -> v^.core == vMinY)- . F.toList . C.rightElements $ vs'+ . F.toList . CV.rightElements $ vs' where f x = map (&extra %~ (x :+)) -- rotates the list to the vtx with max ycoord- Just vs' = C.findRotateTo (\v -> v^.core == vMaxY)- $ pg^.outerBoundary+ Just vs' = CV.findRotateTo (\v -> v^.core == vMaxY)+ $ pg^.outerBoundaryVector vMaxY = getY F.maximumBy vMinY = getY F.minimumBy swap' (Point2 x y) = Point2 y x- getY ff = let p = ff (comparing (^.core.to swap')) $ pg^.outerBoundary+ getY ff = let p = ff (comparing (^.core.to swap')) $ pg^.outerBoundaryVector in p^.core @@ -156,15 +177,15 @@ -testPoly5 :: SimplePolygon () Rational-testPoly5 = toCounterClockWiseOrder . fromPoints $ map ext $ [ Point2 176 736- , Point2 240 688- , Point2 240 608- , Point2 128 576- , Point2 64 640- , Point2 80 720- , Point2 128 752- ]+-- testPoly5 :: SimplePolygon () Rational+-- testPoly5 = toCounterClockWiseOrder . fromPoints $ map ext [ Point2 176 736+-- , Point2 240 688+-- , Point2 240 608+-- , Point2 128 576+-- , Point2 64 640+-- , Point2 80 720+-- , Point2 128 752+-- ] -- testPoly5 :: SimplePolygon () Rational
src/Algorithms/Geometry/PolygonTriangulation/Types.hs view
@@ -1,4 +1,11 @@ {-# LANGUAGE ScopedTypeVariables #-}+--------------------------------------------------------------------------------+-- |+-- Module : Algorithms.Geometry.PolygonTriangulation.Types+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+-------------------------------------------------------------------------------- module Algorithms.Geometry.PolygonTriangulation.Types where import Control.Lens@@ -15,6 +22,7 @@ -------------------------------------------------------------------------------- +-- | After triangulation, edges are either from the original polygon or a new diagonal. data PolygonEdgeType = Original | Diagonal deriving (Show,Read,Eq)
src/Algorithms/Geometry/RedBlueSeparator/RIC.hs view
@@ -65,11 +65,11 @@ -> g (Point 2 r :+ blueData) -> m (Maybe (Line 2 r)) separatingLine' reds blues = case verticalSeparatingLine reds blues of- SP Nothing ((r:+_),(b :+ _)) -> separatingLine'' r b reds blues+ SP Nothing (r:+_,b :+ _) -> separatingLine'' r b reds blues -- observe that if r and b were vertically above each other then we would -- have found a separating line. So r and b are not vertically -- aligned. Hence we satisfy the precondition.- SP ml@(Just _) _ -> pure ml -- already found a line+ SP ml@(Just _) _ -> pure ml -- already found a line -- | given a red and blue point that are *NOT* vertically alligned, and all red
+ src/Algorithms/Geometry/SSSP.hs view
@@ -0,0 +1,454 @@+{-# LANGUAGE RecordWildCards #-}+--------------------------------------------------------------------------------+-- |+-- Module : Algorithms.Geometry.SSSP+-- Copyright : (C) David Himmelstrup+-- License : see the LICENSE file+-- Maintainer : David Himmelstrup+--------------------------------------------------------------------------------+module Algorithms.Geometry.SSSP+ ( SSSP+ , triangulate+ , sssp+ , visibilityDual+ , visibilityFinger+ , visibilitySensitive+ ) where++import Algorithms.Geometry.PolygonTriangulation.Triangulate (triangulate')+import Algorithms.Geometry.PolygonTriangulation.Types (PolygonEdgeType)++import Algorithms.Graph.DFS (adjacencyLists, dfs', dfsSensitive)+import Control.Lens ((^.))+import Data.Bitraversable+import Data.Either+import Data.Ext (ext, extra, type (:+) (..))+import qualified Data.FingerTree as F+import Data.Geometry.Line (lineThrough)+import Data.Geometry.LineSegment (LineSegment (ClosedLineSegment, LineSegment))+import Data.Geometry.PlanarSubdivision (PolygonFaceData (..))+import Data.Geometry.Point (Point, ccw, pattern CCW, pattern CW)+import Data.Geometry.Polygon+import Data.Intersection+import Data.List (sortOn, (\\))+import Data.Maybe (fromMaybe)+import Data.PlanarGraph (PlanarGraph)+import qualified Data.PlanarGraph as Graph+import Data.PlaneGraph (FaceId (..), PlaneGraph, VertexData (..),+ VertexId, VertexId', dual, graph, incidentEdges,+ leftFace, vertices)+import qualified Data.PlaneGraph as PlaneGraph+import Data.Proxy+import Data.Tree (Tree (Node))+import qualified Data.Vector as V+import qualified Data.Vector.Circular as CV+import qualified Data.Vector.Circular.Util as CV+import Data.Vector.Unboxed (Vector)+import qualified Data.Vector.Unboxed as VU+import Data.Vinyl+import Data.Vinyl.CoRec++{-+type AbsOffset = Int++data TriangulatedPolygon t p r = TriangulatedPolygon+ { triangulatedMap :: Map AbsOffset (VertexId () Primal)+ , triangulatedGraph :: PlaneGraph () AbsOffset PolygonEdgeType PolygonFaceData r+ , triangulatedPolygon :: Polygon t p r+ }+-}++++-- | Single-source shortest paths tree. Both keys and values are vertex offset ints.+--+-- @parentOf(i) = sssp[i]@+type SSSP = Vector Int++-- FIXME: The code for generating the dual cannot deal with offsets so+-- we're running 'unsafeFromPoints . toPoints' to reset the polygon.+-- Super silly. Please fix.+-- | \( O(n \log n) \)+triangulate :: (Ord r, Fractional r) => SimplePolygon p r -> PlaneGraph s Int PolygonEdgeType PolygonFaceData r+triangulate p =+ let poly' = snd $ bimapAccumL (\a _ -> (a+1,a)) (,) 0 $ unsafeFromPoints $ toPoints p+ in triangulate' Proxy poly'++-- | \( O(n) \) Single-Source shortest path.+sssp :: (Ord r, Fractional r)+ => PlaneGraph s Int PolygonEdgeType PolygonFaceData r+ -> SSSP+sssp trig =+ ssspFinger d+ where+ Just v0 = fst <$> V.find (\(_vid, VertexData _ idx) -> idx == 0) (vertices trig)+ v0i = incidentEdges v0 trig+ Just (FaceId firstFace) = V.find (/= FaceId outer) $ V.map (`leftFace` trig) v0i+ FaceId outer = PlaneGraph.outerFaceId trig+ dualGraph = trig^.graph.dual+ dualTree' = dfs' (V.map (filter (/= outer)) $ adjacencyLists dualGraph) firstFace+ dualVS = fmap (\v -> toCCW $ PlaneGraph.boundaryVertices (FaceId v) trig) dualTree'+ trigTree = toTrigTree trig dualVS+ d = mkDual trigTree++ toCCW v =+ let cv = CV.reverse $ CV.unsafeFromVector v+ in CV.toVector $ fromMaybe cv $ CV.findRotateTo (== v0) cv++{-+1. Find the starting face.+-}+visibilitySensitive :: forall s r. (Ord r, Fractional r, Show r)+ => PlaneGraph s Int PolygonEdgeType PolygonFaceData r+ -> SimplePolygon () r+visibilitySensitive = fromPoints . map ext . rights . visibilityFinger . visibilityDual+++visibilityDual :: forall s r. (Ord r, Fractional r)+ => PlaneGraph s Int PolygonEdgeType PolygonFaceData r+ -> Dual r+visibilityDual trig = d+ where+ Just v0 = fst <$> V.find (\(_vid, VertexData _ idx) -> idx == 0) (vertices trig)+ v0i = incidentEdges v0 trig++ outer :: VertexId s Graph.Dual+ FaceId outer = PlaneGraph.outerFaceId trig++ firstFace :: VertexId s Graph.Dual+ Just (FaceId firstFace) = V.find (/= FaceId outer) $ V.map (`leftFace` trig) v0i++ dualGraph :: PlanarGraph s Graph.Dual PolygonFaceData PolygonEdgeType (VertexData r Int)+ dualGraph = trig^.graph.dual++ dualTree' :: Tree (VertexId s Graph.Dual)+ dualTree' = dfsSensitive neigh firstFace++ neigh :: VertexId s Graph.Dual -> [VertexId s Graph.Dual]+ neigh v = V.toList $ V.filter (/=outer) $ Graph.neighboursOf v dualGraph++ dualVS :: Tree (V.Vector (VertexId' s))+ dualVS = fmap (\v -> toCCW $ PlaneGraph.boundaryVertices (FaceId v) trig) dualTree'++ trigTree :: Tree (Index r, Index r, Index r)+ trigTree = toTrigTree trig dualVS++ d :: Dual r+ d = mkDual trigTree++ toCCW v =+ let cv = CV.reverse $ CV.unsafeFromVector v+ in CV.toVector $ fromMaybe cv $ CV.findRotateTo (== v0) cv++++visibilityFinger :: forall r. (Fractional r, Ord r, Show r) => Dual r -> [Either (Int, Int, Int) (Point 2 r)]+visibilityFinger d =+ case d of+ Dual (a,b,c) ab bc ca ->+ Left (indexExtra a, indexExtra b, indexExtra c) :+ worker (Funnel (F.singleton b) a F.empty) ab +++ worker (Funnel (F.singleton c) a (F.singleton b)) bc +++ worker (Funnel F.empty a (F.singleton c)) ca+ where+ -- Final edge is the leftmost of each funnel.+ -- The most visible are the rightmost of each funnel.+ -- Cut line segment.+ worker f EmptyDual =+ let edgeA = ringAccess $ funnelRightTop f+ edgeB = ringAccess $ funnelLeftTop f+ edge = ClosedLineSegment (ext edgeA) (ext edgeB)+ coneA = ringAccess $ funnelRightBottom f+ coneB = ringAccess $ funnelLeftBottom f+ lineA = lineThrough (ringAccess $ funnelCusp f) coneA+ lineB = lineThrough (ringAccess $ funnelCusp f) coneB+ -- findIntersection :: Line 2 r -> Point 2 r+ findIntersection line =+ match (edge `intersect` line) $+ H (\NoIntersection -> error "no intersection")+ :& H (\pt -> Right pt)+ :& H (\LineSegment{} -> error "line intersection")+ :& RNil+ in [if edgeA == coneA then Right coneA else findIntersection lineA] +++ if edgeB == coneB then [] else [findIntersection lineB]+ worker f (NodeDual x l r) =+ Left (indexExtra $ fromMaybe (funnelCusp f) $ chainTop (funnelRight f)+ ,indexExtra x+ ,indexExtra $ fromMaybe (funnelCusp f) $ chainTop (funnelLeft f)) :+ case splitFunnel x f of+ (_v, fL, fR, dir) -> case dir of+ -- 'x' is to the left of the visibility cone. Everything further to the left cannot+ -- be visible to just go right.+ SplitLeft -> worker fR r -- assert cusp of fR == cusp of f+ -- 'x' is visible from our cusp. Add it to the output and go both to the left and right.+ NoSplit -> worker fR r ++ [Right (ringAccess x)] ++ worker fL l+ -- 'x' is to the right of the visibility cone. Everything further to the right cannot+ -- be visible to just go left.+ SplitRight -> worker fL l -- assert cusp of fL == cusp of f+++--------------------------------------------------------------------------------+-- SSSP (with fingertree) implementation++++++data MinMax r = MinMax (Index r) (Index r) | MinMaxEmpty deriving (Show)+instance Semigroup (MinMax r) where+ MinMaxEmpty <> b = b+ a <> MinMaxEmpty = a+ MinMax a _b <> MinMax _c d+ = MinMax a d+instance Monoid (MinMax r) where+ mempty = MinMaxEmpty++-- Including the 'Point 2 r' here means we don't have to look it up.+-- This mattered since lookups used to be O(log n) rather than O(1).+newtype Index r = Index (Point 2 r :+ Int) -- deriving (Show)++instance Show (Index r) where+ show = show . indexExtra++indexExtra :: Index r -> Int+indexExtra (Index p) = p^.extra++instance Eq (Index r) where+ Index (_ :+ a) == Index (_ :+ b) = a == b++type Chain r = F.FingerTree (MinMax r) (Index r)+data Funnel r = Funnel+ { funnelLeft :: Chain r -- Left-most element is furthest away from cusp.+ , funnelCusp :: Index r+ , funnelRight :: Chain r -- Left-most element is furthest away from cusp.+ } deriving (Show)++-- Left side of the funnel, furthest away from the cusp.+funnelLeftTop :: Funnel r -> Index r+funnelLeftTop f = fromMaybe (funnelCusp f) $ chainTop (funnelLeft f)++-- Left side of the funnel, closest to the cusp.+funnelLeftBottom :: Funnel r -> Index r+funnelLeftBottom f = fromMaybe (funnelCusp f) $ chainBottom (funnelLeft f)++-- Right side of the funnel, furthest away from the cusp.+funnelRightTop :: Funnel r -> Index r+funnelRightTop f = fromMaybe (funnelCusp f) $ chainTop (funnelRight f)++-- Right side of the funnel, closest to the cusp.+funnelRightBottom :: Funnel r -> Index r+funnelRightBottom f = fromMaybe (funnelCusp f) $ chainBottom (funnelRight f)++-- Element closest to the cusp.+chainBottom :: Chain r -> Maybe (Index r)+chainBottom chain = case F.viewl chain of+ F.EmptyL -> Nothing+ elt F.:< _ -> Just elt++-- Element furthest away from the cusp.+chainTop :: Chain r -> Maybe (Index r)+chainTop chain = case F.viewr chain of+ F.EmptyR -> Nothing+ _ F.:> elt -> Just elt++instance F.Measured (MinMax r) (Index r) where+ measure i = MinMax i i++data SplitDirection = SplitLeft | NoSplit | SplitRight+ deriving (Show)++-- Split a funnel w.r.t. a point 'x'. There are three cases:+-- 1. 'x' is visible from the cusp.+-- 2. the path to 'x' hits the left side of the funnel.+-- 3. the path to 'x' hits the right side of the funnel.+--+-- ********************************************************+-- Drawing guide:+-- \ /+-- left side of funnel -> \ / <- right side of funnel+-- \ /+-- * <- cusp+-- ********************************************************+--+-- Case 1:+-- x+-- \ /+-- \ /+-- \ /+-- *+--+-- Case 2:+--+-- x+-- \ /+-- \ /+-- \ /+-- *+--+-- Case 3:+--+-- x+-- \ /+-- \ /+-- \ /+-- *+--+-- If 'x' is visible from the cusp, then the shortest path is a straight line and we're done.+-- If 'x' is not visible from the cusp, then we find the first point up the funnel where+-- 'x' becomes visible. We'll use a fingertree to find the point in O(log(min(n,m))). Because+-- of math, this adds up to O(n) for the entire SSSP tree.+--+-- Once we've found the first point that can see 'x', we split the funnel in two: One funnel+-- that will be used for points to the left of 'x' and one funnel for points to the right of+-- 'x'. Oh, "left" and "right" here are used to indicate branches in the dual tree.+splitFunnel :: (Fractional r, Ord r) => Index r -> Funnel r -> (Index r, Funnel r, Funnel r, SplitDirection)+splitFunnel x Funnel{..}+ | isOnLeftChain =+ case doSearch isRightTurn funnelLeft of+ (lower, t, upper) ->+ ( t+ , Funnel upper t (F.singleton x)+ , Funnel (lower F.|> t F.|> x) funnelCusp funnelRight+ , SplitLeft)+ | isOnRightChain =+ case doSearch isLeftTurn funnelRight of+ (lower, t, upper) ->+ ( t+ , Funnel funnelLeft funnelCusp (lower F.|> t F.|> x)+ , Funnel (F.singleton x) t upper+ , SplitRight)+ | otherwise =+ ( funnelCusp+ , Funnel funnelLeft funnelCusp (F.singleton x)+ , Funnel (F.singleton x) funnelCusp funnelRight+ , NoSplit)+ where+ isOnLeftChain = fromMaybe False $+ isLeftTurnOrLinear cuspElt <$> leftElt <*> pure targetElt+ isOnRightChain = fromMaybe False $+ isRightTurnOrLinear cuspElt <$> rightElt <*> pure targetElt+ doSearch fn chain =+ case F.search (searchChain fn) chain of+ F.Position lower t upper -> (lower, t, upper)+ F.OnLeft -> error "cannot happen"+ F.OnRight -> error "cannot happen"+ F.Nowhere -> error "cannot happen"+ searchChain _ MinMaxEmpty _ = False+ searchChain _ _ MinMaxEmpty = True+ searchChain check (MinMax _ l) (MinMax r _) =+ check (ringAccess l) (ringAccess r) targetElt+ cuspElt = ringAccess funnelCusp+ targetElt = ringAccess x+ leftElt = ringAccess <$> chainBottom funnelLeft+ rightElt = ringAccess <$> chainBottom funnelRight++-- FIXME: Turning a list of pairs into a vector is incredibly inefficient.+-- Would be much faster to write directly into a mutable vector and+-- then freeze it at the end.+-- \( O(n) \)+ssspFinger :: (Fractional r, Ord r) => Dual r -> SSSP+ssspFinger d = toSSSP $+ case d of+ Dual (a,b,c) ab bc ca ->+ (a, a) :+ (b, a) :+ (c, a) :+ loopLeft a c ca +++ worker (Funnel (F.singleton c) a (F.singleton b)) bc +++ loopRight a b ab+ where+ toSSSP :: [(Index r,Index r)] -> SSSP+ toSSSP lst =+ VU.fromList . map snd . sortOn fst $+ [ (a,b) | (Index (_ :+ a), Index (_ :+ b)) <- lst ]+ loopLeft a outer l =+ case l of+ EmptyDual -> []+ NodeDual x l' r' ->+ (x,a) :+ worker (Funnel (F.singleton x) a (F.singleton outer)) r' +++ loopLeft a x l'+ loopRight a outer r =+ case r of+ EmptyDual -> []+ NodeDual x l' r' ->+ (x, a) :+ worker (Funnel (F.singleton outer) a (F.singleton x)) l' +++ loopRight a x r'+ worker _ EmptyDual = []+ worker f (NodeDual x l r) =+ case splitFunnel x f of+ (v, fL, fR, _) ->+ (x, v) :+ worker fL l +++ worker fR r+++--------------------------------------------------------------------------------+-- Duals++++data Dual r = Dual (Index r, Index r, Index r) -- (a,b,c)+ (DualTree r) -- borders ab+ (DualTree r) -- borders bc+ (DualTree r) -- borders ca+ deriving (Show)++data DualTree r+ = EmptyDual+ | NodeDual (Index r) -- axb triangle, a and b are from parent.+ (DualTree r) -- borders xb+ (DualTree r) -- borders ax+ deriving (Show)++toTrigTree :: PlaneGraph s Int PolygonEdgeType PolygonFaceData r+ -> Tree (V.Vector (VertexId' s))+ -> Tree (Index r,Index r,Index r)+toTrigTree trig = fmap toTrig . fmap (fmap toDat)+ where+ toTrig v = case V.toList v of+ [a,b,c] -> (a,b,c)+ _ -> error "Algorithms.Geometry.SSSP: Invalid triangulation."+ toDat v = Index $ PlaneGraph.vtxDataToExt (trig ^. PlaneGraph.vertexDataOf v)++-- pp :: Show a => Tree a -> IO ()+-- pp = putStrLn . drawTree . fmap show++mkDual :: Tree (Index r,Index r,Index r) -> Dual r+mkDual (Node (a,b,c) forest) =+ Dual (a, b, c)+ (dualTree a b forest)+ (dualTree b c forest)+ (dualTree c a forest)++dualTree :: Index r -> Index r -> [Tree (Index r,Index r,Index r)] -> DualTree r+dualTree p1 p2 (Node (a,b,c) sub:xs) =+ case [a,b,c] \\ [p1,p2] of+ [x] -> NodeDual x (dualTree x p2 sub) (dualTree p1 x sub)+ _ -> dualTree p1 p2 xs+dualTree _p1 _p2 [] = EmptyDual++++++--------------------------------------------------------------------------------+-- Helpers++ringAccess :: Index r -> Point 2 r+ringAccess (Index (pt :+ _idx)) = pt++isRightTurnOrLinear :: (Ord r, Num r) => Point 2 r -> Point 2 r -> Point 2 r -> Bool+isRightTurnOrLinear p1 p2 p3 = not $ isLeftTurn p1 p2 p3++isLeftTurnOrLinear :: (Ord r, Num r) => Point 2 r -> Point 2 r -> Point 2 r -> Bool+isLeftTurnOrLinear p1 p2 p3 = not $ isRightTurn p1 p2 p3++isLeftTurn :: (Ord r, Num r) => Point 2 r -> Point 2 r -> Point 2 r -> Bool+isLeftTurn p1 p2 p3 =+ ccw p1 p2 p3 == CCW++isRightTurn :: (Ord r, Num r) => Point 2 r -> Point 2 r -> Point 2 r -> Bool+isRightTurn p1 p2 p3 =+ ccw p1 p2 p3 == CW
+ src/Algorithms/Geometry/SSSP/Naive.hs view
@@ -0,0 +1,90 @@+{-# LANGUAGE ParallelListComp #-}+--------------------------------------------------------------------------------+-- |+-- Module : Algorithms.Geometry.SSSP.Naive+-- Copyright : (C) David Himmelstrup+-- License : see the LICENSE file+-- Maintainer : David Himmelstrup+--------------------------------------------------------------------------------+module Algorithms.Geometry.SSSP.Naive+ ( sssp+ , sssp'+ ) where++import Algorithms.FloydWarshall (floydWarshall, mkGraph, mkIndex)+import Control.Lens+import Control.Monad.ST (runST)+import Data.Ext (_core, core)+import qualified Data.Foldable as F+import Data.Geometry.Interval (EndPoint (Closed, Open), end, start)+import Data.Geometry.LineSegment (LineSegment (..), sqSegmentLength)+import Data.Geometry.Point (ccwCmpAroundWith')+import Data.Geometry.Polygon (SimplePolygon, listEdges, outerBoundaryVector)+import Data.Intersection (IsIntersectableWith (intersect),+ NoIntersection (NoIntersection))+import Data.Vector (Vector)+import qualified Data.Vector as V+import qualified Data.Vector.Circular as CV+import qualified Data.Vector.Unboxed as VU+import Data.Vinyl (Rec (RNil, (:&)))+import Data.Vinyl.CoRec (Handler (H), match)+import Linear.Affine ((.-.))++type SSSP = VU.Vector Int++-- | \( O(n^3) \) Single-Source Shortest Path.+sssp :: (Real r, Fractional r) => SimplePolygon p r -> SSSP+sssp p = V.head . sssp' $ p++-- | \( O(n^3) \) Single-Source Shortest Path from all vertices.+sssp' :: (Real r, Fractional r) => SimplePolygon p r -> Vector SSSP+sssp' p = runST $ do+ -- Create an n*n matrix containing paths and distances between vertices.+ graph <- mkGraph n infinity (visibleEdges p)+ -- Use FloydWarshall O(n^3) to complete the matrix.+ floydWarshall n graph+ -- Create a tree describing the shortest path from any node to the 0th node.+ g <- VU.unsafeFreeze graph+ pure $ V.generate n $ \origin ->+ VU.generate n $ \i ->+ let (_dist, next) = g VU.! mkIndex n (i, origin)+ in next+ where+ infinity = read "Infinity" :: Double+ n = F.length (p ^. outerBoundaryVector)++-- \( O(n^3) \)+visibleEdges :: (Real r, Fractional r) => SimplePolygon p r -> [(Int, Int, Double)]+visibleEdges p = concat+ [+ [ (i, j, sqrt (realToFrac (sqSegmentLength line)))+ | j <- [i+2 .. n-1]+ , let endPt = CV.index vs j+ , let line = LineSegment (Closed pt) (Open endPt)+ -- Check if the line goes through the inside of the polygon.+ , ccwCmpAroundWith' ((_core prev) .-. (_core pt)) pt endPt next == GT+ -- Check if there are any intersections not the line end points.+ , not (interiorIntersection line edges)+ ]+ | i <- [0 .. n-1]+ , let pt = CV.index vs i+ prev = CV.index vs (i-1)+ next = CV.index vs (i+1)+ ] +++ [ (i,(i+1)`mod`n,sqrt (realToFrac (sqSegmentLength edge)))+ | (i, edge) <- zip [0..] edges+ ]+ where+ vs = p^.outerBoundaryVector+ n = F.length vs+ edges = listEdges p++interiorIntersection :: (Ord r, Fractional r) => LineSegment 2 p r -> [LineSegment 2 p r] -> Bool+interiorIntersection _ [] = False+interiorIntersection l (x:xs) =+ match (l `intersect` x) (+ H (\NoIntersection -> False)+ :& H (\pt -> pt /= l^.start.core && pt /= l^.end.core)+ :& H (\line -> sqSegmentLength line /= 0)+ :& RNil)+ || interiorIntersection l xs
+ src/Algorithms/Geometry/SmallestEnclosingBall.hs view
@@ -0,0 +1,20 @@+--------------------------------------------------------------------------------+-- |+-- Module : Algorithms.Geometry.SmallestEnclosingBall+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+--+-- Types to represent the smallest enclosing disk of a set of points in+-- \(\mathbb{R}^2\)+--+--------------------------------------------------------------------------------+module Algorithms.Geometry.SmallestEnclosingBall+ ( DiskResult(..)+ , enclosingDisk+ , definingPoints+ , TwoOrThree(..)+ , twoOrThreeFromList+ ) where++import Algorithms.Geometry.SmallestEnclosingBall.Types
src/Algorithms/Geometry/SmallestEnclosingBall/Naive.hs view
@@ -9,9 +9,10 @@ -- points in \(\mathbb{R}^2\) -- ---------------------------------------------------------------------------------module Algorithms.Geometry.SmallestEnclosingBall.Naive( smallestEnclosingDisk- , enclosesAll- ) where+module Algorithms.Geometry.SmallestEnclosingBall.Naive+ ( smallestEnclosingDisk+ , enclosesAll+ ) where -- just for the types import Control.Lens@@ -26,7 +27,7 @@ import qualified Data.Util as Util -------------------------------------------------------------------------------- --- | Horrible O(n^4) implementation that simply tries all disks, checks if they+-- | Horrible \( O(n^4) \) implementation that simply tries all disks, checks if they -- enclose all points, and takes the largest one. Basically, this is only useful -- to check correctness of the other algorithm(s) smallestEnclosingDisk :: (Ord r, Fractional r)@@ -44,6 +45,7 @@ triplets pts = [DiskResult (disk' a b c) (Three a b c) | Util.Three a b c <- uniqueTriplets pts] +{- HLINT ignore disk' -} disk' :: (Ord r, Fractional r) => Point 2 r :+ p -> Point 2 r :+ p -> Point 2 r :+ p -> Disk () r disk' a b c = fromMaybe degen $ disk (a^.core) (b^.core) (c^.core)@@ -56,7 +58,7 @@ smallestEnclosingDisk' :: (Ord r, Num r) => [Point 2 r :+ p] -> [DiskResult p r] -> DiskResult p r smallestEnclosingDisk' pts = minimumBy (compare `on` (^.enclosingDisk.squaredRadius))- . filter (flip enclosesAll pts)+ . filter (`enclosesAll` pts) -- | check if a disk encloses all points enclosesAll :: (Num r, Ord r) => DiskResult p r -> [Point 2 r :+ q] -> Bool
src/Algorithms/Geometry/SmallestEnclosingBall/RIC.hs view
@@ -1,5 +1,3 @@-{-# LANGUAGE DeriveFunctor #-}-{-# LANGUAGE TemplateHaskell #-} -------------------------------------------------------------------------------- -- | -- Module : Algorithms.Geometry.SmallestEnclosingBall.RIC@@ -31,8 +29,8 @@ import Data.Ord (comparing) import System.Random.Shuffle (shuffle) -import Data.RealNumber.Rational-import Debug.Trace+-- import Data.RealNumber.Rational+-- import Debug.Trace -------------------------------------------------------------------------------- @@ -48,8 +46,8 @@ => [Point 2 r :+ p] -> m (DiskResult p r) -smallestEnclosingDisk pts@(_:_:_) = ((\(p:q:pts') -> smallestEnclosingDisk' p q pts')- . F.toList) <$> shuffle pts+smallestEnclosingDisk pts@(_:_:_) = (\(p:q:pts') -> smallestEnclosingDisk' p q pts')+ . F.toList <$> shuffle pts smallestEnclosingDisk _ = error "smallestEnclosingDisk: Too few points" -- | Smallest enclosing disk.
src/Algorithms/Geometry/SmallestEnclosingBall/Types.hs view
@@ -27,11 +27,11 @@ foldMap f (Two a b) = f a <> f b foldMap f (Three a b c) = f a <> f b <> f c --fromList :: [a] -> Either String (TwoOrThree a)-fromList [a,b] = Right $ Two a b-fromList [a,b,c] = Right $ Three a b c-fromList _ = Left "Wrong number of elements"+-- | Construct datatype from list with exactly two or three elements.+twoOrThreeFromList :: [a] -> Either String (TwoOrThree a)+twoOrThreeFromList [a,b] = Right $ Two a b+twoOrThreeFromList [a,b,c] = Right $ Three a b c+twoOrThreeFromList _ = Left "Wrong number of elements"
src/Algorithms/Geometry/SoS.hs view
@@ -22,12 +22,6 @@ import Algorithms.Geometry.SoS.Orientation import Algorithms.Geometry.SoS.Determinant import Algorithms.Geometry.SoS.Sign-import Control.CanAquire-import Control.Lens-import Data.Ext-import Data.Geometry.Point.Internal-import Data.Geometry.Properties-import Data.Geometry.Vector --------------------------------------------------------------------------------
src/Algorithms/Geometry/SoS/AsPoint.hs view
@@ -1,9 +1,7 @@ module Algorithms.Geometry.SoS.AsPoint where import Control.CanAquire-import Control.Lens import Data.Ext-import Data.Geometry.Point.Class import Data.Geometry.Point.Internal import Data.Geometry.Properties import Data.Geometry.Vector@@ -18,7 +16,7 @@ instance HasIndex (P i d r) i where indexOf (P i) = i -instance Int `CanAquire` (Point d r) => (P Int d r) `CanAquire` (Point d r) where+instance Int `CanAquire` Point d r => P Int d r `CanAquire` Point d r where aquire (P i) = aquire i type instance NumType (P i d r) = r@@ -26,4 +24,4 @@ asPointWithIndex :: (Arity d, i `CanAquire` Point d r) => P i d r -> Point d r :+ SoSIndex i-asPointWithIndex (P i) = aquire i :+ (SoSIndex i)+asPointWithIndex (P i) = aquire i :+ SoSIndex i
src/Algorithms/Geometry/SoS/Expr.hs view
@@ -3,7 +3,6 @@ import Control.Lens import qualified Data.List as List-import Data.List.NonEmpty (NonEmpty(..),nonEmpty) -------------------------------------------------------------------------------- @@ -36,6 +35,8 @@ instance (Num r) => Num (Expr i r) where fromInteger = Constant . fromInteger+ abs _ = error "'abs' not defined for Algorithms.Geometry.SoS.Expr.Expr"+ signum _ = error "'signum' not defined for Algorithms.Geometry.SoS.Expr.Expr" negate = \case Negate e -> e e -> Negate e
src/Algorithms/Geometry/SoS/Orientation.hs view
@@ -59,7 +59,7 @@ -- | Given an input point, transform its number type to include -- symbolic $\varepsilon$ expressions so that we can use SoS. toSymbolic :: (Ord i, Arity d) => Point d r :+ i -> Point d (Symbolic (i,Int) r)-toSymbolic (p :+ i) = p&vector' %~ imap (\j x -> symbolic x (i,j))+toSymbolic (p :+ i) = p&vector %~ imap (\j x -> symbolic x (i,j)) -- | Given a point q and a vector of d points defining a hyperplane, -- test on which side of the hyperplane q lies.@@ -80,4 +80,4 @@ -- in a homogeneous matrix represetnation. I.e. we add a 1 as an -- additonal column at the end. mkLambdaRow :: (Num r, Arity d, Arity (d+1)) => Point d r -> Vector (d+1) r-mkLambdaRow = flip snoc 1 . view vector'+mkLambdaRow = flip snoc 1 . view vector
src/Algorithms/Geometry/SoS/Sign.hs view
@@ -8,6 +8,7 @@ -- | The sign of an expression data Sign = Negative | Positive deriving (Show,Eq,Ord,Enum,Bounded) +-- | Flip Positive <=> Negative. flipSign :: Sign -> Sign flipSign = \case Negative -> Positive
src/Algorithms/Geometry/SoS/Symbolic.hs view
@@ -1,3 +1,11 @@+--------------------------------------------------------------------------------+-- |+-- Module : Algorithms.Geometry.SoS.Symbolic+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+--+-------------------------------------------------------------------------------- module Algorithms.Geometry.SoS.Symbolic( EpsFold , eps, mkEpsFold@@ -21,8 +29,7 @@ import qualified Data.Map as Map import qualified Data.Map.Merge.Strict as Map import Data.Maybe (isNothing)-import Data.Word-import Test.QuickCheck (Arbitrary(..), listOf, suchThat)+import Test.QuickCheck (Arbitrary(..), listOf) import Test.QuickCheck.Instances () --------------------------------------------------------------------------------@@ -150,7 +157,7 @@ -- biggest of those terms is the pair whose indices comes first. instance (Arbitrary i, Ord i) => Arbitrary (EpsFold i) where- arbitrary = (mkEpsFold . take 4) <$> listOf arbitrary+ arbitrary = mkEpsFold . take 4 <$> listOf arbitrary -- | Test if the epsfold has no pertubation at all (i.e. if it is \(\Pi_{\emptyset}\)@@ -332,7 +339,7 @@ (Bag m) <> (Bag m') = Bag $ Map.unionWith (\d d' -> d + d' + 1) m m' instance Ord k => Monoid (Bag k) where- mempty = Bag $ Map.empty+ mempty = Bag Map.empty -- | Computes the difference of the two maps difference :: Ord a => Bag a -> Bag a -> Bag a
+ src/Algorithms/Geometry/VisibilityPolygon/Lee.hs view
@@ -0,0 +1,537 @@+{-# LANGUAGE TemplateHaskell #-}+--------------------------------------------------------------------------------+-- |+-- Module : Algorithms.Geometry.VisibilityPolygon.Lee+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+--+-- \(O(n\log n)\) time algorithm to compute the visibility polygon of+-- a point inside a polygon (possibly containing holes) with \(n\)+-- vertices, or among a set of \(n\) disjoint segments. The alogirhtm+-- used is the the rotational sweepline algorithm by Lee, described+-- in:+--+-- D. T. Lee. Proximity and reachability in the plane. Report R-831, Dept. Elect.+-- Engrg., Univ. Illinois, Urbana, IL, 1978.+--+--------------------------------------------------------------------------------+module Algorithms.Geometry.VisibilityPolygon.Lee+ ( visibilityPolygon+ , visibilitySweep+ , VisibilityPolygon+ , Definer, StarShapedPolygon+ , compareAroundEndPoint+ ) where++import Control.Lens+import Control.Monad ((<=<))+import Data.Bifunctor (first)+import Data.Ext+import qualified Data.Foldable as F+import Data.Function (on)+import Data.Geometry.HalfLine+import Data.Geometry.Line+import Data.Geometry.LineSegment+import Data.Geometry.Point+import Data.Geometry.Polygon+import Data.Geometry.Vector+import Data.Intersection+import qualified Data.List as List+import qualified Data.List.Util as List+import Data.List.NonEmpty (NonEmpty(..))+import qualified Data.List.NonEmpty as NonEmpty+import Data.Maybe (mapMaybe, isJust)+import Data.Ord (comparing)+import Data.RealNumber.Rational+import Data.Semigroup.Foldable+import qualified Data.Set as Set+import qualified Data.Set.Util as Set+import Data.Util+import Data.Vinyl.CoRec+import Debug.Trace++type R = RealNumber 5++--------------------------------------------------------------------------------++type StarShapedPolygon p r = SimplePolygon p r++-- | Vertices of the visibility polgyon are either original vertices+-- or defined by some vertex and an edge+type Definer p e r = Either p (Point 2 r :+ p,LineSegment 2 p r :+ e)++type VisibilityPolygon p e r = StarShapedPolygon (Definer p e r) r++-- | We either insert or delete segments+data Action a = Insert a | Delete a deriving (Show,Eq,Ord)++isInsert :: Action a -> Bool+isInsert = \case+ Insert _ -> True+ Delete _ -> False++extract :: Action a -> a+extract = \case+ Insert x -> x+ Delete x -> x++-- | An event corresponds to some orientation at which the set of segments+-- intersected by the ray changes (this orientation is defined by a point)+data Event p e r = Event { _eventVtx :: Point 2 r :+ p+ , _actions :: NonEmpty (Action (LineSegment 2 p r :+ e))+ } deriving Show+makeLenses ''Event++-- | The status structure maintains the subset of segments currently+-- intersected by the ray that starts in the query point q, in order+-- of increasing distance along the ray.+type Status p e r = Set.Set (LineSegment 2 p r :+ e)++++--------------------------------------------------------------------------------+++++-- | Computes the visibility polygon of a point q in a polygon with+-- \(n\) vertices.+--+-- pre: q lies strictly inside the polygon+--+-- running time: \(O(n\log n)\)+visibilityPolygon :: forall p t r. (Ord r, Fractional r)+ => Point 2 r+ -> Polygon t p r+ -> StarShapedPolygon (Definer p () r) r+visibilityPolygon q pg =+ fromPoints . visibilitySweep v Nothing q . map ext . closedEdges $ pg+ where+ v = uncurry (startingDirection q) . consecutive q . polygonVertices $ pg++++++++++++++++++++++++-- | Computes the visibility polgyon from a vertex+visibilityPolygonFromVertex :: forall p t r. (Ord r, Fractional r, Show r, Show p)+ => Polygon t p r+ -> Int -- ^ from the i^th vertex on the outer boundary+ -> VisibilityPolygon p () r+visibilityPolygonFromVertex pg i =+ fromPoints . visibilitySweep sv (Just w) v . map ext $ segs+ where+ (v :+ _) = pg^.outerVertex i+ (w :+ _) = pg^.outerVertex (i-1)+ (u :+ _) = pg^.outerVertex (i+1)++ -- rotates the polygon so that u becomes the focus, and gets all+ -- other vertices. Takes the next CCW vertex around v, starting+ -- form the direction indicated by v.+ z = let u' :| rest = traceShowIdWith "vertices"+ $ polygonVertices $ pg&outerBoundary %~ rotateRight (i+1)+ in traceShowIdWith "z" $ consecutiveFrom (u .-. v) v (List.init rest)+ -- the last vertex in rest is v; so kill that++ sv = startingDirection v u z++ segs = map (first (^._2))+ . filter (not . incidentTo i)+ . closedEdges $ numberVertices pg++visibilityPolygonFromVertex' q sv mt segs = sweep q statusStruct (traceShowIdWith "events" events)+ where+ v = undefined++ -- lazily test if the segment intersects the initial ray+ segs' = labelWithDistances q initialRay segs++ events = computeEvents q sv (untilEnd q sv mt) segs'+ -- take only until the end of the range (if defined)++ initialRay = traceShowIdWith "ray" $ HalfLine q sv+ statusStruct = traceShowIdWith "initialSS" $ mkInitialSS segs'+++-- | Test if the line segment is incident to a point with the given+-- index.+incidentTo :: Int -> LineSegment 2 (SP Int a) r -> Bool+incidentTo i s = s^.start.extra._1 == i || s^.end.extra._1 == i++++++++++-- | computes a (partial) visibility polygon of a set of \(n\)+-- disjoint segments. The input segments are allowed to share+-- endpoints, but no intersections or no endpoints in the interior of+-- other segments. The input vector indicates the starting direction,+-- the Maybe point indicates up to which point/dicrection (CCW) of the+-- starting vector we should compute the visibility polygon.+--+-- pre : - all line segments are considered closed.+-- - no singleton linesegments exactly pointing away from q.+-- - for every orientattion the visibility is blocked somewhere, i.e.+-- no rays starting in the query point q that are disjoint from all segments.+-- - no vertices at staring direction sv+--+-- running time: \(O(n\log n)\)+visibilitySweep :: forall p r e. (Ord r, Fractional r)+ => Vector 2 r -- ^ starting direction of the sweep+ -> Maybe (Point 2 r)+ -- ^ -- point indicating the last point to sweep to+ -> Point 2 r -- ^ the point form which we compute the visibility polgyon+ -> [LineSegment 2 p r :+ e]+ -> [Point 2 r :+ Definer p e r]+visibilitySweep sv mt q segs = sweep q statusStruct events+ where+ -- lazily test if the segment intersects the initial ray+ segs' = labelWithDistances q initialRay segs+ events = computeEvents q sv (untilEnd q sv mt) segs'++ initialRay = HalfLine q sv+ statusStruct = mkInitialSS segs'++-- | Take until the ending point if defined. We can use that the list+-- of events appears in sorted order in the cyclic orientation around+-- the query point q+untilEnd :: (Ord r, Num r)+ => Point 2 r -- ^ query point+ -> Vector 2 r -- ^ starting direction+ -> Maybe (Point 2 r) -- ^ possible ending point+ -> [Event a e r] -> [Event a e r]+untilEnd q sv = \case+ Nothing -> id+ Just t -> List.takeWhile (\e -> ccwCmpAroundWith' sv (ext q) (e^.eventVtx) (ext t) == LT)++-- | Runs the actual sweep+sweep :: (Foldable t, Ord r, Fractional r)+ => Point 2 r -- ^ query point+ -> Status p e r -- ^ initial status structure+ -> t (Event p e r) -- ^ events to handle+ -> [Point 2 r :+ Definer p e r]+sweep q statusStruct = snd . List.foldl' (handleEvent q) (statusStruct,[])+++-- | Computes the events in the sweep+computeEvents :: (Ord r, Num r, Foldable t)+ => Point 2 r -- ^ query point+ -> Vector 2 r -- ^ starting direction+ -> ([Event p1 e1 r] -> [Event p2 e2 r]) -- ^ until where to take the vents+ -> t (LineSegment 2 p1 r :+ (Maybe r, e1))+ -> [Event p2 e2 r]+computeEvents q sv takeUntil =+ map (combine q)+ . List.groupBy' (\a b -> ccwCmpAroundWith' sv (ext q) (a^.eventVtx) (b^.eventVtx))+ . takeUntil+ . List.sortBy (cmp `on` (^.eventVtx))+ . concatMap (mkEvent sv q)+ where+ cmp = ccwCmpAroundWith' sv (ext q) <> cmpByDistanceTo' (ext q)++-- | Given multiple events happening at the same orientation, combine+-- them into a single event.+combine :: (Ord r, Num r) => Point 2 r -> NonEmpty (Event p e r) -> Event p e r+combine q es = Event p acts+ where+ acts = foldMap1 (^.actions) es+ p = F.minimumBy (cmpByDistanceTo' (ext q)) . fmap (^.eventVtx) $ es++-- | Constructs the at most two events resulting from this segement.+mkEvent :: (Ord r, Num r)+ => Vector 2 r -- ^ starting direction+ -> Point 2 r -- ^ query point+ -> LineSegment 2 p r :+ (Maybe r, e)+ -> [Event p e r]+mkEvent sv q (s@(LineSegment' u v) :+ (d,e)) = case cmp u v of+ LT -> [ Event u insert+ , Event v delete+ ]+ GT -> [ Event v insert+ , Event u delete+ ]+ EQ -> [] -- zero length segment, just skip+ where+ cmp = ccwCmpAroundWith' sv (ext q) <> cmpByDistanceTo' (ext q)+ s' = s :+ e++ insert = (if isJust d then Delete s' else Insert s') :| []+ delete = (if isJust d then Insert s' else Delete s') :| []+++-- | Handles an event, computes the new status structure and output polygon.+handleEvent :: (Ord r, Fractional r)+ => Point 2 r+ -> (Status p e r, [Point 2 r :+ Definer p e r])+ -> Event p e r+ -> (Status p e r, [Point 2 r :+ Definer p e r])+handleEvent q (ss,out) (Event (p :+ z) acts) = (ss', newVtx <> out)+ where+ (ins,dels) = bimap (map extract) (map extract) . NonEmpty.partition isInsert $ acts++ ss' = flip (foldr (insertAt q p)) ins+ . flip (foldr (deleteAt q p)) dels+ $ ss++ newVtx = let (a :+ sa) = firstHitAt' q p ss+ (b :+ sb) = firstHitAt' q p ss'+ ae = valOf a sa+ be = valOf b sb+ in case (a /= b, a == p) of+ (True, _) -> -- new window of the output polygon discovered+ -- figure out who is the closest vertex, (the reflex vtx)+ -- and add the appropriate two vertices+ case squaredEuclideanDist q a < squaredEuclideanDist q b of+ True -> [ b :+ Right (a :+ ae, sb)+ , a :+ Left ae -- a must be a vertex!+ ]+ False -> [ b :+ Left be+ , a :+ Right (b :+ be, sa)+ ]+ (False,True) -> [ p :+ Left z]+ -- sweeping over a regular vertex of the visibility polygon+ (False,False) -> [] -- sweeping over a vertex not in output++ valOf a (LineSegment' (b :+ be) (_ :+ ce) :+ _ ) | a == b = be+ | otherwise = ce++++--------------------------------------------------------------------------------++-- | Given two points q and p, and a status structure retrieve the+-- first segment in the status structure intersected by the ray from q+-- through p.+--+-- pre: all segments in the status structure should intersect the ray+-- from q through p (in a point), in that order.+--+-- running time: \(O(\log n)\)+firstHitAt :: forall p r e. (Ord r, Fractional r)+ => Point 2 r -> Point 2 r+ -> Status p e r+ -> Maybe (Point 2 r :+ LineSegment 2 p r :+ e)+firstHitAt q p = computeIntersectionPoint <=< Set.lookupMin+ where+ computeIntersectionPoint s = fmap (:+ s) . asA @(Point 2 r)+ $ supportingLine (s^.core) `intersect` lineThrough p q++-- | Given two points q and p, and a status structure retrieve the+-- first segment in the status structure intersected by the ray from q+-- through p.+--+-- pre: - all segments in the status structure should intersect the ray+-- from q through p (in a point), in that order.+-- - the status structure is non-empty+--+-- running time: \(O(\log n)\)+firstHitAt' :: forall p r e. (Ord r, Fractional r)+ => Point 2 r -> Point 2 r+ -> Status p e r+ -> Point 2 r :+ LineSegment 2 p r :+ e+firstHitAt' q p s = case firstHitAt q p s of+ Just x -> x+ Nothing -> error "firstHitAt: precondition failed!"++--------------------------------------------------------------------------------+-- * Status Structure Operations++-- | Insert a new segment into the status structure, depending on the+-- (distance from q to to the) intersection point with the ray from q+-- through p+--+-- pre: all segments in the status structure should intersect the ray+-- from q through p, in that order.+--+-- \(O(\log n)\)+insertAt :: (Ord r, Fractional r)+ => Point 2 r -> Point 2 r -> LineSegment 2 p r :+ e+ -> Status p e r -> Status p e r+insertAt q p = Set.insertBy (compareByDistanceToAt q p <> flip (compareAroundEndPoint q))+ -- if two segments have the same distance, they must share and endpoint+ -- so we use the CCW ordering around this common endpoint to determine+ -- the order.++-- | Delete a segment from the status structure, depending on the+-- (distance from q to to the) intersection point with the ray from q+-- through p+--+-- pre: all segments in the status structure should intersect the ray+-- from q through p, in that order.+--+-- \(O(\log n)\)+deleteAt :: (Ord r, Fractional r)+ => Point 2 r -> Point 2 r -> LineSegment 2 p r :+ e+ -> Status p e r -> Status p e r+deleteAt q p = Set.deleteAllBy (compareByDistanceToAt q p <> compareAroundEndPoint q)+ -- if two segments have the same distance, we use the ccw order around their common+ -- (end) point.++-- FIXME: If there are somehow segmetns that would continue at p as+-- well, they are also deleted.+++-- | Given a list of line segments, each labeled with the distance+-- from their intersection point with the initial ray to the query+-- point, build the initial status structure.+mkInitialSS :: forall r p e. (Ord r, Fractional r)+ => [ LineSegment 2 p r :+ (Maybe r, e)] -> Status p e r+mkInitialSS = Set.mapMonotonic (^.extra)+ . foldr (Set.insertBy $ comparing (^.core)) Set.empty+ . mapMaybe (\(s :+ (md,e)) -> (:+ (s :+ e)) <$> md)++-- | Given q, the initial ray, and a segment s, computes if the+-- segment intersects the initial, rightward ray starting in q, and if+-- so returns the (squared) distance from q to that point together+-- with the segment.+initialIntersection :: forall r p. (Ord r, Fractional r)+ => Point 2 r -> HalfLine 2 r -> LineSegment 2 p r+ -> Maybe r+initialIntersection q ray s =+ case asA @(Point 2 r) $ seg `intersect` ray of+ Nothing -> Nothing+ Just z -> Just $ squaredEuclideanDist q z+ where+ seg = first (const ()) s++-- | Labels the segments with the distance from q to their+-- intersection point with the ray.+labelWithDistances :: (Ord r, Fractional r)+ => Point 2 r -> HalfLine 2 r -> [LineSegment 2 p r :+ b]+ -> [LineSegment 2 p r :+ (Maybe r, b)]+labelWithDistances q ray = map (\(s :+ e) -> s :+ (initialIntersection q ray s, e))++--------------------------------------------------------------------------------+-- * Comparators for the rotating ray++-- | Given two points q and p, and two segments a and b that are guaranteed to+-- intersect the ray from q through p once, order the segments by their+-- intersection point+compareByDistanceToAt :: forall p r e. (Ord r, Fractional r)+ => Point 2 r -> Point 2 r+ -> LineSegment 2 p r :+ e+ -> LineSegment 2 p r :+ e+ -> Ordering+compareByDistanceToAt q p = comparing f+ where+ f (s :+ _) = fmap (squaredEuclideanDist q)+ . asA @(Point 2 r)+ $ supportingLine s `intersect` lineThrough p q++-- | Given two segments that share an endpoint, order them by their+-- order around this common endpoint. I.e. if uv and uw share endpoint+-- u we uv is considered smaller iff v is smaller than w in the+-- counterclockwise order around u (treating the direction from q to+-- the common endpoint as zero).+compareAroundEndPoint :: forall p r e. (Ord r, Fractional r)+ => Point 2 r+ -> LineSegment 2 p r :+ e+ -> LineSegment 2 p r :+ e+ -> Ordering+compareAroundEndPoint q+ (LineSegment' a b :+ _)+ (LineSegment' s t :+ _)+ -- traceshow ("comapreAroundEndPoint ", sa, sb) False = undefined+ | a^.core == s^.core = ccwCmpAroundWith' (a^.core .-. q) a b t+ | a^.core == t^.core = ccwCmpAroundWith' (a^.core .-. q) a b s+ | b^.core == s^.core = ccwCmpAroundWith' (b^.core .-. q) b a t+ | b^.core == t^.core = ccwCmpAroundWith' (b^.core .-. q) b a s+ | otherwise = error "compareAroundEndPoint: precondition failed!"++--------------------------------------------------------------------------------+-- * Helper functions for polygon operations++-- | Given q, and two consecutive points u and v, Computes a direction+-- for the initial ray, i.e. a "generic" ray that does not go through+-- any vertices.+startingDirection :: Fractional r => Point 2 r -> Point 2 r -> Point 2 r -> Vector 2 r+startingDirection q u w = v .-. q+ where+ v = u .+^ ((w .-. u) ^/ 2) -- point in the middle between u and w+ -- note: the segment between u and w could pass on the wrong side of q+ -- (i.e. so that does not "cover" the CCW but the CW range between u and w)+ -- however, in that case there is apparently nothing on the CCW side opposite+ -- to v, as u and w are supposed to be the first two events. This means the+ -- precondition does not hold.++-- | finds two consecutive vertices in the clockwise order around the+-- given point q. I.e. there are no other points in between the two+-- returned points.+consecutive :: (Ord r, Num r) => Point 2 r -> NonEmpty (Point 2 r :+ p)+ -> (Point 2 r, Point 2 r)+consecutive q ((p :+ _):|pts) = (p,consecutiveFrom (p .-. q) q pts)++-- | pre: input list is non-empty+consecutiveFrom :: (Ord r, Num r)+ => Vector 2 r -- ^ starting vector+ -> Point 2 r -- ^ query point+ -> [Point 2 r :+ p] -> Point 2 r+consecutiveFrom v q = view core . List.minimumBy (ccwCmpAroundWith' v (ext q))++-- | Gets the edges of the polygon as closed line segments.+closedEdges :: Polygon t p r -> [LineSegment 2 p r]+closedEdges = map asClosed . listEdges+ where+ asClosed (LineSegment' u v) = ClosedLineSegment u v+++--------------------------------------------------------------------------------+-- * Generic Helper functions++++--------------------------------------------------------------------------------++test :: StarShapedPolygon (Definer Int () R) R+test = visibilityPolygon origin testPg++testVtx = visibilityPolygonFromVertex testPg 0++testPg :: SimplePolygon Int R+testPg = fromPoints $ zipWith (:+) [ Point2 3 1+ , Point2 3 2+ , Point2 4 2+ , Point2 2 4+ , Point2 (-1) 4+ , Point2 1 2+ , Point2 (-3) (-1)+ , Point2 4 (-1)+ ] [1..]++testPg2 :: SimplePolygon Int R+testPg2 = fromPoints $ zipWith (:+) [ Point2 3 1+ , Point2 3 2+ , Point2 4 2+ , Point2 2 4+ , Point2 (-1) 4+ , Point2 1 2.1+ , Point2 (-3) (-1)+ , Point2 4 (-1)+ ] [1..]++++traceShowIdWith x y = traceShow (show x,y) y
+ src/Algorithms/Geometry/WSPD.hs view
@@ -0,0 +1,474 @@+--------------------------------------------------------------------------------+-- |+-- Module : Algorithms.Geometry.WSPD+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+--+-- Algorithm to construct a well separated pair decomposition (wspd).+--+--------------------------------------------------------------------------------+module Algorithms.Geometry.WSPD+ ( fairSplitTree+ , wellSeparatedPairs+ , NodeData(NodeData)+ , WSP+ , SplitTree+ , nodeData+ , Level(..)+ , reIndexPoints+ , distributePoints+ , distributePoints'+ ) where++import Algorithms.Geometry.WSPD.Types+import Control.Lens hiding (Level, levels)+import Control.Monad.Reader+import Control.Monad.ST (ST,runST)+import Data.BinaryTree+import Data.Ext+import qualified Data.Foldable as F+import Data.Geometry.Box+import Data.Geometry.Point+-- import Data.Geometry.Properties+-- import Data.Geometry.Transformation+import Data.Geometry.Vector+import qualified Data.Geometry.Vector as GV+import qualified Data.IntMap.Strict as IntMap+import qualified Data.LSeq as LSeq+import Data.LSeq (LSeq, toSeq,pattern (:<|))+import qualified Data.List as L+import qualified Data.List.NonEmpty as NonEmpty+import Data.Maybe+import Data.Ord (comparing)+import Data.Range+import qualified Data.Range as Range+import qualified Data.Sequence as S+import qualified Data.Vector as V+import qualified Data.Vector.Mutable as MV+import GHC.TypeLits++-- import Debug.Trace++--------------------------------------------------------------------------------++-- | Construct a split tree+--+-- running time: \(O(n \log n)\)+fairSplitTree :: (Fractional r, Ord r, Arity d, 1 <= d+ , Show r, Show p+ )+ => NonEmpty.NonEmpty (Point d r :+ p) -> SplitTree d p r ()+fairSplitTree pts = foldUp node' Leaf $ fairSplitTree' n pts'+ where+ pts' = imap sortOn . pure . g $ pts+ n = length $ pts'^.GV.element (C :: C 0)++ sortOn' i = NonEmpty.sortWith (^.core.unsafeCoord i)+ sortOn i = LSeq.fromNonEmpty . sortOn' (i + 1)+ -- sorts the points on the first coordinate, and then associates each point+ -- with an index,; its rank in terms of this first coordinate.+ g = NonEmpty.zipWith (\i (p :+ e) -> p :+ (i :+ e)) (NonEmpty.fromList [0..])+ . sortOn' 1++ -- node' :: b -> a -> b -> b+ -- node' :: SplitTree d p r () -> Int -> SplitTree d p r () -> SplitTree d p r ()+ node' l j r = Node l (NodeData j (bbOf l <> bbOf r) ()) r+++-- | Given a split tree, generate the Well separated pairs+--+-- running time: \(O(s^d n)\)+wellSeparatedPairs :: (Floating r, Ord r, Arity d, Arity (d + 1))+ => r -> SplitTree d p r a -> [WSP d p r a]+wellSeparatedPairs s = f+ where+ f (Leaf _) = []+ f (Node l _ r) = findPairs s l r ++ f l ++ f r++++-- -- | Given a split tree, generate the well separated pairs such that one set is+-- -- a singleton.+-- -- running time: \(O(s^d n\log n)\)+-- wellSeparatedPairSingletons :: (Fractional r, Ord r, AlwaysTrueWSPD d)+-- => r -> SplitTree d p r a -> [(Point d r :+ p, PointSet d p r (Sized a))]+-- wellSeparatedPairSingletons s t = concatMap split $ wellSeparatedPairs s t'+-- where+-- split (l,r) = undefined+-- -- | measure l <= measure r = map (,r) $ F.toList l+-- -- | otherwise = map (,l) $ F.toList r+-- t' = foldUpData (\l nd r -> )++-- t+++--------------------------------------------------------------------------------+-- * Building the split tree++-- | Given the points, sorted in every dimension, recursively build a split tree+--+-- The algorithm works in rounds. Each round takes \( O(n) \) time, and halves the+-- number of points. Thus, the total running time is \( O(n log n) \).+--+-- The algorithm essentially builds a path in the split tree; at every node on+-- the path that we construct, we split the point set into two sets (L,R)+-- according to the longest side of the bounding box.+--+-- The smaller set is "assigned" to the current node and set asside. We+-- continue to build the path with the larger set until the total number of+-- items remaining is less than n/2.+--+-- To start the next round, each node on the path needs to have the points+-- assigned to that node, sorted in each dimension (i.e. the Vector+-- (PointSeq))'s. Since we have the level assignment, we can compute these+-- lists by traversing each original input list (i.e. one for every dimension)+-- once, and partition the points based on their level assignment.+fairSplitTree' :: (Fractional r, Ord r, Arity d, 1 <= d+ , Show r, Show p+ )+ => Int -> GV.Vector d (PointSeq d (Idx :+ p) r)+ -> BinLeafTree Int (Point d r :+ p)+fairSplitTree' n pts+ | n <= 1 = let p = LSeq.head $ pts^.GV.element (C :: C 0) in Leaf (dropIdx p)+ | otherwise = foldr node' (V.last path) $ V.zip nodeLevels (V.init path)+ where+ -- note that points may also be assigned level 'Nothing'.+ (levels, nodeLevels'@(maxLvl NonEmpty.:| _)) = runST $ do+ lvls <- MV.replicate n Nothing+ ls <- runReaderT (assignLevels (n `div` 2) 0 pts (Level 0 Nothing) []) lvls+ lvls' <- V.unsafeFreeze lvls+ pure (lvls',ls)++ -- TODO: We also need to report the levels in the order in which they are+ -- assigned to nodes++ nodeLevels = V.fromList . L.reverse . NonEmpty.toList $ nodeLevels'++ -- levels = traceShow ("Levels",levels',maxLvl) levels'++ -- path = traceShow ("path", path',nodeLevels) path'+ distrPts = distributePoints (1 + maxLvl^.unLevel) levels pts++ path = recurse <$> distrPts -- (traceShow ("distributed pts",distrPts) distrPts)++ -- node' (lvl,lc) rc | traceShow ("node' ",lvl,lc,rc) False = undefined+ node' (lvl,lc) rc = case lvl^?widestDim._Just of+ Nothing -> error "Unknown widest dimension"+ Just j -> Node lc j rc+ recurse pts' = fairSplitTree' (length $ pts'^.GV.element (C :: C 0))+ (reIndexPoints pts')++-- | Assign the points to their the correct class. The 'Nothing' class is+-- considered the last class+distributePoints :: (Arity d , Show r, Show p)+ => Int -> V.Vector (Maybe Level)+ -> GV.Vector d (PointSeq d (Idx :+ p) r)+ -> V.Vector (GV.Vector d (PointSeq d (Idx :+ p) r))+distributePoints k levels = transpose . fmap (distributePoints' k levels)++transpose :: Arity d => GV.Vector d (V.Vector a) -> V.Vector (GV.Vector d a)+transpose = V.fromList . map GV.vectorFromListUnsafe . L.transpose+ . map V.toList . F.toList++-- | Assign the points to their the correct class. The 'Nothing' class is+-- considered the last class+distributePoints' :: Int -- ^ number of classes+ -> V.Vector (Maybe Level) -- ^ level assignment+ -> PointSeq d (Idx :+ p) r -- ^ input points+ -> V.Vector (PointSeq d (Idx :+ p) r)+distributePoints' k levels pts+ = fmap fromSeqUnsafe $ V.create $ do+ v <- MV.replicate k mempty+ forM_ pts $ \p ->+ append v (level p) p+ pure v+ where+ level p = maybe (k-1) _unLevel $ levels V.! (p^.extra.core)+ append v i p = MV.read v i >>= MV.write v i . (S.|> p)++fromSeqUnsafe :: S.Seq a -> LSeq n a+fromSeqUnsafe = LSeq.promise . LSeq.fromSeq++-- | Given a sequence of points, whose index is increasing in the first+-- dimension, i.e. if idx p < idx q, then p[0] < q[0].+-- Reindex the points so that they again have an index+-- in the range [0,..,n'], where n' is the new number of points.+--+-- running time: O(n' * d) (more or less; we are actually using an intmap for+-- the lookups)+--+-- alternatively: I can unsafe freeze and thaw an existing vector to pass it+-- along to use as mapping. Except then I would have to force the evaluation+-- order, i.e. we cannot be in 'reIndexPoints' for two of the nodes at the same+-- time.+--+-- so, basically, run reIndex points in ST as well.+reIndexPoints :: (Arity d, 1 <= d)+ => GV.Vector d (PointSeq d (Idx :+ p) r)+ -> GV.Vector d (PointSeq d (Idx :+ p) r)+reIndexPoints ptsV = fmap reIndex ptsV+ where+ pts = ptsV^.GV.element (C :: C 0)++ reIndex = fmap (\p -> p&extra.core %~ fromJust . flip IntMap.lookup mapping')+ mapping' = IntMap.fromAscList $ zip (map (^.extra.core) . F.toList $ pts) [0..]++-- | ST monad with access to the vector storign the level of the points.+type RST s = ReaderT (MV.MVector s (Maybe Level)) (ST s)++{- HLINT ignore assignLevels -}+-- | Assigns the points to a level. Returns the list of levels used. The first+-- level in the list is the level assigned to the rest of the nodes. Their+-- level is actually still set to Nothing in the underlying array.+assignLevels :: (Fractional r, Ord r, Arity d+ , Show r, Show p+ )+ => Int -- ^ Number of items we need to collect+ -> Int -- ^ Number of items we collected so far+ -> GV.Vector d (PointSeq d (Idx :+ p) r)+ -> Level -- ^ next level to use+ -> [Level] -- ^ Levels used so far+ -> RST s (NonEmpty.NonEmpty Level)+assignLevels h m pts l prevLvls+ | m >= h = pure (l NonEmpty.:| prevLvls)+ | otherwise = do+ pts' <- compactEnds pts+ -- find the widest dimension j = i+1+ let j = widestDimension pts'+ i = j - 1 -- traceShow ("i",j,pts') j - 1+ extJ = (extends pts')^.ix' i+ mid = midPoint extJ++ -- find the set of points that we have to delete, by looking at the sorted+ -- list L_j. As a side effect, this will remove previously assigned points+ -- from L_j.+ (lvlJPts,deletePts) <- findAndCompact j (pts'^.ix' i) mid+ let pts'' = pts'&ix' i .~ lvlJPts+ l' = l&widestDim ?~ j+ forM_ deletePts $ \p ->+ assignLevel p l'+ assignLevels h (m + length deletePts) pts'' (nextLevel l) (l' : prevLvls)++-- | Remove already assigned pts from the ends of all vectors.+compactEnds :: Arity d+ => GV.Vector d (PointSeq d (Idx :+ p) r)+ -> RST s (GV.Vector d (PointSeq d (Idx :+ p) r))+compactEnds = traverse compactEnds'++-- | Assign level l to point p+assignLevel :: (c :+ (Idx :+ p)) -> Level -> RST s ()+assignLevel p l = ask >>= \levels -> lift $ MV.write levels (p^.extra.core) (Just l)++-- | Get the level of a point+levelOf :: (c :+ (Idx :+ p)) -> RST s (Maybe Level)+levelOf p = ask >>= \levels -> lift $ MV.read levels (p^.extra.core)++-- | Test if the point already has a level assigned to it.+hasLevel :: c :+ (Idx :+ p) -> RST s Bool+hasLevel = fmap isJust . levelOf++-- | Remove allready assigned points from the sequence+--+-- pre: there are points remaining+compactEnds' :: PointSeq d (Idx :+ p) r+ -> RST s (PointSeq d (Idx :+ p) r)+compactEnds' (l0 :<| s0) = fmap fromSeqUnsafe . goL $ l0 S.<| toSeq s0+ where+ goL s@(S.viewl -> l S.:< s') = hasLevel l >>= \case+ False -> goR s+ True -> goL s'+ goL _ = error "Unreachable, but cannot prove it in Haskell"+ goR s@(S.viewr -> s' S.:> r) = hasLevel r >>= \case+ False -> pure s+ True -> goR s'+ goR _ = error "Unreachable, but cannot prove it in Haskell"+++-- | Given the points, ordered by their j^th coordinate, split the point set+-- into a "left" and a "right" half, i.e. the points whose j^th coordinate is+-- at most the given mid point m, and the points whose j^th coordinate is+-- larger than m.+--+-- We return a pair (Largest set, Smallest set)+--+--+--fi ndAndCompact works by simultaneously traversing the points from left to+-- right, and from right to left. As soon as we find a point crossing the mid+-- point we stop and return. Thus, in principle this takes only O(|Smallest+-- set|) time.+--+-- running time: O(|Smallest set|) + R, where R is the number of *old* points+-- (i.e. points that should have been removed) in the list.+findAndCompact :: (Ord r, Arity d+ , Show r, Show p+ )+ => Int+ -- ^ the dimension we are in, i.e. so that we know+ -- which coordinate of the point to compare+ -> PointSeq d (Idx :+ p) r+ -> r -- ^ the mid point+ -> RST s ( PointSeq d (Idx :+ p) r+ , PointSeq d (Idx :+ p) r+ )+findAndCompact j (l0 :<| s0) m = fmap select . stepL $ l0 S.<| toSeq s0+ where+ -- stepL and stepR together build a data structure (FAC l r S) that+ -- contains the left part of the list, i.e. the points before midpoint, and+ -- the right part of the list., and a value S that indicates which part is+ -- the short side.++ -- stepL takes a step on the left side of the list; if the left point l+ -- already has been assigned, we continue waling along (and "ignore" the+ -- point). If it has not been assigned, and is before the mid point, we+ -- take a step from the right, and add l onto the left part. If it is+ -- larger than the mid point, we have found our split.+ -- stepL :: S.Seq (Point d r :+ (Idx :+ p)) -> ST s (FindAndCompact d r (Idx :+ p))+ stepL s = case S.viewl s of+ S.EmptyL -> pure $ FAC mempty mempty L+ l S.:< s' -> hasLevel l >>= \case+ False -> if l^.core.unsafeCoord j <= m+ then addL l <$> stepR s'+ else pure $ FAC mempty s L+ True -> stepL s' -- delete, continue left++ -- stepR :: S.Seq (Point d r :+ (Idx :+ p)) -> ST s (FindAndCompact d r (Idx :+ p))+ stepR s = case S.viewr s of+ S.EmptyR -> pure $ FAC mempty mempty R+ s' S.:> r -> hasLevel r >>= \case+ False -> if r^.core.unsafeCoord j >= m+ then addR r <$> stepL s'+ else pure $ FAC s mempty R+ True -> stepR s'+++ addL l x = x&leftPart %~ (l S.<|)+ addR r x = x&rightPart %~ (S.|> r)++ select = over both fromSeqUnsafe . select'++ -- select' f | traceShow ("select'", f) False = undefined+ select' (FAC l r L) = (r, l)+ select' (FAC l r R) = (l, r)+++-- | Find the widest dimension of the point set+--+-- pre: points are sorted according to their dimension+widestDimension :: (Num r, Ord r, Arity d) => GV.Vector d (PointSeq d p r) -> Int+widestDimension = fst . L.maximumBy (comparing snd) . zip [1..] . F.toList . widths++widths :: (Num r, Arity d) => GV.Vector d (PointSeq d p r) -> GV.Vector d r+widths = fmap Range.width . extends+++{- HLINT ignore extends -}+-- | get the extends of the set of points in every dimension, i.e. the left and+-- right boundaries.+--+-- pre: points are sorted according to their dimension+extends :: Arity d => GV.Vector d (PointSeq d p r) -> GV.Vector d (Range r)+extends = imap (\i pts ->+ ClosedRange ((LSeq.head pts)^.core.unsafeCoord (i + 1))+ ((LSeq.last pts)^.core.unsafeCoord (i + 1)))+++--------------------------------------------------------------------------------+-- * Finding Well Separated Pairs++findPairs :: (Floating r, Ord r, Arity d, Arity (d + 1))+ => r -> SplitTree d p r a -> SplitTree d p r a+ -> [WSP d p r a]+findPairs s l r+ | areWellSeparated' s l r = [(l,r)]+ | maxWidth l <= maxWidth r = concatMap (findPairs s l) $ children' r+ | otherwise = concatMap (findPairs s r) $ children' l+++-- -- | Test if the two sets are well separated with param s+-- areWellSeparated :: (Arity d, Arity (d + 1), Fractional r, Ord r)+-- => r -- ^ separation factor+-- -> SplitTree d p r a+-- -> SplitTree d p r a -> Bool+-- areWellSeparated _ (Leaf _) (Leaf _) = True+-- areWellSeparated s l r = boxBox s (bbOf l) (bbOf r)+++-- areWellSeparated s (Leaf p) (Node _ nd _) = pointBox s (p^.core) (nd^.bBox)+-- areWellSeparated s (Node _ nd _) (Leaf p) = pointBox s (p^.core) (nd^.bBox)+-- areWellSeparated s (Node _ ld _) (Node _ rd _) = boxBox s (ld^.bBox) (rd^.bBox)++{- HLINT ignore boxBox -}+-- -- | Test if the point and the box are far enough appart+-- pointBox :: (Fractional r, Ord r, AlwaysTruePFT d, AlwaysTrueTransformation d)+-- => r -> Point d r -> Box d p r -> Bool+-- pointBox s p b = not $ p `inBox` b'+-- where+-- v = (centerPoint b)^.vector+-- b' = translateBy v . scaleUniformlyBy s . translateBy ((-1) *^ v) $ b++-- -- | Test if the two boxes are sufficiently far appart+-- boxBox :: (Fractional r, Ord r, Arity d, Arity (d + 1))+-- => r -> Box d p r -> Box d p r -> Bool+-- boxBox s lb rb = boxBox' lb rb && boxBox' rb lb+-- where+-- boxBox' b' b = not $ b' `intersects` bOut+-- where+-- v = (centerPoint b)^.vector+-- bOut = translateBy v . scaleUniformlyBy s . translateBy ((-1) *^ v) $ b++--------------------------------------------------------------------------------+-- * Alternative def if wellSeparated that uses fractional+++areWellSeparated' :: (Floating r, Ord r, Arity d)+ => r+ -> SplitTree d p r a+ -> SplitTree d p r a+ -> Bool+areWellSeparated' _ (Leaf _) (Leaf _) = True+areWellSeparated' s l r = boxBox1 s (bbOf l) (bbOf r)++-- (Leaf p) (Node _ nd _) = pointBox' s (p^.core) (nd^.bBox)+-- areWellSeparated' s (Node _ nd _) (Leaf p) = pointBox' s (p^.core) (nd^.bBox)+-- areWellSeparated' s (Node _ ld _) (Node _ rd _) = boxBox' s (ld^.bBox) (rd^.bBox)++boxBox1 :: (Floating r, Ord r, Arity d) => r -> Box d p r -> Box d p r -> Bool+boxBox1 s lb rb = euclideanDist (centerPoint lb) (centerPoint rb) >= (s+1)*d+ where+ diam b = euclideanDist (b^.minP.core.cwMin) (b^.maxP.core.cwMax)+ d = max (diam lb) (diam rb)+++++--------------------------------------------------------------------------------+-- * Helper stuff+++-- | Computes the maximum width of a splitTree+maxWidth :: (Arity d, Num r)+ => SplitTree d p r a -> r+maxWidth (Leaf _) = 0+maxWidth (Node _ (NodeData i b _) _) = fromJust $ widthIn' i b++-- | 'Computes' the bounding box of a split tree+bbOf :: Ord r => SplitTree d p r a -> Box d () r+bbOf (Leaf p) = boundingBox $ p^.core+bbOf (Node _ (NodeData _ b _) _) = b+++children' :: BinLeafTree v a -> [BinLeafTree v a]+children' (Leaf _) = []+children' (Node l _ r) = [l,r]+++-- | Turn a traversal into lens+ix' :: (Arity d, KnownNat d) => Int -> Lens' (GV.Vector d a) a+ix' i = singular (GV.element' i)+++dropIdx :: core :+ (t :+ extra) -> core :+ extra+dropIdx (p :+ (_ :+ e)) = p :+ e++--------------------------------------------------------------------------------
+ src/Algorithms/Geometry/WSPD/Types.hs view
@@ -0,0 +1,85 @@+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE UndecidableInstances #-}+--------------------------------------------------------------------------------+-- |+-- Module : Algorithms.Geometry.WSPD.Types+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+--+-- Data types that can represent a well separated pair decomposition (wspd).+--+--------------------------------------------------------------------------------+module Algorithms.Geometry.WSPD.Types+ where++import Control.Lens hiding (Level)+import Data.BinaryTree+import Data.Ext+import Data.Geometry.Box+import Data.Geometry.Point+import Data.Geometry.Vector+import qualified Data.LSeq as LSeq+import Data.Measured.Class+import qualified Data.Sequence as S+import qualified Data.Traversable as Tr++--------------------------------------------------------------------------------++type SplitTree d p r a = BinLeafTree (NodeData d r a) (Point d r :+ p)++type PointSet d p r a = SplitTree d p r a++type WSP d p r a = (PointSet d p r a, PointSet d p r a)++-- | Data that we store in the split tree+data NodeData d r a = NodeData { _splitDim :: !Int+ , _bBox :: !(Box d () r)+ , _nodeData :: !a+ }+deriving instance (Arity d, Show r, Show a) => Show (NodeData d r a)+deriving instance (Arity d, Eq r, Eq a) => Eq (NodeData d r a)++makeLenses ''NodeData++instance Semigroup v => Measured v (NodeData d r v) where+ measure = _nodeData++instance Functor (NodeData d r) where+ fmap = Tr.fmapDefault++instance Foldable (NodeData d r) where+ foldMap = Tr.foldMapDefault++instance Traversable (NodeData d r) where+ traverse f (NodeData d b x) = NodeData d b <$> f x++--------------------------------------------------------------------------------+-- * Implementation types++-- | Non-empty sequence of points.+type PointSeq d p r = LSeq.LSeq 1 (Point d r :+ p)+++data Level = Level { _unLevel :: Int+ , _widestDim :: Maybe Int+ } deriving (Show,Eq,Ord)+makeLenses ''Level++nextLevel :: Level -> Level+nextLevel (Level i _) = Level (i+1) Nothing+++type Idx = Int+++data ShortSide = L | R deriving (Show,Eq)++data FindAndCompact d r p = FAC { _leftPart :: !(S.Seq (Point d r :+ p))+ , _rightPart :: !(S.Seq (Point d r :+ p))+ , _shortSide :: !ShortSide+ }+deriving instance (Arity d, Show r, Show p) => Show (FindAndCompact d r p)+deriving instance (Arity d, Eq r, Eq p) => Eq (FindAndCompact d r p)++makeLenses ''FindAndCompact
src/Algorithms/Geometry/WellSeparatedPairDecomposition/Types.hs view
@@ -10,75 +10,11 @@ -- Data types that can represent a well separated pair decomposition (wspd). -- ---------------------------------------------------------------------------------module Algorithms.Geometry.WellSeparatedPairDecomposition.Types where--import Control.Lens hiding (Level)-import Data.BinaryTree-import Data.Ext-import Data.Geometry.Box-import Data.Geometry.Point-import Data.Geometry.Vector-import qualified Data.LSeq as LSeq-import Data.Measured.Class-import qualified Data.Sequence as S-import qualified Data.Traversable as Tr------------------------------------------------------------------------------------type SplitTree d p r a = BinLeafTree (NodeData d r a) (Point d r :+ p)--type PointSet d p r a = SplitTree d p r a--type WSP d p r a = (PointSet d p r a, PointSet d p r a)---- | Data that we store in the split tree-data NodeData d r a = NodeData { _splitDim :: !Int- , _bBox :: !(Box d () r)- , _nodeData :: !a- }-deriving instance (Arity d, Show r, Show a) => Show (NodeData d r a)-deriving instance (Arity d, Eq r, Eq a) => Eq (NodeData d r a)--makeLenses ''NodeData--instance Semigroup v => Measured v (NodeData d r v) where- measure = _nodeData--instance Functor (NodeData d r) where- fmap = Tr.fmapDefault--instance Foldable (NodeData d r) where- foldMap = Tr.foldMapDefault--instance Traversable (NodeData d r) where- traverse f (NodeData d b x) = NodeData d b <$> f x------------------------------------------------------------------------------------- * Implementation types--type PointSeq d p r = LSeq.LSeq 1 (Point d r :+ p)---data Level = Level { _unLevel :: Int- , _widestDim :: Maybe Int- } deriving (Show,Eq,Ord)-makeLenses ''Level--nextLevel :: Level -> Level-nextLevel (Level i _) = Level (i+1) Nothing----type Idx = Int---data ShortSide = L | R deriving (Show,Eq)--data FindAndCompact d r p = FAC { _leftPart :: !(S.Seq (Point d r :+ p))- , _rightPart :: !(S.Seq (Point d r :+ p))- , _shortSide :: !ShortSide- }-deriving instance (Arity d, Show r, Show p) => Show (FindAndCompact d r p)-deriving instance (Arity d, Eq r, Eq p) => Eq (FindAndCompact d r p)+-- FIXME: This module should be internal and not exposed. Fix after 2021-06-01.+module Algorithms.Geometry.WellSeparatedPairDecomposition.Types+ {-# DEPRECATED "This module will be deleted after 2021-06-01. \+ \Use Algorithms.Geometry.WSPD instead." #-}+ ( module Algorithms.Geometry.WSPD.Types )+ where -makeLenses ''FindAndCompact+import Algorithms.Geometry.WSPD.Types
src/Algorithms/Geometry/WellSeparatedPairDecomposition/WSPD.hs view
@@ -8,453 +8,10 @@ -- Algorithm to construct a well separated pair decomposition (wspd). -- ---------------------------------------------------------------------------------module Algorithms.Geometry.WellSeparatedPairDecomposition.WSPD where--import Algorithms.Geometry.WellSeparatedPairDecomposition.Types-import Control.Lens hiding (Level, levels)-import Control.Monad.Reader-import Control.Monad.ST (ST,runST)-import Data.BinaryTree-import Data.Ext-import qualified Data.Foldable as F-import Data.Geometry.Box-import Data.Geometry.Point-import Data.Geometry.Properties-import Data.Geometry.Transformation-import Data.Geometry.Vector-import qualified Data.Geometry.Vector as GV-import qualified Data.IntMap.Strict as IntMap-import qualified Data.LSeq as LSeq-import Data.LSeq (LSeq,toSeq,ViewL(..),ViewR(..),pattern (:<|))-import qualified Data.List as L-import qualified Data.List.NonEmpty as NonEmpty-import Data.Maybe-import Data.Ord (comparing)-import Data.Range-import qualified Data.Range as Range-import qualified Data.Sequence as S-import qualified Data.Vector as V-import qualified Data.Vector.Mutable as MV-import GHC.TypeLits--import Debug.Trace-------------------------------------------------------------------------------------- | Construct a split tree------ running time: \(O(n \log n)\)-fairSplitTree :: (Fractional r, Ord r, Arity d, 1 <= d- , Show r, Show p- )- => NonEmpty.NonEmpty (Point d r :+ p) -> SplitTree d p r ()-fairSplitTree pts = foldUp node' Leaf $ fairSplitTree' n pts'+module Algorithms.Geometry.WellSeparatedPairDecomposition.WSPD+ {-# DEPRECATED "This module will be deleted after 2021-06-01. \+ \Use Algorithms.Geometry.WSPD instead." #-}+ ( module Algorithms.Geometry.WSPD ) where- pts' = imap sortOn . pure . g $ pts- n = length $ pts'^.GV.element (C :: C 0) - sortOn' i = NonEmpty.sortWith (^.core.unsafeCoord i)- sortOn i = LSeq.fromNonEmpty . sortOn' (i + 1)- -- sorts the points on the first coordinate, and then associates each point- -- with an index,; its rank in terms of this first coordinate.- g = NonEmpty.zipWith (\i (p :+ e) -> p :+ (i :+ e)) (NonEmpty.fromList [0..])- . sortOn' 1-- -- node' :: b -> a -> b -> b- -- node' :: SplitTree d p r () -> Int -> SplitTree d p r () -> SplitTree d p r ()- node' l j r = Node l (NodeData j (bbOf l <> bbOf r) ()) r----- | Given a split tree, generate the Well separated pairs------ running time: \(O(s^d n)\)-wellSeparatedPairs :: (Floating r, Ord r, Arity d, Arity (d + 1))- => r -> SplitTree d p r a -> [WSP d p r a]-wellSeparatedPairs s = f- where- f (Leaf _) = []- f (Node l _ r) = findPairs s l r ++ f l ++ f r------ -- | Given a split tree, generate the well separated pairs such that one set is--- -- a singleton.--- -- running time: \(O(s^d n\log n)\)--- wellSeparatedPairSingletons :: (Fractional r, Ord r, AlwaysTrueWSPD d)--- => r -> SplitTree d p r a -> [(Point d r :+ p, PointSet d p r (Sized a))]--- wellSeparatedPairSingletons s t = concatMap split $ wellSeparatedPairs s t'--- where--- split (l,r) = undefined--- -- | measure l <= measure r = map (,r) $ F.toList l--- -- | otherwise = map (,l) $ F.toList r--- t' = foldUpData (\l nd r -> )---- t-------------------------------------------------------------------------------------- * Building the split tree---- | Given the points, sorted in every dimension, recursively build a split tree------ The algorithm works in rounds. Each round takes O(n) time, and halves the--- number of points. Thus, the total running time is O(n log n).------ The algorithm essentially builds a path in the split tree; at every node on--- the path that we construct, we split the point set into two sets (L,R)--- according to the longest side of the bounding box.------ The smaller set is "assigned" to the current node and set asside. We--- continue to build the path with the larger set until the total number of--- items remaining is less than n/2.------ To start the next round, each node on the path needs to have the points--- assigned to that node, sorted in each dimension (i.e. the Vector--- (PointSeq))'s. Since we have the level assignment, we can compute these--- lists by traversing each original input list (i.e. one for every dimension)--- once, and partition the points based on their level assignment.-fairSplitTree' :: (Fractional r, Ord r, Arity d, 1 <= d- , Show r, Show p- )- => Int -> GV.Vector d (PointSeq d (Idx :+ p) r)- -> BinLeafTree Int (Point d r :+ p)-fairSplitTree' n pts- | n <= 1 = let p = LSeq.head $ pts^.GV.element (C :: C 0) in Leaf (dropIdx p)- | otherwise = foldr node' (V.last path) $ V.zip nodeLevels (V.init path)- where- -- note that points may also be assigned level 'Nothing'.- (levels, nodeLevels'@(maxLvl NonEmpty.:| _)) = runST $ do- lvls <- MV.replicate n Nothing- ls <- runReaderT (assignLevels (n `div` 2) 0 pts (Level 0 Nothing) []) lvls- lvls' <- V.unsafeFreeze lvls- pure (lvls',ls)-- -- TODO: We also need to report the levels in the order in which they are- -- assigned to nodes-- nodeLevels = V.fromList . L.reverse . NonEmpty.toList $ nodeLevels'-- -- levels = traceShow ("Levels",levels',maxLvl) levels'-- -- path = traceShow ("path", path',nodeLevels) path'- distrPts = distributePoints (1 + maxLvl^.unLevel) levels pts-- path = recurse <$> distrPts -- (traceShow ("distributed pts",distrPts) distrPts)-- -- node' (lvl,lc) rc | traceShow ("node' ",lvl,lc,rc) False = undefined- node' (lvl,lc) rc = case lvl^?widestDim._Just of- Nothing -> error "Unknown widest dimension"- Just j -> Node lc j rc- recurse pts' = fairSplitTree' (length $ pts'^.GV.element (C :: C 0))- (reIndexPoints pts')---- | Assign the points to their the correct class. The 'Nothing' class is--- considered the last class-distributePoints :: (Arity d , Show r, Show p)- => Int -> V.Vector (Maybe Level)- -> GV.Vector d (PointSeq d (Idx :+ p) r)- -> V.Vector (GV.Vector d (PointSeq d (Idx :+ p) r))-distributePoints k levels = transpose . fmap (distributePoints' k levels)--transpose :: Arity d => GV.Vector d (V.Vector a) -> V.Vector (GV.Vector d a)-transpose = V.fromList . map GV.vectorFromListUnsafe . L.transpose- . map V.toList . F.toList---- | Assign the points to their the correct class. The 'Nothing' class is--- considered the last class-distributePoints' :: Int -- ^ number of classes- -> V.Vector (Maybe Level) -- ^ level assignment- -> PointSeq d (Idx :+ p) r -- ^ input points- -> V.Vector (PointSeq d (Idx :+ p) r)-distributePoints' k levels pts- | otherwise- = fmap fromSeqUnsafe $ V.create $ do- v <- MV.replicate k mempty- forM_ pts $ \p ->- append v (level p) p- pure v- where- level p = maybe (k-1) _unLevel $ levels V.! (p^.extra.core)- append v i p = MV.read v i >>= MV.write v i . (S.|> p)--fromSeqUnsafe = LSeq.promise . LSeq.fromSeq---- | Given a sequence of points, whose index is increasing in the first--- dimension, i.e. if idx p < idx q, then p[0] < q[0].--- Reindex the points so that they again have an index--- in the range [0,..,n'], where n' is the new number of points.------ running time: O(n' * d) (more or less; we are actually using an intmap for--- the lookups)------ alternatively: I can unsafe freeze and thaw an existing vector to pass it--- along to use as mapping. Except then I would have to force the evaluation--- order, i.e. we cannot be in 'reIndexPoints' for two of the nodes at the same--- time.------ so, basically, run reIndex points in ST as well.-reIndexPoints :: (Arity d, 1 <= d)- => GV.Vector d (PointSeq d (Idx :+ p) r)- -> GV.Vector d (PointSeq d (Idx :+ p) r)-reIndexPoints ptsV = fmap reIndex ptsV- where- pts = ptsV^.GV.element (C :: C 0)-- reIndex = fmap (\p -> p&extra.core %~ fromJust . flip IntMap.lookup mapping')- mapping' = IntMap.fromAscList $ zip (map (^.extra.core) . F.toList $ pts) [0..]---- | ST monad with access to the vector storign the level of the points.-type RST s = ReaderT (MV.MVector s (Maybe Level)) (ST s)---- | Assigns the points to a level. Returns the list of levels used. The first--- level in the list is the level assigned to the rest of the nodes. Their--- level is actually still set to Nothing in the underlying array.-assignLevels :: (Fractional r, Ord r, Arity d- , Show r, Show p- )- => Int -- ^ Number of items we need to collect- -> Int -- ^ Number of items we collected so far- -> GV.Vector d (PointSeq d (Idx :+ p) r)- -> Level -- ^ next level to use- -> [Level] -- ^ Levels used so far- -> RST s (NonEmpty.NonEmpty Level)-assignLevels h m pts l prevLvls- | m >= h = pure (l NonEmpty.:| prevLvls)- | otherwise = do- pts' <- compactEnds pts- -- find the widest dimension j = i+1- let j = widestDimension pts'- i = j - 1 -- traceShow ("i",j,pts') j - 1- extJ = (extends pts')^.ix' i- mid = midPoint extJ-- -- find the set of points that we have to delete, by looking at the sorted- -- list L_j. As a side effect, this will remove previously assigned points- -- from L_j.- (lvlJPts,deletePts) <- findAndCompact j (pts'^.ix' i) mid- let pts'' = pts'&ix' i .~ lvlJPts- l' = l&widestDim .~ Just j- forM_ deletePts $ \p ->- assignLevel p l'- assignLevels h (m + length deletePts) pts'' (nextLevel l) (l' : prevLvls)---- | Remove already assigned pts from the ends of all vectors.-compactEnds :: Arity d- => GV.Vector d (PointSeq d (Idx :+ p) r)- -> RST s (GV.Vector d (PointSeq d (Idx :+ p) r))-compactEnds = traverse compactEnds'---- | Assign level l to point p-assignLevel :: (c :+ (Idx :+ p)) -> Level -> RST s ()-assignLevel p l = ask >>= \levels -> lift $ MV.write levels (p^.extra.core) (Just l)---- | Get the level of a point-levelOf :: (c :+ (Idx :+ p)) -> RST s (Maybe Level)-levelOf p = ask >>= \levels -> lift $ MV.read levels (p^.extra.core)---- | Test if the point already has a level assigned to it.-hasLevel :: c :+ (Idx :+ p) -> RST s Bool-hasLevel = fmap isJust . levelOf---- | Remove allready assigned points from the sequence------ pre: there are points remaining-compactEnds' :: PointSeq d (Idx :+ p) r- -> RST s (PointSeq d (Idx :+ p) r)-compactEnds' (l0 :<| s0) = fmap fromSeqUnsafe . goL $ l0 S.<| toSeq s0- where- goL s@(S.viewl -> l S.:< s') = hasLevel l >>= \case- False -> goR s- True -> goL s'- goR s@(S.viewr -> s' S.:> r) = hasLevel r >>= \case- False -> pure s- True -> goR s'----- | Given the points, ordered by their j^th coordinate, split the point set--- into a "left" and a "right" half, i.e. the points whose j^th coordinate is--- at most the given mid point m, and the points whose j^th coordinate is--- larger than m.------ We return a pair (Largest set, Smallest set)---------fi ndAndCompact works by simultaneously traversing the points from left to--- right, and from right to left. As soon as we find a point crossing the mid--- point we stop and return. Thus, in principle this takes only O(|Smallest--- set|) time.------ running time: O(|Smallest set|) + R, where R is the number of *old* points--- (i.e. points that should have been removed) in the list.-findAndCompact :: (Ord r, Arity d- , Show r, Show p- )- => Int- -- ^ the dimension we are in, i.e. so that we know- -- which coordinate of the point to compare- -> PointSeq d (Idx :+ p) r- -> r -- ^ the mid point- -> RST s ( PointSeq d (Idx :+ p) r- , PointSeq d (Idx :+ p) r- )-findAndCompact j (l0 :<| s0) m = fmap select . stepL $ l0 S.<| toSeq s0- where- -- stepL and stepR together build a data structure (FAC l r S) that- -- contains the left part of the list, i.e. the points before midpoint, and- -- the right part of the list., and a value S that indicates which part is- -- the short side.-- -- stepL takes a step on the left side of the list; if the left point l- -- already has been assigned, we continue waling along (and "ignore" the- -- point). If it has not been assigned, and is before the mid point, we- -- take a step from the right, and add l onto the left part. If it is- -- larger than the mid point, we have found our split.- -- stepL :: S.Seq (Point d r :+ (Idx :+ p)) -> ST s (FindAndCompact d r (Idx :+ p))- stepL s = case S.viewl s of- S.EmptyL -> pure $ FAC mempty mempty L- l S.:< s' -> hasLevel l >>= \case- False -> if l^.core.unsafeCoord j <= m- then addL l <$> stepR s'- else pure $ FAC mempty s L- True -> stepL s' -- delete, continue left-- -- stepR :: S.Seq (Point d r :+ (Idx :+ p)) -> ST s (FindAndCompact d r (Idx :+ p))- stepR s = case S.viewr s of- S.EmptyR -> pure $ FAC mempty mempty R- s' S.:> r -> hasLevel r >>= \case- False -> if r^.core.unsafeCoord j >= m- then addR r <$> stepL s'- else pure $ FAC s mempty R- True -> stepR s'--- addL l x = x&leftPart %~ (l S.<|)- addR r x = x&rightPart %~ (S.|> r)-- select = over both fromSeqUnsafe . select'-- -- select' f | traceShow ("select'", f) False = undefined- select' (FAC l r L) = (r, l)- select' (FAC l r R) = (l, r)----- | Find the widest dimension of the point set------ pre: points are sorted according to their dimension-widestDimension :: (Num r, Ord r, Arity d) => GV.Vector d (PointSeq d p r) -> Int-widestDimension = fst . L.maximumBy (comparing snd) . zip [1..] . F.toList . widths--widths :: (Num r, Arity d) => GV.Vector d (PointSeq d p r) -> GV.Vector d r-widths = fmap Range.width . extends------ | get the extends of the set of points in every dimension, i.e. the left and--- right boundaries.------ pre: points are sorted according to their dimension-extends :: Arity d => GV.Vector d (PointSeq d p r) -> GV.Vector d (Range r)-extends = imap (\i pts ->- ClosedRange ((LSeq.head pts)^.core.unsafeCoord (i + 1))- ((LSeq.last pts)^.core.unsafeCoord (i + 1)))-------------------------------------------------------------------------------------- * Finding Well Separated Pairs--findPairs :: (Floating r, Ord r, Arity d, Arity (d + 1))- => r -> SplitTree d p r a -> SplitTree d p r a- -> [WSP d p r a]-findPairs s l r- | areWellSeparated' s l r = [(l,r)]- | maxWidth l <= maxWidth r = concatMap (findPairs s l) $ children' r- | otherwise = concatMap (findPairs s r) $ children' l----- | Test if the two sets are well separated with param s-areWellSeparated :: (Arity d, Arity (d + 1), Fractional r, Ord r)- => r -- ^ separation factor- -> SplitTree d p r a- -> SplitTree d p r a -> Bool-areWellSeparated _ (Leaf _) (Leaf _) = True-areWellSeparated s l r = boxBox s (bbOf l) (bbOf r)----- areWellSeparated s (Leaf p) (Node _ nd _) = pointBox s (p^.core) (nd^.bBox)--- areWellSeparated s (Node _ nd _) (Leaf p) = pointBox s (p^.core) (nd^.bBox)--- areWellSeparated s (Node _ ld _) (Node _ rd _) = boxBox s (ld^.bBox) (rd^.bBox)----- -- | Test if the point and the box are far enough appart--- pointBox :: (Fractional r, Ord r, AlwaysTruePFT d, AlwaysTrueTransformation d)--- => r -> Point d r -> Box d p r -> Bool--- pointBox s p b = not $ p `inBox` b'--- where--- v = (centerPoint b)^.vector--- b' = translateBy v . scaleUniformlyBy s . translateBy ((-1) *^ v) $ b---- | Test if the two boxes are sufficiently far appart-boxBox :: (Fractional r, Ord r, Arity d, Arity (d + 1))- => r -> Box d p r -> Box d p r -> Bool-boxBox s lb rb = boxBox' lb rb && boxBox' rb lb- where- boxBox' b' b = not $ b' `intersects` bOut- where- v = (centerPoint b)^.vector- bOut = translateBy v . scaleUniformlyBy s . translateBy ((-1) *^ v) $ b------------------------------------------------------------------------------------- * Alternative def if wellSeparated that uses fractional---areWellSeparated' :: (Floating r, Ord r, Arity d)- => r- -> SplitTree d p r a- -> SplitTree d p r a- -> Bool-areWellSeparated' _ (Leaf _) (Leaf _) = True-areWellSeparated' s l r = boxBox1 s (bbOf l) (bbOf r)---- (Leaf p) (Node _ nd _) = pointBox' s (p^.core) (nd^.bBox)--- areWellSeparated' s (Node _ nd _) (Leaf p) = pointBox' s (p^.core) (nd^.bBox)--- areWellSeparated' s (Node _ ld _) (Node _ rd _) = boxBox' s (ld^.bBox) (rd^.bBox)--boxBox1 :: (Floating r, Ord r, Arity d) => r -> Box d p r -> Box d p r -> Bool-boxBox1 s lb rb = euclideanDist (centerPoint lb) (centerPoint rb) >= (s+1)*d- where- diam b = euclideanDist (b^.minP.core.cwMin) (b^.maxP.core.cwMax)- d = max (diam lb) (diam rb)---------------------------------------------------------------------------------------- * Helper stuff----- | Computes the maximum width of a splitTree-maxWidth :: (Arity d, Num r)- => SplitTree d p r a -> r-maxWidth (Leaf _) = 0-maxWidth (Node _ (NodeData i b _) _) = fromJust $ widthIn' i b---- | 'Computes' the bounding box of a split tree-bbOf :: Ord r => SplitTree d p r a -> Box d () r-bbOf (Leaf p) = boundingBox $ p^.core-bbOf (Node _ (NodeData _ b _) _) = b---children' :: BinLeafTree v a -> [BinLeafTree v a]-children' (Leaf _) = []-children' (Node l _ r) = [l,r]----- | Turn a traversal into lens-ix' :: (Arity d, KnownNat d) => Int -> Lens' (GV.Vector d a) a-ix' i = singular (GV.element' i)---dropIdx :: core :+ (t :+ extra) -> core :+ extra-dropIdx (p :+ (_ :+ e)) = p :+ e----------------------------------------------------------------------------------+import Algorithms.Geometry.WSPD
src/Data/Geometry.hs view
@@ -26,7 +26,7 @@ import Data.Geometry.LineSegment import Data.Geometry.Point import Data.Geometry.PolyLine hiding (fromPoints)-import Data.Geometry.Polygon hiding (fromPoints)+import Data.Geometry.Polygon hiding (fromPoints, maximumBy, minimumBy) import Data.Geometry.Properties import Data.Geometry.Transformation -- import Linear.Affine hiding (Point, Vector, origin)
src/Data/Geometry/Arrangement/Internal.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TemplateHaskell #-} -------------------------------------------------------------------------------- -- | -- Module : Data.Geometry.Arrangement.Internal@@ -13,9 +13,10 @@ import Algorithms.BinarySearch import Control.Lens-import qualified Data.CircularSeq as CSeq+import Data.Bifunctor+import qualified Data.CircularSeq as CSeq import Data.Ext-import qualified Data.Foldable as F+import qualified Data.Foldable as F import Data.Geometry.Boundary import Data.Geometry.Box import Data.Geometry.Line@@ -23,10 +24,10 @@ import Data.Geometry.PlanarSubdivision import Data.Geometry.Point import Data.Geometry.Properties-import qualified Data.List as List+import qualified Data.List as List import Data.Maybe-import Data.Ord (Down(..))-import qualified Data.Vector as V+import Data.Ord (Down (..))+import qualified Data.Vector as V import Data.Vinyl.CoRec --------------------------------------------------------------------------------@@ -97,7 +98,7 @@ computeSegsAndParts rect ls = ( segs <> boundarySegs, parts') where segs = map (&extra %~ Just)- . concatMap (\(l,ls') -> perLine rect l ls') $ makePairs ls+ . concatMap (uncurry (perLine rect)) $ makePairs ls boundarySegs = map (:+ Nothing) . toSegments . dupFirst $ map fst parts' dupFirst = \case [] -> [] xs@(x:_) -> xs ++ [x]@@ -112,7 +113,7 @@ rmDuplicates = map head . List.group vs = mapMaybe (m `intersectionPoint`) ls vs' = maybe [] (\(p,q) -> [p,q]) . asA @(Point 2 r, Point 2 r)- $ (m^.core) `intersect` (Boundary b)+ $ (m^.core) `intersect` Boundary b intersectionPoint :: forall r l. (Ord r, Fractional r)@@ -121,7 +122,7 @@ toSegments :: Ord r => [Point 2 r] -> [LineSegment 2 () r]-toSegments ps = let pts = map ext $ ps in+toSegments ps = let pts = map ext ps in zipWith ClosedLineSegment pts (tail pts) @@ -181,7 +182,7 @@ => [Line 2 r :+ l] -> LineSegment 2 q r -> [(Point 2 r, Line 2 r :+ l)] sideIntersections ls s = let l = supportingLine s :+ undefined- in List.sortOn fst . filter (flip onSegment s . fst)+ in List.sortOn fst . filter ((`intersects` s) . fst) . mapMaybe (\m -> (,m) <$> l `intersectionPoint` m) $ ls -- | Constructs the unbounded intersections. Reported in clockwise direction.@@ -192,8 +193,8 @@ unBoundedParts rect ls = [tl] <> t <> [tr] <> reverse r <> [br] <> reverse b <> [bl] <> l where sideIntersections' = over (traverse._2) Just . sideIntersections ls- Sides t r b l = fmap sideIntersections' $ sides rect- Corners tl tr br bl = fmap ((,Nothing) . (^.core)) $ corners rect+ Sides t r b l = sideIntersections' <$> sides rect+ Corners tl tr br bl = (,Nothing) . (^.core) <$> corners rect -- | Links the vertices of the outer boundary with those in the subdivision@@ -212,10 +213,10 @@ makePairs = go where go [] = []- go (x:xs) = (x,xs) : map (\(y,ys) -> (y,x:ys)) (go xs)+ go (x:xs) = (x,xs) : map (second (x:)) (go xs) -allPairs :: [a] -> [(a,a)]-allPairs ys = go ys+allPairs :: [a] -> [(a,a)]+allPairs = go where go [] = [] go (x:xs) = map (x,) xs ++ go xs@@ -244,7 +245,7 @@ => Line 2 r -> Arrangement s l v (Maybe e) f r -> Maybe (Dart s) findStart l arr = do (p,_) <- asA @(Point 2 r, Point 2 r) $- l `intersect` (Boundary $ arr^.boundedArea)+ l `intersect` Boundary (arr^.boundedArea) (_,v,_) <- findStartVertex p arr findStartDart (arr^.subdivision) v @@ -264,13 +265,13 @@ -> Maybe (Point 2 r, VertexId' s, Maybe (Line 2 r :+ l)) findStartVertex p arr = do ss <- findSide p- i <- binarySearchVec (pred' ss) (arr^.unboundedIntersections)+ i <- binarySearchIdxIn (pred' ss) (arr^.unboundedIntersections) pure $ arr^.unboundedIntersections.singular (ix i) where Sides t r b l = sides'' $ arr^.boundedArea sides'' = fmap (\(ClosedLineSegment a c) -> LineSegment (Closed a) (Open c)) . sides - findSide q = fmap fst . List.find (onSegment q . snd) $ zip [1..] [t,r,b,l]+ findSide q = fmap fst . List.find (intersects q. snd) $ zip [1..] [t,r,b,l] pred' ss (q,_,_) = let Just j = findSide q x = before (ss,p) (j,q)
src/Data/Geometry/Ball.hs view
@@ -75,6 +75,7 @@ -- * Querying if a point lies in a ball +-- | Query location of a point relative to a d-dimensional ball. inBall :: (Arity d, Ord r, Num r) => Point d r -> Ball d p r -> PointLocationResult p `inBall` (Ball c sr) = case qdA p (c^.core) `compare` sr of@@ -148,17 +149,18 @@ pattern Circle c r = Sphere c r {-# COMPLETE Circle #-} +{- HLINT ignore disk -} -- | Given three points, get the disk through the three points. If the three -- input points are colinear we return Nothing -- -- >>> disk (Point2 0 10) (Point2 10 0) (Point2 (-10) 0)--- Just (Ball {_center = Point2 [0.0,0.0] :+ (), _squaredRadius = 100.0})+-- Just (Ball {_center = Point2 0.0 0.0 :+ (), _squaredRadius = 100.0}) disk :: (Eq r, Fractional r) => Point 2 r -> Point 2 r -> Point 2 r -> Maybe (Disk () r) disk p q r = match (f p `intersect` f q) $- (H $ \NoIntersection -> Nothing)- :& (H $ \c@(Point _) -> Just $ Ball (ext c) (qdA c p))- :& (H $ \_ -> Nothing)+ H (\NoIntersection -> Nothing)+ :& H (\c@Point{} -> Just $ Ball (ext c) (qdA c p))+ :& H (\_ -> Nothing) :& RNil -- If the intersection is not a point, The two lines f p and f q are -- parallel, that means the three input points where colinear.@@ -196,7 +198,7 @@ ] -instance (Ord r, Floating r) => (Line 2 r) `IsIntersectableWith` (Circle p r) where+instance (Ord r, Floating r) => Line 2 r `IsIntersectableWith` Circle p r where nonEmptyIntersection = defaultNonEmptyIntersection @@ -238,16 +240,16 @@ ] -instance (Ord r, Floating r) => (LineSegment 2 p r) `IsIntersectableWith` (Circle q r) where+instance (Ord r, Floating r) => LineSegment 2 p r `IsIntersectableWith` Circle q r where nonEmptyIntersection = defaultNonEmptyIntersection s `intersect` c = match (supportingLine s `intersect` c) $- (H $ \NoIntersection -> coRec NoIntersection)- :& (H $ \(Touching p) -> if p `onSegment` s then coRec $ Touching p+ H (\NoIntersection -> coRec NoIntersection)+ :& H (\(Touching p) -> if p `intersects` s then coRec $ Touching p else coRec NoIntersection )- :& (H $ \(p,q) -> case (p `onSegment` s, q `onSegment` s) of+ :& H (\(p,q) -> case (p `intersects` s, q `intersects` s) of (False,False) -> coRec NoIntersection (False,True) -> coRec q (True, False) -> coRec p
src/Data/Geometry/BezierSpline.hs view
@@ -1,5 +1,11 @@ {-# LANGUAGE UndecidableInstances #-}-{-# LANGUAGE TemplateHaskell #-}+--------------------------------------------------------------------------------+-- |+-- Module : Data.Geometry.BezierSpline+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+-------------------------------------------------------------------------------- module Data.Geometry.BezierSpline( BezierSpline (BezierSpline) , controlPoints@@ -34,18 +40,22 @@ -- | Datatype representing a Bezier curve of degree \(n\) in \(d\)-dimensional space. newtype BezierSpline n d r = BezierSpline { _controlPoints :: LSeq (1+n) (Point d r) }-makeLenses ''BezierSpline+-- makeLenses ''BezierSpline +-- | Bezier control points. With n degrees, there are n+1 control points.+controlPoints :: Iso (BezierSpline n1 d1 r1) (BezierSpline n2 d2 r2) (LSeq (1+n1) (Point d1 r1)) (LSeq (1+n2) (Point d2 r2))+controlPoints = iso _controlPoints BezierSpline+ -- | Quadratic Bezier Spline pattern Bezier2 :: Point d r -> Point d r -> Point d r -> BezierSpline 2 d r-pattern Bezier2 p q r <- ((F.toList . LSeq.take 3 . _controlPoints) -> [p,q,r])+pattern Bezier2 p q r <- (F.toList . LSeq.take 3 . _controlPoints -> [p,q,r]) where Bezier2 p q r = fromPointSeq . Seq.fromList $ [p,q,r] {-# COMPLETE Bezier2 #-} -- | Cubic Bezier Spline pattern Bezier3 :: Point d r -> Point d r -> Point d r -> Point d r -> BezierSpline 3 d r-pattern Bezier3 p q r s <- ((F.toList . LSeq.take 4 . _controlPoints) -> [p,q,r,s])+pattern Bezier3 p q r s <- (F.toList . LSeq.take 4 . _controlPoints -> [p,q,r,s]) where Bezier3 p q r s = fromPointSeq . Seq.fromList $ [p,q,r,s] {-# COMPLETE Bezier3 #-}@@ -97,7 +107,7 @@ blend p q = p .+^ t *^ (q .-. p) -+-- | Tangent to the bezier spline at the starting point. tangent :: (Arity d, Num r, 1 <= n) => BezierSpline n d r -> Vector d r tangent b = b^?!controlPoints.ix 1 .-. b^?!controlPoints.ix 0
src/Data/Geometry/Boundary.hs view
@@ -1,3 +1,10 @@+--------------------------------------------------------------------------------+-- |+-- Module : Data.Geometry.Boundary+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+-------------------------------------------------------------------------------- module Data.Geometry.Boundary where import Control.Lens (iso,Iso)
src/Data/Geometry/Box/Corners.hs view
@@ -1,4 +1,11 @@ {-# LANGUAGE TemplateHaskell #-}+--------------------------------------------------------------------------------+-- |+-- Module : Data.Geometry.Box.Corners+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+-------------------------------------------------------------------------------- module Data.Geometry.Box.Corners( Corners(Corners), northWest, northEast, southEast, southWest , corners, cornersInDirection ) where@@ -51,6 +58,7 @@ -------------------------------------------------------------------------------- +{- HLINT ignore corners -} -- | Get the corners of a rectangle, the order is: -- (TopLeft, TopRight, BottomRight, BottomLeft). -- The extra values in the Top points are taken from the Top point,@@ -59,8 +67,8 @@ corners r = let w = width r p = (_maxP r)&core %~ _cwMax q = (_minP r)&core %~ _cwMin- in Corners (p&core.xCoord %~ (subtract w)) p- (q&core.xCoord %~ (+ w)) q+ in Corners (p&core.xCoord %~ subtract w) p+ (q&core.xCoord %~ (+ w)) q --------------------------------------------------------------------------------
src/Data/Geometry/Box/Internal.hs view
@@ -89,6 +89,7 @@ in fromExtent $ FV.zipWith f (toVec c) ((/2) <$> ws) +{- HLINT ignore centerPoint -} -- | Center of the box centerPoint :: (Arity d, Fractional r) => Box d p r -> Point d r centerPoint b = Point $ w V.^/ 2@@ -105,7 +106,7 @@ type instance IntersectionOf (Box d p r) (Box d q r) = '[ NoIntersection, Box d () r] -instance (Ord r, Arity d) => (Box d p r) `IsIntersectableWith` (Box d q r) where+instance (Ord r, Arity d) => Box d p r `IsIntersectableWith` Box d q r where nonEmptyIntersection = defaultNonEmptyIntersection bx `intersect` bx' = f . sequence $ FV.zipWith intersect' (extent bx) (extent bx')@@ -144,7 +145,7 @@ type instance IntersectionOf (Point d r) (Box d p r) = '[ NoIntersection, Point d r] -instance (Arity d, Ord r) => (Point d r) `IsIntersectableWith` (Box d p r) where+instance (Arity d, Ord r) => Point d r `IsIntersectableWith` Box d p r where nonEmptyIntersection = defaultNonEmptyIntersection p `intersect` b | not $ p `inBox` b = coRec NoIntersection@@ -187,12 +188,25 @@ inBox :: (Arity d, Ord r) => Point d r -> Box d p r -> Bool p `inBox` b = FV.and . FV.zipWith R.inRange (toVec p) . extent $ b ++-- | Check if a point lies strictly inside a box (i.e. not on its boundary)+--+-- >>> origin `inBox` (boundingBoxList' [Point3 1 2 3, Point3 10 20 30] :: Box 3 () Int)+-- False+-- >>> origin `inBox` (boundingBoxList' [Point3 (-1) (-2) (-3), Point3 10 20 30] :: Box 3 () Int)+-- True+insideBox :: (Arity d, Ord r) => Point d r -> Box d p r -> Bool+p `insideBox` b = FV.and . FV.zipWith R.inRange (toVec p) . fmap toOpenRange . extent $ b+ where+ toOpenRange (R.Range' l r) = R.OpenRange l r++ -- | Get a vector with the extent of the box in each dimension. Note that the -- resulting vector is 0 indexed whereas one would normally count dimensions -- starting at zero. -- -- >>> extent (boundingBoxList' [Point3 1 2 3, Point3 10 20 30] :: Box 3 () Int)--- Vector3 [Range (Closed 1) (Closed 10),Range (Closed 2) (Closed 20),Range (Closed 3) (Closed 30)]+-- Vector3 (Range (Closed 1) (Closed 10)) (Range (Closed 2) (Closed 20)) (Range (Closed 3) (Closed 30)) extent :: Arity d => Box d p r -> Vector d (R.Range r) extent (Box (CWMin a :+ _) (CWMax b :+ _)) = FV.zipWith R.ClosedRange (toVec a) (toVec b)@@ -201,7 +215,7 @@ -- whereas one would normally count dimensions starting at zero. -- -- >>> size (boundingBoxList' [origin, Point3 1 2 3] :: Box 3 () Int)--- Vector3 [1,2,3]+-- Vector3 1 2 3 size :: (Arity d, Num r) => Box d p r -> Vector d r size = fmap R.width . extent @@ -233,6 +247,7 @@ type Rectangle = Box 2 +-- | -- >>> width (boundingBoxList' [origin, Point2 1 2] :: Rectangle () Int) -- 1 -- >>> width (boundingBoxList' [origin] :: Rectangle () Int)@@ -240,6 +255,7 @@ width :: Num r => Rectangle p r -> r width = widthIn (C :: C 1) +-- | -- >>> height (boundingBoxList' [origin, Point2 1 2] :: Rectangle () Int) -- 2 -- >>> height (boundingBoxList' [origin] :: Rectangle () Int)@@ -256,7 +272,7 @@ class IsBoxable g where boundingBox :: Ord (NumType g) => g -> Box (Dimension g) () (NumType g) -+-- | Create a bounding box that encapsulates a list of objects. boundingBoxList :: (IsBoxable g, F.Foldable1 c, Ord (NumType g), Arity (Dimension g)) => c g -> Box (Dimension g) () (NumType g) boundingBoxList = F.foldMap1 boundingBox
src/Data/Geometry/Box/Sides.hs view
@@ -1,4 +1,11 @@ {-# LANGUAGE TemplateHaskell #-}+--------------------------------------------------------------------------------+-- |+-- Module : Data.Geometry.Box.Sides+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+-------------------------------------------------------------------------------- module Data.Geometry.Box.Sides( Sides(Sides), north, east, south, west , topSide, bottomSide, leftSide, rightSide , sides, sides'
src/Data/Geometry/Directions.hs view
@@ -1,22 +1,29 @@-{-# LANGUAGE TemplateHaskell #-}+--------------------------------------------------------------------------------+-- |+-- Module : Data.Geometry.Directions+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+--+-------------------------------------------------------------------------------- module Data.Geometry.Directions( CardinalDirection(..)- , _North, _East, _South, _West+ -- , _North, _East, _South, _West , oppositeDirection , InterCardinalDirection(..)- , _NorthWest, _NorthEast, _SouthEast, _SouthWest+ -- , _NorthWest, _NorthEast, _SouthEast, _SouthWest , interCardinalsOf ) where -import Control.Lens (makePrisms) import Data.Util import GHC.Generics (Generic) -------------------------------------------------------------------------------- +-- | The four cardinal directions. data CardinalDirection = North | East | South | West deriving (Show,Read,Eq,Ord,Enum,Bounded)-makePrisms ''CardinalDirection+-- makePrisms ''CardinalDirection -------------------------------------------------------------------------------- -- * Functions on Cardinal Directions@@ -34,7 +41,7 @@ -- | Intercardinal directions data InterCardinalDirection = NorthWest | NorthEast | SouthEast | SouthWest deriving (Show,Read,Eq,Ord,Enum,Generic)-makePrisms ''InterCardinalDirection+-- makePrisms ''InterCardinalDirection -------------------------------------------------------------------------------- -- * Functions on InterCardinal Directions
src/Data/Geometry/Duality.hs view
@@ -1,3 +1,10 @@+--------------------------------------------------------------------------------+-- |+-- Module : Data.Geometry.Duality+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+-------------------------------------------------------------------------------- module Data.Geometry.Duality where import Data.Geometry.Line
src/Data/Geometry/Ellipse.hs view
@@ -1,4 +1,11 @@ {-# LANGUAGE TemplateHaskell #-}+--------------------------------------------------------------------------------+-- |+-- Module : Data.Geometry.Ellipse+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+-------------------------------------------------------------------------------- module Data.Geometry.Ellipse( Ellipse(Ellipse) , affineTransformation@@ -18,7 +25,7 @@ -------------------------------------------------------------------------------- --- | A typre representing planar ellipses+-- | A type representing planar ellipses newtype Ellipse r = Ellipse { _affineTransformation :: Transformation 2 r } deriving (Show,Eq,Functor,Foldable,Traversable) makeLenses ''Ellipse
src/Data/Geometry/HalfLine.hs view
@@ -1,13 +1,25 @@-{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE UndecidableInstances #-}-{-# LANGUAGE DeriveAnyClass #-}-module Data.Geometry.HalfLine where-+--------------------------------------------------------------------------------+-- |+-- Module : Data.Geometry.HalfLine+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+--------------------------------------------------------------------------------+module Data.Geometry.HalfLine( HalfLine(HalfLine)+ , startPoint, halfLineDirection+ , toHalfLine+ , halfLineToSubLine, fromSubLine+ ) where import Control.DeepSeq import Control.Lens import Data.Ext import qualified Data.Foldable as F+import Data.Geometry.Boundary+import Data.Geometry.Box import Data.Geometry.Interval import Data.Geometry.Line import Data.Geometry.LineSegment@@ -18,6 +30,9 @@ import Data.Geometry.Vector import qualified Data.Traversable as T import Data.UnBounded+import qualified Data.Vector.Fixed as FV+import Data.Vinyl+import Data.Vinyl.CoRec import GHC.Generics (Generic) import GHC.TypeLits @@ -41,6 +56,14 @@ type instance NumType (HalfLine d r) = r +instance {-# OVERLAPPING #-} (Eq r, Fractional r) => Eq (HalfLine 2 r) where+ (HalfLine p u) == (HalfLine q v) =+ p == q && -- Same starting point.+ isCoLinear p (Point u) (Point v) && -- Directions are on the same line.+ sameSigns -- Directions point in the same quadrant.+ where+ sameSigns = F.and $ FV.zipWith (\a b -> signum a==signum b) u v+ instance (Eq r, Fractional r, Arity d) => Eq (HalfLine d r) where (HalfLine p u) == (HalfLine q v) = let lam = scalarMultiple u v in p == q && (signum <$> lam) == Just 1@@ -77,9 +100,9 @@ (MinInfinity, Val x) -> Just $ HalfLine (pointAt x l) ((-1) *^ l^.direction) _ -> Nothing -type instance IntersectionOf (HalfLine 2 r) (Line 2 r) = [ NoIntersection- , Point 2 r- , HalfLine 2 r+type instance IntersectionOf (HalfLine d r) (Line d r) = [ NoIntersection+ , Point d r+ , HalfLine d r ] type instance IntersectionOf (HalfLine 2 r) (HalfLine 2 r) = [ NoIntersection@@ -88,88 +111,119 @@ , HalfLine 2 r ] -type instance IntersectionOf (HalfLine 2 r) (LineSegment 2 p r) = [ NoIntersection+type instance IntersectionOf (LineSegment 2 p r) (HalfLine 2 r) = [ NoIntersection , Point 2 r , LineSegment 2 () r ] +type instance IntersectionOf (Point d r) (HalfLine d r) = [ NoIntersection+ , Point d r+ ] --- instance (Ord r, Fractional r) => (HalfLine 2 r) `IsIntersectableWith` (Line 2 r) where- -- hl `intersect` l = match (halfLineToSubLine hl, l) +instance (Ord r, Fractional r) => HalfLine 2 r `IsIntersectableWith` Line 2 r where+ nonEmptyIntersection = defaultNonEmptyIntersection+ hl `intersect` l = match (supportingLine hl `intersect` l) $+ H (\NoIntersection -> coRec NoIntersection)+ :& H (\p -> if onHalfLine p hl then coRec p else coRec NoIntersection)+ :& H (\_l' -> coRec hl)+ :& RNil --- instance (Ord r, Fractional r) => (HalfLine 2 r) `IsIntersectableWith` (Line 2 r) where--- data Intersection (HalfLine 2 r) (Line 2 r) = NoHalfLineLineIntersection--- | HalfLineLineIntersection !(Point 2 r)--- | HalfLineLineOverlap !(HalfLine 2 r)--- deriving (Show,Eq) --- nonEmptyIntersection NoHalfLineLineIntersection = False--- nonEmptyIntersection _ = True --- hl `intersect` l = case supportingLine hl `intersect` l of--- SameLine _ -> HalfLineLineOverlap hl--- LineLineIntersection p -> if p `onHalfLine` hl then HalfLineLineIntersection p--- else NoHalfLineLineIntersection--- ParallelLines -> NoHalfLineLineIntersection+instance (Ord r, Fractional r) => HalfLine 2 r `IsIntersectableWith` HalfLine 2 r where+ nonEmptyIntersection = defaultNonEmptyIntersection+ la@(HalfLine a va) `intersect` lb@(HalfLine b vb) =+ match (supportingLine la `intersect` supportingLine lb) $+ H (\NoIntersection -> coRec NoIntersection)+ :& H (\p -> if onHalfLine p la && onHalfLine p lb+ then coRec p else coRec NoIntersection)+ :& H (\_line -> case ( a `onHalfLine ` lb+ , b `onHalfLine ` la+ , va `sameDirection` vb+ ) of+ (False,False,_) -> coRec NoIntersection+ (True,True,True) -> coRec la -- exact same halfline!+ (True,True,False) -> coRec $ ClosedLineSegment (ext a) (ext b)+ (True,_,True) -> coRec la+ (_,True,True) -> coRec lb+ (_,_,False) -> error "HalfLine x Halfline intersection: impossible"+ -- it is impossible for a to be on+ -- lb, while b does not lie on la, while having different+ -- orientations + )+ :& RNil --- instance (Ord r, Fractional r) => (HalfLine 2 r) `IsIntersectableWith` (HalfLine 2 r) where--- data Intersection (HalfLine 2 r) (HalfLine 2 r) = NoHalfLineHalfLineIntersection--- | HLHLIntersectInPoint !(Point 2 r)--- | HLHLIntersectInSegment !(LineSegment 2 () r)--- | HLHLIntersectInHalfLine !(HalfLine 2 r)--- deriving (Show,Eq)+instance (Ord r, Fractional r) => LineSegment 2 () r `IsIntersectableWith` HalfLine 2 r where+ nonEmptyIntersection = defaultNonEmptyIntersection --- nonEmptyIntersection NoHalfLineHalfLineIntersection = False--- nonEmptyIntersection _ = True+ seg@(LineSegment s t) `intersect` hl@(HalfLine o _) =+ match (supportingLine seg `intersect` supportingLine hl) $+ H (\NoIntersection -> coRec NoIntersection)+ :& H (\p -> if onHalfLine p hl && p `intersects` seg then coRec p+ else coRec NoIntersection+ )+ :& H (\_line -> case (o `intersects` seg, onHalfLine (t^.unEndPoint.core) hl) of+ (False,False) -> coRec NoIntersection+ (False,True) -> coRec seg+ (True,True) -> coRec $ LineSegment (Closed $ ext o) t+ (True,False) -> coRec $ LineSegment s (Closed $ ext o)+ )+ :& RNil --- hl' `intersect` hl = case supportingLine hl' `intersect` supportingLine hl of--- ParallelLines -> NoHalfLineHalfLineIntersection--- LineLineIntersection p -> if p `onHalfLine` hl' && p `onHalfLine` hl then HLHLIntersectInPoint p--- else NoHalfLineHalfLineIntersection--- SameLine _ -> let p = _startPoint hl'--- q = _startPoint hl--- seg = LineSegment (p :+ ()) (q :+ ())--- in case (p `onHalfLine` hl, q `onHalfLine` hl') of--- (False,False) -> NoHalfLineHalfLineIntersection--- (False,True) -> HLHLIntersectInHalfLine hl--- (True, False) -> HLHLIntersectInHalfLine hl'--- (True, True) -> if hl == hl' then HLHLIntersectInHalfLine hl--- else HLHLIntersectInSegment seg +instance (Ord r, Fractional r, Arity d) => Point d r `IsIntersectableWith` HalfLine d r where+ nonEmptyIntersection = defaultNonEmptyIntersection+ intersects = onHalfLine+ p `intersect` hl | p `intersects` hl = coRec p+ | otherwise = coRec NoIntersection --- instance (Ord r, Fractional r) => (LineSegment 2 p r) `IsIntersectableWith` (HalfLine 2 r) where--- data Intersection (LineSegment 2 p r) (HalfLine 2 r) = NoSegmentHalfLineIntersection--- | SegmentHalfLineIntersection !(Point 2 r)--- | SegmentOnHalfLine !(LineSegment 2 () r) --- nonEmptyIntersection NoSegmentHalfLineIntersection = False--- nonEmptyIntersection _ = True+type instance IntersectionOf (HalfLine 2 r) (Boundary (Rectangle p r)) =+ [ NoIntersection, Point 2 r, (Point 2 r, Point 2 r) , LineSegment 2 () r] --- s `intersect` hl = case supportingLine s `intersect` supportingLine hl of--- ParallelLines -> NoSegmentHalfLineIntersection--- LineLineIntersection p -> if p `onSegment` s && p `onHalfLine` hl then SegmentHalfLineIntersection p--- else NoSegmentHalfLineIntersection--- SameLine _ -> let p = s ^.start.core--- q = s ^.end.core--- r = hl ^.start.core--- seg a b = LineSegment (a :+ ()) (b :+ ())--- in case (p `onHalfLine` hl, q `onHalfLine` hl) of--- (False, False) -> NoSegmentHalfLineIntersection--- (False, True) -> SegmentOnHalfLine $ seg r q--- (True, False) -> SegmentOnHalfLine $ seg p r--- (True, True) -> SegmentOnHalfLine $ seg p q+type instance IntersectionOf (HalfLine 2 r) (Rectangle p r) = [ NoIntersection+ , Point 2 r+ , LineSegment 2 () r+ ] +instance (Ord r, Fractional r)+ => HalfLine 2 r `IsIntersectableWith` Boundary (Rectangle p r) where+ nonEmptyIntersection = defaultNonEmptyIntersection + hl@(HalfLine o v) `intersect` br = match (Line o v `intersect` br) $+ H coRec -- NoIntersection+ :& H (\p -> if p `intersects` hl then coRec p else coRec NoIntersection)+ :& H (\(p,q) -> case (p `intersects` hl, q `intersects` hl) of+ (False,False) -> coRec NoIntersection+ (False,True) -> coRec q+ (True,False) -> coRec p+ (True,True) -> coRec (p,q))+ :& H (\s@(LineSegment' p q) -> case ((p^.core) `intersects` hl, (q^.core) `intersects` hl) of+ (False,False) -> coRec NoIntersection+ (False,True) -> coRec $ ClosedLineSegment (ext o) q+ (True,False) -> coRec $ ClosedLineSegment (ext o) p+ (True,True) -> coRec s)+ :& RNil +instance (Ord r, Fractional r)+ => HalfLine 2 r `IsIntersectableWith` Rectangle p r where+ nonEmptyIntersection = defaultNonEmptyIntersection + hl@(HalfLine o _) `intersect` rect = match (hl `intersect` Boundary rect) $+ H coRec -- NoIntersection+ :& H (\p -> if o `insideBox` rect then coRec (ClosedLineSegment (ext o) (ext p))+ else coRec p -- p is on the boundary+ )+ :& H (\(p,q) -> coRec $ ClosedLineSegment (ext p) (ext q))+ :& H coRec -- LineSegment+ :& RNil+ -- | Test if a point lies on a half-line onHalfLine :: (Ord r, Fractional r, Arity d) => Point d r -> HalfLine d r -> Bool p `onHalfLine` (HalfLine q v) = maybe False (>= 0) $ scalarMultiple (p .-. q) v--
src/Data/Geometry/HalfSpace.hs view
@@ -59,7 +59,7 @@ instance (Arity d, Eq r, Fractional r) => Eq (HalfSpace d r) where (HalfSpace h) == (HalfSpace h') = let u = h^.normalVec v = h'^.normalVec- d = quadrance (u ^+^ v) - (quadrance u)+ d = quadrance (u ^+^ v) - quadrance u in h == h' && signum d == 1 --------------------------------------------------------------------------------@@ -67,18 +67,18 @@ type HalfPlane = HalfSpace 2 -+{- HLINT ignore leftOf -} -- | Get the halfplane left of a line (i.e. "above") a line -- -- >>> leftOf $ horizontalLine 4--- HalfSpace {_boundingPlane = HyperPlane {_inPlane = Point2 [0,4], _normalVec = Vector2 [0,1]}}+-- HalfSpace {_boundingPlane = HyperPlane {_inPlane = Point2 0 4, _normalVec = Vector2 0 1}} leftOf :: Num r => Line 2 r -> HalfPlane r leftOf l = (rightOf l)&boundingPlane.normalVec %~ ((-1) *^) -- | Get the halfplane right of a line (i.e. "below") a line -- -- >>> rightOf $ horizontalLine 4--- HalfSpace {_boundingPlane = HyperPlane {_inPlane = Point2 [0,4], _normalVec = Vector2 [0,-1]}}+-- HalfSpace {_boundingPlane = HyperPlane {_inPlane = Point2 0 4, _normalVec = Vector2 0 (-1)}} rightOf :: Num r => Line 2 r -> HalfPlane r rightOf l = HalfSpace $ l^.re _asLine @@ -116,13 +116,13 @@ nonEmptyIntersection = defaultNonEmptyIntersection l@(Line o v) `intersect` h = match (l `intersect` m) $- (H $ \NoIntersection -> if o `intersects` h+ H (\NoIntersection -> if o `intersects` h then coRec l else coRec NoIntersection)- :& (H $ \p -> if (p .+^ v) `intersects` h+ :& H (\p -> if (p .+^ v) `intersects` h then coRec $ HalfLine p v else coRec $ HalfLine p ((-1) *^ v))- :& (H $ \_l -> coRec l)+ :& H (\_l -> coRec l) :& RNil where m = h^.boundingPlane._asLine
src/Data/Geometry/HyperPlane.hs view
@@ -1,6 +1,13 @@ {-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE TemplateHaskell #-}+--------------------------------------------------------------------------------+-- |+-- Module : Data.Geometry.HyperPlane+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+-------------------------------------------------------------------------------- module Data.Geometry.HyperPlane where import Control.DeepSeq@@ -77,7 +84,7 @@ -- the normal vector of the resulting plane is pointing "upwards". -- -- >>> from3Points origin (Point3 1 0 0) (Point3 0 1 0)--- HyperPlane {_inPlane = Point3 [0,0,0], _normalVec = Vector3 [0,0,1]}+-- HyperPlane {_inPlane = Point3 0 0 0, _normalVec = Vector3 0 0 1} from3Points :: Num r => Point 3 r -> Point 3 r -> Point 3 r -> HyperPlane 3 r from3Points p q r = let u = q .-. p v = r .-. p@@ -97,7 +104,7 @@ type instance IntersectionOf (Line 3 r) (Plane r) = [NoIntersection, Point 3 r, Line 3 r] -instance (Eq r, Fractional r) => (Line 3 r) `IsIntersectableWith` (Plane r) where+instance (Eq r, Fractional r) => Line 3 r `IsIntersectableWith` Plane r where nonEmptyIntersection = defaultNonEmptyIntersection l@(Line p v) `intersect` (HyperPlane q n) | denum == 0 = if num == 0 then coRec l else coRec NoIntersection@@ -140,7 +147,7 @@ -- y-axis. -- -- >>> planeCoordinatesWith (Plane origin (Vector3 0 0 1)) (Vector3 0 1 0) (Point3 10 10 0)--- Point2 [10.0,10.0]+-- Point2 10.0 10.0 planeCoordinatesWith :: Fractional r => Plane r -> Vector 3 r -> Point 3 r -> Point 2 r planeCoordinatesWith h vup = projectPoint . transformBy (planeCoordinatesTransform h vup)
src/Data/Geometry/Interval.hs view
@@ -1,15 +1,17 @@-{-# LANGUAGE TemplateHaskell #-}+--------------------------------------------------------------------------------+-- |+-- Module : Data.Geometry.Interval+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+-------------------------------------------------------------------------------- module Data.Geometry.Interval(- -- * 1 dimensional Intervals- Interval+ -- * 1 dimensional Intervals+ Interval (Interval, OpenInterval,ClosedInterval) , fromRange, toRange , _Range - , pattern OpenInterval- , pattern ClosedInterval- , pattern Interval-- -- * querying the start and end of intervals+ -- * querying the start and end of intervals , HasStart(..), HasEnd(..) -- * Working with intervals , inInterval@@ -21,18 +23,18 @@ ) where import Control.DeepSeq-import Control.Lens (lens, (^.),(%~),(&), Lens')+import Control.Lens (Iso', Lens', iso, (%~), (&), (^.)) import Data.Bifunctor import Data.Bitraversable import Data.Ext-import qualified Data.Foldable as F+import qualified Data.Foldable as F import Data.Geometry.Properties import Data.Range-import Data.Semigroup(Arg(..))-import qualified Data.Traversable as T+import Data.Semigroup (Arg (..))+import qualified Data.Traversable as T import Data.Vinyl import Data.Vinyl.CoRec-import GHC.Generics (Generic)+import GHC.Generics (Generic) import Test.QuickCheck --------------------------------------------------------------------------------@@ -42,11 +44,16 @@ -- We can think of an interval being defined as: -- -- >>> data Interval a r = Interval (EndPoint (r :+ a)) (EndPoint (r :+ a))-newtype Interval a r = GInterval { toRange :: Range (r :+ a) }+newtype Interval a r = GInterval (Range (r :+ a)) deriving (Eq,Generic,Arbitrary) -_Range :: Lens' (Interval a r) (Range (r :+ a))-_Range = lens toRange (const GInterval)+-- | Cast an interval to a range.+toRange :: Interval a r -> Range (r :+ a)+toRange (GInterval r) = r++-- | Intervals and ranges are isomorphic.+_Range :: Iso' (Interval a r) (Range (r :+ a))+_Range = iso toRange fromRange {-# INLINE _Range #-} -- | Constrct an interval from a Range@@ -78,7 +85,7 @@ -- 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 -> Bool-x `inInterval` r = x `inRange` (fmap (^.core) $ r^._Range )+x `inInterval` r = x `inRange` fmap (^.core) (r^._Range ) pattern OpenInterval :: (r :+ a) -> (r :+ a) -> Interval a r@@ -122,14 +129,14 @@ type instance IntersectionOf (Interval a r) (Interval a r) = [NoIntersection, Interval a r] -instance Ord r => (Interval a r) `IsIntersectableWith` (Interval a r) where+instance Ord r => Interval a r `IsIntersectableWith` Interval a r where nonEmptyIntersection = defaultNonEmptyIntersection (GInterval r) `intersect` (GInterval s) = match (r' `intersect` s') $- (H $ \NoIntersection -> coRec NoIntersection)- :& (H $ \(Range l u) -> coRec . GInterval $ Range (l&unEndPoint %~ g)- (u&unEndPoint %~ g) )+ H (\NoIntersection -> coRec NoIntersection)+ :& H (\(Range l u) -> coRec . GInterval $ Range (l&unEndPoint %~ g)+ (u&unEndPoint %~ g) ) :& RNil where f x = Arg (x^.core) x
src/Data/Geometry/Interval/Util.hs view
@@ -1,4 +1,12 @@ {-# LANGUAGE TemplateHaskell #-}+--------------------------------------------------------------------------------+-- |+-- Module : Data.Geometry.Interval.Util+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+--+-------------------------------------------------------------------------------- module Data.Geometry.Interval.Util where import Control.DeepSeq
src/Data/Geometry/IntervalTree.hs view
@@ -1,4 +1,11 @@ {-# LANGUAGE TemplateHaskell #-}+--------------------------------------------------------------------------------+-- |+-- Module : Data.Geometry.IntervalTree+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+-------------------------------------------------------------------------------- module Data.Geometry.IntervalTree( NodeData(..) , splitPoint, intervalsLeft, intervalsRight , IntervalTree(..), unIntervalTree@@ -44,8 +51,8 @@ -- -- \(O(n)\) createTree :: Ord r => [r] -> IntervalTree i r-createTree pts = IntervalTree . asBalancedBinTree- . map (\m -> NodeData m mempty mempty) $ pts+createTree = IntervalTree . asBalancedBinTree+ . map (\m -> NodeData m mempty mempty) -- | Build an interval tree
src/Data/Geometry/KDTree.hs view
@@ -1,25 +1,31 @@-{-# LANGUAGE UndecidableInstances #-}-{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE UndecidableInstances #-}+--------------------------------------------------------------------------------+-- |+-- Module : Data.Geometry.KDTree+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+-------------------------------------------------------------------------------- module Data.Geometry.KDTree where -import Control.Lens hiding (imap, element, Empty, (:<))+import Control.Lens hiding (Empty, element, imap, (:<)) import Data.BinaryTree-import Unsafe.Coerce(unsafeCoerce) import Data.Ext-import qualified Data.Foldable as F+import qualified Data.Foldable as F import Data.Geometry.Box import Data.Geometry.Point import Data.Geometry.Properties import Data.Geometry.Vector-import qualified Data.List.NonEmpty as NonEmpty-import Data.Maybe (fromJust)+import Data.LSeq (LSeq, pattern (:<|))+import qualified Data.LSeq as LSeq+import qualified Data.List.NonEmpty as NonEmpty import Data.Proxy-import Data.LSeq (LSeq, pattern (:<|))-import qualified Data.LSeq as LSeq import Data.Util-import qualified Data.Vector.Fixed as FV+import qualified Data.Vector.Fixed as FV import GHC.TypeLits-import Prelude hiding (replicate)+import Prelude hiding (replicate)+import Unsafe.Coerce (unsafeCoerce) -------------------------------------------------------------------------------- @@ -165,7 +171,7 @@ where -- i = traceShow (c,j) j - m = let xs = fromJust $ pts^?element' (i-1)+ m = let xs = pts^?!element' (i-1) in xs `LSeq.index` (F.length xs `div` 2) -- Since the input seq has >= 2 elems, F.length xs / 2 >= 1. It follows
src/Data/Geometry/Line.hs view
@@ -48,14 +48,14 @@ type instance IntersectionOf (Point d r) (Line d r) = [NoIntersection, Point d r] -instance (Eq r, Fractional r, Arity d) => (Point d r) `IsIntersectableWith` (Line d r) where+instance (Eq r, Fractional r, Arity d) => Point d r `IsIntersectableWith` Line d r where nonEmptyIntersection = defaultNonEmptyIntersection intersects = onLine p `intersect` l | p `intersects` l = coRec p | otherwise = coRec NoIntersection instance {-# OVERLAPPING #-} (Ord r, Num r)- => (Point 2 r) `IsIntersectableWith` (Line 2 r) where+ => Point 2 r `IsIntersectableWith` Line 2 r where nonEmptyIntersection = defaultNonEmptyIntersection intersects = onLine2 p `intersect` l | p `intersects` l = coRec p@@ -67,7 +67,7 @@ instance (Ord r, Fractional r)- => (Line 2 r) `IsIntersectableWith` (Boundary (Rectangle p r)) where+ => Line 2 r `IsIntersectableWith` Boundary (Rectangle p r) where nonEmptyIntersection = defaultNonEmptyIntersection line' `intersect` (Boundary rect) = case asAP segP of@@ -104,12 +104,12 @@ instance (Ord r, Fractional r)- => (Line 2 r) `IsIntersectableWith` (Rectangle p r) where+ => Line 2 r `IsIntersectableWith` Rectangle p r where nonEmptyIntersection = defaultNonEmptyIntersection - line' `intersect` rect = match (line' `intersect` (Boundary rect)) $- (H $ \NoIntersection -> coRec NoIntersection)- :& (H $ \p@(Point2 _ _) -> coRec p)- :& (H $ \(p,q) -> coRec $ ClosedLineSegment (ext p) (ext q))- :& (H $ \s -> coRec s)+ line' `intersect` rect = match (line' `intersect` Boundary rect) $+ H coRec -- NoIntersection+ :& H coRec -- Point2+ :& H (\(p,q) -> coRec $ ClosedLineSegment (ext p) (ext q))+ :& H coRec -- LineSegment :& RNil
src/Data/Geometry/Line/Internal.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE UndecidableInstances #-} --------------------------------------------------------------------------------@@ -34,8 +33,15 @@ data Line d r = Line { _anchorPoint :: !(Point d r) , _direction :: !(Vector d r) } deriving Generic-makeLenses ''Line +-- | Line anchor point.+anchorPoint :: Lens' (Line d r) (Point d r)+anchorPoint = lens _anchorPoint (\line pt -> line{_anchorPoint=pt})++-- | Line direction.+direction :: Lens' (Line d r) (Vector d r)+direction = lens _direction (\line dir -> line{_direction=dir})+ instance (Show r, Arity d) => Show (Line d r) where show (Line p v) = concat [ "Line (", show p, ") (", show v, ")" ] @@ -69,9 +75,11 @@ lineThrough :: (Num r, Arity d) => Point d r -> Point d r -> Line d r lineThrough p q = Line p (q .-. p) +-- | Vertical line with a given X-coordinate. verticalLine :: Num r => r -> Line 2 r verticalLine x = Line (Point2 x 0) (Vector2 0 1) +-- | Horizontal line with a given Y-coordinate. horizontalLine :: Num r => r -> Line 2 r horizontalLine y = Line (Point2 0 y) (Vector2 1 0) @@ -80,7 +88,7 @@ -- oriented such that v points into the left halfplane of m. -- -- >>> perpendicularTo $ Line (Point2 3 4) (Vector2 (-1) 2)--- Line (Point2 [3,4]) (Vector2 [-2,-1])+-- Line (Point2 3 4) (Vector2 (-2) (-1)) perpendicularTo :: Num r => Line 2 r -> Line 2 r perpendicularTo (Line p ~(Vector2 vx vy)) = Line p (Vector2 (-vy) vx) @@ -137,15 +145,24 @@ toOffset p (Line q v) = scalarMultiple (p .-. q) v --- | Given point p *on* a line (Line q v), Get the scalar lambda s.t.--- p = q + lambda v. (So this is an unsafe version of 'toOffset')+-- | Given point p near a line (Line q v), get the scalar lambda s.t.+-- the distance between 'p' and 'q + lambda v' is minimized. ----- pre: the input point p lies on the line l.+-- >>> toOffset' (Point2 1 1) (lineThrough origin $ Point2 10 10)+-- 0.1+--+-- >>> toOffset' (Point2 5 5) (lineThrough origin $ Point2 10 10)+-- 0.5+--+-- \<6,4\> is not on the line but we can still point closest to it.+-- >>> toOffset' (Point2 6 4) (lineThrough origin $ Point2 10 10)+-- 0.5 toOffset' :: (Eq r, Fractional r, Arity d) => Point d r -> Line d r -> r-toOffset' p = fromJust' . toOffset p- where- fromJust' (Just x) = x- fromJust' _ = error "toOffset: Nothing"+toOffset' p (Line q v) = dot (p .-. q) v / quadrance v+-- toOffset' p = fromJust' . toOffset p+-- where+-- fromJust' (Just x) = x+-- fromJust' _ = error "toOffset: Nothing" -- | The intersection of two lines is either: NoIntersection, a point or a line.@@ -154,7 +171,7 @@ , Line 2 r ] -instance (Eq r, Fractional r) => (Line 2 r) `IsIntersectableWith` (Line 2 r) where+instance (Eq r, Fractional r) => Line 2 r `IsIntersectableWith` Line 2 r where nonEmptyIntersection = defaultNonEmptyIntersection@@ -207,6 +224,7 @@ fromLinearFunction :: Num r => r -> r -> Line 2 r fromLinearFunction a b = Line (Point2 0 b) (Vector2 1 a) +{- HLINT ignore toLinearFunction -} -- | get values a,b s.t. the input line is described by y = ax + b. -- returns Nothing if the line is vertical toLinearFunction :: forall r. (Fractional r, Eq r)@@ -274,6 +292,9 @@ liesAbove :: (Ord r, Num r) => Point 2 r -> Line 2 r -> Bool q `liesAbove` l = q `onSideUpDown` l == Above +-- | Test if the query point q lies (strictly) above line l+liesBelow :: (Ord r, Num r) => Point 2 r -> Line 2 r -> Bool+q `liesBelow` l = q `onSideUpDown` l == Below -- | Get the bisector between two points bisector :: Fractional r => Point 2 r -> Point 2 r -> Line 2 r
src/Data/Geometry/LineSegment.hs view
@@ -10,306 +10,22 @@ -- Line segment data type and some basic functions on line segments -- ---------------------------------------------------------------------------------module Data.Geometry.LineSegment( LineSegment- , pattern LineSegment- , pattern LineSegment'- , pattern ClosedLineSegment- , pattern OpenLineSegment- , endPoints-- , _SubLine- , module Data.Geometry.Interval--- , toLineSegment- , onSegment- , orderedEndPoints- , segmentLength- , sqDistanceToSeg, sqDistanceToSegArg- , flipSegment-- , interpolate- ) where--import Control.Arrow ((&&&))-import Control.DeepSeq-import Control.Lens-import Data.Ext-import qualified Data.Foldable as F-import Data.Geometry.Box.Internal-import Data.Geometry.Interval hiding (width, midPoint)-import Data.Geometry.Line.Internal-import Data.Geometry.Point-import Data.Geometry.Properties-import Data.Geometry.SubLine-import Data.Geometry.Transformation-import Data.Geometry.Vector-import Data.Ord (comparing)-import Data.Vinyl-import Data.Vinyl.CoRec-import GHC.TypeLits-import Test.QuickCheck(Arbitrary(..))------------------------------------------------------------------------------------- * d-dimensional LineSegments----- | 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))-newtype LineSegment d p r = GLineSegment { _unLineSeg :: Interval p (Point d r)}--makeLenses ''LineSegment----- | Pattern that essentially models the line segment as a:------ >>> data LineSegment d p r = LineSegment (EndPoint (Point d r :+ p)) (EndPoint (Point d r :+ p))-pattern LineSegment :: EndPoint (Point d r :+ p)- -> EndPoint (Point d r :+ p)- -> LineSegment d p r-pattern LineSegment s t = GLineSegment (Interval s t)-{-# COMPLETE LineSegment #-}---- | Gets the start and end point, but forgetting if they are open or closed.-pattern LineSegment' :: Point d r :+ p- -> Point d r :+ p- -> LineSegment d p r-pattern LineSegment' s t <- ((^.start) &&& (^.end) -> (s,t))-{-# COMPLETE LineSegment' #-}--pattern ClosedLineSegment :: Point d r :+ p -> Point d r :+ p -> LineSegment d p r-pattern ClosedLineSegment s t = GLineSegment (ClosedInterval s t)-{-# COMPLETE ClosedLineSegment #-}--pattern OpenLineSegment :: Point d r :+ p -> Point d r :+ p -> LineSegment d p r-pattern OpenLineSegment s t = GLineSegment (OpenInterval s t)-{-# COMPLETE OpenLineSegment #-}----type instance Dimension (LineSegment d p r) = d-type instance NumType (LineSegment d p r) = r--instance HasStart (LineSegment d p r) where- type StartCore (LineSegment d p r) = Point d r- type StartExtra (LineSegment d p r) = p- start = unLineSeg.start--instance HasEnd (LineSegment d p r) where- type EndCore (LineSegment d p r) = Point d r- type EndExtra (LineSegment d p r) = p- end = unLineSeg.end--instance (Arbitrary r, Arbitrary p, Arity d) => Arbitrary (LineSegment d p r) where- arbitrary = LineSegment <$> arbitrary <*> arbitrary--deriving instance (Arity d, NFData r, NFData p) => NFData (LineSegment d p r)----- | 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.-endPoints :: Traversal (LineSegment d p r) (LineSegment d' q s)- (Point d r :+ p) (Point d' s :+ q)-endPoints = \f (LineSegment p q) -> LineSegment <$> traverse f p- <*> traverse f q--_SubLine :: (Num r, Arity d) => Iso' (LineSegment d p r) (SubLine d p r r)-_SubLine = iso segment2SubLine subLineToSegment-{-# INLINE _SubLine #-}--segment2SubLine :: (Num r, Arity d)- => LineSegment d p r -> SubLine d p r r-segment2SubLine ss = SubLine (Line p (q .-. p)) (Interval s e)- where- p = ss^.start.core- q = ss^.end.core- (Interval a b) = ss^.unLineSeg- s = a&unEndPoint.core .~ 0- e = b&unEndPoint.core .~ 1--subLineToSegment :: (Num r, Arity d) => SubLine d p r r -> LineSegment d p r-subLineToSegment sl = let (Interval s' e') = (fixEndPoints sl)^.subRange- s = s'&unEndPoint %~ (^.extra)- e = e'&unEndPoint %~ (^.extra)- in LineSegment s e--instance (Num r, Arity d) => HasSupportingLine (LineSegment d p r) where- supportingLine s = lineThrough (s^.start.core) (s^.end.core)---instance (Show r, Show p, Arity d) => Show (LineSegment d p r) where- show ~(LineSegment p q) = concat ["LineSegment (", show p, ") (", show q, ")"]--deriving instance (Eq r, Eq p, Arity d) => Eq (LineSegment d p r)--- deriving instance (Ord r, Ord p, Arity d) => Ord (LineSegment d p r)-deriving instance Arity d => Functor (LineSegment d p)--instance PointFunctor (LineSegment d p) where- pmap f ~(LineSegment s e) = LineSegment (s&unEndPoint.core %~ f)- (e&unEndPoint.core %~ f)--instance Arity d => IsBoxable (LineSegment d p r) where- boundingBox l = boundingBox (l^.start.core) <> boundingBox (l^.end.core)--instance (Fractional r, Arity d, Arity (d + 1)) => IsTransformable (LineSegment d p r) where- transformBy = transformPointFunctor--instance Arity d => Bifunctor (LineSegment d) where- bimap f g (GLineSegment i) = GLineSegment $ bimap f (fmap g) i------ ** Converting between Lines and LineSegments---- | Directly convert a line into a line segment.-toLineSegment :: (Monoid p, Num r, Arity d) => Line d r -> LineSegment d p r-toLineSegment (Line p v) = ClosedLineSegment (p :+ mempty)- (p .+^ v :+ mempty)---- *** Intersecting LineSegments--type instance IntersectionOf (LineSegment 2 p r) (LineSegment 2 p r) = [ NoIntersection- , Point 2 r- , LineSegment 2 p r- ]--type instance IntersectionOf (LineSegment 2 p r) (Line 2 r) = [ NoIntersection- , Point 2 r- , LineSegment 2 p r- ]---instance (Ord r, Fractional r) =>- (LineSegment 2 p r) `IsIntersectableWith` (LineSegment 2 p r) where- nonEmptyIntersection = defaultNonEmptyIntersection-- a `intersect` b = match ((a^._SubLine) `intersect` (b^._SubLine)) $- (H coRec)- :& (H coRec)- :& (H $ coRec . subLineToSegment)- :& RNil--instance (Ord r, Fractional r) =>- (LineSegment 2 p r) `IsIntersectableWith` (Line 2 r) where- nonEmptyIntersection = defaultNonEmptyIntersection-- s `intersect` l = let ubSL = s^._SubLine.re _unBounded.to dropExtra- in match (ubSL `intersect` (fromLine l)) $- (H coRec)- :& (H $ coRec)- :& (H $ const (coRec s))- :& RNil---- * Functions on LineSegments---- | Test if a point lies on a line segment.------ >>> (Point2 1 0) `onSegment` (ClosedLineSegment (origin :+ ()) (Point2 2 0 :+ ()))--- True--- >>> (Point2 1 1) `onSegment` (ClosedLineSegment (origin :+ ()) (Point2 2 0 :+ ()))--- False--- >>> (Point2 5 0) `onSegment` (ClosedLineSegment (origin :+ ()) (Point2 2 0 :+ ()))--- False--- >>> (Point2 (-1) 0) `onSegment` (ClosedLineSegment (origin :+ ()) (Point2 2 0 :+ ()))--- False--- >>> (Point2 1 1) `onSegment` (ClosedLineSegment (origin :+ ()) (Point2 3 3 :+ ()))--- True------ Note that the segments are assumed to be closed. So the end points lie on the segment.------ >>> (Point2 2 0) `onSegment` (ClosedLineSegment (origin :+ ()) (Point2 2 0 :+ ()))--- True--- >>> origin `onSegment` (ClosedLineSegment (origin :+ ()) (Point2 2 0 :+ ()))--- True--------- This function works for arbitrary dimensons.------ >>> (Point3 1 1 1) `onSegment` (ClosedLineSegment (origin :+ ()) (Point3 3 3 3 :+ ()))--- True--- >>> (Point3 1 2 1) `onSegment` (ClosedLineSegment (origin :+ ()) (Point3 3 3 3 :+ ()))--- False-onSegment :: (Ord r, Fractional r, Arity d)- => Point d r -> LineSegment d p r -> Bool-p `onSegment` l = let s = l^.start.core- t = l^.end.core- inRange' x = 0 <= x && x <= 1- in- if s == t -- zero length segment- then p == s- else maybe False inRange' $ scalarMultiple (p .-. s) (t .-. s)----- | The left and right end point (or left below right if they have equal x-coords)-orderedEndPoints :: Ord r => LineSegment 2 p r -> (Point 2 r :+ p, Point 2 r :+ p)-orderedEndPoints s = if pc <= qc then (p, q) else (q,p)- where- p@(pc :+ _) = s^.start- q@(qc :+ _) = s^.end----- | Length of the line segment-segmentLength :: (Arity d, Floating r) => LineSegment d p r -> r-segmentLength ~(LineSegment' p q) = distanceA (p^.core) (q^.core)----- | Squared distance from the point to the Segment s. The same remark as for--- the 'sqDistanceToSegArg' applies here.-sqDistanceToSeg :: (Arity d, Fractional r, Ord r) => Point d r -> LineSegment d p r -> r-sqDistanceToSeg p = fst . sqDistanceToSegArg p----- | 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).-sqDistanceToSegArg :: (Arity d, Fractional r, Ord r)- => Point d r -> LineSegment d p r -> (r, Point d r)-sqDistanceToSegArg p s = let m = sqDistanceToArg p (supportingLine s)- xs = m : map (\(q :+ _) -> (qdA p q, q)) [s^.start, s^.end]- in F.minimumBy (comparing fst)- . filter (flip onSegment s . snd) $ xs---- | flips the start and end point of the segment-flipSegment :: LineSegment d p r -> LineSegment d p r-flipSegment s = let p = s^.start- q = s^.end- in (s&start .~ q)&end .~ p---- testSeg :: LineSegment 2 () Rational--- testSeg = LineSegment (Open $ ext origin) (Closed $ ext (Point2 10 0))---- horL' :: Line 2 Rational--- horL' = horizontalLine 0---- testI = testSeg `intersect` horL'-+module Data.Geometry.LineSegment+ ( LineSegment(LineSegment, LineSegment', ClosedLineSegment, OpenLineSegment)+ , endPoints --- ff = bimap (fmap Val) (const ())+ , _SubLine+ , module Data.Geometry.Interval --- ss' = let (LineSegment p q) = testSeg in--- LineSegment (p&unEndPoint %~ ff)--- (q&unEndPoint %~ ff)+ , toLineSegment+ , orderedEndPoints+ , segmentLength+ , sqSegmentLength+ , sqDistanceToSeg, sqDistanceToSegArg+ , flipSegment --- ss'' = ss'^._SubLine+ , interpolate, sampleLineSegment+ ) where --- | 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]-interpolate :: (Fractional r, Arity d) => r -> LineSegment d p r -> Point d r-interpolate t (LineSegment' p q) = Point $ (asV p ^* (1-t)) ^+^ (asV q ^* t)- where- asV = (^.core.vector)+import Data.Geometry.Interval hiding (width, midPoint)+import Data.Geometry.LineSegment.Internal
+ src/Data/Geometry/LineSegment/Internal.hs view
@@ -0,0 +1,406 @@+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE UndecidableInstances #-}+--------------------------------------------------------------------------------+-- |+-- Module : Data.Geometry.LineSegment.Internal+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+--+-- Line segment data type and some basic functions on line segments+--+--------------------------------------------------------------------------------+module Data.Geometry.LineSegment.Internal+ ( LineSegment(LineSegment, LineSegment', ClosedLineSegment, OpenLineSegment)+ , endPoints++ , _SubLine+ , module Data.Geometry.Interval+++ , toLineSegment+ , onSegment, onSegment2+ , orderedEndPoints+ , segmentLength+ , sqSegmentLength+ , sqDistanceToSeg, sqDistanceToSegArg+ , flipSegment++ , interpolate+ , validSegment+ , sampleLineSegment+ ) where++import Control.Arrow ((&&&))+import Control.DeepSeq+import Control.Lens+import Control.Monad.Random+import Data.Ext+import qualified Data.Foldable as F+import Data.Geometry.Box.Internal+import Data.Geometry.Interval hiding (width, midPoint)+import Data.Geometry.Line.Internal+import Data.Geometry.Point+import Data.Geometry.Properties+import Data.Geometry.SubLine+import Data.Geometry.Transformation+import Data.Geometry.Vector+import Data.Ord (comparing)+import Data.Vinyl+import Data.Vinyl.CoRec+import GHC.TypeLits+import Test.QuickCheck (Arbitrary(..), suchThatMap)+import Text.Read++--------------------------------------------------------------------------------+-- * d-dimensional LineSegments+++-- | 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.+newtype LineSegment d p r = GLineSegment { _unLineSeg :: Interval p (Point d r) }++makeLenses ''LineSegment+++pattern LineSegment :: EndPoint (Point d r :+ p)+ -> EndPoint (Point d r :+ p)+ -> LineSegment d p r+pattern LineSegment s t = GLineSegment (Interval s t)+{-# COMPLETE LineSegment #-}++-- | Gets the start and end point, but forgetting if they are open or closed.+pattern LineSegment' :: Point d r :+ p+ -> Point d r :+ p+ -> LineSegment d p r+pattern LineSegment' s t <- ((^.start) &&& (^.end) -> (s,t))+{-# COMPLETE LineSegment' #-}++pattern ClosedLineSegment :: Point d r :+ p -> Point d r :+ p -> LineSegment d p r+pattern ClosedLineSegment s t = GLineSegment (ClosedInterval s t)+{-# COMPLETE ClosedLineSegment #-}++pattern OpenLineSegment :: Point d r :+ p -> Point d r :+ p -> LineSegment d p r+pattern OpenLineSegment s t = GLineSegment (OpenInterval s t)+{-# COMPLETE OpenLineSegment #-}++++type instance Dimension (LineSegment d p r) = d+type instance NumType (LineSegment d p r) = r++instance HasStart (LineSegment d p r) where+ type StartCore (LineSegment d p r) = Point d r+ type StartExtra (LineSegment d p r) = p+ start = unLineSeg.start++instance HasEnd (LineSegment d p r) where+ type EndCore (LineSegment d p r) = Point d r+ type EndExtra (LineSegment d p r) = p+ end = unLineSeg.end++instance (Arbitrary r, Arbitrary p, Eq r, Arity d) => Arbitrary (LineSegment d p r) where+ arbitrary = suchThatMap ((,) <$> arbitrary <*> arbitrary)+ (uncurry validSegment)+++deriving instance (Arity d, NFData r, NFData p) => NFData (LineSegment d p r)++sampleLineSegment :: (Arity d, RandomGen g, Random r) => Rand g (LineSegment d () r)+sampleLineSegment = do+ a <- ext <$> getRandom+ a' <- getRandom+ b <- ext <$> getRandom+ b' <- getRandom+ pure $ LineSegment (if a' then Open a else Closed a) (if b' then Open b else Closed b)+++{- HLINT ignore endPoints -}+-- | 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.+endPoints :: Traversal (LineSegment d p r) (LineSegment d' q s)+ (Point d r :+ p) (Point d' s :+ q)+endPoints = \f (LineSegment p q) -> LineSegment <$> traverse f p+ <*> traverse f q++_SubLine :: (Num r, Arity d) => Iso' (LineSegment d p r) (SubLine d p r r)+_SubLine = iso segment2SubLine subLineToSegment+{-# INLINE _SubLine #-}++segment2SubLine :: (Num r, Arity d)+ => LineSegment d p r -> SubLine d p r r+segment2SubLine ss = SubLine (Line p (q .-. p)) (Interval s e)+ where+ p = ss^.start.core+ q = ss^.end.core+ (Interval a b) = ss^.unLineSeg+ s = a&unEndPoint.core .~ 0+ e = b&unEndPoint.core .~ 1++{- HLINT ignore subLineToSegment -}+subLineToSegment :: (Num r, Arity d) => SubLine d p r r -> LineSegment d p r+subLineToSegment sl = let Interval s' e' = (fixEndPoints sl)^.subRange+ s = s'&unEndPoint %~ (^.extra)+ e = e'&unEndPoint %~ (^.extra)+ in LineSegment s e++instance (Num r, Arity d) => HasSupportingLine (LineSegment d p r) where+ supportingLine s = lineThrough (s^.start.core) (s^.end.core)+++instance (Show r, Show p, Arity d) => Show (LineSegment d p r) where+ showsPrec d (LineSegment p' q') = case (p',q') of+ (Closed p, Closed q) -> f "ClosedLineSegment" p q+ (Open p, Open q) -> f "OpenLineSegment" p q+ (p,q) -> f "LineSegment" p q+ where+ app_prec = 10+ f :: (Show a, Show b) => String -> a -> b -> String -> String+ f cn p q = showParen (d > app_prec) $+ showString cn . showString " "+ . showsPrec (app_prec+1) p+ . showString " "+ . showsPrec (app_prec+1) q++instance (Read r, Read p, Arity d) => Read (LineSegment d p r) where+ readPrec = parens $ (prec app_prec $ do+ Ident "ClosedLineSegment" <- lexP+ p <- step readPrec+ q <- step readPrec+ return (ClosedLineSegment p q))+ ++++ (prec app_prec $ do+ Ident "OpenLineSegment" <- lexP+ p <- step readPrec+ q <- step readPrec+ return (OpenLineSegment p q))+ ++++ (prec app_prec $ do+ Ident "LineSegment" <- lexP+ p <- step readPrec+ q <- step readPrec+ return (LineSegment p q))+ where app_prec = 10+++deriving instance (Eq r, Eq p, Arity d) => Eq (LineSegment d p r)+-- deriving instance (Ord r, Ord p, Arity d) => Ord (LineSegment d p r)+deriving instance Arity d => Functor (LineSegment d p)++instance PointFunctor (LineSegment d p) where+ pmap f ~(LineSegment s e) = LineSegment (s&unEndPoint.core %~ f)+ (e&unEndPoint.core %~ f)++instance Arity d => IsBoxable (LineSegment d p r) where+ boundingBox l = boundingBox (l^.start.core) <> boundingBox (l^.end.core)++instance (Fractional r, Arity d, Arity (d + 1)) => IsTransformable (LineSegment d p r) where+ transformBy = transformPointFunctor++instance Arity d => Bifunctor (LineSegment d) where+ bimap f g (GLineSegment i) = GLineSegment $ bimap f (fmap g) i++++-- ** Converting between Lines and LineSegments++-- | Directly convert a line into a line segment.+toLineSegment :: (Monoid p, Num r, Arity d) => Line d r -> LineSegment d p r+toLineSegment (Line p v) = ClosedLineSegment (p :+ mempty)+ (p .+^ v :+ mempty)++-- *** Intersecting LineSegments++type instance IntersectionOf (Point d r) (LineSegment d p r) = [ NoIntersection+ , Point d r+ ]++type instance IntersectionOf (LineSegment 2 p r) (LineSegment 2 p r) = [ NoIntersection+ , Point 2 r+ , LineSegment 2 p r+ ]++type instance IntersectionOf (LineSegment 2 p r) (Line 2 r) = [ NoIntersection+ , Point 2 r+ , LineSegment 2 p r+ ]+++instance {-# OVERLAPPING #-} (Ord r, Num r)+ => Point 2 r `IsIntersectableWith` LineSegment 2 p r where+ nonEmptyIntersection = defaultNonEmptyIntersection+ intersects = onSegment2+ p `intersect` seg | p `intersects` seg = coRec p+ | otherwise = coRec NoIntersection++instance {-# OVERLAPPABLE #-} (Ord r, Fractional r, Arity d)+ => Point d r `IsIntersectableWith` LineSegment d p r where+ nonEmptyIntersection = defaultNonEmptyIntersection+ intersects = onSegment+ p `intersect` seg | p `intersects` seg = coRec p+ | otherwise = coRec NoIntersection++-- | Test if a point lies on a line segment.+--+-- As a user, you should typically just use 'intersects' instead.+onSegment :: (Ord r, Fractional r, Arity d) => Point d r -> LineSegment d p r -> Bool+p `onSegment` (LineSegment up vp) =+ maybe False inRange' (scalarMultiple (p .-. u) (v .-. u))+ where+ u = up^.unEndPoint.core+ v = vp^.unEndPoint.core++ atMostUpperBound = if isClosed vp then (<= 1) else (< 1)+ atLeastLowerBound = if isClosed up then (0 <=) else (0 <)++ inRange' x = atLeastLowerBound x && atMostUpperBound x+ -- the type of test we use for the 2D version might actually also+ -- work in higher dimensions that might allow us to drop the+ -- Fractional constraint++++instance (Ord r, Fractional r) =>+ LineSegment 2 p r `IsIntersectableWith` LineSegment 2 p r where+ nonEmptyIntersection = defaultNonEmptyIntersection++ a `intersect` b = match ((a^._SubLine) `intersect` (b^._SubLine)) $+ H coRec+ :& H coRec+ :& H (coRec . subLineToSegment)+ :& RNil++instance (Ord r, Fractional r) =>+ LineSegment 2 p r `IsIntersectableWith` Line 2 r where+ nonEmptyIntersection = defaultNonEmptyIntersection++ s `intersect` l = let ubSL = s^._SubLine.re _unBounded.to dropExtra+ in match (ubSL `intersect` fromLine l) $+ H coRec+ :& H coRec+ :& H (const (coRec s))+ :& RNil++++-- * Functions on LineSegments++-- | 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+onSegment2 :: (Ord r, Num r)+ => Point 2 r -> LineSegment 2 p r -> Bool+p `onSegment2` s@(LineSegment u v) = case ccw' (ext p) (u^.unEndPoint) (v^.unEndPoint) of+ CoLinear -> let su = p `onSide` lu+ sv = p `onSide` lv+ in su /= sv+ && ((su == OnLine) `implies` isClosed u)+ && ((sv == OnLine) `implies` isClosed v)+ _ -> False+ where+ (Line _ w) = perpendicularTo $ supportingLine s+ lu = Line (u^.unEndPoint.core) w+ lv = Line (v^.unEndPoint.core) w++ a `implies` b = b || not a+++-- | The left and right end point (or left below right if they have equal x-coords)+orderedEndPoints :: Ord r => LineSegment 2 p r -> (Point 2 r :+ p, Point 2 r :+ p)+orderedEndPoints s = if pc <= qc then (p, q) else (q,p)+ where+ p@(pc :+ _) = s^.start+ q@(qc :+ _) = s^.end+++-- | Length of the line segment+segmentLength :: (Arity d, Floating r) => LineSegment d p r -> r+segmentLength ~(LineSegment' p q) = distanceA (p^.core) (q^.core)++sqSegmentLength :: (Arity d, Num r) => LineSegment d p r -> r+sqSegmentLength ~(LineSegment' p q) = qdA (p^.core) (q^.core)++-- | Squared distance from the point to the Segment s. The same remark as for+-- the 'sqDistanceToSegArg' applies here.+sqDistanceToSeg :: (Arity d, Fractional r, Ord r) => Point d r -> LineSegment d p r -> r+sqDistanceToSeg p = fst . sqDistanceToSegArg p+++-- | 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).+sqDistanceToSegArg :: (Arity d, Fractional r, Ord r)+ => Point d r -> LineSegment d p r -> (r, Point d r)+sqDistanceToSegArg p s = let m = sqDistanceToArg p (supportingLine s)+ xs = m : map (\(q :+ _) -> (qdA p q, q)) [s^.start, s^.end]+ in F.minimumBy (comparing fst)+ . filter (flip onSegment s . snd) $ xs++-- | flips the start and end point of the segment+flipSegment :: LineSegment d p r -> LineSegment d p r+flipSegment s = let p = s^.start+ q = s^.end+ in (s&start .~ q)&end .~ p++-- testSeg :: LineSegment 2 () Rational+-- testSeg = LineSegment (Open $ ext origin) (Closed $ ext (Point2 10 0))++-- horL' :: Line 2 Rational+-- horL' = horizontalLine 0++-- testI = testSeg `intersect` horL'+++-- ff = bimap (fmap Val) (const ())++-- ss' = let (LineSegment p q) = testSeg in+-- LineSegment (p&unEndPoint %~ ff)+-- (q&unEndPoint %~ ff)++-- ss'' = ss'^._SubLine++-- | 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+interpolate :: (Fractional r, Arity d) => r -> LineSegment d p r -> Point d r+interpolate t (LineSegment' p q) = Point $ (asV p ^* (1-t)) ^+^ (asV q ^* t)+ where+ asV = (^.core.vector)+++-- | smart constructor that creates a valid segment, i.e. it validates+-- that the endpoints are disjoint.+validSegment :: (Eq r, Arity d)+ => EndPoint (Point d r :+ p) -> EndPoint (Point d r :+ p)+ -> Maybe (LineSegment d p r)+validSegment u v = let s = LineSegment u v+ in if s^.start.core /= s^.end.core then Just s else Nothing
src/Data/Geometry/Matrix.hs view
@@ -19,17 +19,18 @@ , HasDeterminant(..) ) where -import Control.Lens (imap)-import Data.Geometry.Matrix.Internal (mkRow)+import Control.Lens (imap)+import Data.Coerce+import Data.Geometry.Matrix.Internal (mkRow) import Data.Geometry.Vector-import Linear.Matrix ((!*),(!*!))-import qualified Linear.Matrix as Lin-import Unsafe.Coerce (unsafeCoerce)+import Data.Geometry.Vector.VectorFamilyPeano+import Linear.Matrix (M22, M33, M44, (!*!), (!*))+import qualified Linear.Matrix as Lin -------------------------------------------------------------------------------- -- * Matrices --- | a matrix of n rows, each of m columns, storing values of type r+-- | A matrix of n rows, each of m columns, storing values of type r. newtype Matrix n m r = Matrix (Vector n (Vector m r)) deriving instance (Show r, Arity n, Arity m) => Show (Matrix n m r)@@ -39,41 +40,56 @@ deriving instance (Arity n, Arity m) => Foldable (Matrix n m) deriving instance (Arity n, Arity m) => Traversable (Matrix n m) +-- | Matrix product. multM :: (Arity r, Arity c, Arity c', Num a) => Matrix r c a -> Matrix c c' a -> Matrix r c' a (Matrix a) `multM` (Matrix b) = Matrix $ a !*! b +-- | Matrix * column vector. mult :: (Arity m, Arity n, Num r) => Matrix n m r -> Vector m r -> Vector n r (Matrix m) `mult` v = m !* v --- | Produces the Identity Matrix+-- | Produces the Identity Matrix. identityMatrix :: (Arity d, Num r) => Matrix d d r identityMatrix = Matrix $ imap mkRow (pure 1) +-- | Class of matrices that are invertible. class Invertible n r where inverse' :: Matrix n n r -> Matrix n n r instance Fractional r => Invertible 2 r where -- >>> inverse' $ Matrix $ Vector2 (Vector2 1 2) (Vector2 3 4.0) -- Matrix Vector2 [Vector2 [-2.0,1.0],Vector2 [1.5,-0.5]]- inverse' (Matrix m) = Matrix . unsafeCoerce . Lin.inv22 . unsafeCoerce $ m+ inverse' = withM22 Lin.inv22 instance Fractional r => Invertible 3 r where -- >>> inverse' $ Matrix $ Vector3 (Vector3 1 2 4) (Vector3 4 2 2) (Vector3 1 1 1.0) -- Matrix Vector3 [Vector3 [0.0,0.5,-1.0],Vector3 [-0.5,-0.75,3.5],Vector3 [0.5,0.25,-1.5]]- inverse' (Matrix m) = Matrix . unsafeCoerce . Lin.inv33 . unsafeCoerce $ m+ inverse' = withM33 Lin.inv33 instance Fractional r => Invertible 4 r where- inverse' (Matrix m) = Matrix . unsafeCoerce . Lin.inv44 . unsafeCoerce $ m-+ inverse' = withM44 Lin.inv44 +-- | Class of matrices that have a determinant. class Arity d => HasDeterminant d where det :: Num r => Matrix d d r -> r instance HasDeterminant 1 where det (Matrix (Vector1 (Vector1 x))) = x instance HasDeterminant 2 where- det = Lin.det22 . unsafeCoerce+ det = Lin.det22 . coerce instance HasDeterminant 3 where- det = Lin.det33 . unsafeCoerce+ det = Lin.det33 . coerce instance HasDeterminant 4 where- det = Lin.det44 . unsafeCoerce+ det = Lin.det44 . coerce++--------------------------------------------------------------------------------+-- Boilerplate code for converting between Matrix and M22/M33/M44.++withM22 :: (M22 a -> M22 b) -> Matrix 2 2 a -> Matrix 2 2 b+withM22 f = coerce . f . coerce++withM33 :: (M33 a -> M33 b) -> Matrix 3 3 a -> Matrix 3 3 b+withM33 f = coerce . f . coerce++withM44 :: (M44 a -> M44 b) -> Matrix 4 4 a -> Matrix 4 4 b+withM44 f = coerce . f . coerce
src/Data/Geometry/PlanarSubdivision.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE PartialTypeSignatures #-} {-# LANGUAGE ScopedTypeVariables #-} --------------------------------------------------------------------------------@@ -76,7 +75,7 @@ -> f -- ^ data inside -> f -- ^ data outside the polygon -> PlanarSubdivision s p () f r-fromPolygon p pg@(SimplePolygon _) iD oD = fromSimplePolygon p pg iD oD+fromPolygon p pg@SimplePolygon{} iD oD = fromSimplePolygon p pg iD oD fromPolygon p (MultiPolygon vs hs) iD oD = case NonEmpty.nonEmpty hs of Nothing -> outerPG Just hs' -> let hs'' = (\pg -> fromSimplePolygon wp (toCounterClockWiseOrder pg) oD iD) <$> hs'@@ -84,7 +83,7 @@ where wp = Proxy :: Proxy (Wrap s) - outerPG = fromSimplePolygon p (SimplePolygon vs) iD oD+ outerPG = fromSimplePolygon p vs iD oD i = V.last $ faces' outerPG @@ -122,13 +121,13 @@ data HoleData f p = Outer !f | Hole !f !p deriving (Show,Eq) -holeData :: HoleData f p -> f-holeData (Outer f) = f-holeData (Hole f _) = f+_holeData :: HoleData f p -> f+_holeData (Outer f) = f+_holeData (Hole f _) = f -getP :: HoleData f p -> Maybe p-getP (Outer _) = Nothing-getP (Hole _ p) = Just p+_getP :: HoleData f p -> Maybe p+_getP (Outer _) = Nothing+_getP (Hole _ p) = Just p --------------------------------------------------------------------------------
src/Data/Geometry/PlanarSubdivision/Basic.hs view
@@ -155,6 +155,7 @@ => PlaneGraph s v e f r -> PlanarSubdivision s v e f r fromPlaneGraph g = fromPlaneGraph' g (PG.outerFaceDart g) +{- HLINT ignore fromPlaneGraph' -} -- | Given a (connected) PlaneGraph and a dart that has the outerface on its left -- | Constructs a planarsubdivision --@@ -280,7 +281,7 @@ numEdges :: PlanarSubdivision s v e f r -> Int numEdges = (`div` 2) . V.length . _rawDartData --- | Get the number of faces+-- | \( O(1) \). Get the number of faces -- -- >>> numFaces myGraph -- 4@@ -327,11 +328,12 @@ edges :: PlanarSubdivision s v e f r -> V.Vector (Dart s, e) edges ps = (\e -> (e,ps^.dataOf e)) <$> edges' ps -+-- | \( O(n) \). Vector of all primal faces. faces' :: PlanarSubdivision s v e f r -> V.Vector (FaceId' s) faces' ps = let n = numFaces ps in V.fromList $ map (FaceId . VertexId) [0..n-1] +-- | \( O(n) \). Vector of all primal faces with associated data. faces :: PlanarSubdivision s v e f r -> V.Vector (FaceId' s, FaceData (Dart s) f) faces ps = (\fi -> (fi,ps^.faceDataOf fi)) <$> faces' ps @@ -492,7 +494,7 @@ -- running time: \(O(k)\), where \(k\) is the output size. boundaryVertices :: FaceId' s -> PlanarSubdivision s v e f r -> V.Vector (VertexId' s)-boundaryVertices f ps = (\d -> headOf d ps) <$> outerBoundaryDarts f ps+boundaryVertices f ps = (`headOf` ps) <$> outerBoundaryDarts f ps -- | Lists the holes in this face, given as a list of darts to arbitrary darts@@ -640,7 +642,7 @@ -- -- \(O(k)\), where \(k\) is the complexity of the outer boundary of the face rawFaceBoundary :: FaceId' s -> PlanarSubdivision s v e f r -> SimplePolygon v r :+ f-rawFaceBoundary i ps = fromPoints pts :+ (ps^.dataOf i)+rawFaceBoundary i ps = unsafeFromPoints pts :+ (ps^.dataOf i) where d = V.head $ outerBoundaryDarts i ps pts = (\d' -> PG.vtxDataToExt $ ps^.vertexDataOf (headOf d' ps))@@ -654,10 +656,10 @@ -> SomePolygon v r :+ f rawFacePolygon i ps = case F.toList $ holesOf i ps of [] -> Left res :+ x- hs -> Right (MultiPolygon vs $ map toHole hs) :+ x+ hs -> Right (MultiPolygon res $ map toHole hs) :+ x where- res@(SimplePolygon vs) :+ x = rawFaceBoundary i ps- toHole d = (rawFaceBoundary (leftFace d ps) ps)^.core+ res :+ x = rawFaceBoundary i ps+ toHole d = rawFaceBoundary (leftFace d ps) ps ^. core -- | Lists all *internal* faces of the planar subdivision. rawFacePolygons :: PlanarSubdivision s v e f r
src/Data/Geometry/PlanarSubdivision/Merge.hs view
@@ -23,9 +23,6 @@ import Data.Geometry.Point import Data.Geometry.Polygon import Data.PlanarGraph.Dart-import Data.PlaneGraph ( Dart, VertexId(..), FaceId(..)- , VertexId', FaceId'- ) import qualified Data.PlaneGraph as PG import Data.Semigroup.Foldable import qualified Data.Vector as V@@ -215,34 +212,39 @@ -------------------------------------------------------------------------------- data Test = Test-data Id a = Id a+newtype Id a = Id a triangle1 :: PlanarSubdivision Test () () Int Rational triangle1 = (\pg -> fromSimplePolygon (Id Test) pg 1 0)- $ trianglePG1+ trianglePG1+trianglePG1 :: SimplePolygon () Rational trianglePG1 = fromPoints . map ext $ [origin, Point2 200 0, Point2 200 200] triangle2 :: PlanarSubdivision Test () () Int Rational triangle2 = (\pg -> fromSimplePolygon (Id Test) pg 2 0)- $ trianglePG2+ trianglePG2+trianglePG2 :: SimplePolygon () Rational trianglePG2 = fromPoints . map ext $ [Point2 0 30, Point2 10 30, Point2 10 40] triangle4 :: PlanarSubdivision Test () () Int Rational triangle4 = (\pg -> fromSimplePolygon (Id Test) pg 1 0)- $ trianglePG4+ trianglePG4+trianglePG4 :: SimplePolygon () Rational trianglePG4 = fromPoints . map ext $ [Point2 400 400, Point2 600 400, Point2 600 600] triangle3 :: PlanarSubdivision Test () () Int Rational triangle3 = (\pg -> fromSimplePolygon (Id Test) pg 3 0)- $ trianglePG3+ trianglePG3+trianglePG3 :: SimplePolygon () Rational trianglePG3 = fromPoints . map ext $ [Point2 401 530, Point2 410 530, Point2 410 540] -myPS = embedAsHoleIn triangle2 const (mkFI 1) triangle1+_myPS :: PlanarSubdivision Test () () Int Rational+_myPS = embedAsHoleIn triangle2 const (mkFI 1) triangle1 `merge` embedAsHoleIn triangle3 const (mkFI 1) triangle4
src/Data/Geometry/PlanarSubdivision/Raw.hs view
@@ -46,7 +46,7 @@ -------------------------------------------------------------------------------- -- | The Face data consists of the data itself and a list of holes-data FaceData h f = FaceData { _holes :: (Seq.Seq h)+data FaceData h f = FaceData { _holes :: Seq.Seq h , _fData :: !f } deriving (Show,Eq,Ord,Functor,Foldable,Traversable,Generic) makeLenses ''FaceData
src/Data/Geometry/Point.hs view
@@ -10,32 +10,32 @@ -- \(d\)-dimensional points. -- ---------------------------------------------------------------------------------module Data.Geometry.Point( Point(..)+module Data.Geometry.Point( Point(.., Point1, Point2, Point3) , origin, vector , pointFromList , projectPoint - , pattern Point1- , pattern Point2- , pattern Point3 , xCoord, yCoord, zCoord , PointFunctor(..) - , CCW, ccw, ccw'+ , CCW, ccw, ccw', isCoLinear , pattern CCW, pattern CW, pattern CoLinear - , ccwCmpAround, cwCmpAround, ccwCmpAroundWith, cwCmpAroundWith- , sortAround, insertIntoCyclicOrder+ , ccwCmpAround, ccwCmpAround'+ , cwCmpAround, cwCmpAround'+ , ccwCmpAroundWith, ccwCmpAroundWith'+ , cwCmpAroundWith, cwCmpAroundWith'+ , sortAround, sortAround'+ , insertIntoCyclicOrder , Quadrant(..), quadrantWith, quadrant, partitionIntoQuadrants - , cmpByDistanceTo+ , cmpByDistanceTo, cmpByDistanceTo' , squaredEuclideanDist, euclideanDist -- , AsAPoint(..), coord, unsafeCoord, vector'+ , coord, unsafeCoord ) where import Data.Geometry.Point.Class
src/Data/Geometry/Point/Class.hs view
@@ -9,7 +9,7 @@ -------------------------------------------------------------------------------- -- $setup--- >>> import Data.Geometry.Point.Internal (pattern Point2, pattern Point3)+-- >>> import Data.Geometry.Point.Internal (pattern Point2, pattern Point3, origin) class ToAPoint point d r where toPoint :: Prism' (point d r) (Point d r)@@ -17,12 +17,32 @@ class AsAPoint p where asAPoint :: Lens (p d r) (p d' r') (Point d r) (Point d' r') +-- | Lens to access the vector corresponding to this point.+--+-- >>> (Point3 1 2 3) ^. vector'+-- Vector3 1 2 3+-- >>> origin & vector' .~ Vector3 1 2 3+-- Point3 1 2 3 vector' :: AsAPoint p => Lens (p d r) (p d r') (Vector d r) (Vector d r') vector' = asAPoint . lens Internal.toVec (const Internal.Point) +-- | Get the coordinate in a given dimension+--+-- >>> Point3 1 2 3 ^. coord (C :: C 2)+-- 2+-- >>> Point3 1 2 3 & coord (C :: C 1) .~ 10+-- Point3 10 2 3+-- >>> Point3 1 2 3 & coord (C :: C 3) %~ (+1)+-- Point3 1 2 4 coord :: (1 <= i, i <= d, KnownNat i, Arity d, AsAPoint p) => proxy i -> Lens' (p d r) r coord i = asAPoint.Internal.coord i +-- | Get the coordinate in a given dimension. This operation is unsafe in the+-- sense that no bounds are checked. Consider using `coord` instead.+--+--+-- >>> Point3 1 2 3 ^. unsafeCoord 2+-- 2 unsafeCoord :: (Arity d, AsAPoint p) => Int -> Lens' (p d r) r unsafeCoord i = asAPoint.Internal.unsafeCoord i @@ -33,14 +53,12 @@ asAPoint = id -- -- | Shorthand to access the first coordinate C 1 -- -- >>> Point3 1 2 3 ^. xCoord -- 1 -- >>> Point2 1 2 & xCoord .~ 10--- Point2 [10,2]+-- Point2 10 2 xCoord :: (1 <= d, Arity d, AsAPoint point) => Lens' (point d r) r xCoord = coord (C :: C 1) {-# INLINABLE xCoord #-}@@ -50,7 +68,7 @@ -- >>> Point2 1 2 ^. yCoord -- 2 -- >>> Point3 1 2 3 & yCoord %~ (+1)--- Point3 [1,3,3]+-- Point3 1 3 3 yCoord :: (2 <= d, Arity d, AsAPoint point) => Lens' (point d r) r yCoord = coord (C :: C 2) {-# INLINABLE yCoord #-}@@ -60,7 +78,7 @@ -- >>> Point3 1 2 3 ^. zCoord -- 3 -- >>> Point3 1 2 3 & zCoord %~ (+1)--- Point3 [1,2,4]-zCoord :: (3 <= d, Arity d,AsAPoint point) => Lens' (point d r) r+-- Point3 1 2 4+zCoord :: (3 <= d, Arity d, AsAPoint point) => Lens' (point d r) r zCoord = coord (C :: C 3) {-# INLINABLE zCoord #-}
src/Data/Geometry/Point/Internal.hs view
@@ -25,27 +25,29 @@ , PointFunctor(..) , cmpByDistanceTo+ , cmpByDistanceTo' , squaredEuclideanDist, euclideanDist ) where import Control.DeepSeq import Control.Lens+import Control.Monad import Data.Aeson import Data.Ext-import qualified Data.Foldable as F+import qualified Data.Foldable as F+import Data.Functor.Classes import Data.Geometry.Properties import Data.Geometry.Vector-import qualified Data.Geometry.Vector as Vec+import qualified Data.Geometry.Vector as Vec import Data.Hashable-import Data.Ord (comparing)+import Data.List (intersperse)+import Data.Ord (comparing) import Data.Proxy-import GHC.Generics (Generic)+import GHC.Generics (Generic) import GHC.TypeLits-import System.Random (Random(..))-import Test.QuickCheck (Arbitrary)-import Text.ParserCombinators.ReadP (ReadP, string,pfail)-import Text.ParserCombinators.ReadPrec (lift)-import Text.Read (Read(..),readListPrecDefault, readPrec_to_P,minPrec)+import System.Random (Random (..))+import Test.QuickCheck (Arbitrary, Arbitrary1)+import Text.Read (Read (..), readListPrecDefault) --------------------------------------------------------------------------------@@ -61,31 +63,65 @@ -- * A d-dimensional Point -- | A d-dimensional point.+--+-- There are convenience pattern synonyms for 1, 2 and 3 dimensional points.+--+-- >>> let f (Point1 x) = x in f (Point1 1)+-- 1+-- >>> let f (Point2 x y) = x in f (Point2 1 2)+-- 1+-- >>> let f (Point3 x y z) = z in f (Point3 1 2 3)+-- 3+-- >>> let f (Point3 x y z) = z in f (Point $ Vector3 1 2 3)+-- 3 newtype Point d r = Point { toVec :: Vector d r } deriving (Generic) instance (Show r, Arity d) => Show (Point d r) where- show (Point v) = mconcat [ "Point", show $ F.length v , " "- , show $ F.toList v- ]+ showsPrec = liftShowsPrec showsPrec showList++instance (Arity d) => Show1 (Point d) where+ liftShowsPrec sp _ d (Point v) = showParen (d > 10) $+ showString constr . showChar ' ' .+ unwordsS (map (sp 11) (F.toList v))+ where+ constr = "Point" <> show (fromIntegral (natVal @d Proxy))+ unwordsS = foldr (.) id . intersperse (showChar ' ')+ instance (Read r, Arity d) => Read (Point d r) where- readPrec = lift readPt+ readPrec = liftReadPrec readPrec readListPrec readListPrec = readListPrecDefault -readPt :: forall d r. (Arity d, Read r) => ReadP (Point d r)-readPt = do let d = natVal (Proxy :: Proxy d)- _ <- string $ "Point" <> show d <> " "- rs <- readPrec_to_P readPrec minPrec- case pointFromList rs of- Just p -> pure p- _ -> pfail+instance (Arity d) => Read1 (Point d) where+ liftReadPrec rp _rl = readData $+ readUnaryWith (replicateM d rp) constr $ \rs ->+ case pointFromList rs of+ Just p -> p+ _ -> error "internal error in Data.Geometry.Point read instance."+ where+ d = fromIntegral (natVal (Proxy :: Proxy d))+ constr = "Point" <> show d+ liftReadListPrec = liftReadListPrecDefault +-- readPt :: forall d r. (Arity d, Read r) => ReadP (Point d r)+-- readPt = do let d = natVal (Proxy :: Proxy d)+-- _ <- string $ "Point" <> show d+-- rs <- if d > 3+-- then readPrec_to_P readPrec minPrec+-- else replicateM (fromIntegral d) (readPrec_to_P readPrec minPrec)+-- case pointFromList rs of+-- Just p -> pure p+-- _ -> pfail+ deriving instance (Eq r, Arity d) => Eq (Point d r)+deriving instance Arity d => Eq1 (Point d) deriving instance (Ord r, Arity d) => Ord (Point d r) deriving instance Arity d => Functor (Point d)+deriving instance Arity d => Applicative (Point d) deriving instance Arity d => Foldable (Point d) deriving instance Arity d => Traversable (Point d) deriving instance (Arity d, NFData r) => NFData (Point d r) deriving instance (Arity d, Arbitrary r) => Arbitrary (Point d r)+deriving instance Arity d => Arbitrary1 (Point d) deriving instance (Arity d, Hashable r) => Hashable (Point d r) deriving instance (Arity d, Random r) => Random (Point d r) @@ -109,7 +145,7 @@ -- | Point representing the origin in d dimensions -- -- >>> origin :: Point 4 Int--- Point4 [0,0,0,0]+-- Point4 0 0 0 0 origin :: (Arity d, Num r) => Point d r origin = Point $ pure 0 @@ -119,10 +155,10 @@ -- | Lens to access the vector corresponding to this point. -- -- >>> (Point3 1 2 3) ^. vector--- Vector3 [1,2,3]+-- Vector3 1 2 3 -- >>> origin & vector .~ Vector3 1 2 3--- Point3 [1,2,3]-vector :: Lens' (Point d r) (Vector d r)+-- Point3 1 2 3+vector :: Lens (Point d r) (Point d r') (Vector d r) (Vector d r') vector = lens toVec (const Point) {-# INLINABLE vector #-} @@ -142,9 +178,9 @@ -- >>> Point3 1 2 3 ^. coord (C :: C 2) -- 2 -- >>> Point3 1 2 3 & coord (C :: C 1) .~ 10--- Point3 [10,2,3]+-- Point3 10 2 3 -- >>> Point3 1 2 3 & coord (C :: C 3) %~ (+1)--- Point3 [1,2,4]+-- Point3 1 2 4 coord :: forall proxy i d r. (1 <= i, i <= d, Arity d, KnownNat i) => proxy i -> Lens' (Point d r) r coord _ = unsafeCoord $ fromIntegral (natVal $ C @i)@@ -160,7 +196,7 @@ -- list has to match the dimension exactly. -- -- >>> pointFromList [1,2,3] :: Maybe (Point 3 Int)--- Just Point3 [1,2,3]+-- Just (Point3 1 2 3) -- >>> pointFromList [1] :: Maybe (Point 3 Int) -- Nothing -- >>> pointFromList [1,2,3,4] :: Maybe (Point 3 Int)@@ -176,44 +212,18 @@ -------------------------------------------------------------------------------- -- * Convenience functions to construct 1, 2 and 3 dimensional points --- | We provide pattern synonyms for 1, 2 and 3 dimensional points. i.e.--- we can write:--------- >>> :{--- let--- f :: Num r => Point 1 r -> r--- f (Point1 x) = x + 1--- in f (Point1 1)--- :}--- 2+-- | A bidirectional pattern synonym for 1 dimensional points. pattern Point1 :: r -> Point 1 r pattern Point1 x = Point (Vector1 x) {-# COMPLETE Point1 #-} --- | Pattern synonym for 2 dimensional points------ >>> :{--- let--- f :: Point 2 r -> r--- f (Point2 x y) = x--- in f (Point2 1 2)--- :}--- 1+-- | A bidirectional pattern synonym for 2 dimensional points. pattern Point2 :: r -> r -> Point 2 r pattern Point2 x y = Point (Vector2 x y) {-# COMPLETE Point2 #-} --- | Similarly, we can write:------ >>> :{--- let--- g :: Point 3 r -> r--- g (Point3 x y z) = z--- in g myPoint--- :}--- 3+-- | A bidirectional pattern synonym for 3 dimensional points. pattern Point3 :: r -> r -> r -> Point 3 r pattern Point3 x y z = (Point (Vector3 x y z)) {-# COMPLETE Point3 #-}@@ -237,9 +247,13 @@ -- | Compare by distance to the first argument cmpByDistanceTo :: (Ord r, Num r, Arity d)- => Point d r :+ c -> Point d r :+ p -> Point d r :+ q -> Ordering-cmpByDistanceTo (c :+ _) p q = comparing (squaredEuclideanDist c) (p^.core) (q^.core)+ => Point d r -> Point d r -> Point d r -> Ordering+cmpByDistanceTo c p q = comparing (squaredEuclideanDist c) p q +-- | Compare by distance to the first argument+cmpByDistanceTo' :: (Ord r, Num r, Arity d)+ => Point d r :+ c -> Point d r :+ p -> Point d r :+ q -> Ordering+cmpByDistanceTo' c p q = cmpByDistanceTo (c^.core) (p^.core) (q^.core)
src/Data/Geometry/Point/Orientation/Degenerate.hs view
@@ -4,11 +4,15 @@ , ccw, ccw' - , sortAround+ , isCoLinear - , ccwCmpAroundWith, cwCmpAroundWith- , ccwCmpAround, cwCmpAround+ , sortAround, sortAround' + , ccwCmpAroundWith, ccwCmpAroundWith'+ , cwCmpAroundWith, cwCmpAroundWith'+ , ccwCmpAround, ccwCmpAround'+ , cwCmpAround, cwCmpAround'+ , insertIntoCyclicOrder ) where @@ -22,16 +26,22 @@ -------------------------------------------------------------------------------- +-- $setup+-- >>> import Data.Double.Approximate+ -- | Data type for expressing the orientation of three points, with -- the option of allowing Colinearities. newtype CCW = CCWWrap Ordering deriving Eq +-- | CounterClockwise orientation. Also called a left-turn. pattern CCW :: CCW pattern CCW = CCWWrap GT +-- | Clockwise orientation. Also called a right-turn. pattern CW :: CCW pattern CW = CCWWrap LT +-- | CoLinear orientation. Also called a straight line. pattern CoLinear :: CCW pattern CoLinear = CCWWrap EQ {-# COMPLETE CCW, CW, CoLinear #-}@@ -44,8 +54,22 @@ -- | Given three points p q and r determine the orientation when going from p to r via q.+--+-- Be vary of numerical instability:+-- >>> ccw (Point2 0 0.3) (Point2 1 0.6) (Point2 2 (0.9::Double))+-- CCW+--+-- >>> ccw (Point2 0 0.3) (Point2 1 0.6) (Point2 2 (0.9::Rational))+-- CoLinear+--+-- If you can't use 'Rational', try 'SafeDouble' instead of 'Double':+-- >>> ccw (Point2 0 0.3) (Point2 1 0.6) (Point2 2 (0.9::SafeDouble))+-- CoLinear+-- ccw :: (Ord r, Num r) => Point 2 r -> Point 2 r -> Point 2 r -> CCW-ccw p q r = CCWWrap $ z `compare` 0+ccw p q r = CCWWrap $ (ux*vy) `compare` (uy*vx)+-- ccw p q r = CCWWrap $ z `compare` 0 -- Comparing against 0 is bad for numerical robustness.+ -- I've added a testcase that fails if comparing against 0. -- case z `compare` 0 of -- LT -> CW -- GT -> CCW@@ -53,21 +77,38 @@ where Vector2 ux uy = q .-. p Vector2 vx vy = r .-. p- z = ux * vy - uy * vx+ -- _z = ux * vy - uy * vx +-- | Given three points p q and r determine if the line from p to r via q is straight/colinear.+--+-- This is identical to `ccw p q r == CoLinear` but doesn't have the `Ord` constraint.+isCoLinear :: (Eq r, Num r) => Point 2 r -> Point 2 r -> Point 2 r -> Bool+isCoLinear p q r = (ux * vy) == (uy * vx)+ where+ Vector2 ux uy = q .-. p+ Vector2 vx vy = r .-. p+ -- | Given three points p q and r determine the orientation when going from p to r via q. ccw' :: (Ord r, Num r) => Point 2 r :+ a -> Point 2 r :+ b -> Point 2 r :+ c -> CCW ccw' p q r = ccw (p^.core) (q^.core) (r^.core) --- | Sort the points arround the given point p in counter clockwise order with+-- | \( O(n log n) \)+-- Sort the points arround the given point p in counter clockwise order with -- respect to the rightward horizontal ray starting from p. If two points q -- and r are colinear with p, the closest one to p is reported first.--- running time: O(n log n) sortAround :: (Ord r, Num r)- => Point 2 r :+ q -> [Point 2 r :+ p] -> [Point 2 r :+ p]+ => Point 2 r -> [Point 2 r] -> [Point 2 r] sortAround c = L.sortBy (ccwCmpAround c <> cmpByDistanceTo c) +-- | \( O(n log n) \)+-- Sort the points arround the given point p in counter clockwise order with+-- respect to the rightward horizontal ray starting from p. If two points q+-- and r are colinear with p, the closest one to p is reported first.+sortAround' :: (Ord r, Num r)+ => Point 2 r :+ q -> [Point 2 r :+ p] -> [Point 2 r :+ p]+sortAround' c = L.sortBy (ccwCmpAround' c <> cmpByDistanceTo' c) + -- | Given a zero vector z, a center c, and two points p and q, -- compute the ccw ordering of p and q around c with this vector as zero -- direction.@@ -75,10 +116,10 @@ -- pre: the points p,q /= c ccwCmpAroundWith :: (Ord r, Num r) => Vector 2 r- -> Point 2 r :+ c- -> Point 2 r :+ a -> Point 2 r :+ b+ -> Point 2 r+ -> Point 2 r -> Point 2 r -> Ordering-ccwCmpAroundWith z@(Vector2 zx zy) (c :+ _) (q :+ _) (r :+ _) =+ccwCmpAroundWith z@(Vector2 zx zy) c q r = case (ccw c a q, ccw c a r) of (CCW,CCW) -> cmp (CCW,CW) -> LT@@ -115,36 +156,71 @@ CoLinear -> EQ -- | Given a zero vector z, a center c, and two points p and q,+-- compute the ccw ordering of p and q around c with this vector as zero+-- direction.+--+-- pre: the points p,q /= c+ccwCmpAroundWith' :: (Ord r, Num r)+ => Vector 2 r+ -> Point 2 r :+ c+ -> Point 2 r :+ a -> Point 2 r :+ b+ -> Ordering+ccwCmpAroundWith' z (c :+ _) (q :+ _) (r :+ _) = ccwCmpAroundWith z c q r++-- | Given a zero vector z, a center c, and two points p and q, -- compute the cw ordering of p and q around c with this vector as zero -- direction. -- -- pre: the points p,q /= c cwCmpAroundWith :: (Ord r, Num r) => Vector 2 r+ -> Point 2 r+ -> Point 2 r -> Point 2 r+ -> Ordering+cwCmpAroundWith z c = flip (ccwCmpAroundWith z c)+++-- | Given a zero vector z, a center c, and two points p and q,+-- compute the cw ordering of p and q around c with this vector as zero+-- direction.+--+-- pre: the points p,q /= c+cwCmpAroundWith' :: (Ord r, Num r)+ => Vector 2 r -> Point 2 r :+ a -> Point 2 r :+ b -> Point 2 r :+ c -> Ordering-cwCmpAroundWith z c = flip (ccwCmpAroundWith z c)+cwCmpAroundWith' z c = flip (ccwCmpAroundWith' z c) -- | Counter clockwise ordering of the points around c. Points are ordered with -- respect to the positive x-axis. ccwCmpAround :: (Num r, Ord r)- => Point 2 r :+ qc -> Point 2 r :+ p -> Point 2 r :+ q -> Ordering+ => Point 2 r -> Point 2 r -> Point 2 r -> Ordering ccwCmpAround = ccwCmpAroundWith (Vector2 1 0) +-- | Counter clockwise ordering of the points around c. Points are ordered with+-- respect to the positive x-axis.+ccwCmpAround' :: (Num r, Ord r)+ => Point 2 r :+ qc -> Point 2 r :+ p -> Point 2 r :+ q -> Ordering+ccwCmpAround' = ccwCmpAroundWith' (Vector2 1 0)+ -- | Clockwise ordering of the points around c. Points are ordered with -- respect to the positive x-axis. cwCmpAround :: (Num r, Ord r)- => Point 2 r :+ qc -> Point 2 r :+ p -> Point 2 r :+ q -> Ordering+ => Point 2 r -> Point 2 r -> Point 2 r -> Ordering cwCmpAround = cwCmpAroundWith (Vector2 1 0) +-- | Clockwise ordering of the points around c. Points are ordered with+-- respect to the positive x-axis.+cwCmpAround' :: (Num r, Ord r)+ => Point 2 r :+ qc -> Point 2 r :+ p -> Point 2 r :+ q -> Ordering+cwCmpAround' a b c = cwCmpAround (a^.core) (b^.core) (c^.core) --- | Given a center c, a new point p, and a list of points ps, sorted in+-- | \( O(n) \)+-- Given a center c, a new point p, and a list of points ps, sorted in -- counter clockwise order around c. Insert p into the cyclic order. The focus -- of the returned cyclic list is the new point p.------ running time: O(n) insertIntoCyclicOrder :: (Ord r, Num r) => Point 2 r :+ q -> Point 2 r :+ p -> C.CList (Point 2 r :+ p) -> C.CList (Point 2 r :+ p)-insertIntoCyclicOrder c = CU.insertOrdBy (ccwCmpAround c <> cmpByDistanceTo c)+insertIntoCyclicOrder c = CU.insertOrdBy (ccwCmpAround' c <> cmpByDistanceTo' c)
src/Data/Geometry/Point/Quadrants.hs view
@@ -1,26 +1,19 @@+--------------------------------------------------------------------------------+-- |+-- Module : Data.Geometry.Point.Quadrants+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+-------------------------------------------------------------------------------- module Data.Geometry.Point.Quadrants where -import Control.DeepSeq import Control.Lens-import Data.Aeson import Data.Ext-import qualified Data.Foldable as F import Data.Geometry.Point.Class import Data.Geometry.Point.Internal-import Data.Geometry.Properties import Data.Geometry.Vector-import qualified Data.Geometry.Vector as Vec-import Data.Hashable import qualified Data.List as L-import Data.Ord (comparing)-import Data.Proxy-import GHC.Generics (Generic) import GHC.TypeLits-import System.Random (Random(..))-import Test.QuickCheck (Arbitrary)-import Text.ParserCombinators.ReadP (ReadP, string,pfail)-import Text.ParserCombinators.ReadPrec (lift)-import Text.Read (Read(..),readListPrecDefault, readPrec_to_P,minPrec) --------------------------------------------------------------------------------
+ src/Data/Geometry/PointLocation.hs view
@@ -0,0 +1,12 @@+--------------------------------------------------------------------------------+-- |+-- Module : Data.Geometry.PointLocation+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+--------------------------------------------------------------------------------+module Data.Geometry.PointLocation+ ( module Data.Geometry.PointLocation.PersistentSweep+ ) where++import Data.Geometry.PointLocation.PersistentSweep
+ src/Data/Geometry/PointLocation/PersistentSweep.hs view
@@ -0,0 +1,177 @@+{-# Language TemplateHaskell #-}+{-# Language TypeApplications #-}+--------------------------------------------------------------------------------+-- |+-- Module : Data.Geometry.PointLocation.PersistentSweep+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+--------------------------------------------------------------------------------+module Data.Geometry.PointLocation.PersistentSweep+ ( PointLocationDS(PointLocationDS)+ , verticalRayShootingStructure, subdivision, outerFace++ -- * Building the Data Structure+ , pointLocationDS+ -- * Querying the Data Structure+ , dartAbove, dartAboveOrOn+ , faceContaining, faceIdContaining++ , InPolygonDS, inPolygonDS+ , InOut(..)++ , pointInPolygon+ , edgeOnOrAbove+ ) where++import qualified Data.Geometry.VerticalRayShooting.PersistentSweep as VRS+import Control.Lens hiding (contains, below)+import Data.Ext+import Data.Geometry.LineSegment+import Data.Geometry.PlanarSubdivision+import Data.Geometry.Point+import Data.Geometry.Polygon+import qualified Data.List.NonEmpty as NonEmpty+import Data.Proxy+import Data.Util (SP(..))+import qualified Data.Vector as V++--------------------------------------------------------------------------------++-- | Planar Point Location Data structure+data PointLocationDS s v e f r = PointLocationDS {+ _verticalRayShootingStructure :: VRS.VerticalRayShootingStructure v (Dart s) r+ , _subdivision :: PlanarSubdivision s v e f r+ , _outerFace :: FaceId' s+ } deriving (Show,Eq)++makeLensesWith (lensRules&generateUpdateableOptics .~ False) ''PointLocationDS++--------------------------------------------------------------------------------+-- * Buidlding the Point location Data structure++-- | Builds a pointlocation data structure on the planar subdivision with \(n\)+-- vertices.+--+-- running time: \(O(n\log n)\).+-- space: \(O(n\log n)\).+pointLocationDS :: (Ord r, Fractional r)+ => PlanarSubdivision s v e f r -> PointLocationDS s v e f r+pointLocationDS ps = PointLocationDS (VRS.verticalRayShootingStructure es) ps (outerFaceId ps)+ where+ es = NonEmpty.fromList . V.toList . fmap (\(d,s) -> s&extra .~ d) . edgeSegments $ ps+ -- the VRS structure will throw away vertical edges. So there is no need to+ -- explicitly filter them yet at this point++--------------------------------------------------------------------------------+-- * Querying the Structure++-- | Locates the first edge (dart) strictly above the query point.+-- returns Nothing if the query point lies in the outer face and there is no dart+-- above it.+--+-- running time: \(O(\log n)\)+dartAbove :: (Ord r, Fractional r)+ => Point 2 r -> PointLocationDS s v e f r -> Maybe (Dart s)+dartAbove = queryWith VRS.segmentAbove++dartAboveOrOn :: (Ord r, Fractional r)+ => Point 2 r -> PointLocationDS s v e f r -> Maybe (Dart s)+dartAboveOrOn = queryWith VRS.segmentAboveOrOn++type QueryAlgorithm v e r =+ Point 2 r -> VRS.VerticalRayShootingStructure v e r -> Maybe (LineSegment 2 v r :+ e)++queryWith :: (Ord r, Fractional r)+ => QueryAlgorithm v (Dart s) r+ -> Point 2 r -> PointLocationDS s v e f r -> Maybe (Dart s)+queryWith query q = fmap (view extra) . query q . view verticalRayShootingStructure++-- | Locates the face containing the query point.+--+-- running time: \(O(\log n)\)+faceContaining :: (Ord r, Fractional r)+ => Point 2 r -> PointLocationDS s v e f r -> f+faceContaining q ds = ds^.subdivision.dataOf (faceIdContaining q ds)++-- | Locates the faceId of the face containing the query point.+--+-- If the query point lies *on* an edge, an arbitrary face incident to+-- the edge is returned.+--+-- running time: \(O(\log n)\)+faceIdContaining :: (Ord r, Fractional r)+ => Point 2 r -> PointLocationDS s v e f r -> FaceId' s+faceIdContaining q ds = dartToFace ds $ dartAbove q ds++-- | Given the dart determine the faceId correspondig to it (depending+-- on the orientation of the dart that is returned.)+dartToFace :: Ord r => PointLocationDS s v e f r -> Maybe (Dart s) -> FaceId' s+dartToFace ds = maybe (ds^.outerFace) getFace+ where+ ps = ds^.subdivision+ getFace d = let (u,v) = bimap (^.location) (^.location) $ endPointData d ps+ in if u <= v then rightFace d ps+ else leftFace d ps+++data OneOrTwo a = One !a | Two !a !a deriving (Show,Read,Eq,Ord,Functor,Foldable,Traversable)++-- | Locates the faceId of the face containing the query point. If the+-- query point lies on an edge, it returns both faces incident to the+-- edge; first the one below the edge then the one above the edge.+--+-- running time: \(O(\log n)\)+faceIdContaining' :: (Ord r, Fractional r)+ => Point 2 r -> PointLocationDS s v e f r -> OneOrTwo (FaceId' s)+faceIdContaining' q ds = maybe (One $ ds^.outerFace) getFace $ dartAboveOrOn q ds+ where+ ps = ds^.subdivision++ getFace = getFace' . orient++ orient d = let (u,v) = bimap (^.location) (^.location) $ endPointData d ps+ in if u <= v then (d,u,v) else (twin d, v, u)+++ getFace' (d,u,v) = case ccw u q v of+ CoLinear -> Two (rightFace d ps) (leftFace d ps)+ _ -> One (rightFace d ps)++--------------------------------------------------------------------------------++-- | Data structure for fast InPolygon Queries+-- newtype InPolygonDS v r = InPolygonDS (VRS.VerticalRayShootingStructure (Vertex v r) () r)+-- deriving (Show,Eq)++data InOut = In | Out deriving (Show,Eq)++data Dummy+type InPolygonDS v r = PointLocationDS Dummy (SP Int v) () InOut r+++-- type Vertex v r = Int :+ (Point 2 r :+ v)++inPolygonDS :: (Fractional r, Ord r) => SimplePolygon v r -> InPolygonDS v r+inPolygonDS pg = pointLocationDS $ fromSimplePolygon (Proxy @Dummy) (numberVertices pg) In Out++-- | Finds the edge on or above the query point, if it exists+--+--+edgeOnOrAbove :: (Ord r, Fractional r)+ => Point 2 r -> InPolygonDS v r -> Maybe (LineSegment 2 (SP Int v) r)+edgeOnOrAbove q ds = view core . flip edgeSegment (ds^.subdivision) <$> dartAboveOrOn q ds+++-- | Returns if a query point lies in (or on the boundary of) the polygon.+--+-- \(O(\log n)\)+pointInPolygon :: (Ord r, Fractional r) => Point 2 r -> InPolygonDS v r -> InOut+pointInPolygon q ds = case faceIdContaining' q ds of+ One i -> ds^.subdivision.dataOf i+ Two _ _ -> In -- on an edge, so inside.++ -- FIXME: Make sure to also test the edge "below" q, i.e. if q is on+ -- some edge we should return that edge.++ -- FIXME: Figure out if this works ok for vertical edges as well
src/Data/Geometry/PolyLine.hs view
@@ -1,6 +1,11 @@-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE UndecidableInstances #-}+--------------------------------------------------------------------------------+-- |+-- Module : Data.Geometry.PolyLine+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+-------------------------------------------------------------------------------- module Data.Geometry.PolyLine where import Control.Lens@@ -35,8 +40,11 @@ -- | A Poly line in R^d has at least 2 vertices newtype PolyLine d p r = PolyLine { _points :: LSeq 2 (Point d r :+ p) } deriving (Generic)-makeLenses ''PolyLine +-- | PolyLines are isomorphic to a sequence of points with at least 2 members.+points :: Iso (PolyLine d1 p1 r1) (PolyLine d2 p2 r2) (LSeq 2 (Point d1 r1 :+ p1)) (LSeq 2 (Point d2 r2 :+ p2))+points = iso (\(PolyLine s) -> s) PolyLine+ deriving instance (Show r, Show p, Arity d) => Show (PolyLine d p r) deriving instance (Eq r, Eq p, Arity d) => Eq (PolyLine d p r) deriving instance (Ord r, Ord p, Arity d) => Ord (PolyLine d p r)@@ -70,6 +78,16 @@ toEncoding = genericToEncoding defaultOptions instance (FromJSON p, FromJSON r, Arity d, KnownNat d) => FromJSON (PolyLine d p r) +instance HasStart (PolyLine d p r) where+ type StartCore (PolyLine d p r) = Point d r+ type StartExtra (PolyLine d p r) = p+ start = points.head1++instance HasEnd (PolyLine d p r) where+ type EndCore (PolyLine d p r) = Point d r+ type EndExtra (PolyLine d p r) = p+ end = points.last1+ -- | Builds a Polyline from a list of points, if there are sufficiently many points fromPoints :: [Point d r :+ p] -> Maybe (PolyLine d p r) fromPoints = fmap PolyLine . LSeq.eval (C @ 2) . LSeq.fromList@@ -81,7 +99,7 @@ -- | pre: The input list contains at least two points. All extra vields are -- initialized with mempty. fromPointsUnsafe' :: (Monoid p) => [Point d r] -> PolyLine d p r-fromPointsUnsafe' = fromPointsUnsafe . map (\p -> p :+ mempty)+fromPointsUnsafe' = fromPointsUnsafe . map (:+ mempty) -- | We consider the line-segment as closed.@@ -111,9 +129,9 @@ -- running time: \(O(\log n)\) -- -- >>> interpolatePoly 0.5 myPolyLine--- Point2 [5.0,5.0]+-- Point2 5.0 5.0 -- >>> interpolatePoly 1.5 myPolyLine--- Point2 [10.0,15.0]+-- Point2 10.0 15.0 interpolatePoly :: (RealFrac r, Arity d) => r -> PolyLine d p r -> Point d r interpolatePoly t pl = let i = floor t in case edgeSegments pl^?ix i of Nothing -> pl^.points.to LSeq.last.core
src/Data/Geometry/Polygon.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE TemplateHaskell #-} -------------------------------------------------------------------------------- -- | -- Module : Data.Geometry.Polygon@@ -9,43 +8,76 @@ -- A Polygon data type and some basic functions to interact with them. -- ---------------------------------------------------------------------------------module Data.Geometry.Polygon( PolygonType(..)- , Polygon(..)- , _SimplePolygon, _MultiPolygon- , SimplePolygon, MultiPolygon, SomePolygon+module Data.Geometry.Polygon+ ( -- * Types+ PolygonType(..)+ , Polygon(..)+ , _SimplePolygon, _MultiPolygon+ , SimplePolygon, MultiPolygon, SomePolygon - , fromPoints+ -- * Conversion+ , fromPoints+ , fromCircularVector - , polygonVertices, listEdges+ , simpleFromPoints+ , simpleFromCircularVector - , outerBoundary, outerBoundaryEdges- , outerVertex, outerBoundaryEdge+ , unsafeFromPoints+ , unsafeFromCircularVector+ , unsafeFromVector+ , toVector+ , toPoints - , polygonHoles, polygonHoles'- , holeList+ , isSimple - , inPolygon, insidePolygon, onBoundary+ -- * Accessors - , area, signedArea+ , size+ , polygonVertices, listEdges - , centroid- , pickPoint+ , outerBoundary, outerBoundaryVector+ , unsafeOuterBoundaryVector+ , outerBoundaryEdges+ , outerVertex, outerBoundaryEdge - , isTriangle, isStarShaped+ , polygonHoles, polygonHoles'+ , holeList - , isCounterClockwise- , toCounterClockWiseOrder, toCounterClockWiseOrder'- , toClockwiseOrder, toClockwiseOrder'- , reverseOuterBoundary+ -- * Properties - , findDiagonal+ , area, signedArea+ , centroid - , withIncidentEdges, numberVertices+ -- * Queries+ , inPolygon, insidePolygon, onBoundary - , asSimplePolygon- , extremesLinear, cmpExtreme- ) where + , isTriangle, isStarShaped++ , isCounterClockwise+ , toCounterClockWiseOrder, toCounterClockWiseOrder'+ , toClockwiseOrder, toClockwiseOrder'+ , reverseOuterBoundary++ , rotateLeft+ , rotateRight+ , maximumVertexBy+ , minimumVertexBy+++ -- * Misc+ , pickPoint+ , findDiagonal++ , withIncidentEdges, numberVertices++ , extremesLinear, cmpExtreme++ , findRotateTo++ ) where++import Algorithms.Geometry.InPolygon import Algorithms.Geometry.LinearProgramming.LP2DRIC import Algorithms.Geometry.LinearProgramming.Types import Control.Lens hiding (Simple)@@ -54,10 +86,13 @@ import qualified Data.Foldable as F import Data.Geometry.HalfSpace (rightOf) import Data.Geometry.Line+import Data.Geometry.LineSegment import Data.Geometry.Point+import Data.Geometry.Boundary import Data.Geometry.Polygon.Core import Data.Geometry.Polygon.Extremes-+import Data.Geometry.Properties+import qualified Data.Sequence as Seq -------------------------------------------------------------------------------- -- * Polygons@@ -76,3 +111,30 @@ -- the first vertex is the intersection point of the two supporting lines -- bounding it, so the first two edges bound the shape in this sirection hs = fmap (rightOf . supportingLine) . outerBoundaryEdges $ pg+++--------------------------------------------------------------------------------+-- * Instances++type instance IntersectionOf (Line 2 r) (Boundary (Polygon t p r)) =+ '[Seq.Seq (Either (Point 2 r) (LineSegment 2 () r))]++type instance IntersectionOf (Point 2 r) (Polygon t p r) = [NoIntersection, Point 2 r]++instance (Fractional r, Ord r) => Point 2 r `IsIntersectableWith` Polygon t p r where+ nonEmptyIntersection = defaultNonEmptyIntersection+ q `intersects` pg = q `inPolygon` pg /= Outside+ q `intersect` pg | q `intersects` pg = coRec q+ | otherwise = coRec NoIntersection++-- instance IsIntersectableWith (Line 2 r) (Boundary (Polygon t p r)) where+-- nonEmptyIntersection _ _ (CoRec xs) = null xs+-- l `intersect` (Boundary (SimplePolygon vs)) =+-- undefined+ -- l `intersect` (Boundary (MultiPolygon vs hs)) = coRec .+ -- Seq.sortBy f . Seq.fromList+ -- . concatMap (unpack . (l `intersect`) . Boundary)+ -- $ SimplePolygon vs : hs+ -- where+ -- unpack (CoRec x) = x+ -- f = undefined
src/Data/Geometry/Polygon/Convex.hs view
@@ -1,5 +1,4 @@ {-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TemplateHaskell #-} -------------------------------------------------------------------------------- -- | -- Module : Data.Geometry.Polygon.Convex@@ -10,54 +9,82 @@ -- Convex Polygons -- ---------------------------------------------------------------------------------module Data.Geometry.Polygon.Convex( ConvexPolygon(..), simplePolygon- , merge- , lowerTangent, lowerTangent'- , upperTangent, upperTangent'+module Data.Geometry.Polygon.Convex+ ( ConvexPolygon(..), simplePolygon+ , convexPolygon+ , isConvex, verifyConvex+ , merge+ , lowerTangent, lowerTangent'+ , upperTangent, upperTangent' - , extremes- , maxInDirection+ , extremes+ , maxInDirection - , leftTangent, rightTangent+ , leftTangent, rightTangent - , minkowskiSum- , bottomMost- ) where+ , minkowskiSum+ , bottomMost+ , inConvex+ , randomConvex -import Control.DeepSeq-import Control.Lens hiding ((:<), (:>))-import Data.CircularSeq (CSeq)-import qualified Data.CircularSeq as C+ , diameter+ , diametralPair+ , diametralIndexPair+ ) where+++import Control.DeepSeq (NFData)+import Control.Lens (Iso, iso, over, view, (%~), (&), (^.))+import Control.Monad.Random+import Control.Monad.ST+import Control.Monad.State+import Data.Coerce import Data.Ext-import qualified Data.Foldable as F-import Data.Function (on)-import Data.Geometry.Box (IsBoxable(..))+import qualified Data.Foldable as F+import Data.Function (on)+import Data.Geometry.Boundary+import Data.Geometry.Box (IsBoxable (..)) import Data.Geometry.LineSegment import Data.Geometry.Point-import Data.Geometry.Polygon.Core (fromPoints, SimplePolygon, outerBoundary)-import Data.Geometry.Polygon.Extremes(cmpExtreme)+import Data.Geometry.Polygon.Core (Polygon (..), SimplePolygon, centroid,+ outerBoundaryVector, outerVertex, size,+ unsafeFromPoints, unsafeFromVector,+ unsafeOuterBoundaryVector)+import Data.Geometry.Polygon.Extremes (cmpExtreme) import Data.Geometry.Properties import Data.Geometry.Transformation+import Data.Geometry.Triangle import Data.Geometry.Vector-import Data.List.NonEmpty (NonEmpty(..))-import qualified Data.List.NonEmpty as NonEmpty-import Data.Maybe (fromJust)-import Data.Ord (comparing)-import Data.Semigroup.Foldable (Foldable1(..))-import Data.Sequence (viewl,viewr, ViewL(..), ViewR(..))-import qualified Data.Sequence as S+import qualified Data.IntSet as IS+import Data.List.NonEmpty (NonEmpty (..))+import qualified Data.List.NonEmpty as NonEmpty+import Data.Maybe (fromJust)+import Data.Ord (comparing)+import Data.Semigroup.Foldable (Foldable1 (..)) import Data.Util-+import qualified Data.Vector as V+import Data.Vector.Circular (CircularVector)+import qualified Data.Vector.Circular as CV+import qualified Data.Vector.Circular.Util as CV+import qualified Data.Vector.Mutable as Mut+import qualified Data.Vector.NonEmpty as NE+import qualified Data.Vector.Unboxed as VU -- import Data.Geometry.Ipe--- import Debug.Trace+-- import Data.Ratio+-- import Data.RealNumber.Rational+-- import Debug.Trace -------------------------------------------------------------------------------- -- | Data Type representing a convex polygon newtype ConvexPolygon p r = ConvexPolygon {_simplePolygon :: SimplePolygon p r } deriving (Show,Eq,NFData)-makeLenses ''ConvexPolygon +-- | ConvexPolygons are isomorphic to SimplePolygons with the added constraint that they have no+-- reflex vertices.+simplePolygon :: Iso (ConvexPolygon p1 r1) (ConvexPolygon p2 r2) (SimplePolygon p1 r1) (SimplePolygon p2 r2)+simplePolygon = iso _simplePolygon ConvexPolygon+ instance PointFunctor (ConvexPolygon p) where pmap f (ConvexPolygon p) = ConvexPolygon $ pmap f p @@ -73,14 +100,110 @@ boundingBox = boundingBox . _simplePolygon --- convexPolygon :: SimplePolygon p r -> Maybe (ConvexPolygon p r)--- convexPolygon p = if isConvex p then Just p else Nothing --- isConvex :: SimplePolygon p r -> Bool--- isConvex p = let ch = convexHull $ p^.vertices--- in p^.vertices.size == ch^.simplePolygon.vertices.size+--------------------------------------------------------------------------------+-- Convex hull of simple polygon. +type M s v a = StateT (Mut.MVector s v, Int) (ST s) a +runM :: Int -> M s v () -> ST s (Mut.MVector s v)+runM s action = do+ v <- Mut.new (2*s)+ (v', f) <- execStateT action (Mut.drop s v, 0)+ return $ Mut.tail $ Mut.take f v'++dequeRemove :: M s a ()+dequeRemove = do+ modify $ \(Mut.MVector offset len arr, f) -> (Mut.MVector (offset+1) (len-1) arr, f-1)++dequeInsert :: a -> M s a ()+dequeInsert a = do+ modify $ \(Mut.MVector offset len arr, f) -> (Mut.MVector (offset-1) (len+1) arr, f+1)+ (v,_) <- get+ Mut.write v 0 a++dequePush :: a -> M s a ()+dequePush a = do+ (v, f) <- get+ Mut.write v f a+ put (v,f+1)++dequePop :: M s a ()+dequePop = do+ modify $ \(v,f) -> (v,f-1)++dequeBottom :: Int -> M s a a+dequeBottom idx = do+ (v,_) <- get+ Mut.read v idx++dequeTop :: Int -> M s a a+dequeTop idx = do+ (v,f) <- get+ Mut.read v (f-idx-1)++-- Melkman's algorithm: http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.512.9681&rep=rep1&type=pdf++-- | \( O(n) \) Convex hull of a simple polygon.+--+-- For algorithmic details see: <https://en.wikipedia.org/wiki/Convex_hull_of_a_simple_polygon>+convexPolygon :: forall t p r. (Ord r, Num r, Show r, Show p) => Polygon t p r -> ConvexPolygon p r+convexPolygon p = ConvexPolygon $ unsafeFromVector $ V.create $ runM (size p) $+ findStartingPoint 2+ where+ -- Find the first spot where 0,n-1,n is not colinear.+ findStartingPoint :: Int -> M s (Point 2 r :+ p) ()+ findStartingPoint nth = do+ let vPrev = NE.unsafeIndex vs (nth-1)+ vNth = NE.unsafeIndex vs nth+ case ccw' v1 vPrev vNth of+ CoLinear -> findStartingPoint (nth+1)+ CCW -> do+ dequePush v1 >> dequePush vPrev+ dequePush vNth; dequeInsert vNth+ V.mapM_ build (NE.drop (nth+1) vs)+ CW -> do+ dequePush vPrev >> dequePush v1+ dequePush vNth; dequeInsert vNth+ V.mapM_ build (NE.drop (nth+1) vs)++ v1 = NE.unsafeIndex vs 0+ vs = CV.vector (p^.outerBoundaryVector)+ build v = do+ botTurn <- ccw' <$> pure v <*> dequeBottom 0 <*> dequeBottom 1+ topTurn <- ccw' <$> dequeTop 1 <*> dequeTop 0 <*> pure v+ when (botTurn == CW || topTurn == CW) $ do+ backtrackTop v; dequePush v+ backtrackBot v; dequeInsert v+ backtrackTop v = do+ turn <- ccw' <$> dequeTop 1 <*> dequeTop 0 <*> pure v+ unless (turn == CCW) $ do+ dequePop+ backtrackTop v+ backtrackBot v = do+ turn <- ccw' <$> pure v <*> dequeBottom 0 <*> dequeBottom 1+ unless (turn == CCW) $ do+ dequeRemove+ backtrackBot v++++++++-- | \( O(n) \) Check if a polygon is strictly convex.+isConvex :: (Ord r, Num r) => SimplePolygon p r -> Bool+isConvex s =+ CV.and (CV.zipWith3 f (CV.rotateLeft 1 vs) vs (CV.rotateRight 1 vs))+ where+ f a b c = ccw' a b c == CCW+ vs = s ^. outerBoundaryVector++-- | \( O(n) \) Verify that a convex polygon is strictly convex.+verifyConvex :: (Ord r, Num r) => ConvexPolygon p r -> Bool+verifyConvex = isConvex . _simplePolygon+ -- mainWith inFile outFile = do -- ePage <- readSinglePageFile inFile -- case ePage of@@ -115,13 +238,40 @@ -- -- pre: The input polygon is strictly convex. ----- running time: \(O(\log^2 n)\)+-- running time: \(O(\log n)\) maxInDirection :: (Num r, Ord r) => Vector 2 r -> ConvexPolygon p r -> Point 2 r :+ p maxInDirection u = findMaxWith (cmpExtreme u) +-- FIXME: c+1 is always less than n so we don't need to use `mod` or do bounds checking.+-- Use unsafe indexing.+-- \( O(\log n) \)+findMaxWith :: (Point 2 r :+ p -> Point 2 r :+ p -> Ordering)+ -> ConvexPolygon p r -> Point 2 r :+ p+findMaxWith cmp p = CV.index v (worker 0 (F.length v))+ where+ v = p ^. simplePolygon.outerBoundaryVector+ a `icmp` b = CV.index v a `cmp` CV.index v b+ worker a b+ | localMaximum c = c+ | a+1==b = b+ | otherwise =+ case (isUpwards a, isUpwards c, c `icmp` a /= LT) of+ (True, False, _) -> worker a c -- A is up, C is down, pick [a,c]+ (True, True, True) -> worker c b -- A is up, C is up, C is GTE A, pick [c,b]+ (True, True, False) -> worker a c -- A is up, C is LT A, pick [a,c]+ (False, True, _) -> worker c b -- A is down, C is up, pick [c,b]+ (False, False, False) -> worker c b -- A is down, C is down, C is LT A, pick [c,b]+ (False, _, True) -> worker a c -- A is down, C is GTE A, pick [a,c]+ where+ c = (a+b) `div` 2+ localMaximum idx = idx `icmp` (c-1) == GT && idx `icmp` (c+1) == GT+ isUpwards idx = idx `icmp` (idx+1) /= GT++{- Convex binary search using sequences in \( O(log^2 n) \)+ findMaxWith :: (Point 2 r :+ p -> Point 2 r :+ p -> Ordering) -> ConvexPolygon p r -> Point 2 r :+ p-findMaxWith cmp p = findMaxStart . C.rightElements . getVertices $ p+findMaxWith cmp = findMaxStart . S.fromList . F.toList . getVertices where p' >=. q = (p' `cmp` q) /= LT @@ -140,7 +290,7 @@ | otherwise = binSearch ac c cb -- | Given the vertices [a..] c [..b] find the exteral vtx- binSearch ac@(viewl -> a:<r) c cb = case (isUpwards a r, isUpwards c cb, a >=. c) of+ binSearch ac@(viewl -> a:<r) c cb = case (isUpwards a (r |> c), isUpwards c cb, a >=. c) of (True,False,_) -> findMax (ac |> c) (True,True,True) -> findMax (ac |> c) (True,True,False) -> findMax (c <| cb)@@ -157,7 +307,7 @@ -- the Edge from a to b is upwards w.r.t b if a is not larger than b isUpwards a (viewl -> b :< _) = (a `cmp` b) /= GT isUpwards _ _ = error "isUpwards: no edge endpoint"-+-} tangentCmp :: (Num r, Ord r) => Point 2 r -> Point 2 r :+ p -> Point 2 r :+ q -> Ordering@@ -167,19 +317,19 @@ CW -> GT -- q is right of the line from o to p --- | Given a convex polygon poly, and a point outside the polygon, find the+-- | Given a convex polygon poly, and a point outside the polygon, find the -- left tangent of q and the polygon, i.e. the vertex v of the convex polygon -- s.t. the polygon lies completely to the right of the line from q to v. ----- running time: \(O(\log^2 n)\).+-- running time: \(O(\log n)\). leftTangent :: (Ord r, Num r) => ConvexPolygon p r -> Point 2 r -> Point 2 r :+ p leftTangent poly q = findMaxWith (tangentCmp q) poly --- | Given a convex polygon poly, and a point outside the polygon, find the+-- | Given a convex polygon poly, and a point outside the polygon, find the -- right tangent of q and the polygon, i.e. the vertex v of the convex polygon -- s.t. the polygon lies completely to the left of the line from q to v. ----- running time: \(O(\log^2 n)\).+-- running time: \(O(\log n)\). rightTangent :: (Ord r, Num r) => ConvexPolygon p r -> Point 2 r -> Point 2 r :+ p rightTangent poly q = findMaxWith (flip $ tangentCmp q) poly @@ -209,21 +359,21 @@ -- Running time: O(n+m), where n and m are the sizes of the two polygons respectively merge :: (Num r, Ord r) => ConvexPolygon p r -> ConvexPolygon p r -> (ConvexPolygon p r, LineSegment 2 p r, LineSegment 2 p r)-merge lp rp = (ConvexPolygon . fromPoints $ r' ++ l', lt, ut)+merge lp rp = (ConvexPolygon . unsafeFromPoints $ r' ++ l', lt, ut) where lt@(ClosedLineSegment a b) = lowerTangent lp rp ut@(ClosedLineSegment c d) = upperTangent lp rp takeUntil p xs = let (xs',x:_) = break p xs in xs' ++ [x]- rightElems = F.toList . C.rightElements+ rightElems = F.toList . CV.rightElements takeAndRotate x y = takeUntil (coreEq x) . rightElems . rotateTo' y . getVertices r' = takeAndRotate b d rp l' = takeAndRotate c a lp -rotateTo' :: Eq a => (a :+ b) -> CSeq (a :+ b) -> CSeq (a :+ b)-rotateTo' x = fromJust . C.findRotateTo (coreEq x)+rotateTo' :: Eq a => (a :+ b) -> CircularVector (a :+ b) -> CircularVector (a :+ b)+rotateTo' x = fromJust . CV.findRotateTo (coreEq x) coreEq :: Eq a => (a :+ b) -> (a :+ b) -> Bool coreEq = (==) `on` (^.core)@@ -246,9 +396,8 @@ -> LineSegment 2 p r lowerTangent lp rp = ClosedLineSegment l r where- mkH f = NonEmpty.fromList . F.toList . f . getVertices- lh = mkH (C.rightElements . rightMost) lp- rh = mkH (C.leftElements . leftMost) rp+ lh = CV.rightElements . rightMost . getVertices $ lp+ rh = CV.leftElements . leftMost . getVertices $ rp (Two (l :+ _) (r :+ _)) = lowerTangent' lh rh -- | Compute the lower tangent of the two convex chains lp and rp@@ -286,16 +435,15 @@ -- the two polygons. -- - The vertices of the polygons are given in clockwise order ----- Running time: O(n+m), where n and m are the sizes of the two polygons respectively+-- Running time: \( O(n+m) \), where n and m are the sizes of the two polygons respectively upperTangent :: (Num r, Ord r) => ConvexPolygon p r -> ConvexPolygon p r -> LineSegment 2 p r upperTangent lp rp = ClosedLineSegment l r where- mkH f = NonEmpty.fromList . F.toList . f . getVertices- lh = mkH (C.leftElements . rightMost) lp- rh = mkH (C.rightElements . leftMost) rp+ lh = CV.leftElements . rightMost . getVertices $ lp+ rh = CV.rightElements . leftMost . getVertices $ rp (Two (l :+ _) (r :+ _)) = upperTangent' lh rh -- | Compute the upper tangent of the two convex chains lp and rp@@ -335,14 +483,14 @@ -- running time: \(O(n+m)\). minkowskiSum :: (Ord r, Num r) => ConvexPolygon p r -> ConvexPolygon q r -> ConvexPolygon (p,q) r-minkowskiSum p q = ConvexPolygon . fromPoints $ merge' (f p) (f q)+minkowskiSum p q = ConvexPolygon . unsafeFromPoints $ merge' (f p) (f q) where- f p' = let xs@(S.viewl -> (v :< _)) = C.asSeq . bottomMost . getVertices $ p'- in F.toList $ xs |> v- (v :+ ve) .+. (w :+ we) = v .+^ (toVec w) :+ (ve,we)+ f p' = let (v:xs) = F.toList . bottomMost . getVertices $ p'+ in v:xs++[v]+ (v :+ ve) .+. (w :+ we) = v .+^ toVec w :+ (ve,we) cmpAngle v v' w w' =- ccwCmpAround (ext $ origin) (ext . Point $ v' .-. v) (ext . Point $ w' .-. w)+ ccwCmpAround origin (Point $ v' .-. v) (Point $ w' .-. w) merge' [_] [_] = [] merge' vs@[v] (w:ws) = v .+. w : merge' vs ws@@ -352,32 +500,117 @@ LT -> merge' (v':vs) (w:w':ws) GT -> merge' (v:v':vs) (w':ws) EQ -> merge' (v':vs) (w':ws)- merge' _ _ = error $ "minkowskiSum: Should not happen"+ merge' _ _ = error "minkowskiSum: Should not happen" +--------------------------------------------------------------------------------+-- inConvex +-- 1. Check if p is on left edge or right edge.+-- 2. Do binary search:+-- Find the largest n where p is on the right of 0 to n.+-- 3. Check if p is on segment n,n+1+-- 4. Check if p is in triangle 0,n,n+1 +-- | \( O(\log n) \)+-- Check if a point lies inside a convex polygon, on the boundary, or outside of the+-- convex polygon.+inConvex :: forall p r. (Fractional r, Ord r)+ => Point 2 r -> ConvexPolygon p r+ -> PointLocationResult+inConvex p (ConvexPolygon poly)+ | p `intersects` leftEdge = OnBoundary+ | p `intersects` rightEdge = OnBoundary+ | otherwise = worker 1 n+ where+ p' = p :+ undefined+ n = size poly - 1+ point0 = point 0+ leftEdge = ClosedLineSegment point0 (point n)+ rightEdge = ClosedLineSegment point0 (point 1)+ worker a b+ | a+1 == b =+ if p `intersects` (ClosedLineSegment (point a) (point b))+ then OnBoundary+ else+ if inTriangle p (Triangle point0 (point a) (point b)) == Outside+ then Outside+ else Inside+ | ccw' point0 (point c) p' == CCW = worker c b+ | otherwise = worker a c+ where c = (a+b) `div` 2+ point x = poly ^. outerVertex x+ --------------------------------------------------------------------------------+-- Diameter +-- | \( O(n) \) Computes the Euclidean diameter by scanning antipodal pairs.+diameter :: (Ord r, Floating r) => ConvexPolygon p r -> r+diameter p = euclideanDist (a^.core) (b^.core)+ where+ (a,b) = diametralPair p++-- | \( O(n) \)+-- Computes the Euclidean diametral pair by scanning antipodal pairs.+diametralPair :: (Ord r, Num r) => ConvexPolygon p r -> (Point 2 r :+ p, Point 2 r :+ p)+diametralPair p = (p^.simplePolygon.outerVertex a, p^.simplePolygon.outerVertex b)+ where+ (a,b) = diametralIndexPair p++-- | \( O(n) \)+-- Computes the Euclidean diametral pair by scanning antipodal pairs.+diametralIndexPair :: (Ord r, Num r) => ConvexPolygon p r -> (Int, Int)+diametralIndexPair p = F.maximumBy fn $ antipodalPairs p+ where+ fn (a1,b1) (a2,b2) =+ squaredEuclideanDist (p^.simplePolygon.outerVertex a1.core) (p^.simplePolygon.outerVertex b1.core)+ `compare`+ squaredEuclideanDist (p^.simplePolygon.outerVertex a2.core) (p^.simplePolygon.outerVertex b2.core)++antipodalPairs :: forall p r. (Ord r, Num r) => ConvexPolygon p r -> [(Int, Int)]+antipodalPairs p = worker 0 (CV.index vectors 0) 1+ where+ n = size (p^.simplePolygon)+ vs = p^.simplePolygon.outerBoundaryVector++ worker a aElt b+ | a == n = []+ | otherwise =+ case ccw aElt (Point2 0 0) (CV.index vectors b) of+ CW -> worker a aElt (b+1)+ _ ->+ (a, b `mod` n) :+ worker (a+1) (CV.index vectors (a+1)) b++ vectors :: CircularVector (Point 2 r)+ vectors = CV.unsafeFromVector $ V.generate n $ \i ->+ let Point p1 = point i+ p2 = point (i+1)+ in p2 .-^ p1++ point x = CV.index vs x ^. core++--------------------------------------------------------------------------------+ -- | Rotate to the rightmost point (rightmost and topmost in case of ties)-rightMost :: Ord r => CSeq (Point 2 r :+ p) -> CSeq (Point 2 r :+ p)-rightMost xs = let m = F.maximumBy (comparing (^.core)) xs in rotateTo' m xs+rightMost :: Ord r => CircularVector (Point 2 r :+ p) -> CircularVector (Point 2 r :+ p)+rightMost = CV.rotateToMaximumBy (comparing (^.core)) -- | Rotate to the leftmost point (and bottommost in case of ties)-leftMost :: Ord r => CSeq (Point 2 r :+ p) -> CSeq (Point 2 r :+ p)-leftMost xs = let m = F.minimumBy (comparing (^.core)) xs in rotateTo' m xs+leftMost :: Ord r => CircularVector (Point 2 r :+ p) -> CircularVector (Point 2 r :+ p)+leftMost = CV.rotateToMinimumBy (comparing (^.core)) -- | Rotate to the bottommost point (and leftmost in case of ties)-bottomMost :: Ord r => CSeq (Point 2 r :+ p) -> CSeq (Point 2 r :+ p)-bottomMost xs = let f p = (p^.core.yCoord,p^.core.xCoord)- m = F.minimumBy (comparing f) xs- in rotateTo' m xs+bottomMost :: Ord r => CircularVector (Point 2 r :+ p) -> CircularVector (Point 2 r :+ p)+bottomMost = CV.rotateToMinimumBy (comparing f)+ where+ f p = (p^.core.yCoord,p^.core.xCoord) -- | Helper to get the vertices of a convex polygon-getVertices :: ConvexPolygon p r -> CSeq (Point 2 r :+ p)-getVertices = view (simplePolygon.outerBoundary)+getVertices :: ConvexPolygon p r -> CircularVector (Point 2 r :+ p)+getVertices = view (simplePolygon.outerBoundaryVector) -- -- | rotate right while p 'current' 'rightNeibhour' is true -- rotateRWhile :: (a -> a -> Bool) -> C.CList a -> C.CList a@@ -401,3 +634,76 @@ -- testB :: Num r => ConvexPolygon () r -- testB = ConvexPolygon . fromPoints . map ext $ [origin, Point2 5 3, Point2 (-2) 2, Point2 (-2) 1]+++++--------------------------------------------------------------------------------+-- Random convex polygons++-- This is true for all convex polygons:+-- 1. the sum of all edge vectors is (0,0). This is even true for all polygons.+-- 2. edges are sorted by angle. Ie. all vertices are convex, not reflex.+--+-- So, if we can generate a set of vectors that sum to zero then we can sort them+-- and place them end-to-end and the result will be a convex polygon.+--+-- So, we need to generate N points that sum to 0. This can be done by generating+-- two sets of N points that sum to M, and the subtracting them from each other.+--+-- Generating N points that sum to M is done like this: Generate (N-1) unique points+-- between (but not including) 0 and M. Write down the distance between the points.+-- Imagine a scale from 0 to M:+-- 0 M+-- | |+-- Then we add two randomly selected points:+-- 0 M+-- | * * |+-- Then we look at the distance between 0 and point1, point1 and point2, and point2 to M:+-- 0 M+-- |--*------*--|+-- 2 6 2+-- 2+6+2 = 10 = M+--+-- Doing this again might yield [5,2,3]. Subtract them:+-- [2, 6, 2 ]+-- - [5, 2, 3 ]+-- = [2-5, 6-2, 2-3]+-- = [-3, 4, -1 ]+-- And the sum of [-3, 4, -1] = -3+4-1 = 0.++-- O(n log n)+randomBetween :: RandomGen g => Int -> Int -> Rand g (VU.Vector Int)+randomBetween n vMax | vMax < n+1 = pure $ VU.replicate vMax 1+randomBetween n vMax = worker (n-1) IS.empty+ where+ gen from [] = [vMax-from]+ gen from (x:xs) = (x-from) : gen x xs+ worker 0 seen = pure (VU.fromList (gen 0 $ IS.elems seen))+ worker i seen = do+ v <- getRandomR (1, vMax-1)+ if IS.member v seen+ then worker i seen+ else worker (i-1) (IS.insert v seen)++randomBetweenZero :: RandomGen g => Int -> Int -> Rand g (VU.Vector Int)+randomBetweenZero n vMax = VU.zipWith (-) <$> randomBetween n vMax <*> randomBetween n vMax++randomEdges :: RandomGen g => Int -> Int -> Rand g [Vector 2 Int]+randomEdges n vMax = do+ zipWith Vector2+ <$> fmap VU.toList (randomBetweenZero n vMax)+ <*> fmap VU.toList (randomBetweenZero n vMax)++-- | \( O(n \log n) \)+-- Generate a uniformly random ConvexPolygon with @N@ vertices and a granularity of @vMax@.+randomConvex :: RandomGen g => Int -> Int -> Rand g (ConvexPolygon () Rational)+randomConvex n _vMax | n < 3 =+ error "Data.Geometry.Polygon.Convex.randomConvex: At least 3 edges are required."+randomConvex n vMax = do+ ~(v:vs) <- coerce . sortAround origin . coerce <$> randomEdges n vMax+ let vertices = fmap ((/ realToFrac vMax) . realToFrac) <$> scanl (.+^) (Point v) vs+ pRational = unsafeFromPoints $ map ext vertices+ Point c = centroid pRational+ pFinal = pRational & unsafeOuterBoundaryVector %~ CV.map (over core (.-^ c))+ pure $ ConvexPolygon pFinal
src/Data/Geometry/Polygon/Core.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE OverloadedStrings #-} -------------------------------------------------------------------------------- -- | -- Module : Data.Geometry.Polygon.Core@@ -8,104 +9,167 @@ -- A Polygon data type and some basic functions to interact with them. -- ---------------------------------------------------------------------------------module Data.Geometry.Polygon.Core( PolygonType(..)- , Polygon(..)- , _SimplePolygon, _MultiPolygon- , SimplePolygon, MultiPolygon, SomePolygon+module Data.Geometry.Polygon.Core+ ( PolygonType(..)+ , Polygon(..)+ , Vertices+ , _SimplePolygon, _MultiPolygon+ , SimplePolygon, MultiPolygon, SomePolygon + -- * Construction+ , fromPoints+ , fromCircularVector - , fromPoints+ , simpleFromPoints+ , simpleFromCircularVector - , polygonVertices, listEdges+ , unsafeFromPoints+ , unsafeFromCircularVector+ , unsafeFromVector+ , toVector+ , toPoints - , outerBoundary, outerBoundaryEdges- , outerVertex, outerBoundaryEdge+ , isSimple - , polygonHoles, polygonHoles'- , holeList+ , size+ , polygonVertices, listEdges - , inPolygon, insidePolygon, onBoundary+ , outerBoundary, outerBoundaryVector+ , unsafeOuterBoundaryVector+ , outerBoundaryEdges+ , outerVertex, unsafeOuterVertex+ , outerBoundaryEdge - , area, signedArea+ , polygonHoles, polygonHoles'+ , holeList - , centroid- , pickPoint+ , area, signedArea - , isTriangle+ , centroid+ , pickPoint - , isCounterClockwise- , toCounterClockWiseOrder, toCounterClockWiseOrder'- , toClockwiseOrder, toClockwiseOrder'- , reverseOuterBoundary+ , isTriangle - , findDiagonal+ , isCounterClockwise+ , toCounterClockWiseOrder, toCounterClockWiseOrder'+ , toClockwiseOrder, toClockwiseOrder'+ , reverseOuterBoundary - , withIncidentEdges, numberVertices+ , findDiagonal - , asSimplePolygon- ) where+ , withIncidentEdges, numberVertices + -- * Testing for Reflex or Convex++ , isReflexVertex, isConvexVertex, isStrictlyConvexVertex+ , reflexVertices, convexVertices, strictlyConvexVertices++ -- * Specialized folds+ , maximumVertexBy+ , minimumVertexBy+ , findRotateTo+ , rotateLeft+ , rotateRight+ ) where++import qualified Algorithms.Geometry.LineSegmentIntersection.BentleyOttmann as BO import Control.DeepSeq-import Control.Lens hiding (Simple)+import Control.Lens (Getter, Lens', Prism',+ Traversal', lens, over,+ prism', to, toListOf,+ view, (%~), (&), (.~),+ (^.))+import Data.Aeson import Data.Bifoldable import Data.Bifunctor import Data.Bitraversable-import qualified Data.CircularSeq as C import Data.Ext-import qualified Data.Foldable as F+import qualified Data.Foldable as F import Data.Geometry.Boundary-import Data.Geometry.Box+import Data.Geometry.Box (IsBoxable (..),+ boundingBoxList') import Data.Geometry.Line import Data.Geometry.LineSegment import Data.Geometry.Point import Data.Geometry.Properties import Data.Geometry.Transformation-import Data.Geometry.Triangle (Triangle(..), inTriangle)-import Data.Geometry.Vector-import qualified Data.List as List-import Data.List.NonEmpty (NonEmpty(..))-import qualified Data.List.NonEmpty as NonEmpty-import Data.Maybe (mapMaybe, catMaybes)-import Data.Ord (comparing)-import Data.Semigroup (sconcat)+import Data.Geometry.Triangle (Triangle (..),+ inTriangle)+import Data.Geometry.Vector (Additive (zero, (^+^)),+ Affine ((.+^), (.-.)),+ (*^), (^*), (^/))+import qualified Data.List as List+import qualified Data.List.NonEmpty as NonEmpty+import Data.Maybe (catMaybes)+import Data.Ord (comparing)+import Data.Semigroup (sconcat) import Data.Semigroup.Foldable-import qualified Data.Sequence as Seq import Data.Util-import Data.Vinyl.CoRec (asA)+import Data.Vector (Vector)+import qualified Data.Vector as V+import Data.Vector.Circular (CircularVector)+import qualified Data.Vector.Circular as CV+import qualified Data.Vector.Circular.Util as CV + -- import Data.RealNumber.Rational -------------------------------------------------------------------------------- {- $setup >>> import Data.RealNumber.Rational+>>> import Data.Foldable+>>> import Control.Lens.Extras >>> :{--- import qualified Data.CircularSeq as C+-- import qualified Data.Vector.Circular as CV let simplePoly :: SimplePolygon () (RealNumber 10)- simplePoly = SimplePolygon . C.fromList . map ext $ [ Point2 0 0- , Point2 10 0- , Point2 10 10- , Point2 5 15- , Point2 1 11- ]+ simplePoly = fromPoints . map ext $+ [ Point2 0 0+ , Point2 10 0+ , Point2 10 10+ , Point2 5 15+ , Point2 1 11+ ]+ simpleTriangle :: SimplePolygon () (RealNumber 10)+ simpleTriangle = fromPoints . map ext $+ [ Point2 0 0, Point2 2 0, Point2 1 1]+ multiPoly :: MultiPolygon () (RealNumber 10)+ multiPoly = MultiPolygon+ (fromPoints . map ext $ [Point2 (-1) (-1), Point2 3 (-1), Point2 2 2])+ [simpleTriangle] :} -} --- | We distinguish between simple polygons (without holes) and Polygons with holes.+-- | We distinguish between simple polygons (without holes) and polygons with holes. data PolygonType = Simple | Multi -+-- | Polygons are sequences of points and may or may not contain holes.+--+-- Degenerate polygons (polygons with self-intersections or fewer than 3 points)+-- are only possible if you use functions marked as unsafe. data Polygon (t :: PolygonType) p r where- SimplePolygon :: C.CSeq (Point 2 r :+ p) -> Polygon Simple p r- MultiPolygon :: C.CSeq (Point 2 r :+ p) -> [Polygon Simple p r] -> Polygon Multi p r+ SimplePolygon :: Vertices (Point 2 r :+ p) -> SimplePolygon p r+ MultiPolygon :: SimplePolygon p r -> [SimplePolygon p r] -> MultiPolygon p r +newtype Vertices a = Vertices (CircularVector a)+ deriving (Functor, Foldable, Foldable1, Traversable, NFData, Eq, Ord)+ -- | Prism to 'test' if we are a simple polygon-_SimplePolygon :: Prism' (Polygon Simple p r) (C.CSeq (Point 2 r :+ p))+--+-- >>> is _SimplePolygon simplePoly+-- True+_SimplePolygon :: Prism' (Polygon Simple p r) (Vertices (Point 2 r :+ p)) _SimplePolygon = prism' SimplePolygon (\(SimplePolygon vs) -> Just vs) -- | Prism to 'test' if we are a Multi polygon-_MultiPolygon :: Prism' (Polygon Multi p r) (C.CSeq (Point 2 r :+ p), [Polygon Simple p r])+--+-- >>> is _MultiPolygon multiPoly+-- True+_MultiPolygon :: Prism' (Polygon Multi p r) (Polygon Simple p r, [Polygon Simple p r]) _MultiPolygon = prism' (uncurry MultiPolygon) (\(MultiPolygon vs hs) -> Just (vs,hs)) +instance Functor (Polygon t p) where+ fmap = bimap id+ instance Bifunctor (Polygon t) where bimap = bimapDefault @@ -115,7 +179,7 @@ instance Bitraversable (Polygon t) where bitraverse f g p = case p of SimplePolygon vs -> SimplePolygon <$> bitraverseVertices f g vs- MultiPolygon vs hs -> MultiPolygon <$> bitraverseVertices f g vs+ MultiPolygon vs hs -> MultiPolygon <$> bitraverse f g vs <*> traverse (bitraverse f g) hs instance (NFData p, NFData r) => NFData (Polygon t p r) where@@ -126,8 +190,10 @@ -> t (Point 2 r :+ p) -> f (t (Point 2 s :+ q)) bitraverseVertices f g = traverse (bitraverse (traverse g) f) +-- | Polygon without holes. type SimplePolygon = Polygon Simple +-- | Polygon with zero or more holes. type MultiPolygon = Polygon Multi -- | Either a simple or multipolygon@@ -141,9 +207,23 @@ type instance NumType (Polygon t p r) = r instance (Show p, Show r) => Show (Polygon t p r) where- show (SimplePolygon vs) = "SimplePolygon (" <> show vs <> ")"+ show (SimplePolygon vs) = "SimplePolygon " <> show (F.toList vs) show (MultiPolygon vs hs) = "MultiPolygon (" <> show vs <> ") (" <> show hs <> ")" +instance (Read p, Read r) => Read (SimplePolygon p r) where+ readsPrec d = readParen (d > app_prec) $ \r ->+ [ (unsafeFromPoints vs, t)+ | ("SimplePolygon", s) <- lex r, (vs, t) <- reads s ]+ where app_prec = 10++instance (Read p, Read r) => Read (MultiPolygon p r) where+ readsPrec d = readParen (d > app_prec) $ \r ->+ [ (MultiPolygon vs hs, t')+ | ("MultiPolygon", s) <- lex r+ , (vs, t) <- reads s+ , (hs, t') <- reads t ]+ where app_prec = 10+ -- instance (Read p, Read r) => Show (Polygon t p r) where -- show (SimplePolygon vs) = "SimplePolygon (" <> show vs <> ")" -- show (MultiPolygon vs hs) = "MultiPolygon (" <> show vs <> ") (" <> show hs <> ")"@@ -156,54 +236,94 @@ instance PointFunctor (Polygon t p) where pmap f (SimplePolygon vs) = SimplePolygon (fmap (first f) vs)- pmap f (MultiPolygon vs hs) = MultiPolygon (fmap (first f) vs) (map (pmap f) hs)+ pmap f (MultiPolygon vs hs) = MultiPolygon (pmap f vs) (map (pmap f) hs) instance Fractional r => IsTransformable (Polygon t p r) where transformBy = transformPointFunctor instance IsBoxable (Polygon t p r) where- boundingBox = boundingBoxList' . toListOf (outerBoundary.traverse.core)+ boundingBox = boundingBoxList' . toListOf (outerBoundaryVector.traverse.core) -type instance IntersectionOf (Line 2 r) (Boundary (Polygon t p r)) =- '[Seq.Seq (Either (Point 2 r) (LineSegment 2 () r))] -type instance IntersectionOf (Point 2 r) (Polygon t p r) = [NoIntersection, Point 2 r]--instance (Fractional r, Ord r) => (Point 2 r) `IsIntersectableWith` (Polygon t p r) where- nonEmptyIntersection = defaultNonEmptyIntersection- q `intersects` pg = q `inPolygon` pg /= Outside- q `intersect` pg | q `intersects` pg = coRec q- | otherwise = coRec NoIntersection+instance (ToJSON r, ToJSON p) => ToJSON (Polygon t p r) where+ toJSON = \case+ (SimplePolygon vs) -> object [ "tag" .= ("SimplePolygon" :: String)+ , "vertices" .= F.toList vs+ ]+ (MultiPolygon vs hs) -> object [ "tag" .= ("MultiPolygon" :: String)+ , "outerBoundary" .= getVertices vs+ , "holes" .= map getVertices hs+ ]+ where+ getVertices = view (outerBoundaryVector.to F.toList) --- instance IsIntersectableWith (Line 2 r) (Boundary (Polygon t p r)) where--- nonEmptyIntersection _ _ (CoRec xs) = null xs--- l `intersect` (Boundary (SimplePolygon vs)) =--- undefined- -- l `intersect` (Boundary (MultiPolygon vs hs)) = coRec .- -- Seq.sortBy f . Seq.fromList- -- . concatMap (unpack . (l `intersect`) . Boundary)- -- $ SimplePolygon vs : hs- -- where- -- unpack (CoRec x) = x- -- f = undefined+instance (FromJSON r, Eq r, Num r, FromJSON p) => FromJSON (Polygon Simple p r) where+ parseJSON = withObject "Polygon" $ \o -> o .: "tag" >>= \case+ "SimplePolygon" -> pSimple o+ (_ :: String) -> fail "Not a SimplePolygon"+ where+ pSimple o = fromPoints <$> o .: "vertices" +instance (FromJSON r, Eq r, Num r, FromJSON p) => FromJSON (Polygon Multi p r) where+ parseJSON = withObject "Polygon" $ \o -> o .: "tag" >>= \case+ "MultiPolygon" -> pMulti o+ (_ :: String) -> fail "Not a MultiPolygon"+ where+ pMulti o = (\vs hs -> MultiPolygon (fromPoints vs) (map fromPoints hs))+ <$> o .: "outerBoundary" <*> o .: "holes" -- * Functions on Polygons -outerBoundary :: forall t p r. Lens' (Polygon t p r) (C.CSeq (Point 2 r :+ p))+-- | Getter access to the outer boundary vector of a polygon.+--+-- >>> toList (simpleTriangle ^. outerBoundaryVector)+-- [Point2 0 0 :+ (),Point2 2 0 :+ (),Point2 1 1 :+ ()]+outerBoundaryVector :: forall t p r. Getter (Polygon t p r) (CircularVector (Point 2 r :+ p))+outerBoundaryVector = to g+ where+ g :: Polygon t p r -> CircularVector (Point 2 r :+ p)+ g (SimplePolygon (Vertices vs)) = vs+ g (MultiPolygon (SimplePolygon (Vertices vs)) _) = vs++-- | Unsafe lens access to the outer boundary vector of a polygon.+--+-- >>> toList (simpleTriangle ^. unsafeOuterBoundaryVector)+-- [Point2 0 0 :+ (),Point2 2 0 :+ (),Point2 1 1 :+ ()]+--+-- >>> simpleTriangle & unsafeOuterBoundaryVector .~ CV.singleton (Point2 0 0 :+ ())+-- SimplePolygon [Point2 0 0 :+ ()]+unsafeOuterBoundaryVector :: forall t p r. Lens' (Polygon t p r) (CircularVector (Point 2 r :+ p))+unsafeOuterBoundaryVector = lens g s+ where+ g :: Polygon t p r -> CircularVector (Point 2 r :+ p)+ g (SimplePolygon (Vertices vs)) = vs+ g (MultiPolygon (SimplePolygon (Vertices vs)) _) = vs++ s :: Polygon t p r -> CircularVector (Point 2 r :+ p)+ -> Polygon t p r+ s SimplePolygon{} vs = SimplePolygon (Vertices vs)+ s (MultiPolygon _ hs) vs = MultiPolygon (SimplePolygon (Vertices vs)) hs+++-- | \( O(1) \) Lens access to the outer boundary of a polygon.+outerBoundary :: forall t p r. Lens' (Polygon t p r) (SimplePolygon p r) outerBoundary = lens g s where- g :: Polygon t p r -> C.CSeq (Point 2 r :+ p)- g (SimplePolygon vs) = vs- g (MultiPolygon vs _) = vs+ g :: Polygon t p r -> SimplePolygon p r+ g poly@SimplePolygon{} = poly+ g (MultiPolygon simple _) = simple - s :: Polygon t p r -> C.CSeq (Point 2 r :+ p)+ s :: Polygon t p r -> SimplePolygon p r -> Polygon t p r- s (SimplePolygon _) vs = SimplePolygon vs- s (MultiPolygon _ hs) vs = MultiPolygon vs hs+ s SimplePolygon{} simple = simple+ s (MultiPolygon _ hs) simple = MultiPolygon simple hs +-- | Lens access for polygon holes.+--+-- >>> multiPoly ^. polygonHoles+-- [SimplePolygon [Point2 0 0 :+ (),Point2 2 0 :+ (),Point2 1 1 :+ ()]] polygonHoles :: forall p r. Lens' (Polygon Multi p r) [Polygon Simple p r] polygonHoles = lens g s where@@ -213,16 +333,30 @@ -> Polygon Multi p r s (MultiPolygon vs _) = MultiPolygon vs +{- HLINT ignore polygonHoles' -}+-- | \( O(1) \). Traversal lens for polygon holes. Does nothing for simple polygons. polygonHoles' :: Traversal' (Polygon t p r) [Polygon Simple p r] polygonHoles' = \f -> \case- p@(SimplePolygon _) -> pure p- (MultiPolygon vs hs) -> MultiPolygon vs <$> f hs+ p@SimplePolygon{} -> pure p+ MultiPolygon vs hs -> MultiPolygon vs <$> f hs --- | Access the i^th vertex on the outer boundary-outerVertex :: Int -> Lens' (Polygon t p r) (Point 2 r :+ p)-outerVertex i = outerBoundary.C.item i+-- | /O(1)/ Access the i^th vertex on the outer boundary. Indices are modulo \(n\).+--+-- >>> simplePoly ^. outerVertex 0+-- Point2 0 0 :+ ()+outerVertex :: Int -> Getter (Polygon t p r) (Point 2 r :+ p)+outerVertex i = outerBoundaryVector . CV.item i --- running time: \(O(\log i)\)+-- | \( O(1) \) read and \( O(n) \) write. Access the i^th vertex on the outer boundary+--+-- >>> simplePoly ^. unsafeOuterVertex 0+-- Point2 0 0 :+ ()+-- >>> simplePoly & unsafeOuterVertex 0 .~ (Point2 10 10 :+ ())+-- SimplePolygon [Point2 10 10 :+ (),Point2 10 0 :+ (),Point2 10 10 :+ (),Point2 5 15 :+ (),Point2 1 11 :+ ()]+unsafeOuterVertex :: Int -> Lens' (Polygon t p r) (Point 2 r :+ p)+unsafeOuterVertex i = unsafeOuterBoundaryVector . CV.item i++-- | \( O(1) \) Get the n^th edge along the outer boundary of the polygon. The edge is half open. outerBoundaryEdge :: Int -> Polygon t p r -> LineSegment 2 p r outerBoundaryEdge i p = let u = p^.outerVertex i v = p^.outerVertex (i+1)@@ -231,36 +365,116 @@ -- | Get all holes in a polygon holeList :: Polygon t p r -> [Polygon Simple p r]-holeList (SimplePolygon _) = []+holeList SimplePolygon{} = [] holeList (MultiPolygon _ hs) = hs --- | The vertices in the polygon. No guarantees are given on the order in which+-- | \( O(1) \) Vertex count. Includes the vertices of holes.+size :: Polygon t p r -> Int+size (SimplePolygon (Vertices cv)) = F.length cv+size (MultiPolygon b hs) = sum (map size (b:hs))++-- | \( O(n) \) The vertices in the polygon. No guarantees are given on the order in which -- they appear! polygonVertices :: Polygon t p r -> NonEmpty.NonEmpty (Point 2 r :+ p)-polygonVertices (SimplePolygon vs) = toNonEmpty vs+polygonVertices p@SimplePolygon{} = toNonEmpty $ p^.outerBoundaryVector polygonVertices (MultiPolygon vs hs) =- sconcat $ toNonEmpty vs NonEmpty.:| map polygonVertices hs+ sconcat $ toNonEmpty (polygonVertices vs) NonEmpty.:| map polygonVertices hs +-- FIXME: Get rid of 'Fractional r' constraint.+-- | \( O(n \log n) \) Check if a polygon has any holes, duplicate points, or+-- self-intersections.+isSimple :: (Ord r, Fractional r) => Polygon p t r -> Bool+isSimple p@SimplePolygon{} = null . BO.interiorIntersections $ listEdges p+isSimple (MultiPolygon b []) = isSimple b+isSimple MultiPolygon{} = False --- | Creates a simple polygon from the given list of vertices.+requireThree :: String -> [a] -> [a]+requireThree _ lst@(_:_:_:_) = lst+requireThree label _ = error $+ "Data.Geometry.Polygon." ++ label ++ ": Polygons must have at least three points."++-- | \( O(n) \) Creates a polygon from the given list of vertices. --+-- The points are placed in CCW order if they are not already. Overlapping+-- edges and repeated vertices are allowed.+--+fromPoints :: forall p r. (Eq r, Num r) => [Point 2 r :+ p] -> SimplePolygon p r+fromPoints = fromCircularVector . CV.unsafeFromList . requireThree "fromPoints"++-- | \( O(n) \) Creates a polygon from the given vector of vertices.+--+-- The points are placed in CCW order if they are not already. Overlapping+-- edges and repeated vertices are allowed.+--+fromCircularVector :: forall p r. (Eq r, Num r) => CircularVector (Point 2 r :+ p) -> SimplePolygon p r+fromCircularVector = toCounterClockWiseOrder . unsafeFromCircularVector++-- | \( O(n \log n) \) Creates a simple polygon from the given list of vertices.+--+-- The points are placed in CCW order if they are not already. Overlapping+-- edges and repeated vertices are /not/ allowed and will trigger an exception.+--+simpleFromPoints :: forall p r. (Ord r, Fractional r) => [Point 2 r :+ p] -> SimplePolygon p r+simpleFromPoints =+ simpleFromCircularVector . CV.unsafeFromList . requireThree "simpleFromPoints"++-- | \( O(n \log n) \) Creates a simple polygon from the given vector of vertices.+--+-- The points are placed in CCW order if they are not already. Overlapping+-- edges and repeated vertices are /not/ allowed and will trigger an exception.+--+simpleFromCircularVector :: forall p r. (Ord r, Fractional r)+ => CircularVector (Point 2 r :+ p) -> SimplePolygon p r+simpleFromCircularVector v =+ let p = fromCircularVector v+ hasInteriorIntersections = not . null . BO.interiorIntersections+ in if hasInteriorIntersections (listEdges p)+ then error "Data.Geometry.Polygon.simpleFromCircularVector: \+ \Found self-intersections or repeated vertices."+ else p++-- | \( O(n) \) Creates a simple polygon from the given list of vertices.+-- -- pre: the input list constains no repeated vertices.-fromPoints :: [Point 2 r :+ p] -> SimplePolygon p r-fromPoints = SimplePolygon . C.fromList+unsafeFromPoints :: [Point 2 r :+ p] -> SimplePolygon p r+unsafeFromPoints = unsafeFromCircularVector . CV.unsafeFromList +-- | \( O(1) \) Creates a simple polygon from the given vector of vertices.+--+-- pre: the input list constains no repeated vertices.+unsafeFromCircularVector :: CircularVector (Point 2 r :+ p) -> SimplePolygon p r+unsafeFromCircularVector = SimplePolygon . Vertices --- | The edges along the outer boundary of the polygon. The edges are half open.+-- | \( O(1) \) Creates a simple polygon from the given vector of vertices. ----- running time: \(O(n)\)-outerBoundaryEdges :: Polygon t p r -> C.CSeq (LineSegment 2 p r)-outerBoundaryEdges = toEdges . (^.outerBoundary)+-- pre: the input list constains no repeated vertices.+unsafeFromVector :: Vector (Point 2 r :+ p) -> SimplePolygon p r+unsafeFromVector = unsafeFromCircularVector . CV.unsafeFromVector --- | Lists all edges. The edges on the outer boundary are given before the ones+-- -- | Polygon points, from left to right.+-- toList :: Polygon t p r -> [Point 2 r :+ p]+-- toList (SimplePolygon c) = F.toList c+-- toList (MultiPolygon s hs) = toList s ++ concatMap toList hs++-- | \( O(n) \)+-- Polygon points, from left to right.+toVector :: Polygon t p r -> Vector (Point 2 r :+ p)+toVector p@SimplePolygon{} = CV.toVector $ p^.outerBoundaryVector+toVector (MultiPolygon s hs) = foldr (<>) (toVector s) (map toVector hs)++-- | \( O(n) \)+-- Polygon points, from left to right.+toPoints :: Polygon t p r -> [Point 2 r :+ p]+toPoints = V.toList . toVector++-- | \( O(n) \) The edges along the outer boundary of the polygon. The edges are half open.+outerBoundaryEdges :: Polygon t p r -> CircularVector (LineSegment 2 p r)+outerBoundaryEdges = toEdges . (^.outerBoundaryVector)++-- | \( O(n) \) Lists all edges. The edges on the outer boundary are given before the ones -- on the holes. However, no other guarantees are given on the order.------ running time: \(O(n)\) listEdges :: Polygon t p r -> [LineSegment 2 p r] listEdges pg = let f = F.toList . outerBoundaryEdges in f pg <> concatMap f (holeList pg)@@ -271,20 +485,21 @@ -- -- -- >>> mapM_ print . polygonVertices $ withIncidentEdges simplePoly--- Point2 [0,0] :+ V2 LineSegment (Closed (Point2 [1,11] :+ ())) (Closed (Point2 [0,0] :+ ())) LineSegment (Closed (Point2 [0,0] :+ ())) (Closed (Point2 [10,0] :+ ()))--- Point2 [10,0] :+ V2 LineSegment (Closed (Point2 [0,0] :+ ())) (Closed (Point2 [10,0] :+ ())) LineSegment (Closed (Point2 [10,0] :+ ())) (Closed (Point2 [10,10] :+ ()))--- Point2 [10,10] :+ V2 LineSegment (Closed (Point2 [10,0] :+ ())) (Closed (Point2 [10,10] :+ ())) LineSegment (Closed (Point2 [10,10] :+ ())) (Closed (Point2 [5,15] :+ ()))--- Point2 [5,15] :+ V2 LineSegment (Closed (Point2 [10,10] :+ ())) (Closed (Point2 [5,15] :+ ())) LineSegment (Closed (Point2 [5,15] :+ ())) (Closed (Point2 [1,11] :+ ()))--- Point2 [1,11] :+ V2 LineSegment (Closed (Point2 [5,15] :+ ())) (Closed (Point2 [1,11] :+ ())) LineSegment (Closed (Point2 [1,11] :+ ())) (Closed (Point2 [0,0] :+ ()))+-- Point2 0 0 :+ V2 (ClosedLineSegment (Point2 1 11 :+ ()) (Point2 0 0 :+ ())) (ClosedLineSegment (Point2 0 0 :+ ()) (Point2 10 0 :+ ()))+-- Point2 10 0 :+ V2 (ClosedLineSegment (Point2 0 0 :+ ()) (Point2 10 0 :+ ())) (ClosedLineSegment (Point2 10 0 :+ ()) (Point2 10 10 :+ ()))+-- Point2 10 10 :+ V2 (ClosedLineSegment (Point2 10 0 :+ ()) (Point2 10 10 :+ ())) (ClosedLineSegment (Point2 10 10 :+ ()) (Point2 5 15 :+ ()))+-- Point2 5 15 :+ V2 (ClosedLineSegment (Point2 10 10 :+ ()) (Point2 5 15 :+ ())) (ClosedLineSegment (Point2 5 15 :+ ()) (Point2 1 11 :+ ()))+-- Point2 1 11 :+ V2 (ClosedLineSegment (Point2 5 15 :+ ()) (Point2 1 11 :+ ())) (ClosedLineSegment (Point2 1 11 :+ ()) (Point2 0 0 :+ ())) withIncidentEdges :: Polygon t p r -> Polygon t (Two (LineSegment 2 p r)) r-withIncidentEdges (SimplePolygon vs) =- SimplePolygon $ C.zip3LWith f (C.rotateL vs) vs (C.rotateR vs)+withIncidentEdges poly@SimplePolygon{} =+ unsafeFromCircularVector $ CV.zipWith3 f (CV.rotateLeft 1 vs) vs (CV.rotateRight 1 vs) where+ vs = poly ^. outerBoundaryVector f p c n = c&extra .~ Two (ClosedLineSegment p c) (ClosedLineSegment c n) withIncidentEdges (MultiPolygon vs hs) = MultiPolygon vs' hs' where- (SimplePolygon vs') = withIncidentEdges $ SimplePolygon vs+ vs' = withIncidentEdges vs hs' = map withIncidentEdges hs -- -- | Gets the i^th edge on the outer boundary of the polygon, that is the edge@@ -292,143 +507,33 @@ -- -- modulo n. -- -- +-- FIXME: Test that \poly -> fromEdges (toEdges poly) == poly -- | Given the vertices of the polygon. Produce a list of edges. The edges are -- half-open.-toEdges :: C.CSeq (Point 2 r :+ p) -> C.CSeq (LineSegment 2 p r)-toEdges vs = C.zipLWith (\p q -> LineSegment (Closed p) (Open q)) vs (C.rotateR vs)- -- let vs' = F.toList vs in- -- C.fromList $ zipWith (\p q -> LineSegment (Closed p) (Open q)) vs' (tail vs' ++ vs')----- | Test if q lies on the boundary of the polygon. Running time: O(n)------ >>> Point2 1 1 `onBoundary` simplePoly--- False--- >>> Point2 0 0 `onBoundary` simplePoly--- True--- >>> Point2 10 0 `onBoundary` simplePoly--- True--- >>> Point2 5 13 `onBoundary` simplePoly--- False--- >>> Point2 5 10 `onBoundary` simplePoly--- False--- >>> Point2 10 5 `onBoundary` simplePoly--- True--- >>> Point2 20 5 `onBoundary` simplePoly--- False------ TODO: testcases multipolygon-onBoundary :: (Fractional r, Ord r) => Point 2 r -> Polygon t p r -> Bool-q `onBoundary` pg = any (q `onSegment`) es- where- out = SimplePolygon $ pg^.outerBoundary- es = concatMap (F.toList . outerBoundaryEdges) $ out : holeList pg---- | Check if a point lies inside a polygon, on the boundary, or outside of the polygon.--- Running time: O(n).------ >>> Point2 1 1 `inPolygon` simplePoly--- Inside--- >>> Point2 0 0 `inPolygon` simplePoly--- OnBoundary--- >>> Point2 10 0 `inPolygon` simplePoly--- OnBoundary--- >>> Point2 5 13 `inPolygon` simplePoly--- Inside--- >>> Point2 5 10 `inPolygon` simplePoly--- Inside--- >>> Point2 10 5 `inPolygon` simplePoly--- OnBoundary--- >>> Point2 20 5 `inPolygon` simplePoly--- Outside------ TODO: Add some testcases with multiPolygons--- TODO: Add some more onBoundary testcases-inPolygon :: forall t p r. (Fractional r, Ord r)- => Point 2 r -> Polygon t p r- -> PointLocationResult-q `inPolygon` pg- | q `onBoundary` pg = OnBoundary- | odd kl && odd kr && not (any (q `inHole`) hs) = Inside- | otherwise = Outside- where- l = horizontalLine $ q^.yCoord-- -- Given a line segment, compute the intersection point (if a point) with the- -- line l- intersectionPoint = asA @(Point 2 r) . (`intersect` l)-- -- Count the number of intersections that the horizontal line through q- -- maxes with the polygon, that are strictly to the left and strictly to- -- the right of q. If these numbers are both odd the point lies within the polygon.- --- --- -- note that: - by the asA (Point 2 r) we ignore horizontal segments (as desired)- -- - by the filtering, we effectively limit l to an open-half line, starting- -- at the (open) point q.- -- - by using half-open segments as edges we avoid double counting- -- intersections that coincide with vertices.- -- - If the point is outside, and on the same height as the- -- minimum or maximum coordinate of the polygon. The number of- -- intersections to the left or right may be one. Thus- -- incorrectly classifying the point as inside. To avoid this,- -- we count both the points to the left *and* to the right of- -- p. Only if both are odd the point is inside. so that if- -- the point is outside, and on the same y-coordinate as one- -- of the extermal vertices (one ofth)- --- -- See http://geomalgorithms.com/a03-_inclusion.html for more information.- SP kl kr = count (\p -> (p^.xCoord) `compare` (q^.xCoord))- . mapMaybe intersectionPoint . F.toList . outerBoundaryEdges $ pg-- -- For multi polygons we have to test if we do not lie in a hole .- inHole = insidePolygon- hs = holeList pg-- count :: (a -> Ordering) -> [a] -> SP Int Int- count f = foldr (\x (SP lts gts) -> case f x of- LT -> SP (lts + 1) gts- EQ -> SP lts gts- GT -> SP lts (gts + 1)) (SP 0 0)----- | Test if a point lies strictly inside the polgyon.-insidePolygon :: (Fractional r, Ord r) => Point 2 r -> Polygon t p r -> Bool-q `insidePolygon` pg = q `inPolygon` pg == Inside----- testQ = map (`inPolygon` testPoly) [ Point2 1 1 -- Inside--- , Point2 0 0 -- OnBoundary--- , Point2 5 14 -- Inside--- , Point2 5 10 -- Inside--- , Point2 10 5 -- OnBoundary--- , Point2 20 5 -- Outside--- ]---- testPoly :: SimplePolygon () Rational--- testPoly = SimplePolygon . C.fromList . map ext $ [ Point2 0 0--- , Point2 10 0--- , Point2 10 10--- , Point2 5 15--- , Point2 1 11--- ]+toEdges :: CircularVector (Point 2 r :+ p) -> CircularVector (LineSegment 2 p r)+toEdges vs = CV.zipWith (\p q -> LineSegment (Closed p) (Open q)) vs (CV.rotateRight 1 vs) -- | Compute the area of a polygon area :: Fractional r => Polygon t p r -> r-area poly@(SimplePolygon _) = abs $ signedArea poly-area (MultiPolygon vs hs) = area (SimplePolygon vs) - sum [area h | h <- hs]+area poly@SimplePolygon{} = abs $ signedArea poly+area (MultiPolygon vs hs) = area vs - sum [area h | h <- hs] -- | Compute the signed area of a simple polygon. The the vertices are in -- clockwise order, the signed area will be negative, if the verices are given -- in counter clockwise order, the area will be positive. signedArea :: Fractional r => SimplePolygon p r -> r-signedArea poly = x / 2+signedArea poly = signedArea2X poly / 2++-- | Compute the signed area times 2 of a simple polygon. The the vertices are in+-- clockwise order, the signed area will be negative, if the verices are given+-- in counter clockwise order, the area will be positive.+signedArea2X :: Num r => SimplePolygon p r -> r+signedArea2X poly = x where x = sum [ p^.core.xCoord * q^.core.yCoord - q^.core.xCoord * p^.core.yCoord | LineSegment' p q <- F.toList $ outerBoundaryEdges poly ] - -- | Compute the centroid of a simple polygon. centroid :: Fractional r => SimplePolygon p r -> Point 2 r centroid poly = Point $ sum' xs ^/ (6 * signedArea poly)@@ -439,43 +544,33 @@ sum' = F.foldl' (^+^) zero --- | Pick a point that is inside the polygon.+-- | \( O(n) \) Pick a point that is inside the polygon. -- -- (note: if the polygon is degenerate; i.e. has <3 vertices, we report a -- vertex of the polygon instead.) -- -- pre: the polygon is given in CCW order------ running time: \(O(n)\) pickPoint :: (Ord r, Fractional r) => Polygon p t r -> Point 2 r-pickPoint pg | isTriangle pg = centroid . SimplePolygon $ pg^.outerBoundary+pickPoint pg | isTriangle pg = centroid $ pg^.outerBoundary | otherwise = let LineSegment' (p :+ _) (q :+ _) = findDiagonal pg in p .+^ (0.5 *^ (q .-. p)) --- | Test if the polygon is a triangle------ running time: \(O(1)\)+-- | \( O(1) \) Test if the polygon is a triangle isTriangle :: Polygon p t r -> Bool isTriangle = \case- SimplePolygon vs -> go vs- MultiPolygon vs [] -> go vs+ p@SimplePolygon{} -> F.length (p^.outerBoundaryVector) == 3+ MultiPolygon vs [] -> isTriangle vs MultiPolygon _ _ -> False- where- go vs = case toNonEmpty vs of- (_ :| [_,_]) -> True- _ -> False --- | Find a diagonal of the polygon.+-- | \( O(n) \) Find a diagonal of the polygon. -- -- pre: the polygon is given in CCW order------ running time: \(O(n)\) findDiagonal :: (Ord r, Fractional r) => Polygon t p r -> LineSegment 2 p r findDiagonal pg = List.head . catMaybes . F.toList $ diags -- note that a diagonal is guaranteed to exist, so the usage of head is safe. where- vs = pg^.outerBoundary- diags = C.zip3LWith f (C.rotateL vs) vs (C.rotateR vs)+ vs = pg^.outerBoundaryVector+ diags = CV.zipWith3 f (CV.rotateLeft 1 vs) vs (CV.rotateRight 1 vs) f u v w = case ccw (u^.core) (v^.core) (w^.core) of CCW -> Just $ findDiag u v w -- v is a convex vertex, so find a diagonal@@ -508,59 +603,48 @@ xs -> Just $ List.maximumBy (comparing f) xs --- | Test if the outer boundary of the polygon is in clockwise or counter+-- | \( O(n) \) Test if the outer boundary of the polygon is in clockwise or counter -- clockwise order.------ running time: \(O(n)\)----isCounterClockwise :: (Eq r, Fractional r) => Polygon t p r -> Bool-isCounterClockwise = (\x -> x == abs x) . signedArea- . fromPoints . F.toList . (^.outerBoundary)+isCounterClockwise :: (Eq r, Num r) => Polygon t p r -> Bool+isCounterClockwise = (\x -> x == abs x) . signedArea2X . view outerBoundary --- | Make sure that every edge has the polygon's interior on its+-- | \( O(n) \) Make sure that every edge has the polygon's interior on its -- right, by orienting the outer boundary into clockwise order, and -- the inner borders (i.e. any holes, if they exist) into -- counter-clockwise order.------ running time: \(O(n)\)--- | Orient the outer boundary of the polygon to clockwise order-toClockwiseOrder :: (Eq r, Fractional r) => Polygon t p r -> Polygon t p r-toClockwiseOrder p = (toClockwiseOrder' p)&polygonHoles'.traverse %~ toCounterClockWiseOrder'+toClockwiseOrder :: (Eq r, Num r) => Polygon t p r -> Polygon t p r+toClockwiseOrder p = toClockwiseOrder' p & polygonHoles'.traverse %~ toCounterClockWiseOrder' --- | Orient the outer boundary into clockwise order. Leaves any holes+-- | \( O(n) \) Orient the outer boundary into clockwise order. Leaves any holes -- as they are. ---toClockwiseOrder' :: (Eq r, Fractional r) => Polygon t p r -> Polygon t p r+toClockwiseOrder' :: (Eq r, Num r) => Polygon t p r -> Polygon t p r toClockwiseOrder' pg | isCounterClockwise pg = reverseOuterBoundary pg | otherwise = pg --- | Make sure that every edge has the polygon's interior on its left,+-- | \( O(n) \) Make sure that every edge has the polygon's interior on its left, -- by orienting the outer boundary into counter-clockwise order, and -- the inner borders (i.e. any holes, if they exist) into clockwise order.------ running time: \(O(n)\)-toCounterClockWiseOrder :: (Eq r, Fractional r) => Polygon t p r -> Polygon t p r+toCounterClockWiseOrder :: (Eq r, Num r) => Polygon t p r -> Polygon t p r toCounterClockWiseOrder p =- (toCounterClockWiseOrder' p)&polygonHoles'.traverse %~ toClockwiseOrder'+ toCounterClockWiseOrder' p & polygonHoles'.traverse %~ toClockwiseOrder' --- | Orient the outer boundary into counter-clockwise order. Leaves+-- | \( O(n) \) Orient the outer boundary into counter-clockwise order. Leaves -- any holes as they are.----toCounterClockWiseOrder' :: (Eq r, Fractional r) => Polygon t p r -> Polygon t p r+toCounterClockWiseOrder' :: (Eq r, Num r) => Polygon t p r -> Polygon t p r toCounterClockWiseOrder' p | not $ isCounterClockwise p = reverseOuterBoundary p | otherwise = p +-- FIXME: Delete this function.+-- | Reorient the outer boundary from clockwise order to counter-clockwise order or+-- from counter-clockwise order to clockwise order. Leaves+-- any holes as they are.+-- reverseOuterBoundary :: Polygon t p r -> Polygon t p r-reverseOuterBoundary p = p&outerBoundary %~ C.reverseDirection----- | Convert a Polygon to a simple polygon by forgetting about any holes.-asSimplePolygon :: Polygon t p r -> SimplePolygon p r-asSimplePolygon poly@(SimplePolygon _) = poly-asSimplePolygon (MultiPolygon vs _) = SimplePolygon vs+reverseOuterBoundary p = p&unsafeOuterBoundaryVector %~ CV.reverse -- | assigns unique integer numbers to all vertices. Numbers start from 0, and@@ -568,7 +652,164 @@ -- will be numbered last, in the same order. -- -- >>> numberVertices simplePoly--- SimplePolygon (CSeq [Point2 [0,0] :+ SP 0 (),Point2 [10,0] :+ SP 1 (),Point2 [10,10] :+ SP 2 (),Point2 [5,15] :+ SP 3 (),Point2 [1,11] :+ SP 4 ()])+-- SimplePolygon [Point2 0 0 :+ SP 0 (),Point2 10 0 :+ SP 1 (),Point2 10 10 :+ SP 2 (),Point2 5 15 :+ SP 3 (),Point2 1 11 :+ SP 4 ()] numberVertices :: Polygon t p r -> Polygon t (SP Int p) r-numberVertices = snd . bimapAccumL (\a p -> (a+1,SP a p)) (\a r -> (a,r)) 0+numberVertices = snd . bimapAccumL (\a p -> (a+1,SP a p)) (,) 0 -- TODO: Make sure that this does not have the same issues as foldl vs foldl'++--------------------------------------------------------------------------------+-- Specialized folds++-- maximum and minimum probably aren't useful. Disabled for now. Lemmih, 2020-12-26.++-- | \( O(n) \) Yield the maximum point of the polygon. Points are compared first by x-coordinate+-- and then by y-coordinate. The maximum point will therefore be the right-most point in+-- the polygon (and top-most if multiple points share the largest x-coordinate).+--+-- Hole vertices are ignored since they cannot be the maximum.+_maximum :: Ord r => Polygon t p r -> Point 2 r :+ p+_maximum = F.maximumBy (comparing _core) . view outerBoundaryVector++-- | \( O(n) \) Yield the maximum point of a polygon according to the given comparison function.+maximumVertexBy :: (Point 2 r :+ p -> Point 2 r :+ p -> Ordering) -> Polygon t p r -> Point 2 r :+ p+maximumVertexBy fn (SimplePolygon vs) = F.maximumBy fn vs+maximumVertexBy fn (MultiPolygon b hs) = F.maximumBy fn $ map (maximumVertexBy fn) (b:hs)++-- | \( O(n) \) Yield the maximum point of the polygon. Points are compared first by x-coordinate+-- and then by y-coordinate. The minimum point will therefore be the left-most point in+-- the polygon (and bottom-most if multiple points share the smallest x-coordinate).+--+-- Hole vertices are ignored since they cannot be the minimum.+_minimum :: Ord r => Polygon t p r -> Point 2 r :+ p+_minimum = F.minimumBy (comparing _core) . view outerBoundaryVector++-- | \( O(n) \) Yield the maximum point of a polygon according to the given comparison function.+minimumVertexBy :: (Point 2 r :+ p -> Point 2 r :+ p -> Ordering) -> Polygon t p r -> Point 2 r :+ p+minimumVertexBy fn (SimplePolygon vs) = F.minimumBy fn vs+minimumVertexBy fn (MultiPolygon b hs) = F.minimumBy fn $ map (minimumVertexBy fn) (b:hs)++-- | Rotate to the first point that matches the given condition.+--+-- >>> toVector <$> findRotateTo (== (Point2 1 0 :+ ())) (unsafeFromPoints [Point2 0 0 :+ (), Point2 1 0 :+ (), Point2 1 1 :+ ()])+-- Just [Point2 1 0 :+ (),Point2 1 1 :+ (),Point2 0 0 :+ ()]+-- >>> findRotateTo (== (Point2 7 0 :+ ())) $ unsafeFromPoints [Point2 0 0 :+ (), Point2 1 0 :+ (), Point2 1 1 :+ ()]+-- Nothing+findRotateTo :: (Point 2 r :+ p -> Bool) -> SimplePolygon p r -> Maybe (SimplePolygon p r)+findRotateTo fn = fmap unsafeFromCircularVector . CV.findRotateTo fn . view outerBoundaryVector++--------------------------------------------------------------------------------+-- Rotation++-- | \( O(1) \) Rotate the polygon to the left by n number of points.+rotateLeft :: Int -> SimplePolygon p r -> SimplePolygon p r+rotateLeft n = over unsafeOuterBoundaryVector (CV.rotateLeft n)++-- | \( O(1) \) Rotate the polygon to the right by n number of points.+rotateRight :: Int -> SimplePolygon p r -> SimplePolygon p r+rotateRight n = over unsafeOuterBoundaryVector (CV.rotateRight n)++--------------------------------------------------------------------------------+-- Testing for reflex or convex++-- | Test if a given vertex is a reflex vertex.+--+-- \(O(1)\)+isReflexVertex :: (Ord r, Num r) => Int -> Polygon Simple p r -> Bool+isReflexVertex i pg = ccw' u v w == CW+ where+ u = pg^.outerVertex (i-1)+ v = pg^.outerVertex i+ w = pg^.outerVertex (i+1)++-- | Test if a given vertex is a convex vertex (i.e. not a reflex vertex).+--+-- \(O(1)\)+isConvexVertex :: (Ord r, Num r) => Int -> Polygon Simple p r -> Bool+isConvexVertex i = not . isReflexVertex i++-- | Test if a given vertex is a strictly convex vertex.+--+-- \(O(1)\)+isStrictlyConvexVertex :: (Ord r, Num r) => Int -> Polygon t p r -> Bool+isStrictlyConvexVertex i pg = ccw' u v w == CCW+ where+ u = pg^.outerVertex (i-1)+ v = pg^.outerVertex i+ w = pg^.outerVertex (i+1)+++-- | Computes all reflex vertices of the polygon.+--+-- \(O(n)\)+reflexVertices :: (Ord r, Num r) => Polygon t p r -> [Int :+ (Point 2 r :+ p)]+reflexVertices p@(SimplePolygon _) = reflexVertices' p+reflexVertices (numberVertices -> MultiPolygon vs hs) =+ map (\(_ :+ (p :+ SP i e)) -> i :+ (p :+ e)) $+ reflexVertices' vs <> concatMap strictlyConvexVertices' hs++-- | Computes all convex (i.e. non-reflex) vertices of the polygon.+--+-- \(O(n)\)+convexVertices :: (Ord r, Num r) => Polygon t p r -> [Int :+ (Point 2 r :+ p)]+convexVertices = \case+ p@(SimplePolygon _) -> convexVertices' p+ (numberVertices -> MultiPolygon vs hs) ->+ map (\(_ :+ (p :+ SP i e)) -> i :+ (p :+ e)) $+ convexVertices' vs <> concatMap reflexVertices' hs++-- | Computes all strictly convex vertices of the polygon.+--+-- \(O(n)\)+strictlyConvexVertices :: (Ord r, Num r) => Polygon t p r -> [Int :+ (Point 2 r :+ p)]+strictlyConvexVertices = \case+ p@(SimplePolygon _) -> convexVertices' p+ (numberVertices -> MultiPolygon vs hs) ->+ map (\(_ :+ (p :+ SP i e)) -> i :+ (p :+ e)) $+ strictlyConvexVertices' vs <> concatMap reflexVertices' hs++----------------------------------------++-- | Return (the indices of) all reflex vertices, in increasing order+-- along the boundary.+--+-- \(O(n)\)+reflexVertices' :: (Ord r, Num r) => SimplePolygon p r -> [Int :+ (Point 2 r :+ p)]+reflexVertices' = filterReflexConvexWorker asReflex+ where+ asReflex u v w | ccw' (u^.extra) (v^.extra) (w^.extra) == CW = Just v+ | otherwise = Nothing++-- | Return (the indices of) all strictly convex vertices, in+-- increasing order along the boundary.+--+-- \(O(n)\)+strictlyConvexVertices' :: (Ord r, Num r) => SimplePolygon p r -> [Int :+ (Point 2 r :+ p)]+strictlyConvexVertices' = filterReflexConvexWorker asStrictlyConvex+ where+ asStrictlyConvex u v w | ccw' (u^.extra) (v^.extra) (w^.extra) == CCW = Just v+ | otherwise = Nothing++-- | Return (the indices of) all convex (= non-reflex) vertices, in increasing order+-- along the boundary.+--+-- \(O(n)\)+convexVertices' :: (Ord r, Num r) => SimplePolygon p r -> [Int :+ (Point 2 r :+ p)]+convexVertices' = filterReflexConvexWorker asConvex+ where+ asConvex u v w | ccw' (u^.extra) (v^.extra) (w^.extra) /= CW = Just v+ | otherwise = Nothing++-- | Helper function to implement convexVertices, reflexVertices, and+-- strictlyConvexVertices+filterReflexConvexWorker :: (Ord r, Num r)+ => ( Int :+ (Point 2 r :+ p)+ -> Int :+ (Point 2 r :+ p)+ -> Int :+ (Point 2 r :+ p)+ -> Maybe (Int :+ (Point 2 r :+ p))+ )+ -> SimplePolygon p r -> [Int :+ (Point 2 r :+ p)]+filterReflexConvexWorker g pg =+ catMaybes $ zip3RWith g (CV.rotateLeft 1 vs) vs (CV.rotateRight 1 vs)+ where+ vs = CV.withIndicesRight $ pg^.outerBoundaryVector+ zip3RWith f us' vs' ws' = zipWith3 f (F.toList us') (F.toList vs') (F.toList ws')
src/Data/Geometry/Polygon/Extremes.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE TemplateHaskell #-} -------------------------------------------------------------------------------- -- | -- Module : Data.Geometry.Polygon.Extremes@@ -13,15 +12,15 @@ , extremesLinear ) where -import Control.Lens hiding (Simple)+import Control.Lens hiding (Simple,simple) import Data.Ext-import qualified Data.Foldable as F import Data.Geometry.Point-import Data.Geometry.Polygon.Core+import Data.Geometry.Polygon.Core as P import Data.Geometry.Vector -------------------------------------------------------------------------------- +{- HLINT ignore cmpExtreme -} -- | Comparison that compares which point is 'larger' in the direction given by -- the vector u. cmpExtreme :: (Num r, Ord r)@@ -34,6 +33,6 @@ -- running time: \(O(n)\) extremesLinear :: (Ord r, Num r) => Vector 2 r -> Polygon t p r -> (Point 2 r :+ p, Point 2 r :+ p)-extremesLinear u p = let vs = p^.outerBoundary+extremesLinear u p = let simple = p^.outerBoundary f = cmpExtreme u- in (F.minimumBy f vs, F.maximumBy f vs)+ in (P.minimumVertexBy f simple, P.maximumVertexBy f simple)
+ src/Data/Geometry/Polygon/Inflate.hs view
@@ -0,0 +1,142 @@+--------------------------------------------------------------------------------+-- |+-- Module : Data.Geometry.Polygon.Inflate+-- Copyright : (C) David Himmelstrup+-- License : see the LICENSE file+-- Maintainer : David Himmelstrup+--------------------------------------------------------------------------------+module Data.Geometry.Polygon.Inflate+ ( Arc(..)+ , inflate+ ) where++import Algorithms.Geometry.SSSP (SSSP, sssp, triangulate)+import Control.Lens+import Data.Ext+import Data.Geometry.Line (lineThrough)+import Data.Geometry.LineSegment (LineSegment (LineSegment, OpenLineSegment),+ interpolate, sqSegmentLength)+import Data.Geometry.Point+import Data.Geometry.Polygon.Core+import Data.Intersection (IsIntersectableWith (intersect),+ NoIntersection (NoIntersection))+import Data.Maybe (catMaybes)+import qualified Data.Vector as V+import qualified Data.Vector.Circular as CV+import qualified Data.Vector.Unboxed as VU+import Data.Vinyl (Rec (RNil, (:&)))+import Data.Vinyl.CoRec (Handler (H), match)++----------------------------------------------------+-- Implementation++-- | Points annotated with an 'Arc' indicate that the edge from this point to+-- the next should not be a straight line but instead an arc with a given center+-- and a given border edge.+data Arc r = Arc+ { arcCenter :: Point 2 r+ , arcEdge :: (Point 2 r, Point 2 r)+ } deriving (Show)++type Parent = Int++markParents :: SSSP -> SimplePolygon p r -> SimplePolygon Parent r+markParents t p = unsafeFromCircularVector $+ CV.imap (\i (pt :+ _) -> pt :+ t VU.! i) (p^.outerBoundaryVector)++addSteinerPoints :: (Ord r, Fractional r) => SimplePolygon Parent r -> SimplePolygon Parent r+addSteinerPoints p = fromPoints $ concatMap worker [0 .. size p - 1]+ where+ worker nth = do+ pointA : catMaybes [ (:+ parent nth) <$> getIntersection edge lineA+ , (:+ parent (nth+1)) <$> getIntersection edge lineB ]+ where+ fetch idx = p ^. outerVertex idx+ pointA = fetch nth+ pointB = fetch (nth+1)+ parent idx = p^.outerVertex idx.extra+ lineA = lineThrough+ (fetch (parent nth) ^. core)+ (fetch (parent (parent nth)) ^. core)+ lineB = lineThrough+ (fetch (parent (nth+1)) ^. core)+ (fetch (parent (parent (nth+1))) ^. core)+ edge = OpenLineSegment pointA pointB+ getIntersection segment line =+ match (segment `intersect` line) (+ H (\NoIntersection -> Nothing)+ :& H (\pt -> Just pt)+ :& H (\LineSegment{} -> Nothing)+ :& RNil+ )++annotate :: (Real r, Fractional r) =>+ Double -> SimplePolygon Parent r -> SimplePolygon Parent r -> SimplePolygon (Arc r) r+annotate t original p = unsafeFromCircularVector $+ CV.imap ann (p^.outerBoundaryVector)+ -- CV.generate (size p) ann -- Use this when circular-vector-0.1.2 is out.+ where+ nO = size original+ visibleDist = V.maximum distanceTreeSum * t+ parent idx = p^.outerVertex idx.extra+ parentO idx = original^.outerVertex idx.extra+ getLineO idx = OpenLineSegment (original ^. outerVertex (parentO idx)) (original ^. outerVertex idx)+ getLineP idx = OpenLineSegment (original ^. outerVertex (parent idx)) (p ^. outerVertex idx)++ ann i _ =+ ptLocation i :+ arc+ where+ start = p ^. outerVertex i . core+ end = p ^. outerVertex (i+1) . core+ arc = Arc+ { arcCenter =+ original ^. outerVertex (commonParent original (parent i) (parent (i+1))) . core+ , arcEdge = (start, end) }++ -- Array of locations for points in the original polygon.+ ptLocationsO = V.generate nO ptLocationO+ ptLocationO 0 = (original ^. outerVertex 0 . core)+ ptLocationO i+ | frac <= 0 = ptLocationsO V.! (parentO i)+ | frac >= 1 = (original ^. outerVertex i . core)+ | otherwise = (interpolate frac (getLineO i))+ where+ dParent = distanceTreeSum V.! parentO i+ dSelf = oDistance VU.! i+ frac = realToFrac ((visibleDist - dParent) / dSelf)++ -- Locations for original points and steiner points.+ ptLocation 0 = (p ^. outerVertex 0 . core)+ ptLocation i+ | frac <= 0 = ptLocationsO V.! (parent i)+ | frac >= 1 = (p ^. outerVertex i . core)+ | otherwise = (interpolate frac (getLineP i))+ where+ dParent = distanceTreeSum V.! parent i+ dSelf = sqrt $ realToFrac $ sqSegmentLength $ getLineP i+ frac = realToFrac ((visibleDist - dParent) / dSelf)++ oDistance = VU.generate nO $ \i ->+ case i of+ 0 -> 0+ _ -> sqrt $ realToFrac $ sqSegmentLength $ getLineO i+ distanceTreeSum = V.generate nO $ \i ->+ case i of+ 0 -> 0+ _ -> distanceTreeSum V.! parentO i + oDistance VU.! i++commonParent :: SimplePolygon Parent r -> Int -> Int -> Int+commonParent p a b = worker 0 (parents a) (parents b)+ where+ worker _shared (x:xs) (y:ys)+ | x == y = worker x xs ys+ worker shared _ _ = shared+ parents 0 = [0]+ parents i = parents (p ^. outerVertex i . extra) ++ [i]++-- | \( O(n \log n) \)+inflate :: (Real r, Fractional r) => Double -> SimplePolygon () r -> SimplePolygon (Arc r) r+inflate t p = annotate t marked steiner+ where+ marked = markParents (sssp (triangulate p)) p+ steiner = addSteinerPoints marked
+ src/Data/Geometry/Polygon/Monotone.hs view
@@ -0,0 +1,118 @@+--------------------------------------------------------------------------------+-- |+-- Module : Data.Geometry.Polygon.Monotone+-- Copyright : (C) 1ndy+-- License : see the LICENSE file+-- Maintainer : David Himmelstrup+--+-- A polygon is monotone in a certain direction if rays orthogonal to that+-- direction intersects the polygon at most twice. See+-- <https://en.wikipedia.org/wiki/Monotone_polygon>+--+--------------------------------------------------------------------------------+module Data.Geometry.Polygon.Monotone+ ( isMonotone+ , randomMonotone+ , randomMonotoneDirected+ , monotoneFrom+ , randomNonZeroVector+ ) where++import Control.Monad.Random+import Data.Ext+import qualified Data.Foldable as F+import Data.Geometry.Line (Line (..))+import Data.Geometry.LineSegment+import Data.Geometry.Point+import Data.Geometry.Polygon.Core+import Data.Geometry.Polygon.Extremes+import Data.Geometry.Vector+import Data.Intersection+import Data.List+import Data.Vinyl+import Data.Vinyl.CoRec+import Prelude hiding (max, min)++-- | \( O(n \log n) \)+-- A polygon is monotone if a straight line in a given direction+-- cannot have more than two intersections.+isMonotone :: (Fractional r, Ord r) => Vector 2 r -> SimplePolygon p r -> Bool+-- Check for each vertex that the number of intersections with the+-- line starting at the vertex and going out in the given direction+-- intersects with the edges of the polygon no more than 2 times.+isMonotone direction p = all isMonotoneAt (map _core $ toPoints p)+ where+ isMonotoneAt pt =+ sum (map (intersectionsThrough pt) (F.toList $ outerBoundaryEdges p)) <= 2+ intersectionsThrough pt edge =+ match (Data.Intersection.intersect edge line) $+ H (\NoIntersection -> 0)+ :& H (\Point{} -> 1)+ -- This happens when an edge is parallel with the given direction.+ -- I think it's correct to count it as a single intersection.+ :& H (\LineSegment{} -> 1)+ :& RNil+ where+ line = Line pt (rot90 direction)+ rot90 (Vector2 x y) = Vector2 (-y) x++{- Algorithm overview:++ 1. Create N `Point 2 Rational` (N >= 3)+ 2. Create a random `Vector 2 Rational`+ 3. Find the extremes (min and max) of the points when sorted in the direction of the vector.+ We already have code for this. See `maximumBy (cmpExtreme vector)` and+ `minimumBy (cmpExtreme vector)`.+ 4. Take out the two extremal points from the set.+ 5. Partition the remaining points according to whether they're on the left side or right side+ of the imaginary line between the two extremal points.+ 6. Sort the two partitioned sets, one in the direction of the vector and one in the opposite+ direction.+ 7. Connect the points, starting from the minimal extreme point, going through the set of points+ that are increasing in the direction of the vector, then to the maximal point, and finally+ down through the points that are decreasing in the direction of the vector.+-}+-- | \( O(n \log n) \)+-- Generate a random N-sided polygon that is monotone in a random direction.+randomMonotone :: (RandomGen g, Random r, Ord r, Num r) => Int -> Rand g (SimplePolygon () r)+randomMonotone nVertices = randomMonotoneDirected nVertices =<< randomNonZeroVector++-- Pick a random vector and then call 'randomMonotone'.+-- | \( O(n \log n) \)+-- Generate a random N-sided polygon that is monotone in the given direction.+randomMonotoneDirected :: (RandomGen g, Random r, Ord r, Num r)+ => Int -> Vector 2 r -> Rand g (SimplePolygon () r)+randomMonotoneDirected nVertices direction = do+ points <- replicateM nVertices getRandom+ return (monotoneFrom direction points)++-- | \( O(n \log n) \)+-- Assemble a given set of points in a polygon that is monotone in the given direction.+monotoneFrom :: (Ord r, Num r) => Vector 2 r -> [Point 2 r] -> SimplePolygon () r+monotoneFrom direction vertices = fromPoints ([min] ++ rightHalf ++ [max] ++ leftHalf)+ where+ specialPoints = map (\x -> x :+ ()) vertices+ min = Data.List.minimumBy (cmpExtreme direction) specialPoints+ max = Data.List.maximumBy (cmpExtreme direction) specialPoints+ -- 4+ pointsWithoutExtremes = filter (\x -> x /= min && x /= max) specialPoints+ -- 5, 6+ (leftHalfUnsorted,rightHalfUnsorted) = Data.List.partition (toTheLeft min max) pointsWithoutExtremes+ leftHalf = sortBy (flip $ cmpExtreme direction) leftHalfUnsorted+ rightHalf = sortBy (cmpExtreme direction) rightHalfUnsorted++-------------------------------------------------------------------------------------------------+-- helper functions++-- for partitioning points+toTheLeft :: (Ord r, Num r) => Point 2 r :+ () -> Point 2 r :+ () -> Point 2 r :+ () -> Bool+toTheLeft min max x = ccw' min max x == CCW++-- | \( O(1) \)+-- Create a random 2D vector which has a non-zero magnitude.+randomNonZeroVector :: (RandomGen g, Random r, Eq r, Num r) => Rand g (Vector 2 r)+randomNonZeroVector = do+ v <- getRandom+ if (quadrance v==0)+ then randomNonZeroVector+ else pure v
src/Data/Geometry/PrioritySearchTree.hs view
@@ -41,7 +41,7 @@ } deriving (Show,Eq) instance Bifunctor NodeData where- bimap f g (NodeData x m) = NodeData (g x) ((bimap (fmap g) f) <$> m)+ bimap f g (NodeData x m) = NodeData (g x) (bimap (fmap g) f <$> m) maxVal :: Lens' (NodeData p r) (Maybe (Point 2 r :+ p)) maxVal = lens _maxVal (\(NodeData x _) m -> NodeData x m)@@ -97,7 +97,7 @@ -- TODO: In case we have multiple points with the same x-coord, these points -- are not really in decreasing y-order. Node l d r | py > d^?maxVal._Just.core.yCoord ->- node' l (d&maxVal .~ Just p) r (d^.maxVal)+ node' l (d&maxVal ?~ p) r (d^.maxVal) -- push the existing point down | otherwise -> node' l d r (Just p)
src/Data/Geometry/Properties.hs view
@@ -1,6 +1,5 @@ {-# LANGUAGE ImpredicativeTypes #-} {-# LANGUAGE UnicodeSyntax #-}-{-# LANGUAGE DefaultSignatures #-} -------------------------------------------------------------------------------- -- | -- Module : Data.Geometry.Properties
src/Data/Geometry/QuadTree.hs view
@@ -1,5 +1,12 @@ {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TypeApplications #-}+--------------------------------------------------------------------------------+-- |+-- Module : Data.Geometry.QuadTree+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+-------------------------------------------------------------------------------- module Data.Geometry.QuadTree-- ( module Data.Geometry.QuadTree.Cell -- , module Data.Geometry.QuadTree.Quadrants -- , module Data.Geometry.QuadTree.Split@@ -78,6 +85,7 @@ where c = fitsRectangle $ boundingBoxList (view core <$> pts) +{- HLINT ignore findLeaf -} -- | Locates the cell containing the given point, if it exists. -- -- running time: \(O(h)\), where \(h\) is the height of the quadTree@@ -147,7 +155,7 @@ GT -> Positive fromSignum :: (Num a, Eq a) => (b -> a) -> b -> Sign-fromSignum f = \x -> case signum (f x) of+fromSignum f x = case signum (f x) of -1 -> Negative 0 -> Zero 1 -> Positive
src/Data/Geometry/QuadTree/Cell.hs view
@@ -1,4 +1,11 @@ {-# LANGUAGE TemplateHaskell #-}+--------------------------------------------------------------------------------+-- |+-- Module : Data.Geometry.QuadTree.Cell+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+-------------------------------------------------------------------------------- module Data.Geometry.QuadTree.Cell where import Control.Lens (makeLenses, (^.),(&),(%~),ix, to)@@ -41,7 +48,7 @@ type instance IntersectionOf (Point 2 r) (Cell r) = '[ NoIntersection, Point 2 r] -instance (Ord r, Fractional r) => (Point 2 r) `IsIntersectableWith` (Cell r) where+instance (Ord r, Fractional r) => Point 2 r `IsIntersectableWith` Cell r where nonEmptyIntersection = defaultNonEmptyIntersection p `intersect` c = p `intersect` toBox c @@ -55,7 +62,7 @@ cellWidth (Cell w _) = pow w toBox :: Fractional r => Cell r -> Box 2 () r-toBox (Cell w p) = box (ext $ p) (ext $ p .+^ Vector2 (pow w) (pow w))+toBox (Cell w p) = box (ext p) (ext $ p .+^ Vector2 (pow w) (pow w)) inCell :: (Fractional r, Ord r) => Point 2 r :+ p -> Cell r -> Bool inCell (p :+ _) c = p `inBox` toBox c
src/Data/Geometry/QuadTree/Quadrants.hs view
@@ -1,3 +1,10 @@+--------------------------------------------------------------------------------+-- |+-- Module : Data.Geometry.QuadTree.Quadrants+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+-------------------------------------------------------------------------------- module Data.Geometry.QuadTree.Quadrants( pattern Quadrants , Quadrants , module Data.Geometry.Box.Corners
src/Data/Geometry/QuadTree/Split.hs view
@@ -1,4 +1,11 @@ {-# LANGUAGE TemplateHaskell #-}+--------------------------------------------------------------------------------+-- |+-- Module : Data.Geometry.QuadTree.Split+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+-------------------------------------------------------------------------------- module Data.Geometry.QuadTree.Split where import Control.Lens (makePrisms,(^.))@@ -22,10 +29,11 @@ -- | Split only when the Cell-width is at least wMin limitWidthTo :: WidthIndex -- ^ smallest allowed width of a cell (i.e. width of a leaf) -> Limiter r i v p-limitWidthTo wMin f = \c pts -> case f c pts of- No p -> No (Right p)- Yes v qs | wMin < c^.cellWidthIndex -> Yes v qs- | otherwise -> No (Left pts)+limitWidthTo wMin f c pts =+ case f c pts of+ No p -> No (Right p)+ Yes v qs | wMin < c^.cellWidthIndex -> Yes v qs+ | otherwise -> No (Left pts) -- note that it is important that we still evaluate the function so -- that we can distinguish at the last level i.e. between a regular -- " we are done splitting (No (Right p))" and a "we are no longer
src/Data/Geometry/QuadTree/Tree.hs view
@@ -1,5 +1,12 @@ {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TypeApplications #-}+--------------------------------------------------------------------------------+-- |+-- Module : Data.Geometry.QuadTree.Tree+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+-------------------------------------------------------------------------------- module Data.Geometry.QuadTree.Tree where
src/Data/Geometry/RangeTree.hs view
@@ -1,4 +1,11 @@ {-# LANGUAGE UndecidableInstances #-}+--------------------------------------------------------------------------------+-- |+-- Module : Data.Geometry.RangeTree+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+-------------------------------------------------------------------------------- module Data.Geometry.RangeTree where import Control.Lens hiding (element)@@ -13,8 +20,6 @@ import Data.Measured.Class import Data.Proxy import Data.Range-import Data.Semigroup.Foldable-import Data.Vector.Fixed.Cont (Peano, PeanoNum(..)) import GHC.TypeLits import Prelude hiding (last,init,head)
src/Data/Geometry/RangeTree/Generic.hs view
@@ -1,9 +1,15 @@+--------------------------------------------------------------------------------+-- |+-- Module : Data.Geometry.RangeTree.Generic+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+-------------------------------------------------------------------------------- module Data.Geometry.RangeTree.Generic where import Control.Lens import Data.BinaryTree import Data.Ext-import Data.Geometry.Point import Data.Geometry.Properties import Data.Geometry.RangeTree.Measure import Data.List.NonEmpty (NonEmpty(..))@@ -13,7 +19,6 @@ import Data.Measured.Size import Data.Semigroup import Data.Semigroup.Foldable-import qualified Data.Set as Set import Data.Util --------------------------------------------------------------------------------
src/Data/Geometry/RangeTree/Measure.hs view
@@ -1,3 +1,11 @@+{-# OPTIONS_GHC -Wno-orphans #-}+--------------------------------------------------------------------------------+-- |+-- Module : Data.Geometry.RangeTree.Measure+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+-------------------------------------------------------------------------------- module Data.Geometry.RangeTree.Measure where import Data.Measured.Class
src/Data/Geometry/SegmentTree.hs view
@@ -1,3 +1,10 @@+--------------------------------------------------------------------------------+-- |+-- Module : Data.Geometry.SegmentTree+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+-------------------------------------------------------------------------------- module Data.Geometry.SegmentTree( module Data.Geometry.SegmentTree.Generic ) where
src/Data/Geometry/SegmentTree/Generic.hs view
@@ -189,7 +189,7 @@ insert i (SegmentTree t) = SegmentTree $ insertRoot t where ri@(Range a b) = asRange i- insertRoot t' = maybe t' (flip insert' t') $ getRange t'+ insertRoot t' = maybe t' (`insert'` t') $ getRange t' insert' inR lf@(Leaf nd@(LeafData rr _)) | coversAtomic ri inR rr = Leaf $ nd&leafAssoc %~ insertAssoc i
src/Data/Geometry/Slab.hs view
@@ -1,5 +1,12 @@ {-# Language ScopedTypeVariables #-} {-# Language TemplateHaskell #-}+--------------------------------------------------------------------------------+-- |+-- Module : Data.Geometry.Slab+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+-------------------------------------------------------------------------------- module Data.Geometry.Slab where import Control.Lens (makeLenses, (^.),(%~),(.~),(&), both, from)@@ -56,15 +63,15 @@ '[Rectangle (a,a) r] -instance Ord r => (Slab o a r) `IsIntersectableWith` (Slab o a r) where+instance Ord r => Slab o a r `IsIntersectableWith` Slab o a r where nonEmptyIntersection = defaultNonEmptyIntersection (Slab i) `intersect` (Slab i') = match (i `intersect` i') $- (H $ \NoIntersection -> coRec NoIntersection)- :& (H $ \i'' -> coRec (Slab i'' :: Slab o a r))+ H (\NoIntersection -> coRec NoIntersection)+ :& H (\i'' -> coRec (Slab i'' :: Slab o a r)) :& RNil -instance (Slab Horizontal a r) `IsIntersectableWith` (Slab Vertical a r) where+instance Slab Horizontal a r `IsIntersectableWith` Slab Vertical a r where nonEmptyIntersection _ _ _ = True (Slab h) `intersect` (Slab v) = coRec $ box low high@@ -98,18 +105,18 @@ [NoIntersection, Line 2 r, LineSegment 2 a r] instance (Fractional r, Ord r, HasBoundingLines o) =>- Line 2 r `IsIntersectableWith` (Slab o a r) where+ Line 2 r `IsIntersectableWith` Slab o a r where nonEmptyIntersection = defaultNonEmptyIntersection l@(Line p _) `intersect` s = match (l `intersect` a) $- (H $ \NoIntersection -> if p `inSlab` s then coRec l else coRec NoIntersection)- :& (H $ \pa -> match (l `intersect` b) $- (H $ \NoIntersection -> coRec NoIntersection)- :& (H $ \pb -> coRec $ lineSegment' pa pb)- :& (H $ \_ -> coRec l)+ H (\NoIntersection -> if p `inSlab` s then coRec l else coRec NoIntersection)+ :& H (\pa -> match (l `intersect` b) $+ H coRec -- NoIntersection+ :& H (coRec . lineSegment' pa)+ :& H (\_ -> coRec l) :& RNil )- :& (H $ \_ -> coRec l)+ :& H (\_ -> coRec l) :& RNil where (a :+ _,b :+ _) = boundingLines s@@ -125,17 +132,17 @@ [NoIntersection, SubLine 2 () s r] instance (Fractional r, Ord r, HasBoundingLines o) =>- SubLine 2 a r r `IsIntersectableWith` (Slab o a r) where+ SubLine 2 a r r `IsIntersectableWith` Slab o a r where nonEmptyIntersection = defaultNonEmptyIntersection sl@(SubLine l _) `intersect` s = match (l `intersect` s) $- (H $ \NoIntersection -> coRec NoIntersection)- :& (H $ \(Line _ _) -> coRec $ dropExtra sl)- :& (H $ \seg -> match (sl `intersect` (seg^._SubLine)) $- (H $ \NoIntersection -> coRec NoIntersection)- :& (H $ \p@(Point2 _ _) -> coRec $ singleton p)- :& (H $ \ss -> coRec $ dropExtra ss)+ H (\NoIntersection -> coRec NoIntersection)+ :& H (\(Line _ _) -> coRec $ dropExtra sl)+ :& H (\seg -> match (sl `intersect` (seg^._SubLine)) $+ H (\NoIntersection -> coRec NoIntersection)+ :& H (\p@Point2{} -> coRec $ singleton p)+ :& H ( coRec . dropExtra) :& RNil) :& RNil where@@ -146,12 +153,12 @@ [NoIntersection, LineSegment 2 () r] instance (Fractional r, Ord r, HasBoundingLines o) =>- LineSegment 2 a r `IsIntersectableWith` (Slab o a r) where+ LineSegment 2 a r `IsIntersectableWith` Slab o a r where nonEmptyIntersection = defaultNonEmptyIntersection seg `intersect` slab = match ((seg^._SubLine) `intersect` slab) $- (H $ \NoIntersection -> coRec NoIntersection)- :& (H $ \sl -> coRec $ sl^. from _SubLine)+ H (\NoIntersection -> coRec NoIntersection)+ :& H (\sl -> coRec $ sl^. from _SubLine) :& RNil
src/Data/Geometry/SubLine.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE UndecidableInstances #-} -------------------------------------------------------------------------------- -- |@@ -10,7 +9,22 @@ -- SubLine; a part of a line -- ---------------------------------------------------------------------------------module Data.Geometry.SubLine where+module Data.Geometry.SubLine+ ( SubLine(..)+ , line+ , subRange+ , fixEndPoints+ , dropExtra+ , _unBounded+ , toUnbounded+ , fromUnbounded+ , onSubLine+ , onSubLineUB+ , onSubLine2+ , onSubLine2UB+ , getEndPointsUnBounded+ , fromLine+ ) where import Control.Lens import Data.Bifunctor@@ -27,8 +41,6 @@ import Data.Vinyl.CoRec import Test.QuickCheck(Arbitrary(..)) -import Data.Ratio- -------------------------------------------------------------------------------- -- | Part of a line. The interval is ranged based on the vector of the@@ -36,8 +48,15 @@ data SubLine d p s r = SubLine { _line :: Line d r , _subRange :: Interval p s }-makeLenses ''SubLine +-- | Line part of SubLine.+line :: Lens (SubLine d1 p s r1) (SubLine d2 p s r2) (Line d1 r1) (Line d2 r2)+line = lens _line (\sub l -> SubLine l (_subRange sub))++-- | Interval part of SubLine.+subRange :: Lens (SubLine d p1 s1 r) (SubLine d p2 s2 r) (Interval p1 s1) (Interval p2 s2)+subRange = lens _subRange (SubLine . _line)+ type instance Dimension (SubLine d p s r) = d @@ -57,7 +76,7 @@ fixEndPoints sl = sl&subRange %~ f where ptAt = flip pointAt (sl^.line)- label (c :+ e) = (c :+ (ptAt c :+ e))+ label (c :+ e) = c :+ (ptAt c :+ e) f ~(Interval l u) = Interval (l&unEndPoint %~ label) (u&unEndPoint %~ label) @@ -65,6 +84,7 @@ dropExtra :: SubLine d p s r -> SubLine d () s r dropExtra = over subRange (first (const ())) +-- | Prism for downcasting an unbounded subline to a subline. _unBounded :: Prism' (SubLine d p (UnBounded r) r) (SubLine d p r r) _unBounded = prism' toUnbounded fromUnbounded @@ -88,10 +108,14 @@ -- lies on the subline, i.e. in the interval r onSubLineUB :: (Ord r, Fractional r) => Point 2 r -> SubLine 2 p (UnBounded r) r -> Bool-p `onSubLineUB` (SubLine l r) = case toOffset p l of- Nothing -> False- Just x -> Val x `inInterval` r+p `onSubLineUB` (SubLine l r) =+ p `onLine2` l &&+ Val (toOffset' p l) `inInterval` r +inSubLineIntervalUB :: (Ord r, Fractional r)+ => Point 2 r -> SubLine 2 p (UnBounded r) r -> Bool+p `inSubLineIntervalUB` (SubLine l r) = Val (toOffset' p l) `inInterval` r+ -- | given point p, and a Subline l r such that p lies on line l, test if it -- lies on the subline, i.e. in the interval r onSubLine2 :: (Ord r, Num r) => Point 2 r -> SubLine 2 p r r -> Bool@@ -118,19 +142,20 @@ , SubLine 2 p s r ] +{- HLINT ignore "Redundant bracket" -} instance (Ord r, Fractional r) =>- (SubLine 2 p r r) `IsIntersectableWith` (SubLine 2 p r r) where+ SubLine 2 p r r `IsIntersectableWith` SubLine 2 p r r where nonEmptyIntersection = defaultNonEmptyIntersection sl@(SubLine l r) `intersect` sm@(SubLine m _) = match (l `intersect` m) $- (H $ \NoIntersection -> coRec NoIntersection)- :& (H $ \p@(Point _) -> if onSubLine2 p sl && onSubLine2 p sm+ H (\NoIntersection -> coRec NoIntersection)+ :& H (\p@(Point _) -> if onSubLine2 p sl && onSubLine2 p sm then coRec p else coRec NoIntersection)- :& (H $ \_ -> match (r `intersect` s'') $- (H $ \NoIntersection -> coRec NoIntersection)- :& (H $ \i -> coRec $ SubLine l i)+ :& H (\_ -> match (r `intersect` s'') $+ H coRec -- NoIntersection+ :& H (coRec . SubLine l) :& RNil ) :& RNil@@ -141,17 +166,17 @@ &end.core .~ toOffset' (s'^.end.extra.core) l instance (Ord r, Fractional r) =>- (SubLine 2 p (UnBounded r) r) `IsIntersectableWith` (SubLine 2 p (UnBounded r) r) where+ SubLine 2 p (UnBounded r) r `IsIntersectableWith` SubLine 2 p (UnBounded r) r where nonEmptyIntersection = defaultNonEmptyIntersection sl@(SubLine l r) `intersect` sm@(SubLine m _) = match (l `intersect` m) $- (H $ \NoIntersection -> coRec NoIntersection)- :& (H $ \p@(Point _) -> if onSubLine2UB p sl && onSubLine2UB p sm+ H (\NoIntersection -> coRec NoIntersection)+ :& H (\p@(Point _) -> if inSubLineIntervalUB p sl && inSubLineIntervalUB p sm then coRec p else coRec NoIntersection)- :& (H $ \_ -> match (r `intersect` s'') $- (H $ \NoIntersection -> coRec NoIntersection)- :& (H $ \i -> coRec $ SubLine l i)+ :& H (\_ -> match (r `intersect` s'') $+ H coRec -- NoIntersection+ :& H (coRec . SubLine l) :& RNil ) :& RNil@@ -168,6 +193,7 @@ where f = flip pointAt (sl^.line) +-- | Create a SubLine that covers the original line from -infinity to +infinity. fromLine :: Arity d => Line d r -> SubLine d () (UnBounded r) r fromLine l = SubLine l (ClosedInterval (ext MinInfinity) (ext MaxInfinity)) @@ -185,6 +211,6 @@ -- testzz = let f = bimap (fmap Val) (const ()) -- in -testz :: SubLine 2 () Rational Rational-testz = SubLine (Line (Point2 0 0) (Vector2 10 0))- (Interval (Closed (0 % 1 :+ ())) (Closed (1 % 1 :+ ())))+-- testz :: SubLine 2 () Rational Rational+-- testz = SubLine (Line (Point2 0 0) (Vector2 10 0))+-- (Interval (Closed (0 % 1 :+ ())) (Closed (1 % 1 :+ ())))
src/Data/Geometry/Transformation.hs view
@@ -1,5 +1,12 @@ {-# LANGUAGE Unsafe #-} {-# LANGUAGE UndecidableInstances #-}+--------------------------------------------------------------------------------+-- |+-- Module : Data.Geometry.Transformation+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+-------------------------------------------------------------------------------- module Data.Geometry.Transformation where import Control.Lens (iso,set,Iso,imap)@@ -12,6 +19,10 @@ import Data.Proxy import GHC.TypeLits +{- $setup+>>> import Data.Geometry.LineSegment+>>> import Data.Ext+-} -------------------------------------------------------------------------------- -- * Transformations@@ -19,6 +30,7 @@ -- | A type representing a Transformation for d dimensional objects newtype Transformation d r = Transformation { _transformationMatrix :: Matrix (d + 1) (d + 1) r } +-- | Transformations and Matrices are isomorphic. transformationMatrix :: Iso (Transformation d r) (Transformation d s) (Matrix (d + 1) (d + 1) r) (Matrix (d + 1) (d + 1) s) transformationMatrix = iso _transformationMatrix Transformation@@ -42,7 +54,7 @@ -- | Compute the inverse transformation -- -- >>> inverseOf $ translation (Vector2 (10.0) (5.0))--- Transformation {_transformationMatrix = Matrix Vector3 [Vector3 [1.0,0.0,-10.0],Vector3 [0.0,1.0,-5.0],Vector3 [0.0,0.0,1.0]]}+-- Transformation {_transformationMatrix = Matrix (Vector3 (Vector3 1.0 0.0 (-10.0)) (Vector3 0.0 1.0 (-5.0)) (Vector3 0.0 0.0 1.0))} inverseOf :: (Fractional r, Invertible (d + 1) r) => Transformation d r -> Transformation d r inverseOf = Transformation . inverse' . _transformationMatrix@@ -54,11 +66,19 @@ class IsTransformable g where transformBy :: Transformation (Dimension g) (NumType g) -> g -> g +-- | Apply a transformation to a collection of objects.+--+-- >>> transformAllBy (uniformScaling 2) [Point1 1, Point1 2, Point1 3]+-- [Point1 2.0,Point1 4.0,Point1 6.0] transformAllBy :: (Functor c, IsTransformable g) => Transformation (Dimension g) (NumType g) -> c g -> c g transformAllBy t = fmap (transformBy t) -+-- | Apply transformation to a PointFunctor, ie something that contains+-- points. Polygons, triangles, line segments, etc, are all PointFunctors.+--+-- >>> transformPointFunctor (uniformScaling 2) $ OpenLineSegment (Point1 1 :+ ()) (Point1 2 :+ ())+-- OpenLineSegment (Point1 2.0 :+ ()) (Point1 4.0 :+ ()) transformPointFunctor :: ( PointFunctor g, Fractional r, d ~ Dimension (g r) , Arity d, Arity (d + 1) ) => Transformation d r -> g r -> g r@@ -78,15 +98,31 @@ -------------------------------------------------------------------------------- -- * Common transformations +-- | Create translation transformation from a vector.+--+-- >>> transformBy (translation $ Vector2 1 2) $ Point2 2 3+-- Point2 3.0 5.0 translation :: (Num r, Arity d, Arity (d + 1)) => Vector d r -> Transformation d r translation v = Transformation . Matrix $ imap transRow (snoc v 1) -+-- | Create scaling transformation from a vector.+--+-- >>> transformBy (scaling $ Vector2 2 (-1)) $ Point2 2 3+-- Point2 4.0 (-3.0) scaling :: (Num r, Arity d, Arity (d + 1)) => Vector d r -> Transformation d r scaling v = Transformation . Matrix $ imap mkRow (snoc v 1) +-- | Create scaling transformation from a scalar that is applied+-- to all dimensions.+--+-- >>> transformBy (uniformScaling 5) $ Point2 2 3+-- Point2 10.0 15.0+-- >>> uniformScaling 5 == scaling (Vector2 5 5)+-- True+-- >>> uniformScaling 5 == scaling (Vector3 5 5 5)+-- True uniformScaling :: (Num r, Arity d, Arity (d + 1)) => r -> Transformation d r uniformScaling = scaling . pure @@ -94,17 +130,29 @@ -------------------------------------------------------------------------------- -- * Functions that execute transformations +-- | Translate a given point.+--+-- >>> translateBy (Vector2 1 2) $ Point2 2 3+-- Point2 3.0 5.0 translateBy :: ( IsTransformable g, Num (NumType g) , Arity (Dimension g), Arity (Dimension g + 1) ) => Vector (Dimension g) (NumType g) -> g -> g translateBy = transformBy . translation +-- | Scale a given point.+--+-- >>> scaleBy (Vector2 2 (-1)) $ Point2 2 3+-- Point2 4.0 (-3.0) scaleBy :: ( IsTransformable g, Num (NumType g) , Arity (Dimension g), Arity (Dimension g + 1) ) => Vector (Dimension g) (NumType g) -> g -> g scaleBy = transformBy . scaling +-- | Scale a given point uniformly in all dimensions.+--+-- >>> scaleUniformlyBy 5 $ Point2 2 3+-- Point2 10.0 15.0 scaleUniformlyBy :: ( IsTransformable g, Num (NumType g) , Arity (Dimension g), Arity (Dimension g + 1) ) => NumType g -> g -> g
src/Data/Geometry/Triangle.hs view
@@ -1,36 +1,37 @@ {-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE UndecidableInstances #-}+-- | Triangles in \(d\)-dimensional space. module Data.Geometry.Triangle where -import Control.DeepSeq+import Control.DeepSeq (NFData) import Control.Lens-import Data.Bifoldable-import Data.Bifunctor+import Data.Bifoldable (Bifoldable (bifoldMap))+import Data.Bifunctor (Bifunctor (first)) import Data.Bitraversable-import Data.Either (partitionEithers)+import Data.Either (partitionEithers) import Data.Ext-import Data.Geometry.Ball (Disk, disk)-import Data.Geometry.Boundary+import Data.Geometry.Ball (Disk, disk)+import Data.Geometry.Boundary (PointLocationResult (..))+import Data.Geometry.Box (IsBoxable (..)) import Data.Geometry.HyperPlane-import Data.Geometry.Line+import Data.Geometry.Line (Line (Line)) import Data.Geometry.LineSegment import Data.Geometry.Point import Data.Geometry.Properties import Data.Geometry.Transformation import Data.Geometry.Vector-import qualified Data.Geometry.Vector as V-import qualified Data.List as List-import Data.Maybe (mapMaybe)-import Data.Util-import Data.Vinyl-import Data.Vinyl.CoRec-import GHC.Generics (Generic)-import GHC.TypeLits+import qualified Data.Geometry.Vector as V+import qualified Data.List as List+import Data.Maybe (mapMaybe)+import Data.Util (Three, pattern Three)+import Data.Vinyl (Rec (RNil, (:&)))+import Data.Vinyl.CoRec (Handler (H), match)+import GHC.Generics (Generic)+import GHC.TypeLits (type (+)) -------------------------------------------------------------------------------- --- | Triangles in \(d\)-dimensional space.+-- | A triangle in \(d\)-dimensional space. data Triangle d p r = Triangle !(Point d r :+ p) !(Point d r :+ p) !(Point d r :+ p)@@ -62,6 +63,7 @@ type instance NumType (Triangle d p r) = r type instance Dimension (Triangle d p r) = d +-- | A \(d\)-dimensional triangle is isomorphic to a triple of \(d\)-dimensional points. _TriangleThreePoints :: Iso' (Triangle d p r) (Three (Point d r :+ p)) _TriangleThreePoints = iso (\(Triangle p q r) -> Three p q r) (\(Three p q r) -> Triangle p q r) @@ -77,7 +79,7 @@ where Triangle' p q r = Triangle (ext p) (ext q) (ext r) -+-- | Get the three line-segments that make up the sides of a triangle. sideSegments :: Triangle d p r -> [LineSegment d p r] sideSegments (Triangle p q r) = [ClosedLineSegment p q, ClosedLineSegment q r, ClosedLineSegment r p]@@ -101,7 +103,7 @@ isDegenerateTriangle :: (Num r, Eq r) => Triangle 2 p r -> Bool isDegenerateTriangle = (== 0) . doubleArea --- | get the inscribed disk. Returns Nothing if the triangle is degenerate,+-- | Get the inscribed disk. Returns Nothing if the triangle is degenerate, -- i.e. if the points are colinear. inscribedDisk :: (Eq r, Fractional r) => Triangle 2 p r -> Maybe (Disk () r)@@ -144,18 +146,33 @@ inTriangle :: (Ord r, Fractional r) => Point 2 r -> Triangle 2 p r -> PointLocationResult inTriangle q t- | all (`inRange` (OpenRange 0 1)) [a,b,c] = Inside- | all (`inRange` (ClosedRange 0 1)) [a,b,c] = OnBoundary+ | all (`inRange` OpenRange 0 1) [a,b,c] = Inside+ | all (`inRange` ClosedRange 0 1) [a,b,c] = OnBoundary | otherwise = Outside where Vector3 a b c = toBarricentric q t +inTriangleRelaxed :: (Ord r, Num r)+ => Point 2 r -> Triangle 2 p r -> PointLocationResult+inTriangleRelaxed q (Triangle a b c)+ | ab == CoLinear && bc == ca = OnBoundary+ | bc == CoLinear && ca == ab = OnBoundary+ | ca == CoLinear && bc == ab = OnBoundary+ | ab == bc && bc == ca = Inside+ | otherwise = Outside+ where+ ab = ccw (a^.core) (b^.core) q+ bc = ccw (b^.core) (c^.core) q+ ca = ccw (c^.core) (a^.core) q+ -- | Test if a point lies inside or on the boundary of a triangle onTriangle :: (Ord r, Fractional r) => Point 2 r -> Triangle 2 p r -> Bool q `onTriangle` t = let Vector3 a b c = toBarricentric q t- in all (`inRange` (ClosedRange 0 1)) [a,b,c]+ in all (`inRange` ClosedRange 0 1) [a,b,c] +onTriangleRelaxed :: (Ord r, Num r) => Point 2 r -> Triangle 2 p r -> Bool+q `onTriangleRelaxed` t = inTriangleRelaxed q t /= Outside -- myQ :: Point 2 Rational -- myQ = read "Point2 [(-5985) % 16,(-14625) % 1]"@@ -165,7 +182,7 @@ type instance IntersectionOf (Line 2 r) (Triangle 2 p r) = [ NoIntersection, Point 2 r, LineSegment 2 () r ] -instance (Fractional r, Ord r) => (Line 2 r) `IsIntersectableWith` (Triangle 2 p r) where+instance (Fractional r, Ord r) => Line 2 r `IsIntersectableWith` Triangle 2 p r where nonEmptyIntersection = defaultNonEmptyIntersection l `intersect` (Triangle p q r) =@@ -180,9 +197,9 @@ collect :: LineSegment 2 p r -> Maybe (Either (Point 2 r) (LineSegment 2 p r)) collect s = match (s `intersect` l) $- (H $ \NoIntersection -> Nothing)- :& (H $ \(a :: Point 2 r) -> Just $ Left a)- :& (H $ \(e :: LineSegment 2 p r) -> Just $ Right e)+ H (\NoIntersection -> Nothing)+ :& H (\(a :: Point 2 r) -> Just $ Left a)+ :& H (\(e :: LineSegment 2 p r) -> Just $ Right e) :& RNil @@ -190,14 +207,15 @@ type instance IntersectionOf (Line 3 r) (Triangle 3 p r) = [ NoIntersection, Point 3 r, LineSegment 3 () r ] -instance (Fractional r, Ord r) => (Line 3 r) `IsIntersectableWith` (Triangle 3 p r) where+{- HLINT ignore "Use const" -}+instance (Fractional r, Ord r) => Line 3 r `IsIntersectableWith` Triangle 3 p r where nonEmptyIntersection = defaultNonEmptyIntersection l@(Line a v) `intersect` t@(Triangle (p :+ _) (q :+ _) (r :+ _)) = match (l `intersect` h) $- (H $ \NoIntersection -> coRec NoIntersection)- :& (H $ \i@(Point3 _ _ _) -> if onTriangle' i then coRec i else coRec NoIntersection)- :& (H $ \_ -> intersect2d)+ H (\NoIntersection -> coRec NoIntersection)+ :& H (\i@Point3{} -> if onTriangle' i then coRec i else coRec NoIntersection)+ :& H (\_ -> intersect2d) :& RNil where h@(Plane _ n) = supportingPlane t@@ -210,13 +228,13 @@ -- test if the point in terms of its 2d coords lies in side the projected triangle onTriangle' :: Point 3 r -> Bool- onTriangle' i = (project i) `onTriangle` t'+ onTriangle' i = project i `onTriangle` t' -- FIXME! these vectors may not be unit vectors. How do we deal with -- that? (and does that really matter here?) transf :: Transformation 3 r transf = let u = p .-. q- in rotateTo (Vector3 u (n `cross` u) n) |.| translation ((-1) *^ (toVec q))+ in rotateTo (Vector3 u (n `cross` u) n) |.| translation ((-1) *^ toVec q) -- inverse of the transformation above. invTrans :: Transformation 3 r invTrans = inverseOf transf@@ -233,8 +251,11 @@ intersect2d :: Intersection (Line 3 r) (Triangle 3 p r) intersect2d = match (l' `intersect` t') $- (H $ \NoIntersection -> coRec NoIntersection)- :& (H $ \i@(Point2 _ _) -> coRec $ lift i)- :& (H $ \(LineSegment s e) -> coRec $ LineSegment (s&unEndPoint.core %~ lift)- (e&unEndPoint.core %~ lift))+ H (\NoIntersection -> coRec NoIntersection)+ :& H (\i@(Point2 _ _) -> coRec $ lift i)+ :& H (\(LineSegment s e) -> coRec $ LineSegment (s&unEndPoint.core %~ lift)+ (e&unEndPoint.core %~ lift)) :& RNil++instance (Arity d, Ord r) => IsBoxable (Triangle d p r) where+ boundingBox (Triangle a b c) = boundingBox a <> boundingBox b <> boundingBox c
src/Data/Geometry/Vector.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE UndecidableInstances #-} {-# OPTIONS_GHC -fno-warn-orphans #-} -------------------------------------------------------------------------------- -- |@@ -17,35 +17,42 @@ , quadrance, qdA, distanceA , dot, norm, signorm , isScalarMultipleOf- , scalarMultiple+ , scalarMultiple, sameDirection -- reexports , FV.replicate , xComponent, yComponent, zComponent ) where -import Control.Applicative (liftA2)-import Control.Lens (Lens')+import Control.Applicative (liftA2)+import Control.Lens (Lens') import Control.Monad.State-import qualified Data.Foldable as F+import qualified Data.Foldable as F import Data.Geometry.Properties import Data.Geometry.Vector.VectorFamily-import Data.Geometry.Vector.VectorFixed (C(..))-import qualified Data.Vector.Fixed as FV+import Data.Geometry.Vector.VectorFixed (C (..))+import qualified Data.Vector.Fixed as FV import GHC.TypeLits-import Linear.Affine (Affine(..), qdA, distanceA)-import Linear.Metric (dot,norm,signorm,quadrance)-import Linear.Vector as LV hiding (E(..))-import System.Random (Random(..))-import Test.QuickCheck (Arbitrary(..),infiniteList)+import Linear.Affine (Affine (..), distanceA, qdA)+import Linear.Metric (dot, norm, quadrance, signorm)+import Linear.Vector as LV hiding (E (..))+import System.Random (Random (..))+import Test.QuickCheck (Arbitrary (..), Arbitrary1 (..), infiniteList,+ infiniteListOf) -------------------------------------------------------------------------------- +-- $setup+-- >>> import Control.Lens+ type instance Dimension (Vector d r) = d type instance NumType (Vector d r) = r instance (Arbitrary r, Arity d) => Arbitrary (Vector d r) where arbitrary = vectorFromListUnsafe <$> infiniteList +instance (Arity d) => Arbitrary1 (Vector d) where+ liftArbitrary gen = vectorFromListUnsafe <$> infiniteListOf gen+ instance (Random r, Arity d) => Random (Vector d r) where randomR (lows,highs) g0 = flip runState g0 $ FV.zipWithM (\l h -> state $ randomR (l,h)) lows highs@@ -79,7 +86,7 @@ => Vector d r -> Vector d r -> Bool u `isScalarMultipleOf` v = let d = u `dot` v num = quadrance u * quadrance v- in num == 0 || 1 == d*d / num+ in num == 0 || num == d*d -- u `isScalarMultipleOf` v = isJust $ scalarMultiple u v {-# SPECIALIZE isScalarMultipleOf :: (Eq r, Fractional r) => Vector 2 r -> Vector 2 r -> Bool #-}@@ -146,17 +153,46 @@ scalarMultiple' :: (Eq r, Fractional r) => Vector 2 r -> Vector 2 r -> Maybe r #-} +-- | Given two colinar vectors, u and v, test if they point in the same direction, i.e.+-- iff scalarMultiple' u v == Just lambda, with lambda > 0+--+-- pre: u and v are colinear, u and v are non-zero+sameDirection :: (Eq r, Num r, Arity d) => Vector d r -> Vector d r -> Bool+sameDirection u v = and $ FV.zipWith (\ux vx -> signum ux == signum vx) u v++-- sameDirectionProp :: (Eq r, Fractional r, Arity d)+-- => Vector d r -> Vector d r -> Bool+-- sameDirectionProp u v = sameDirection u v == maybe False ((/= (-1)) . signum) (scalarMultiple' u v)+ -------------------------------------------------------------------------------- -- * Helper functions specific to two and three dimensional vectors +-- | Shorthand to access the first component+--+-- >>> Vector3 1 2 3 ^. xComponent+-- 1+-- >>> Vector2 1 2 & xComponent .~ 10+-- Vector2 10 2 xComponent :: (1 <= d, Arity d) => Lens' (Vector d r) r xComponent = element (C :: C 0) {-# INLINABLE xComponent #-} +-- | Shorthand to access the second component+--+-- >>> Vector3 1 2 3 ^. yComponent+-- 2+-- >>> Vector2 1 2 & yComponent .~ 10+-- Vector2 1 10 yComponent :: (2 <= d, Arity d) => Lens' (Vector d r) r yComponent = element (C :: C 1) {-# INLINABLE yComponent #-} +-- | Shorthand to access the third component+--+-- >>> Vector3 1 2 3 ^. zComponent+-- 3+-- >>> Vector3 1 2 3 & zComponent .~ 10+-- Vector3 1 2 10 zComponent :: (3 <= d, Arity d) => Lens' (Vector d r) r zComponent = element (C :: C 2) {-# INLINABLE zComponent #-}
src/Data/Geometry/Vector/VectorFamily.hs view
@@ -15,31 +15,29 @@ module Data.Geometry.Vector.VectorFamily where import Control.DeepSeq-import Control.Lens hiding (element)+import Control.Lens hiding (element)+import Control.Monad import Data.Aeson--- import Data.Aeson (ToJSON(..),FromJSON(..))-import qualified Data.Foldable as F-import qualified Data.List as L-import Data.Geometry.Vector.VectorFixed (C(..))+import qualified Data.Foldable as F+import Data.Functor.Classes+import Data.Geometry.Vector.VectorFamilyPeano (ImplicitArity, VectorFamily (..),+ VectorFamilyF) import qualified Data.Geometry.Vector.VectorFamilyPeano as Fam-import Data.Geometry.Vector.VectorFamilyPeano ( VectorFamily(..)- , VectorFamilyF- , ImplicitArity- )-import qualified Data.Vector.Fixed as V-import Data.Vector.Fixed.Cont (Peano)+import Data.Geometry.Vector.VectorFixed (C (..))+import Data.Hashable+import Data.List+import qualified Data.List as L+import Data.Proxy+import qualified Data.Vector.Fixed as V+import Data.Vector.Fixed.Cont (Peano) import GHC.TypeLits-import Linear.Affine (Affine(..))+import Linear.Affine (Affine (..)) import Linear.Metric-import qualified Linear.V2 as L2-import qualified Linear.V3 as L3-import qualified Linear.V4 as L4+import qualified Linear.V2 as L2+import qualified Linear.V3 as L3+import qualified Linear.V4 as L4 import Linear.Vector-import Text.ParserCombinators.ReadP (ReadP, string,pfail)-import Text.ParserCombinators.ReadPrec (lift)-import Text.Read (Read(..),readListPrecDefault, readPrec_to_P,minPrec)-import Data.Proxy-import Data.Hashable+import Text.Read (Read (..), readListPrecDefault) -------------------------------------------------------------------------------- -- * d dimensional Vectors@@ -56,8 +54,9 @@ type instance Index (Vector d r) = Int type instance IxValue (Vector d r) = r -unV :: Lens (Vector d r) (Vector d s) (VectorFamily (Peano d) r) (VectorFamily (Peano d) s)-unV = lens _unV (const MKVector)+-- | Vectors are isomorphic to a definition determined by 'VectorFamily'.+unV :: Iso (Vector d r) (Vector d s) (VectorFamily (Peano d) r) (VectorFamily (Peano d) s)+unV = iso _unV MKVector {-# INLINE unV #-} -- type Arity d = (ImplicitArity (Peano d), KnownNat d)@@ -66,6 +65,7 @@ deriving instance (Eq r, Arity d) => Eq (Vector d r)+deriving instance Arity d => Eq1 (Vector d) deriving instance (Ord r, Arity d) => Ord (Vector d r) deriving instance Arity d => Functor (Vector d)@@ -99,22 +99,50 @@ inspect = V.inspect . _unV basicIndex = V.basicIndex . _unV -instance (Arity d, Show r) => Show (Vector d r) where- show v = mconcat [ "Vector", show $ F.length v , " "- , show $ F.toList v ]+-- instance (Arity d, Show r) => Show (Vector d r) where+-- show v = mconcat [ "Vector", show $ F.length v , " "+-- , show $ F.toList v ] +-- instance (Read r, Arity d) => Read (Vector d r) where+-- readPrec = lift readVec+-- where+-- readVec :: (Arity d, Read r) => ReadP (Vector d r)+-- readVec = do let d = natVal (Proxy :: Proxy d)+-- _ <- string $ "Vector" <> show d <> " "+-- rs <- readPrec_to_P readPrec minPrec+-- case vectorFromList rs of+-- Just v -> pure v+-- _ -> pfail+-- readListPrec = readListPrecDefault++instance (Show r, Arity d) => Show (Vector d r) where+ showsPrec = liftShowsPrec showsPrec showList++instance (Arity d) => Show1 (Vector d) where+ liftShowsPrec sp _ d v = showParen (d > 10) $+ showString constr . showChar ' ' .+ unwordsS (map (sp 11) (F.toList v))+ where+ constr = "Vector" <> show (fromIntegral (natVal @d Proxy))+ unwordsS = foldr (.) id . intersperse (showChar ' ')+ instance (Read r, Arity d) => Read (Vector d r) where- readPrec = lift readVec+ readPrec = liftReadPrec readPrec readListPrec readListPrec = readListPrecDefault -readVec :: forall d r. (Arity d, Read r) => ReadP (Vector d r)-readVec = do let d = natVal (Proxy :: Proxy d)- _ <- string $ "Vector" <> show d <> " "- rs <- readPrec_to_P readPrec minPrec- case vectorFromList rs of- Just v -> pure v- _ -> pfail+instance (Arity d) => Read1 (Vector d) where+ liftReadPrec rp _rl = readData $+ readUnaryWith (replicateM d rp) constr $ \rs ->+ case vectorFromList rs of+ Just p -> p+ _ -> error "internal error in Data.Geometry.Vector read instance."+ where+ d = fromIntegral (natVal (Proxy :: Proxy d))+ constr = "Vector" <> show d+ liftReadListPrec = liftReadListPrecDefault ++ deriving instance (FromJSON r, Arity d) => FromJSON (Vector d r) instance (ToJSON r, Arity d) => ToJSON (Vector d r) where toJSON = toJSON . _unV@@ -125,39 +153,48 @@ -------------------------------------------------------------------------------- -- * Convenience "constructors" +-- | Constant sized vector with d elements. pattern Vector :: VectorFamilyF (Peano d) r -> Vector d r pattern Vector v = MKVector (VectorFamily v) {-# COMPLETE Vector #-} +-- | Constant sized vector with 1 element. pattern Vector1 :: r -> Vector 1 r pattern Vector1 x = (Vector (Identity x)) {-# COMPLETE Vector1 #-} +-- | Constant sized vector with 2 elements. pattern Vector2 :: r -> r -> Vector 2 r pattern Vector2 x y = (Vector (L2.V2 x y)) {-# COMPLETE Vector2 #-} +-- | Constant sized vector with 3 elements. pattern Vector3 :: r -> r -> r -> Vector 3 r pattern Vector3 x y z = (Vector (L3.V3 x y z)) {-# COMPLETE Vector3 #-} +-- | Constant sized vector with 4 elements. pattern Vector4 :: r -> r -> r -> r -> Vector 4 r pattern Vector4 x y z w = (Vector (L4.V4 x y z w)) {-# COMPLETE Vector4 #-} -------------------------------------------------------------------------------- +-- | \( O(n) \) Convert from a list to a non-empty vector. vectorFromList :: Arity d => [r] -> Maybe (Vector d r) vectorFromList = V.fromListM +-- | \( O(n) \) Convert from a list to a non-empty vector. vectorFromListUnsafe :: Arity d => [r] -> Vector d r vectorFromListUnsafe = V.fromList +-- | \( O(n) \) Pop the first element off a vector. destruct :: (Arity d, Arity (d + 1)) => Vector (d + 1) r -> (r, Vector d r) destruct v = (L.head $ F.toList v, vectorFromListUnsafe . tail $ F.toList v) -- FIXME: this implementaion of tail is not particularly nice +-- | \( O(1) \) First element. Since arity is at least 1, this function is total. head :: (Arity d, 1 <= d) => Vector d r -> r head = view $ element (C :: C 0) @@ -174,15 +211,16 @@ -- | Similar to 'element' above. Except that we don't have a static guarantee -- that the index is in bounds. Hence, we can only return a Traversal element' :: forall d r. Arity d => Int -> Traversal' (Vector d r) r-element' i = unV.(e (C :: C d) i)+element' i = unV.e (C :: C d) i where e :: Arity d => proxy d -> Int -> Traversal' (VectorFamily (Peano d) r) r- e _ = Fam.element'+ e _ = ix {-# INLINE element' #-} -------------------------------------------------------------------------------- -- * Snoccing and consindg +-- | \( O(n) \) Prepend an element. cons :: (Arity d, Arity (d+1)) => r -> Vector d r -> Vector (d + 1) r cons x = vectorFromListUnsafe . (x:) . F.toList @@ -195,6 +233,7 @@ init :: (Arity d, Arity (d + 1)) => Vector (d + 1) r -> Vector d r init = vectorFromListUnsafe . L.init . F.toList +-- | \( O(1) \) Last element. Since the vector is non-empty, runtime bounds checks are bypassed. last :: forall d r. (KnownNat d, Arity (d + 1)) => Vector (d + 1) r -> r last = view $ element (C :: C d)
src/Data/Geometry/Vector/VectorFamilyPeano.hs view
@@ -1,6 +1,19 @@ {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE UndecidableInstances #-}-module Data.Geometry.Vector.VectorFamilyPeano where+--------------------------------------------------------------------------------+-- |+-- Module : Data.Geometry.Vector.VectorFamilyPeano+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+--------------------------------------------------------------------------------+module Data.Geometry.Vector.VectorFamilyPeano+ ( ImplicitArity+ , VectorFamily(VectorFamily)+ , VectorFamilyF+ , FromPeano+ , Two+ ) where import Control.Applicative (liftA2) import Control.DeepSeq@@ -10,6 +23,7 @@ import qualified Data.Foldable as F import qualified Data.Geometry.Vector.VectorFixed as FV import Data.Proxy+import Data.Functor.Classes import qualified Data.Vector.Fixed as V import Data.Vector.Fixed.Cont (PeanoNum(..), Fun(..)) import GHC.TypeLits@@ -92,6 +106,15 @@ (SS (SS (SS (SS (SS _))))) -> u == v {-# INLINE (==) #-} +instance (ImplicitArity d) => Eq1 (VectorFamily d) where+ liftEq eq (VectorFamily u) (VectorFamily v) = case (implicitPeano :: SingPeano d) of+ SZ -> liftEq eq u v+ (SS SZ) -> liftEq eq u v+ (SS (SS SZ)) -> liftEq eq u v+ (SS (SS (SS SZ))) -> liftEq eq u v+ (SS (SS (SS (SS SZ)))) -> liftEq eq u v+ (SS (SS (SS (SS (SS _))))) -> liftEq eq u v+ instance (Ord r, ImplicitArity d) => Ord (VectorFamily d r) where (VectorFamily u) `compare` (VectorFamily v) = case (implicitPeano :: SingPeano d) of SZ -> u `compare` v@@ -216,13 +239,13 @@ {-# INLINE element' #-} elem0 :: Int -> Traversal' (VectorFamily Z r) r-elem0 _ = \_ v -> pure v+elem0 _ _ = pure {-# INLINE elem0 #-} -- zero length vectors don't store any elements elem1 :: Int -> Traversal' (VectorFamily One r) r elem1 = \case- 0 -> unVF.(lens runIdentity (\_ -> Identity))+ 0 -> unVF.lens runIdentity (const Identity) _ -> \_ v -> pure v {-# INLINE elem1 #-} @@ -287,14 +310,14 @@ vectorFromList :: ImplicitArity d => [r] -> Maybe (VectorFamily d r) vectorFromList = V.fromListM -vectorFromListUnsafe :: ImplicitArity d => [r] -> VectorFamily d r-vectorFromListUnsafe = V.fromList+-- vectorFromListUnsafe :: ImplicitArity d => [r] -> VectorFamily d r+-- vectorFromListUnsafe = V.fromList --- | Get the head and tail of a vector-destruct :: (ImplicitArity d, ImplicitArity (S d))- => VectorFamily (S d) r -> (r, VectorFamily d r)-destruct v = (head $ F.toList v, vectorFromListUnsafe . tail $ F.toList v)- -- FIXME: this implementaion of tail is not particularly nice+-- -- | Get the head and tail of a vector+-- destruct :: (ImplicitArity d, ImplicitArity (S d))+-- => VectorFamily (S d) r -> (r, VectorFamily d r)+-- destruct v = (head $ F.toList v, vectorFromListUnsafe . tail $ F.toList v)+-- -- FIXME: this implementaion of tail is not particularly nice -- snoc :: (ImplicitArity d, ImplicitArity (S d)) -- => VectorFamily d r -> r -> VectorFamily (S d) r
src/Data/Geometry/Vector/VectorFixed.hs view
@@ -1,5 +1,12 @@ {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE UndecidableInstances #-}+--------------------------------------------------------------------------------+-- |+-- Module : Data.Geometry.Vector.VectorFixed+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+-------------------------------------------------------------------------------- module Data.Geometry.Vector.VectorFixed where import Control.DeepSeq@@ -9,6 +16,7 @@ import Data.Proxy import qualified Data.Vector.Fixed as V import Data.Vector.Fixed (Arity)+import Data.Functor.Classes import Data.Vector.Fixed.Boxed import GHC.Generics (Generic) import GHC.TypeLits@@ -46,7 +54,7 @@ element' :: forall d r. Arity d => Int -> Traversal' (Vector d r) r element' i f v | 0 <= i && i < fromInteger (natVal (C :: C d)) = f (v V.! i)- <&> \a -> (v&V.element i .~ a)+ <&> \a -> v&V.element i .~ a -- Implementation based on that of Ixed Vector in Control.Lens.At | otherwise = pure v @@ -64,6 +72,11 @@ ] deriving instance (Eq r, Arity d) => Eq (Vector d r)++-- FIXME: Upstream Eq1 instance to 'fixed-vector' package.+instance Arity d => Eq1 (Vector d) where+ liftEq eq (Vector lhs) (Vector rhs) = V.and $ V.zipWith eq lhs rhs+ deriving instance (Ord r, Arity d) => Ord (Vector d r) -- deriving instance Arity d => Functor (Vector d) @@ -125,7 +138,7 @@ -- | Cross product of two three-dimensional vectors cross :: Num r => Vector 3 r -> Vector 3 r -> Vector 3 r-u `cross` v = fromV3 $ (toV3 u) `L3.cross` (toV3 v)+u `cross` v = fromV3 $ toV3 u `L3.cross` toV3 v --------------------------------------------------------------------------------
+ src/Data/Geometry/VerticalRayShooting.hs view
@@ -0,0 +1,12 @@+--------------------------------------------------------------------------------+-- |+-- Module : Data.Geometry.VerticalRayShooting+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+--------------------------------------------------------------------------------+module Data.Geometry.VerticalRayShooting+ ( module Data.Geometry.VerticalRayShooting.PersistentSweep+ ) where++import Data.Geometry.VerticalRayShooting.PersistentSweep
+ src/Data/Geometry/VerticalRayShooting/PersistentSweep.hs view
@@ -0,0 +1,230 @@+{-# Language TemplateHaskell #-}+--------------------------------------------------------------------------------+-- |+-- Module : Data.Geometry.VerticalRayShooting.PersistentSweep+-- Copyright : (C) Frank Staals+-- License : see the LICENSE file+-- Maintainer : Frank Staals+--------------------------------------------------------------------------------+module Data.Geometry.VerticalRayShooting.PersistentSweep+ ( VerticalRayShootingStructure(VerticalRayShootingStructure), StatusStructure+ , leftMost, sweepStruct++ -- * Building the Data Structure+ , verticalRayShootingStructure+ -- * Querying the Data Structure+ , segmentAbove, segmentAboveOrOn+ , findSlab+ , lookupAbove, lookupAboveOrOn, searchInSlab+ , ordAt, yCoordAt+ ) where++import Algorithms.BinarySearch (binarySearchIn)+import Control.Lens hiding (contains, below)+import Data.Ext+import Data.Foldable (toList)+import Data.Geometry.Line+import Data.Geometry.LineSegment+import Data.Geometry.Point+import qualified Data.List as List+import Data.List.NonEmpty (NonEmpty(..))+import qualified Data.List.NonEmpty as NonEmpty+import Data.Maybe (mapMaybe)+import Data.Ord (comparing)+import Data.Semigroup.Foldable+import qualified Data.Set as SS -- status struct+import qualified Data.Set.Util as SS+import qualified Data.Vector as V+++import Data.RealNumber.Rational++type R = RealNumber 5+--------------------------------------------------------------------------------++-- | The vertical ray shooting data structure+data VerticalRayShootingStructure p e r =+ VerticalRayShootingStructure { _leftMost :: r+ , _sweepStruct :: V.Vector (r :+ StatusStructure p e r)+ -- ^ entry (r :+ s) means that "just" left of "r" the+ -- status structure is 's', i.e up to 'r'+ } deriving (Show,Eq)++type StatusStructure p e r = SS.Set (LineSegment 2 p r :+ e)++makeLensesWith (lensRules&generateUpdateableOptics .~ False) ''VerticalRayShootingStructure++--------------------------------------------------------------------------------+-- * Building the DS++-- | Given a set of \(n\) interiorly pairwise disjoint *closed* segments,+-- compute a vertical ray shooting data structure. (i.e. the+-- endpoints of the segments may coincide).+--+-- pre: no vertical segments+--+-- running time: \(O(n\log n)\).+-- space: \(O(n\log n)\).+verticalRayShootingStructure :: (Ord r, Fractional r, Foldable1 t)+ => t (LineSegment 2 p r :+ e)+ -> VerticalRayShootingStructure p e r+verticalRayShootingStructure ss = VerticalRayShootingStructure (eventX e) (sweep' events)+ where+ events@(e :| _) = fmap combine+ . NonEmpty.groupAllWith1 eventX+ . foldMap1 toEvents+ . NonEmpty.fromList -- precondition guarantees that this is safe+ . mapMaybe reOrient . toList+ $ ss+ sweep' = V.fromList . toList . sweep++ reOrient s'@(s :+ z) = case (s^.start.core.xCoord) `compare` (s^.end.core.xCoord) of+ LT -> Just s'+ GT -> let s'' = s&start .~ (s^.end) -- flip the segment+ &end .~ (s^.start)+ in Just $ s'' :+ z+ EQ -> Nothing -- precondition says this won't happen, but kill+ -- them anyway++-- | Given a bunch of events happening at the same time, merge them into a single event+-- where we apply all actions.+combine :: NonEmpty (Event p e r) -> Event p e r+combine es@((x :+ _) :| _) = x :+ foldMap1 eventActions es++-- | Given a line segment construct the two events; i.e. when we+-- insert it and when we delete it.+toEvents :: Ord r => LineSegment 2 p r :+ e -> NonEmpty (Event p e r)+toEvents s@(LineSegment' p q :+ _) = NonEmpty.fromList [ (p^.core.xCoord) :+ Insert s :| []+ , (q^.core.xCoord) :+ Delete s :| []+ ]++----------------------------------------++data Action a = Insert a | Delete a deriving (Show,Eq)++{- HLINT ignore "Avoid lambda using `infix`" -}+interpret :: Action a -> (a -> a -> Ordering) -> SS.Set a -> SS.Set a+interpret = \case+ Insert s -> \cmp -> SS.insertBy cmp s+ Delete s -> \cmp -> SS.deleteAllBy cmp s+++type Event p e r = r :+ NonEmpty (Action (LineSegment 2 p r :+ e))++eventX :: Event p e r -> r+eventX = view core++eventActions :: Event p e r -> NonEmpty (Action (LineSegment 2 p r :+ e))+eventActions = view extra++----------------------------------------++-- | Runs the sweep building the data structure from left to right.+sweep :: (Ord r, Fractional r)+ => NonEmpty (Event p e r) -> NonEmpty (r :+ StatusStructure p e r)+sweep es = NonEmpty.fromList+ . snd . List.mapAccumL h SS.empty+ $ zip (toList es) (NonEmpty.tail es)+ where+ h ss evts = let x :+ ss' = handle ss evts in (ss',x :+ ss')++-- | Given the current status structure (for left of the next event+-- 'l'), and the next two events (l,r); essentially defining the slab+-- between l and r, we construct the status structure for in the slab (l,r).+-- returns the right boundary and this status structure.+handle :: (Ord r, Fractional r)+ => StatusStructure p e r+ -> (Event p e r, Event p e r)+ -> r :+ StatusStructure p e r+handle ss ( l :+ acts+ , r :+ _) = let mid = (l+r)/2+ runActionAt x act = interpret act (ordAt x)+ in r :+ foldr (runActionAt mid) ss (orderActs acts)+ -- run deletions first++-- | orders the actions to put insertions first and then all deletions+orderActs :: NonEmpty (Action a) -> NonEmpty (Action a)+orderActs acts = let (dels,ins) = NonEmpty.partition (\case+ Delete _ -> True+ Insert _ -> False+ ) acts+ in NonEmpty.fromList $ ins <> dels+++--------------------------------------------------------------------------------+-- * Querying the DS++-- | Find the segment vertically strictly above query point q, if it+-- exists.+--+-- \(O(\log n)\)+segmentAbove :: (Ord r, Num r) => Point 2 r -> VerticalRayShootingStructure p e r+ -> Maybe (LineSegment 2 p r :+ e)+segmentAbove q ds = findSlab q ds >>= lookupAbove q++-- | Find the segment vertically query point q, if it exists.+--+-- \(O(\log n)\)+segmentAboveOrOn :: (Ord r, Num r)+ => Point 2 r -> VerticalRayShootingStructure p e r+ -> Maybe (LineSegment 2 p r :+ e)+segmentAboveOrOn q ds = findSlab q ds >>= lookupAboveOrOn q++++-- | Given a query point, find the (data structure of the) slab containing the query point+--+-- \(O(\log n)\)+findSlab :: Ord r+ => Point 2 r -> VerticalRayShootingStructure p e r -> Maybe (StatusStructure p e r)+findSlab q ds | q^.xCoord < ds^.leftMost = Nothing+ | otherwise = view extra+ <$> binarySearchIn (q `leftOf `) (ds^.sweepStruct)+ where+ q' `leftOf` (r :+ _) = q'^.xCoord <= r++--------------------------------------------------------------------------------+-- * Querying in a single slab++-- | Finds the segment containing or above the query point 'q'+--+-- \(O(\log n)\)+lookupAboveOrOn :: (Ord r, Num r)+ => Point 2 r -> StatusStructure p e r -> Maybe (LineSegment 2 p r :+ e)+lookupAboveOrOn q = searchInSlab (not . (q `liesAbove`))++-- | Finds the first segment strictly above q+--+-- \(O(\log n)\)+lookupAbove :: (Ord r, Num r)+ => Point 2 r -> StatusStructure p e r -> Maybe (LineSegment 2 p r :+ e)+lookupAbove q = searchInSlab (q `liesBelow`)++-- | generic searching function+searchInSlab :: Num r => (Line 2 r -> Bool)+ -> StatusStructure p e r -> Maybe (LineSegment 2 p r :+ e)+searchInSlab p = binarySearchIn (p . supportingLine . view core)+++----------------------------------------------------------------------------------++type Compare a = a -> a -> Ordering++-- | Compare based on the y-coordinate of the intersection with the horizontal+-- line through y+ordAt :: (Fractional r, Ord r) => r -> Compare (LineSegment 2 p r :+ e)+ordAt x = comparing (yCoordAt x)+++-- | 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+yCoordAt :: (Fractional r, Ord r) => r -> LineSegment 2 p r :+ e -> r+yCoordAt x (LineSegment' (Point2 px py :+ _) (Point2 qx qy :+ _) :+ _)+ | px == qx = py `max` qy -- s is vertical, since by the precondition it+ -- intersects we return the y-coord of the topmost+ -- endpoint.+ | otherwise = py + alpha * (qy - py)+ where+ alpha = (x - px) / (qx - px)
src/Data/PlaneGraph.hs view
@@ -1,6 +1,4 @@-{-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE OverloadedStrings #-} -------------------------------------------------------------------------------- -- | -- Module : Data.PlaneGraph
src/Data/PlaneGraph/Core.hs view
@@ -1,6 +1,6 @@-{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-} -------------------------------------------------------------------------------- -- | -- Module : Data.PlaneGraph.Core@@ -58,33 +58,29 @@ ) where -import Control.Lens hiding (holes, holesOf, (.=))+import Control.Lens hiding (holes, holesOf, (.=)) import Data.Aeson-import qualified Data.CircularSeq as C import Data.Ext-import qualified Data.Foldable as F-import Data.Function (on)+import qualified Data.Foldable as F+import Data.Function (on) import Data.Geometry.Box import Data.Geometry.Interval-import Data.Geometry.Line (cmpSlope, supportingLine)+import Data.Geometry.Line (cmpSlope, supportingLine) import Data.Geometry.LineSegment hiding (endPoints) import Data.Geometry.Point import Data.Geometry.Polygon import Data.Geometry.Properties-import qualified Data.List.NonEmpty as NonEmpty-import qualified Data.Map as M-import Data.Ord (comparing)-import qualified Data.PlanarGraph as PG-import Data.PlanarGraph( PlanarGraph, planarGraph, dual- , Dart(..), VertexId(..), FaceId(..), Arc(..)- , Direction(..), twin- , World(..)- , FaceId', VertexId'- , HasDataOf(..)- )+import qualified Data.List.NonEmpty as NonEmpty+import qualified Data.Map as M+import Data.Ord (comparing)+import Data.PlanarGraph (Arc (..), Dart (..), Direction (..), FaceId (..),+ FaceId', HasDataOf (..), PlanarGraph, VertexId (..),+ VertexId', World (..), dual, planarGraph, twin)+import qualified Data.PlanarGraph as PG import Data.Util-import qualified Data.Vector as V-import GHC.Generics (Generic)+import qualified Data.Vector as V+import Data.Vector.Circular (CircularVector)+import GHC.Generics (Generic) -------------------------------------------------------------------------------- @@ -182,15 +178,16 @@ -> f -- ^ data inside -> f -- ^ data outside the polygon -> PlaneGraph s p () f r-fromSimplePolygon p (SimplePolygon vs) iD oD = PlaneGraph g'+fromSimplePolygon p poly iD oD = PlaneGraph g' where+ vs = poly ^. outerBoundaryVector g = fromVertices p vs fData' = V.fromList [iD, oD] g' = g & PG.faceData .~ fData' -- | Constructs a planar from the given vertices fromVertices :: proxy s- -> C.CSeq (Point 2 r :+ p)+ -> CircularVector (Point 2 r :+ p) -> PlanarGraph s Primal (VertexData r p) () () fromVertices _ vs = g&PG.vertexData .~ vData' where@@ -223,7 +220,7 @@ sing x = x NonEmpty.:| [] - vts = map (\(p,sp) -> (p,map (^.extra) . sortAround (ext p) <$> sp))+ vts = map (\(p,sp) -> (p,map (^.extra) . sortAround' (ext p) <$> sp)) . M.assocs $ pts -- vertex Data vxData = V.fromList . map (\(p,sp) -> VertexData p (sp^._1)) $ vts@@ -272,10 +269,10 @@ -- | Enumerate all vertices, together with their vertex data -- -- >>> mapM_ print $ vertices smallG--- (VertexId 0,VertexData {_location = Point2 [0,0], _vData = 0})--- (VertexId 1,VertexData {_location = Point2 [2,2], _vData = 1})--- (VertexId 2,VertexData {_location = Point2 [2,0], _vData = 2})--- (VertexId 3,VertexData {_location = Point2 [-1,4], _vData = 3})+-- (VertexId 0,VertexData {_location = Point2 0 0, _vData = 0})+-- (VertexId 1,VertexData {_location = Point2 2 2, _vData = 1})+-- (VertexId 2,VertexData {_location = Point2 2 0, _vData = 2})+-- (VertexId 3,VertexData {_location = Point2 (-1) 4, _vData = 3}) vertices :: PlaneGraph s v e f r -> V.Vector (VertexId' s, VertexData r v) vertices = PG.vertices . _graph @@ -565,7 +562,7 @@ => (VertexId' s -> v -> m v') -> PlaneGraph s v e f r -> m (PlaneGraph s v' e f r)-traverseVertices f = itraverseOf (vertexData.itraversed) (\i -> f (VertexId i))+traverseVertices f = itraverseOf (vertexData.itraversed) (f . VertexId) -- | Traverses the darts --@@ -636,7 +633,7 @@ -- compare lexicographically; i.e. if same x-coord prefer the one with the -- smallest y-coord d :+ _ = V.maximumBy (cmpSlope `on` (^.extra))- . fmap (\d' -> d' :+ (edgeSegment d' ps)^.core.to supportingLine)+ . fmap (\d' -> d' :+ edgeSegment d' ps ^. core.to supportingLine) $ incidentEdges v ps -- based on the approach sketched at https://cstheory.stackexchange.com/questions/27586/finding-outer-face-in-plane-graph-embedded-planar-graph -- basically: find the leftmost vertex, find the incident edge with the largest slope@@ -650,11 +647,11 @@ -- | Reports all edges as line segments -- -- >>> mapM_ print $ edgeSegments smallG--- (Dart (Arc 0) +1,LineSegment (Closed (Point2 [0,0] :+ 0)) (Closed (Point2 [2,0] :+ 2)) :+ "0->2")--- (Dart (Arc 1) +1,LineSegment (Closed (Point2 [0,0] :+ 0)) (Closed (Point2 [2,2] :+ 1)) :+ "0->1")--- (Dart (Arc 2) +1,LineSegment (Closed (Point2 [0,0] :+ 0)) (Closed (Point2 [-1,4] :+ 3)) :+ "0->3")--- (Dart (Arc 4) +1,LineSegment (Closed (Point2 [2,2] :+ 1)) (Closed (Point2 [2,0] :+ 2)) :+ "1->2")--- (Dart (Arc 3) +1,LineSegment (Closed (Point2 [2,2] :+ 1)) (Closed (Point2 [-1,4] :+ 3)) :+ "1->3")+-- (Dart (Arc 0) +1,ClosedLineSegment (Point2 0 0 :+ 0) (Point2 2 0 :+ 2) :+ "0->2")+-- (Dart (Arc 1) +1,ClosedLineSegment (Point2 0 0 :+ 0) (Point2 2 2 :+ 1) :+ "0->1")+-- (Dart (Arc 2) +1,ClosedLineSegment (Point2 0 0 :+ 0) (Point2 (-1) 4 :+ 3) :+ "0->3")+-- (Dart (Arc 4) +1,ClosedLineSegment (Point2 2 2 :+ 1) (Point2 2 0 :+ 2) :+ "1->2")+-- (Dart (Arc 3) +1,ClosedLineSegment (Point2 2 2 :+ 1) (Point2 (-1) 4 :+ 3) :+ "1->3") edgeSegments :: PlaneGraph s v e f r -> V.Vector (Dart s, LineSegment 2 v r :+ e) edgeSegments ps = fmap withSegment . edges $ ps where@@ -683,7 +680,7 @@ -> SimplePolygon v r :+ f rawFaceBoundary i ps = pg :+ (ps^.dataOf i) where- pg = fromPoints . F.toList . fmap (\j -> ps^.graph.dataOf j.to vtxDataToExt)+ pg = unsafeFromPoints . F.toList . fmap (\j -> ps^.graph.dataOf j.to vtxDataToExt) . boundaryVertices i $ ps -- | Alias for rawFace Boundary
src/Data/PlaneGraph/IO.hs view
@@ -16,7 +16,6 @@ import Data.Aeson import Data.Bifunctor import qualified Data.ByteString as B-import Data.Ext import Data.Geometry.Point import qualified Data.List as List import qualified Data.PlanarGraph.AdjRep as PGA@@ -123,11 +122,11 @@ location' = V.create $ do a <- MV.new (length vs) forM_ vs $ \(Vtx i p _ _) ->- MV.write a i $ ext p+ MV.write a i p pure a -- sort the adjacencies around every vertex v sort' (Vtx v p ajs x) = Vtx v p (List.sortBy (around p) ajs) x- around p (a,_) (b,_) = ccwCmpAround (ext p) (location' V.! a) (location' V.! b)+ around p (a,_) (b,_) = ccwCmpAround p (location' V.! a) (location' V.! b) -- note: since the graph is planar, there should not be -- any pairs of points for which ccwCmpAround returns EQ -- hence, no need to pick a secondary comparison
src/Graphics/Camera.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE TemplateHaskell #-} -------------------------------------------------------------------------------- -- | -- Module : Graphics.Camera@@ -32,7 +31,7 @@ -- | A basic camera data type. The fields stored are: -- -- * the camera position,--- * the raw camera normal, i.e. a unit vecotr into the center of the screen,+-- * the raw camera normal, i.e. a unit vector into the center of the screen, -- * the raw view up vector indicating which side points "upwards" in the scene, -- * the viewplane depth (i.e. the distance from the camera position to the plane on which we project), -- * the near distance (everything closer than this is clipped),@@ -53,8 +52,38 @@ ---------------------------------------- -- * Field Accessor Lenses -makeLenses ''Camera+-- Lemmih: Writing out the lenses by hand so they can be documented.+-- makeLenses ''Camera +-- | Camera position.+cameraPosition :: Lens' (Camera r) (Point 3 r)+cameraPosition = lens _cameraPosition (\cam p -> cam{_cameraPosition=p})++-- | Raw camera normal, i.e. a unit vector into the center of the screen.+rawCameraNormal :: Lens' (Camera r) (Vector 3 r)+rawCameraNormal = lens _rawCameraNormal (\cam r -> cam{_rawCameraNormal=r})++-- | Raw view up vector indicating which side points "upwards" in the scene.+rawViewUp :: Lens' (Camera r) (Vector 3 r)+rawViewUp = lens _rawViewUp (\cam r -> cam{_rawViewUp=r})++-- | Viewplane depth (i.e. the distance from the camera position to the plane on which we project).+viewPlaneDepth :: Lens' (Camera r) r+viewPlaneDepth = lens _viewPlaneDepth (\cam v -> cam{_viewPlaneDepth=v})++-- | Near distance (everything closer than this is clipped).+nearDist :: Lens' (Camera r) r+nearDist = lens _nearDist (\cam n -> cam{_nearDist=n})++-- | Far distance (everything further away than this is clipped).+farDist :: Lens' (Camera r) r+farDist = lens _farDist (\cam f -> cam{_farDist=f})++-- | Screen dimensions.+screenDimensions :: Lens' (Camera r) (Vector 2 r)+screenDimensions = lens _screenDimensions (\cam d -> cam{_screenDimensions=d})++ -------------------------------------------------------------------------------- -- * Accessor Lenses @@ -82,8 +111,7 @@ -- | Translates world coordinates into view coordinates worldToView :: Fractional r => Camera r -> Transformation 3 r-worldToView c = rotateCoordSystem c- |.| (translation $ (-1) *^ c^.cameraPosition.vector)+worldToView c = rotateCoordSystem c |.| translation ((-1) *^ c^.cameraPosition.vector) -- | Transformation into viewport coordinates toViewPort :: Fractional r => Camera r -> Transformation 3 r
− test/Algorithms/Geometry/LineSegmentIntersection/manual.ipe
@@ -1,324 +0,0 @@-<?xml version="1.0"?>-<!DOCTYPE ipe SYSTEM "ipe.dtd">-<ipe version="70107" creator="Ipe 7.2.2">-<info created="D:20160903131616" modified="D:20161022125153"/>-<ipestyle name="basic">-<symbol name="arrow/arc(spx)">-<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/farc(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/ptarc(spx)">-<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">-0 0 m--1 0.333 l--0.8 0 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/fptarc(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--0.8 0 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="mark/circle(sx)" transformations="translations">-<path fill="sym-stroke">-0.6 0 0 0.6 0 0 e-0.4 0 0 0.4 0 0 e-</path>-</symbol>-<symbol name="mark/disk(sx)" transformations="translations">-<path fill="sym-stroke">-0.6 0 0 0.6 0 0 e-</path>-</symbol>-<symbol name="mark/fdisk(sfx)" transformations="translations">-<group>-<path fill="sym-fill">-0.5 0 0 0.5 0 0 e-</path>-<path fill="sym-stroke" fillrule="eofill">-0.6 0 0 0.6 0 0 e-0.4 0 0 0.4 0 0 e-</path>-</group>-</symbol>-<symbol name="mark/box(sx)" transformations="translations">-<path fill="sym-stroke" fillrule="eofill">--0.6 -0.6 m-0.6 -0.6 l-0.6 0.6 l--0.6 0.6 l-h--0.4 -0.4 m-0.4 -0.4 l-0.4 0.4 l--0.4 0.4 l-h-</path>-</symbol>-<symbol name="mark/square(sx)" transformations="translations">-<path fill="sym-stroke">--0.6 -0.6 m-0.6 -0.6 l-0.6 0.6 l--0.6 0.6 l-h-</path>-</symbol>-<symbol name="mark/fsquare(sfx)" transformations="translations">-<group>-<path fill="sym-fill">--0.5 -0.5 m-0.5 -0.5 l-0.5 0.5 l--0.5 0.5 l-h-</path>-<path fill="sym-stroke" fillrule="eofill">--0.6 -0.6 m-0.6 -0.6 l-0.6 0.6 l--0.6 0.6 l-h--0.4 -0.4 m-0.4 -0.4 l-0.4 0.4 l--0.4 0.4 l-h-</path>-</group>-</symbol>-<symbol name="mark/cross(sx)" transformations="translations">-<group>-<path fill="sym-stroke">--0.43 -0.57 m-0.57 0.43 l-0.43 0.57 l--0.57 -0.43 l-h-</path>-<path fill="sym-stroke">--0.43 0.57 m-0.57 -0.43 l-0.43 -0.57 l--0.57 0.43 l-h-</path>-</group>-</symbol>-<symbol name="arrow/fnormal(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/pointed(spx)">-<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">-0 0 m--1 0.333 l--0.8 0 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/fpointed(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--0.8 0 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/linear(spx)">-<path stroke="sym-stroke" pen="sym-pen">--1 0.333 m-0 0 l--1 -0.333 l-</path>-</symbol>-<symbol name="arrow/fdouble(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h--1 0 m--2 0.333 l--2 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/double(spx)">-<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h--1 0 m--2 0.333 l--2 -0.333 l-h-</path>-</symbol>-<pen name="heavier" value="0.8"/>-<pen name="fat" value="1.2"/>-<pen name="ultrafat" value="2"/>-<symbolsize name="large" value="5"/>-<symbolsize name="small" value="2"/>-<symbolsize name="tiny" value="1.1"/>-<arrowsize name="large" value="10"/>-<arrowsize name="small" value="5"/>-<arrowsize name="tiny" value="3"/>-<color name="red" value="1 0 0"/>-<color name="green" value="0 1 0"/>-<color name="blue" value="0 0 1"/>-<color name="yellow" value="1 1 0"/>-<color name="orange" value="1 0.647 0"/>-<color name="gold" value="1 0.843 0"/>-<color name="purple" value="0.627 0.125 0.941"/>-<color name="gray" value="0.745"/>-<color name="brown" value="0.647 0.165 0.165"/>-<color name="navy" value="0 0 0.502"/>-<color name="pink" value="1 0.753 0.796"/>-<color name="seagreen" value="0.18 0.545 0.341"/>-<color name="turquoise" value="0.251 0.878 0.816"/>-<color name="violet" value="0.933 0.51 0.933"/>-<color name="darkblue" value="0 0 0.545"/>-<color name="darkcyan" value="0 0.545 0.545"/>-<color name="darkgray" value="0.663"/>-<color name="darkgreen" value="0 0.392 0"/>-<color name="darkmagenta" value="0.545 0 0.545"/>-<color name="darkorange" value="1 0.549 0"/>-<color name="darkred" value="0.545 0 0"/>-<color name="lightblue" value="0.678 0.847 0.902"/>-<color name="lightcyan" value="0.878 1 1"/>-<color name="lightgray" value="0.827"/>-<color name="lightgreen" value="0.565 0.933 0.565"/>-<color name="lightyellow" value="1 1 0.878"/>-<dashstyle name="dashed" value="[4] 0"/>-<dashstyle name="dotted" value="[1 3] 0"/>-<dashstyle name="dash dotted" value="[4 2 1 2] 0"/>-<dashstyle name="dash dot dotted" value="[4 2 1 2 1 2] 0"/>-<textsize name="large" value="\large"/>-<textsize name="Large" value="\Large"/>-<textsize name="LARGE" value="\LARGE"/>-<textsize name="huge" value="\huge"/>-<textsize name="Huge" value="\Huge"/>-<textsize name="small" value="\small"/>-<textsize name="footnote" value="\footnotesize"/>-<textsize name="tiny" value="\tiny"/>-<textstyle name="center" begin="\begin{center}" end="\end{center}"/>-<textstyle name="itemize" begin="\begin{itemize}" end="\end{itemize}"/>-<textstyle name="item" begin="\begin{itemize}\item{}" end="\end{itemize}"/>-<gridsize name="4 pts" value="4"/>-<gridsize name="8 pts (~3 mm)" value="8"/>-<gridsize name="16 pts (~6 mm)" value="16"/>-<gridsize name="32 pts (~12 mm)" value="32"/>-<gridsize name="10 pts (~3.5 mm)" value="10"/>-<gridsize name="20 pts (~7 mm)" value="20"/>-<gridsize name="14 pts (~5 mm)" value="14"/>-<gridsize name="28 pts (~10 mm)" value="28"/>-<gridsize name="56 pts (~20 mm)" value="56"/>-<anglesize name="90 deg" value="90"/>-<anglesize name="60 deg" value="60"/>-<anglesize name="45 deg" value="45"/>-<anglesize name="30 deg" value="30"/>-<anglesize name="22.5 deg" value="22.5"/>-<opacity name="10%" value="0.1"/>-<opacity name="30%" value="0.3"/>-<opacity name="50%" value="0.5"/>-<opacity name="75%" value="0.75"/>-<tiling name="falling" angle="-60" step="4" width="1"/>-<tiling name="rising" angle="30" step="4" width="1"/>-</ipestyle>-<ipestyle name="frank">-<arrowsize name="normal" value="5"/>-<arrowsize name="large" value="8"/>-<arrowsize name="huge" value="10"/>-<arrowsize name="small" value="3"/>-<arrowsize name="tiny" value="1"/>-<dashstyle name="dashed" value="[2 2] 0"/>-<dashstyle name="dotted" value="[0.5 1] 0"/>-<dashstyle name="dash dotted" value="[4 2 1 2] 0"/>-<dashstyle name="dash dot dotted" value="[4 2 1 2 1 2] 0"/>-<gridsize name="1 pts" value="1"/>-<gridsize name="2 pts" value="2"/>-<opacity name="10%" value="0.1"/>-<opacity name="30%" value="0.3"/>-<opacity name="50%" value="0.5"/>-<opacity name="20%" value="0.2"/>-<opacity name="40%" value="0.4"/>-<opacity name="60%" value="0.6"/>-<opacity name="70%" value="0.7"/>-<opacity name="80%" value="0.8"/>-<opacity name="90%" value="0.9"/>-</ipestyle>-<page>-<layer name="alpha"/>-<view layers="alpha" active="alpha"/>-<path layer="alpha" stroke="black">-16 16 m-144 80 l-</path>-<path stroke="black">-128 32 m-256 112 l-</path>-<path stroke="black">-144 80 m-225.708 52.1085 l-</path>-<path matrix="2.39165 0 0 2.39165 -206.711 -120.784" stroke="black">-144 80 m-148.537 86.7918 l-</path>-<path stroke="black">-144 80 m-140.284 85.5945 l-</path>-<path stroke="black">-137.686 70.5482 m-173.031 38.3458 l-</path>-<path stroke="black">-89.5694 78.2992 m-186.333 44.2802 l-</path>-<path stroke="black">-75.255 80.7127 m-75.255 24.0132 l-</path>-<path stroke="black">-35.9103 40.8867 m-180.812 40.8867 l-</path>-<path stroke="black">-82.6725 35.3346 m-57.1425 25.6907 l-</path>-<path stroke="black">-40.6648 34.541 m-144.411 12.4306 l-</path>-</page>-</ipe>
− test/Algorithms/Geometry/LineSegmentIntersection/selfIntersections.ipe
@@ -1,313 +0,0 @@-<?xml version="1.0"?>-<!DOCTYPE ipe SYSTEM "ipe.dtd">-<ipe version="70107" creator="Ipe 7.2.2">-<info created="D:20170428203409" modified="D:20170428203521"/>-<ipestyle name="basic">-<symbol name="arrow/arc(spx)">-<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/farc(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/ptarc(spx)">-<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">-0 0 m--1 0.333 l--0.8 0 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/fptarc(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--0.8 0 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="mark/circle(sx)" transformations="translations">-<path fill="sym-stroke">-0.6 0 0 0.6 0 0 e-0.4 0 0 0.4 0 0 e-</path>-</symbol>-<symbol name="mark/disk(sx)" transformations="translations">-<path fill="sym-stroke">-0.6 0 0 0.6 0 0 e-</path>-</symbol>-<symbol name="mark/fdisk(sfx)" transformations="translations">-<group>-<path fill="sym-fill">-0.5 0 0 0.5 0 0 e-</path>-<path fill="sym-stroke" fillrule="eofill">-0.6 0 0 0.6 0 0 e-0.4 0 0 0.4 0 0 e-</path>-</group>-</symbol>-<symbol name="mark/box(sx)" transformations="translations">-<path fill="sym-stroke" fillrule="eofill">--0.6 -0.6 m-0.6 -0.6 l-0.6 0.6 l--0.6 0.6 l-h--0.4 -0.4 m-0.4 -0.4 l-0.4 0.4 l--0.4 0.4 l-h-</path>-</symbol>-<symbol name="mark/square(sx)" transformations="translations">-<path fill="sym-stroke">--0.6 -0.6 m-0.6 -0.6 l-0.6 0.6 l--0.6 0.6 l-h-</path>-</symbol>-<symbol name="mark/fsquare(sfx)" transformations="translations">-<group>-<path fill="sym-fill">--0.5 -0.5 m-0.5 -0.5 l-0.5 0.5 l--0.5 0.5 l-h-</path>-<path fill="sym-stroke" fillrule="eofill">--0.6 -0.6 m-0.6 -0.6 l-0.6 0.6 l--0.6 0.6 l-h--0.4 -0.4 m-0.4 -0.4 l-0.4 0.4 l--0.4 0.4 l-h-</path>-</group>-</symbol>-<symbol name="mark/cross(sx)" transformations="translations">-<group>-<path fill="sym-stroke">--0.43 -0.57 m-0.57 0.43 l-0.43 0.57 l--0.57 -0.43 l-h-</path>-<path fill="sym-stroke">--0.43 0.57 m-0.57 -0.43 l-0.43 -0.57 l--0.57 0.43 l-h-</path>-</group>-</symbol>-<symbol name="arrow/fnormal(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/pointed(spx)">-<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">-0 0 m--1 0.333 l--0.8 0 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/fpointed(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--0.8 0 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/linear(spx)">-<path stroke="sym-stroke" pen="sym-pen">--1 0.333 m-0 0 l--1 -0.333 l-</path>-</symbol>-<symbol name="arrow/fdouble(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h--1 0 m--2 0.333 l--2 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/double(spx)">-<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h--1 0 m--2 0.333 l--2 -0.333 l-h-</path>-</symbol>-<pen name="heavier" value="0.8"/>-<pen name="fat" value="1.2"/>-<pen name="ultrafat" value="2"/>-<symbolsize name="large" value="5"/>-<symbolsize name="small" value="2"/>-<symbolsize name="tiny" value="1.1"/>-<arrowsize name="large" value="10"/>-<arrowsize name="small" value="5"/>-<arrowsize name="tiny" value="3"/>-<color name="red" value="1 0 0"/>-<color name="green" value="0 1 0"/>-<color name="blue" value="0 0 1"/>-<color name="yellow" value="1 1 0"/>-<color name="orange" value="1 0.647 0"/>-<color name="gold" value="1 0.843 0"/>-<color name="purple" value="0.627 0.125 0.941"/>-<color name="gray" value="0.745"/>-<color name="brown" value="0.647 0.165 0.165"/>-<color name="navy" value="0 0 0.502"/>-<color name="pink" value="1 0.753 0.796"/>-<color name="seagreen" value="0.18 0.545 0.341"/>-<color name="turquoise" value="0.251 0.878 0.816"/>-<color name="violet" value="0.933 0.51 0.933"/>-<color name="darkblue" value="0 0 0.545"/>-<color name="darkcyan" value="0 0.545 0.545"/>-<color name="darkgray" value="0.663"/>-<color name="darkgreen" value="0 0.392 0"/>-<color name="darkmagenta" value="0.545 0 0.545"/>-<color name="darkorange" value="1 0.549 0"/>-<color name="darkred" value="0.545 0 0"/>-<color name="lightblue" value="0.678 0.847 0.902"/>-<color name="lightcyan" value="0.878 1 1"/>-<color name="lightgray" value="0.827"/>-<color name="lightgreen" value="0.565 0.933 0.565"/>-<color name="lightyellow" value="1 1 0.878"/>-<dashstyle name="dashed" value="[4] 0"/>-<dashstyle name="dotted" value="[1 3] 0"/>-<dashstyle name="dash dotted" value="[4 2 1 2] 0"/>-<dashstyle name="dash dot dotted" value="[4 2 1 2 1 2] 0"/>-<textsize name="large" value="\large"/>-<textsize name="Large" value="\Large"/>-<textsize name="LARGE" value="\LARGE"/>-<textsize name="huge" value="\huge"/>-<textsize name="Huge" value="\Huge"/>-<textsize name="small" value="\small"/>-<textsize name="footnote" value="\footnotesize"/>-<textsize name="tiny" value="\tiny"/>-<textstyle name="center" begin="\begin{center}" end="\end{center}"/>-<textstyle name="itemize" begin="\begin{itemize}" end="\end{itemize}"/>-<textstyle name="item" begin="\begin{itemize}\item{}" end="\end{itemize}"/>-<gridsize name="4 pts" value="4"/>-<gridsize name="8 pts (~3 mm)" value="8"/>-<gridsize name="16 pts (~6 mm)" value="16"/>-<gridsize name="32 pts (~12 mm)" value="32"/>-<gridsize name="10 pts (~3.5 mm)" value="10"/>-<gridsize name="20 pts (~7 mm)" value="20"/>-<gridsize name="14 pts (~5 mm)" value="14"/>-<gridsize name="28 pts (~10 mm)" value="28"/>-<gridsize name="56 pts (~20 mm)" value="56"/>-<anglesize name="90 deg" value="90"/>-<anglesize name="60 deg" value="60"/>-<anglesize name="45 deg" value="45"/>-<anglesize name="30 deg" value="30"/>-<anglesize name="22.5 deg" value="22.5"/>-<opacity name="10%" value="0.1"/>-<opacity name="30%" value="0.3"/>-<opacity name="50%" value="0.5"/>-<opacity name="75%" value="0.75"/>-<tiling name="falling" angle="-60" step="4" width="1"/>-<tiling name="rising" angle="30" step="4" width="1"/>-</ipestyle>-<ipestyle name="frank">-<arrowsize name="normal" value="5"/>-<arrowsize name="large" value="8"/>-<arrowsize name="huge" value="10"/>-<arrowsize name="small" value="3"/>-<arrowsize name="tiny" value="1"/>-<dashstyle name="dashed" value="[2 2] 0"/>-<dashstyle name="dotted" value="[0.5 1] 0"/>-<dashstyle name="dash dotted" value="[4 2 1 2] 0"/>-<dashstyle name="dash dot dotted" value="[4 2 1 2 1 2] 0"/>-<gridsize name="1 pts" value="1"/>-<gridsize name="2 pts" value="2"/>-<opacity name="10%" value="0.1"/>-<opacity name="30%" value="0.3"/>-<opacity name="50%" value="0.5"/>-<opacity name="20%" value="0.2"/>-<opacity name="40%" value="0.4"/>-<opacity name="60%" value="0.6"/>-<opacity name="70%" value="0.7"/>-<opacity name="80%" value="0.8"/>-<opacity name="90%" value="0.9"/>-</ipestyle>-<page>-<layer name="alpha"/>-<view layers="alpha" active="alpha"/>-<path layer="alpha" stroke="red">-96 704 m-192 816 l-352 656 l-208 640 l-336 784 l-h-</path>-<path stroke="red">-144 592 m-336 624 l-320 544 l-240 624 l-h-</path>-<path stroke="blue">-80 624 m-32 576 l-128 576 l-h-</path>-<path stroke="blue">-64 784 m-32 752 l-32 688 l-64 672 l-144 672 l-96 688 l-80 768 l-128 768 l-112 800 l-h-</path>-</page>-</ipe>
− test/Algorithms/Geometry/LinearProgramming/manual.ipe
@@ -1,370 +0,0 @@-<?xml version="1.0"?>-<!DOCTYPE ipe SYSTEM "ipe.dtd">-<ipe version="70206" creator="Ipe 7.2.7">-<info created="D:20190310094400" modified="D:20190310110316"/>-<ipestyle name="basic">-<symbol name="arrow/arc(spx)">-<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/farc(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/ptarc(spx)">-<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">-0 0 m--1 0.333 l--0.8 0 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/fptarc(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--0.8 0 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="mark/circle(sx)" transformations="translations">-<path fill="sym-stroke">-0.6 0 0 0.6 0 0 e-0.4 0 0 0.4 0 0 e-</path>-</symbol>-<symbol name="mark/disk(sx)" transformations="translations">-<path fill="sym-stroke">-0.6 0 0 0.6 0 0 e-</path>-</symbol>-<symbol name="mark/fdisk(sfx)" transformations="translations">-<group>-<path fill="sym-fill">-0.5 0 0 0.5 0 0 e-</path>-<path fill="sym-stroke" fillrule="eofill">-0.6 0 0 0.6 0 0 e-0.4 0 0 0.4 0 0 e-</path>-</group>-</symbol>-<symbol name="mark/box(sx)" transformations="translations">-<path fill="sym-stroke" fillrule="eofill">--0.6 -0.6 m-0.6 -0.6 l-0.6 0.6 l--0.6 0.6 l-h--0.4 -0.4 m-0.4 -0.4 l-0.4 0.4 l--0.4 0.4 l-h-</path>-</symbol>-<symbol name="mark/square(sx)" transformations="translations">-<path fill="sym-stroke">--0.6 -0.6 m-0.6 -0.6 l-0.6 0.6 l--0.6 0.6 l-h-</path>-</symbol>-<symbol name="mark/fsquare(sfx)" transformations="translations">-<group>-<path fill="sym-fill">--0.5 -0.5 m-0.5 -0.5 l-0.5 0.5 l--0.5 0.5 l-h-</path>-<path fill="sym-stroke" fillrule="eofill">--0.6 -0.6 m-0.6 -0.6 l-0.6 0.6 l--0.6 0.6 l-h--0.4 -0.4 m-0.4 -0.4 l-0.4 0.4 l--0.4 0.4 l-h-</path>-</group>-</symbol>-<symbol name="mark/cross(sx)" transformations="translations">-<group>-<path fill="sym-stroke">--0.43 -0.57 m-0.57 0.43 l-0.43 0.57 l--0.57 -0.43 l-h-</path>-<path fill="sym-stroke">--0.43 0.57 m-0.57 -0.43 l-0.43 -0.57 l--0.57 0.43 l-h-</path>-</group>-</symbol>-<symbol name="arrow/fnormal(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/pointed(spx)">-<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">-0 0 m--1 0.333 l--0.8 0 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/fpointed(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--0.8 0 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/linear(spx)">-<path stroke="sym-stroke" pen="sym-pen">--1 0.333 m-0 0 l--1 -0.333 l-</path>-</symbol>-<symbol name="arrow/fdouble(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h--1 0 m--2 0.333 l--2 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/double(spx)">-<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h--1 0 m--2 0.333 l--2 -0.333 l-h-</path>-</symbol>-<pen name="heavier" value="0.8"/>-<pen name="fat" value="1.2"/>-<pen name="ultrafat" value="2"/>-<symbolsize name="large" value="5"/>-<symbolsize name="small" value="2"/>-<symbolsize name="tiny" value="1.1"/>-<arrowsize name="large" value="10"/>-<arrowsize name="small" value="5"/>-<arrowsize name="tiny" value="3"/>-<color name="red" value="1 0 0"/>-<color name="green" value="0 1 0"/>-<color name="blue" value="0 0 1"/>-<color name="yellow" value="1 1 0"/>-<color name="orange" value="1 0.647 0"/>-<color name="gold" value="1 0.843 0"/>-<color name="purple" value="0.627 0.125 0.941"/>-<color name="gray" value="0.745"/>-<color name="brown" value="0.647 0.165 0.165"/>-<color name="navy" value="0 0 0.502"/>-<color name="pink" value="1 0.753 0.796"/>-<color name="seagreen" value="0.18 0.545 0.341"/>-<color name="turquoise" value="0.251 0.878 0.816"/>-<color name="violet" value="0.933 0.51 0.933"/>-<color name="darkblue" value="0 0 0.545"/>-<color name="darkcyan" value="0 0.545 0.545"/>-<color name="darkgray" value="0.663"/>-<color name="darkgreen" value="0 0.392 0"/>-<color name="darkmagenta" value="0.545 0 0.545"/>-<color name="darkorange" value="1 0.549 0"/>-<color name="darkred" value="0.545 0 0"/>-<color name="lightblue" value="0.678 0.847 0.902"/>-<color name="lightcyan" value="0.878 1 1"/>-<color name="lightgray" value="0.827"/>-<color name="lightgreen" value="0.565 0.933 0.565"/>-<color name="lightyellow" value="1 1 0.878"/>-<dashstyle name="dashed" value="[4] 0"/>-<dashstyle name="dotted" value="[1 3] 0"/>-<dashstyle name="dash dotted" value="[4 2 1 2] 0"/>-<dashstyle name="dash dot dotted" value="[4 2 1 2 1 2] 0"/>-<textsize name="large" value="\large"/>-<textsize name="Large" value="\Large"/>-<textsize name="LARGE" value="\LARGE"/>-<textsize name="huge" value="\huge"/>-<textsize name="Huge" value="\Huge"/>-<textsize name="small" value="\small"/>-<textsize name="footnote" value="\footnotesize"/>-<textsize name="tiny" value="\tiny"/>-<textstyle name="center" begin="\begin{center}" end="\end{center}"/>-<textstyle name="itemize" begin="\begin{itemize}" end="\end{itemize}"/>-<textstyle name="item" begin="\begin{itemize}\item{}" end="\end{itemize}"/>-<gridsize name="4 pts" value="4"/>-<gridsize name="8 pts (~3 mm)" value="8"/>-<gridsize name="16 pts (~6 mm)" value="16"/>-<gridsize name="32 pts (~12 mm)" value="32"/>-<gridsize name="10 pts (~3.5 mm)" value="10"/>-<gridsize name="20 pts (~7 mm)" value="20"/>-<gridsize name="14 pts (~5 mm)" value="14"/>-<gridsize name="28 pts (~10 mm)" value="28"/>-<gridsize name="56 pts (~20 mm)" value="56"/>-<anglesize name="90 deg" value="90"/>-<anglesize name="60 deg" value="60"/>-<anglesize name="45 deg" value="45"/>-<anglesize name="30 deg" value="30"/>-<anglesize name="22.5 deg" value="22.5"/>-<opacity name="10%" value="0.1"/>-<opacity name="30%" value="0.3"/>-<opacity name="50%" value="0.5"/>-<opacity name="75%" value="0.75"/>-<tiling name="falling" angle="-60" step="4" width="1"/>-<tiling name="rising" angle="30" step="4" width="1"/>-</ipestyle>-<ipestyle name="frank">-<arrowsize name="normal" value="5"/>-<arrowsize name="large" value="8"/>-<arrowsize name="huge" value="10"/>-<arrowsize name="small" value="3"/>-<arrowsize name="tiny" value="1"/>-<dashstyle name="dashed" value="[2 2] 0"/>-<dashstyle name="dotted" value="[0.5 1] 0"/>-<dashstyle name="dash dotted" value="[4 2 1 2] 0"/>-<dashstyle name="dash dot dotted" value="[4 2 1 2 1 2] 0"/>-<gridsize name="1 pts" value="1"/>-<gridsize name="2 pts" value="2"/>-<opacity name="10%" value="0.1"/>-<opacity name="30%" value="0.3"/>-<opacity name="50%" value="0.5"/>-<opacity name="20%" value="0.2"/>-<opacity name="40%" value="0.4"/>-<opacity name="60%" value="0.6"/>-<opacity name="70%" value="0.7"/>-<opacity name="80%" value="0.8"/>-<opacity name="90%" value="0.9"/>-</ipestyle>-<page>-<layer name="alpha"/>-<view layers="alpha" active="alpha"/>-<path layer="alpha" stroke="blue">-80 512 m-496 688 l-</path>-<path stroke="blue">-32 656 m-400 496 l-</path>-<path stroke="blue">-192 512 m-512 592 l-</path>-<path stroke="blue">-80 544 m-448 512 l-</path>-<path stroke="red">-48 608 m-400 768 l-</path>-<path stroke="red">-64 784 m-512 672 l-</path>-<path stroke="red">-64 720 m-560 688 l-</path>-<use name="mark/disk(sx)" pos="223.532 572.725" size="normal" stroke="black"/>-</page>-<page>-<layer name="alpha"/>-<view layers="alpha" active="alpha"/>-<path layer="alpha" matrix="2.40555 0 0 2.40555 -64.8028 -863.829" stroke="red">-46.1048 614.582 m-429.2 688.899 l-</path>-<path matrix="2.32631 0 0 2.32631 -54.964 -984.057" stroke="blue">-41.4414 741.953 m-423.596 711.062 l-</path>-<path stroke="red">-121.985 842 m-859.993 369.865 l-</path>-</page>-<page>-<layer name="alpha"/>-<view layers="alpha" active="alpha"/>-<path layer="alpha" stroke="red">-22.6642 533.532 m-595 760.836 l-</path>-<path stroke="red">-0 803.856 m-595 555.084 l-</path>-<path stroke="red">--29.9681 598.468 m-794.006 675.181 l-</path>-<path stroke="red">-411.476 809.515 m-595 311.453 l-</path>-<path stroke="red">-0 382.909 m-437.853 1024.64 l-</path>-<path stroke="blue">--16.5606 862.606 m-411.101 433.915 l-</path>-<path stroke="blue">-95.0642 522.237 m-857.65 676.395 l-</path>-<path stroke="blue">-277.375 460.704 m-642.518 950.636 l-</path>-<path stroke="blue">-450.168 450.864 m-868.112 754.196 l-</path>-<path stroke="blue">-28.6395 500.773 m-594.217 555.411 l-</path>-<use name="mark/disk(sx)" pos="284.74 560.58" size="normal" stroke="blue"/>-</page>-</ipe>
− test/Algorithms/Geometry/LowerEnvelope/manual.ipe
@@ -1,299 +0,0 @@-<?xml version="1.0"?>-<!DOCTYPE ipe SYSTEM "ipe.dtd">-<ipe version="70107" creator="Ipe 7.2.2">-<info created="D:20170715125328" modified="D:20170715125434"/>-<ipestyle name="basic">-<symbol name="arrow/arc(spx)">-<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/farc(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/ptarc(spx)">-<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">-0 0 m--1 0.333 l--0.8 0 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/fptarc(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--0.8 0 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="mark/circle(sx)" transformations="translations">-<path fill="sym-stroke">-0.6 0 0 0.6 0 0 e-0.4 0 0 0.4 0 0 e-</path>-</symbol>-<symbol name="mark/disk(sx)" transformations="translations">-<path fill="sym-stroke">-0.6 0 0 0.6 0 0 e-</path>-</symbol>-<symbol name="mark/fdisk(sfx)" transformations="translations">-<group>-<path fill="sym-fill">-0.5 0 0 0.5 0 0 e-</path>-<path fill="sym-stroke" fillrule="eofill">-0.6 0 0 0.6 0 0 e-0.4 0 0 0.4 0 0 e-</path>-</group>-</symbol>-<symbol name="mark/box(sx)" transformations="translations">-<path fill="sym-stroke" fillrule="eofill">--0.6 -0.6 m-0.6 -0.6 l-0.6 0.6 l--0.6 0.6 l-h--0.4 -0.4 m-0.4 -0.4 l-0.4 0.4 l--0.4 0.4 l-h-</path>-</symbol>-<symbol name="mark/square(sx)" transformations="translations">-<path fill="sym-stroke">--0.6 -0.6 m-0.6 -0.6 l-0.6 0.6 l--0.6 0.6 l-h-</path>-</symbol>-<symbol name="mark/fsquare(sfx)" transformations="translations">-<group>-<path fill="sym-fill">--0.5 -0.5 m-0.5 -0.5 l-0.5 0.5 l--0.5 0.5 l-h-</path>-<path fill="sym-stroke" fillrule="eofill">--0.6 -0.6 m-0.6 -0.6 l-0.6 0.6 l--0.6 0.6 l-h--0.4 -0.4 m-0.4 -0.4 l-0.4 0.4 l--0.4 0.4 l-h-</path>-</group>-</symbol>-<symbol name="mark/cross(sx)" transformations="translations">-<group>-<path fill="sym-stroke">--0.43 -0.57 m-0.57 0.43 l-0.43 0.57 l--0.57 -0.43 l-h-</path>-<path fill="sym-stroke">--0.43 0.57 m-0.57 -0.43 l-0.43 -0.57 l--0.57 0.43 l-h-</path>-</group>-</symbol>-<symbol name="arrow/fnormal(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/pointed(spx)">-<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">-0 0 m--1 0.333 l--0.8 0 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/fpointed(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--0.8 0 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/linear(spx)">-<path stroke="sym-stroke" pen="sym-pen">--1 0.333 m-0 0 l--1 -0.333 l-</path>-</symbol>-<symbol name="arrow/fdouble(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h--1 0 m--2 0.333 l--2 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/double(spx)">-<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h--1 0 m--2 0.333 l--2 -0.333 l-h-</path>-</symbol>-<pen name="heavier" value="0.8"/>-<pen name="fat" value="1.2"/>-<pen name="ultrafat" value="2"/>-<symbolsize name="large" value="5"/>-<symbolsize name="small" value="2"/>-<symbolsize name="tiny" value="1.1"/>-<arrowsize name="large" value="10"/>-<arrowsize name="small" value="5"/>-<arrowsize name="tiny" value="3"/>-<color name="red" value="1 0 0"/>-<color name="green" value="0 1 0"/>-<color name="blue" value="0 0 1"/>-<color name="yellow" value="1 1 0"/>-<color name="orange" value="1 0.647 0"/>-<color name="gold" value="1 0.843 0"/>-<color name="purple" value="0.627 0.125 0.941"/>-<color name="gray" value="0.745"/>-<color name="brown" value="0.647 0.165 0.165"/>-<color name="navy" value="0 0 0.502"/>-<color name="pink" value="1 0.753 0.796"/>-<color name="seagreen" value="0.18 0.545 0.341"/>-<color name="turquoise" value="0.251 0.878 0.816"/>-<color name="violet" value="0.933 0.51 0.933"/>-<color name="darkblue" value="0 0 0.545"/>-<color name="darkcyan" value="0 0.545 0.545"/>-<color name="darkgray" value="0.663"/>-<color name="darkgreen" value="0 0.392 0"/>-<color name="darkmagenta" value="0.545 0 0.545"/>-<color name="darkorange" value="1 0.549 0"/>-<color name="darkred" value="0.545 0 0"/>-<color name="lightblue" value="0.678 0.847 0.902"/>-<color name="lightcyan" value="0.878 1 1"/>-<color name="lightgray" value="0.827"/>-<color name="lightgreen" value="0.565 0.933 0.565"/>-<color name="lightyellow" value="1 1 0.878"/>-<dashstyle name="dashed" value="[4] 0"/>-<dashstyle name="dotted" value="[1 3] 0"/>-<dashstyle name="dash dotted" value="[4 2 1 2] 0"/>-<dashstyle name="dash dot dotted" value="[4 2 1 2 1 2] 0"/>-<textsize name="large" value="\large"/>-<textsize name="Large" value="\Large"/>-<textsize name="LARGE" value="\LARGE"/>-<textsize name="huge" value="\huge"/>-<textsize name="Huge" value="\Huge"/>-<textsize name="small" value="\small"/>-<textsize name="footnote" value="\footnotesize"/>-<textsize name="tiny" value="\tiny"/>-<textstyle name="center" begin="\begin{center}" end="\end{center}"/>-<textstyle name="itemize" begin="\begin{itemize}" end="\end{itemize}"/>-<textstyle name="item" begin="\begin{itemize}\item{}" end="\end{itemize}"/>-<gridsize name="4 pts" value="4"/>-<gridsize name="8 pts (~3 mm)" value="8"/>-<gridsize name="16 pts (~6 mm)" value="16"/>-<gridsize name="32 pts (~12 mm)" value="32"/>-<gridsize name="10 pts (~3.5 mm)" value="10"/>-<gridsize name="20 pts (~7 mm)" value="20"/>-<gridsize name="14 pts (~5 mm)" value="14"/>-<gridsize name="28 pts (~10 mm)" value="28"/>-<gridsize name="56 pts (~20 mm)" value="56"/>-<anglesize name="90 deg" value="90"/>-<anglesize name="60 deg" value="60"/>-<anglesize name="45 deg" value="45"/>-<anglesize name="30 deg" value="30"/>-<anglesize name="22.5 deg" value="22.5"/>-<opacity name="10%" value="0.1"/>-<opacity name="30%" value="0.3"/>-<opacity name="50%" value="0.5"/>-<opacity name="75%" value="0.75"/>-<tiling name="falling" angle="-60" step="4" width="1"/>-<tiling name="rising" angle="30" step="4" width="1"/>-</ipestyle>-<ipestyle name="frank">-<arrowsize name="normal" value="5"/>-<arrowsize name="large" value="8"/>-<arrowsize name="huge" value="10"/>-<arrowsize name="small" value="3"/>-<arrowsize name="tiny" value="1"/>-<dashstyle name="dashed" value="[2 2] 0"/>-<dashstyle name="dotted" value="[0.5 1] 0"/>-<dashstyle name="dash dotted" value="[4 2 1 2] 0"/>-<dashstyle name="dash dot dotted" value="[4 2 1 2 1 2] 0"/>-<gridsize name="1 pts" value="1"/>-<gridsize name="2 pts" value="2"/>-<opacity name="10%" value="0.1"/>-<opacity name="30%" value="0.3"/>-<opacity name="50%" value="0.5"/>-<opacity name="20%" value="0.2"/>-<opacity name="40%" value="0.4"/>-<opacity name="60%" value="0.6"/>-<opacity name="70%" value="0.7"/>-<opacity name="80%" value="0.8"/>-<opacity name="90%" value="0.9"/>-</ipestyle>-<page>-<layer name="alpha"/>-<view layers="alpha" active="alpha"/>-<path layer="alpha" stroke="black">-80 496 m-304 624 l-</path>-<path stroke="black">-320 512 m-176 624 l-</path>-<path stroke="black">-80 560 m-368 560 l-</path>-<path stroke="black">-80 512 m-320 608 l-</path>-<use name="mark/disk(sx)" pos="173.333 549.333" size="normal" stroke="black"/>-<use name="mark/disk(sx)" pos="200 560" size="normal" stroke="black"/>-<use name="mark/disk(sx)" pos="258.286 560" size="normal" stroke="black"/>-</page>-</ipe>
− test/Algorithms/Geometry/PolygonTriangulation/monotone.ipe
@@ -1,364 +0,0 @@-<?xml version="1.0"?>-<!DOCTYPE ipe SYSTEM "ipe.dtd">-<ipe version="70107" creator="Ipe 7.2.2">-<info created="D:20170207224641" modified="D:20180526104709"/>-<ipestyle name="basic">-<symbol name="arrow/arc(spx)">-<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/farc(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/ptarc(spx)">-<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">-0 0 m--1 0.333 l--0.8 0 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/fptarc(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--0.8 0 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="mark/circle(sx)" transformations="translations">-<path fill="sym-stroke">-0.6 0 0 0.6 0 0 e-0.4 0 0 0.4 0 0 e-</path>-</symbol>-<symbol name="mark/disk(sx)" transformations="translations">-<path fill="sym-stroke">-0.6 0 0 0.6 0 0 e-</path>-</symbol>-<symbol name="mark/fdisk(sfx)" transformations="translations">-<group>-<path fill="sym-fill">-0.5 0 0 0.5 0 0 e-</path>-<path fill="sym-stroke" fillrule="eofill">-0.6 0 0 0.6 0 0 e-0.4 0 0 0.4 0 0 e-</path>-</group>-</symbol>-<symbol name="mark/box(sx)" transformations="translations">-<path fill="sym-stroke" fillrule="eofill">--0.6 -0.6 m-0.6 -0.6 l-0.6 0.6 l--0.6 0.6 l-h--0.4 -0.4 m-0.4 -0.4 l-0.4 0.4 l--0.4 0.4 l-h-</path>-</symbol>-<symbol name="mark/square(sx)" transformations="translations">-<path fill="sym-stroke">--0.6 -0.6 m-0.6 -0.6 l-0.6 0.6 l--0.6 0.6 l-h-</path>-</symbol>-<symbol name="mark/fsquare(sfx)" transformations="translations">-<group>-<path fill="sym-fill">--0.5 -0.5 m-0.5 -0.5 l-0.5 0.5 l--0.5 0.5 l-h-</path>-<path fill="sym-stroke" fillrule="eofill">--0.6 -0.6 m-0.6 -0.6 l-0.6 0.6 l--0.6 0.6 l-h--0.4 -0.4 m-0.4 -0.4 l-0.4 0.4 l--0.4 0.4 l-h-</path>-</group>-</symbol>-<symbol name="mark/cross(sx)" transformations="translations">-<group>-<path fill="sym-stroke">--0.43 -0.57 m-0.57 0.43 l-0.43 0.57 l--0.57 -0.43 l-h-</path>-<path fill="sym-stroke">--0.43 0.57 m-0.57 -0.43 l-0.43 -0.57 l--0.57 0.43 l-h-</path>-</group>-</symbol>-<symbol name="arrow/fnormal(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/pointed(spx)">-<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">-0 0 m--1 0.333 l--0.8 0 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/fpointed(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--0.8 0 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/linear(spx)">-<path stroke="sym-stroke" pen="sym-pen">--1 0.333 m-0 0 l--1 -0.333 l-</path>-</symbol>-<symbol name="arrow/fdouble(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h--1 0 m--2 0.333 l--2 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/double(spx)">-<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h--1 0 m--2 0.333 l--2 -0.333 l-h-</path>-</symbol>-<pen name="heavier" value="0.8"/>-<pen name="fat" value="1.2"/>-<pen name="ultrafat" value="2"/>-<symbolsize name="large" value="5"/>-<symbolsize name="small" value="2"/>-<symbolsize name="tiny" value="1.1"/>-<arrowsize name="large" value="10"/>-<arrowsize name="small" value="5"/>-<arrowsize name="tiny" value="3"/>-<color name="red" value="1 0 0"/>-<color name="green" value="0 1 0"/>-<color name="blue" value="0 0 1"/>-<color name="yellow" value="1 1 0"/>-<color name="orange" value="1 0.647 0"/>-<color name="gold" value="1 0.843 0"/>-<color name="purple" value="0.627 0.125 0.941"/>-<color name="gray" value="0.745"/>-<color name="brown" value="0.647 0.165 0.165"/>-<color name="navy" value="0 0 0.502"/>-<color name="pink" value="1 0.753 0.796"/>-<color name="seagreen" value="0.18 0.545 0.341"/>-<color name="turquoise" value="0.251 0.878 0.816"/>-<color name="violet" value="0.933 0.51 0.933"/>-<color name="darkblue" value="0 0 0.545"/>-<color name="darkcyan" value="0 0.545 0.545"/>-<color name="darkgray" value="0.663"/>-<color name="darkgreen" value="0 0.392 0"/>-<color name="darkmagenta" value="0.545 0 0.545"/>-<color name="darkorange" value="1 0.549 0"/>-<color name="darkred" value="0.545 0 0"/>-<color name="lightblue" value="0.678 0.847 0.902"/>-<color name="lightcyan" value="0.878 1 1"/>-<color name="lightgray" value="0.827"/>-<color name="lightgreen" value="0.565 0.933 0.565"/>-<color name="lightyellow" value="1 1 0.878"/>-<dashstyle name="dashed" value="[4] 0"/>-<dashstyle name="dotted" value="[1 3] 0"/>-<dashstyle name="dash dotted" value="[4 2 1 2] 0"/>-<dashstyle name="dash dot dotted" value="[4 2 1 2 1 2] 0"/>-<textsize name="large" value="\large"/>-<textsize name="Large" value="\Large"/>-<textsize name="LARGE" value="\LARGE"/>-<textsize name="huge" value="\huge"/>-<textsize name="Huge" value="\Huge"/>-<textsize name="small" value="\small"/>-<textsize name="footnote" value="\footnotesize"/>-<textsize name="tiny" value="\tiny"/>-<textstyle name="center" begin="\begin{center}" end="\end{center}"/>-<textstyle name="itemize" begin="\begin{itemize}" end="\end{itemize}"/>-<textstyle name="item" begin="\begin{itemize}\item{}" end="\end{itemize}"/>-<gridsize name="4 pts" value="4"/>-<gridsize name="8 pts (~3 mm)" value="8"/>-<gridsize name="16 pts (~6 mm)" value="16"/>-<gridsize name="32 pts (~12 mm)" value="32"/>-<gridsize name="10 pts (~3.5 mm)" value="10"/>-<gridsize name="20 pts (~7 mm)" value="20"/>-<gridsize name="14 pts (~5 mm)" value="14"/>-<gridsize name="28 pts (~10 mm)" value="28"/>-<gridsize name="56 pts (~20 mm)" value="56"/>-<anglesize name="90 deg" value="90"/>-<anglesize name="60 deg" value="60"/>-<anglesize name="45 deg" value="45"/>-<anglesize name="30 deg" value="30"/>-<anglesize name="22.5 deg" value="22.5"/>-<opacity name="10%" value="0.1"/>-<opacity name="30%" value="0.3"/>-<opacity name="50%" value="0.5"/>-<opacity name="75%" value="0.75"/>-<tiling name="falling" angle="-60" step="4" width="1"/>-<tiling name="rising" angle="30" step="4" width="1"/>-</ipestyle>-<ipestyle name="frank">-<arrowsize name="normal" value="5"/>-<arrowsize name="large" value="8"/>-<arrowsize name="huge" value="10"/>-<arrowsize name="small" value="3"/>-<arrowsize name="tiny" value="1"/>-<dashstyle name="dashed" value="[2 2] 0"/>-<dashstyle name="dotted" value="[0.5 1] 0"/>-<dashstyle name="dash dotted" value="[4 2 1 2] 0"/>-<dashstyle name="dash dot dotted" value="[4 2 1 2 1 2] 0"/>-<gridsize name="1 pts" value="1"/>-<gridsize name="2 pts" value="2"/>-<opacity name="10%" value="0.1"/>-<opacity name="30%" value="0.3"/>-<opacity name="50%" value="0.5"/>-<opacity name="20%" value="0.2"/>-<opacity name="40%" value="0.4"/>-<opacity name="60%" value="0.6"/>-<opacity name="70%" value="0.7"/>-<opacity name="80%" value="0.8"/>-<opacity name="90%" value="0.9"/>-</ipestyle>-<page>-<layer name="alpha"/>-<view layers="alpha" active="alpha"/>-<path layer="alpha" stroke="black">-176 736 m-240 688 l-240 608 l-128 576 l-64 640 l-80 720 l-128 752 l-h-</path>-<path stroke="black">-240 608 m-64 640 l-</path>-<path stroke="black">-64 640 m-240 688 l-</path>-<path stroke="black">-240 688 m-80 720 l-</path>-<path stroke="black">-80 720 m-176 736 l-</path>-<path matrix="1 0 0 1 32 96" stroke="red">-160 384 m-352 384 l-128 176 l-224 320 l-48 400 l-h-</path>-<path stroke="red">-384 480 m-256 416 l-</path>-<path stroke="red">-256 416 m-192 480 l-</path>-<path matrix="1 0 0 1 208 320" stroke="green">-320 320 m-256 320 l-224 320 l-128 240 l-64 224 l-256 192 l-h-</path>-<path matrix="1 0 0 1 208 320" stroke="green">-256 320 m-128 240 l-</path>-<path matrix="1 0 0 1 208 320" stroke="green">-128 240 m-320 320 l-</path>-<path matrix="1 0 0 1 208 320" stroke="green">-256 192 m-128 240 l-</path>-<path matrix="-1 0 -0 -1 592 400" stroke="violet">-320 320 m-256 320 l-224 320 l-128 240 l-64 224 l-256 192 l-h-</path>-<path stroke="violet">-464 160 m-336 208 l-</path>-<path stroke="violet">-336 80 m-336 208 l-</path>-<path stroke="violet">-368 80 m-336 208 l-</path>-</page>-</ipe>
− test/Algorithms/Geometry/PolygonTriangulation/simplepolygon6.ipe
@@ -1,297 +0,0 @@-<?xml version="1.0"?>-<!DOCTYPE ipe SYSTEM "ipe.dtd">-<ipe version="70107" creator="Ipe 7.2.2">-<info created="D:20180524200410" modified="D:20180524221410"/>-<ipestyle name="basic">-<symbol name="arrow/arc(spx)">-<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/farc(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/ptarc(spx)">-<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">-0 0 m--1 0.333 l--0.8 0 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/fptarc(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--0.8 0 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="mark/circle(sx)" transformations="translations">-<path fill="sym-stroke">-0.6 0 0 0.6 0 0 e-0.4 0 0 0.4 0 0 e-</path>-</symbol>-<symbol name="mark/disk(sx)" transformations="translations">-<path fill="sym-stroke">-0.6 0 0 0.6 0 0 e-</path>-</symbol>-<symbol name="mark/fdisk(sfx)" transformations="translations">-<group>-<path fill="sym-fill">-0.5 0 0 0.5 0 0 e-</path>-<path fill="sym-stroke" fillrule="eofill">-0.6 0 0 0.6 0 0 e-0.4 0 0 0.4 0 0 e-</path>-</group>-</symbol>-<symbol name="mark/box(sx)" transformations="translations">-<path fill="sym-stroke" fillrule="eofill">--0.6 -0.6 m-0.6 -0.6 l-0.6 0.6 l--0.6 0.6 l-h--0.4 -0.4 m-0.4 -0.4 l-0.4 0.4 l--0.4 0.4 l-h-</path>-</symbol>-<symbol name="mark/square(sx)" transformations="translations">-<path fill="sym-stroke">--0.6 -0.6 m-0.6 -0.6 l-0.6 0.6 l--0.6 0.6 l-h-</path>-</symbol>-<symbol name="mark/fsquare(sfx)" transformations="translations">-<group>-<path fill="sym-fill">--0.5 -0.5 m-0.5 -0.5 l-0.5 0.5 l--0.5 0.5 l-h-</path>-<path fill="sym-stroke" fillrule="eofill">--0.6 -0.6 m-0.6 -0.6 l-0.6 0.6 l--0.6 0.6 l-h--0.4 -0.4 m-0.4 -0.4 l-0.4 0.4 l--0.4 0.4 l-h-</path>-</group>-</symbol>-<symbol name="mark/cross(sx)" transformations="translations">-<group>-<path fill="sym-stroke">--0.43 -0.57 m-0.57 0.43 l-0.43 0.57 l--0.57 -0.43 l-h-</path>-<path fill="sym-stroke">--0.43 0.57 m-0.57 -0.43 l-0.43 -0.57 l--0.57 0.43 l-h-</path>-</group>-</symbol>-<symbol name="arrow/fnormal(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/pointed(spx)">-<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">-0 0 m--1 0.333 l--0.8 0 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/fpointed(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--0.8 0 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/linear(spx)">-<path stroke="sym-stroke" pen="sym-pen">--1 0.333 m-0 0 l--1 -0.333 l-</path>-</symbol>-<symbol name="arrow/fdouble(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h--1 0 m--2 0.333 l--2 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/double(spx)">-<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h--1 0 m--2 0.333 l--2 -0.333 l-h-</path>-</symbol>-<pen name="heavier" value="0.8"/>-<pen name="fat" value="1.2"/>-<pen name="ultrafat" value="2"/>-<symbolsize name="large" value="5"/>-<symbolsize name="small" value="2"/>-<symbolsize name="tiny" value="1.1"/>-<arrowsize name="large" value="10"/>-<arrowsize name="small" value="5"/>-<arrowsize name="tiny" value="3"/>-<color name="red" value="1 0 0"/>-<color name="green" value="0 1 0"/>-<color name="blue" value="0 0 1"/>-<color name="yellow" value="1 1 0"/>-<color name="orange" value="1 0.647 0"/>-<color name="gold" value="1 0.843 0"/>-<color name="purple" value="0.627 0.125 0.941"/>-<color name="gray" value="0.745"/>-<color name="brown" value="0.647 0.165 0.165"/>-<color name="navy" value="0 0 0.502"/>-<color name="pink" value="1 0.753 0.796"/>-<color name="seagreen" value="0.18 0.545 0.341"/>-<color name="turquoise" value="0.251 0.878 0.816"/>-<color name="violet" value="0.933 0.51 0.933"/>-<color name="darkblue" value="0 0 0.545"/>-<color name="darkcyan" value="0 0.545 0.545"/>-<color name="darkgray" value="0.663"/>-<color name="darkgreen" value="0 0.392 0"/>-<color name="darkmagenta" value="0.545 0 0.545"/>-<color name="darkorange" value="1 0.549 0"/>-<color name="darkred" value="0.545 0 0"/>-<color name="lightblue" value="0.678 0.847 0.902"/>-<color name="lightcyan" value="0.878 1 1"/>-<color name="lightgray" value="0.827"/>-<color name="lightgreen" value="0.565 0.933 0.565"/>-<color name="lightyellow" value="1 1 0.878"/>-<dashstyle name="dashed" value="[4] 0"/>-<dashstyle name="dotted" value="[1 3] 0"/>-<dashstyle name="dash dotted" value="[4 2 1 2] 0"/>-<dashstyle name="dash dot dotted" value="[4 2 1 2 1 2] 0"/>-<textsize name="large" value="\large"/>-<textsize name="Large" value="\Large"/>-<textsize name="LARGE" value="\LARGE"/>-<textsize name="huge" value="\huge"/>-<textsize name="Huge" value="\Huge"/>-<textsize name="small" value="\small"/>-<textsize name="footnote" value="\footnotesize"/>-<textsize name="tiny" value="\tiny"/>-<textstyle name="center" begin="\begin{center}" end="\end{center}"/>-<textstyle name="itemize" begin="\begin{itemize}" end="\end{itemize}"/>-<textstyle name="item" begin="\begin{itemize}\item{}" end="\end{itemize}"/>-<gridsize name="4 pts" value="4"/>-<gridsize name="8 pts (~3 mm)" value="8"/>-<gridsize name="16 pts (~6 mm)" value="16"/>-<gridsize name="32 pts (~12 mm)" value="32"/>-<gridsize name="10 pts (~3.5 mm)" value="10"/>-<gridsize name="20 pts (~7 mm)" value="20"/>-<gridsize name="14 pts (~5 mm)" value="14"/>-<gridsize name="28 pts (~10 mm)" value="28"/>-<gridsize name="56 pts (~20 mm)" value="56"/>-<anglesize name="90 deg" value="90"/>-<anglesize name="60 deg" value="60"/>-<anglesize name="45 deg" value="45"/>-<anglesize name="30 deg" value="30"/>-<anglesize name="22.5 deg" value="22.5"/>-<opacity name="10%" value="0.1"/>-<opacity name="30%" value="0.3"/>-<opacity name="50%" value="0.5"/>-<opacity name="75%" value="0.75"/>-<tiling name="falling" angle="-60" step="4" width="1"/>-<tiling name="rising" angle="30" step="4" width="1"/>-</ipestyle>-<ipestyle name="frank">-<arrowsize name="normal" value="5"/>-<arrowsize name="large" value="8"/>-<arrowsize name="huge" value="10"/>-<arrowsize name="small" value="3"/>-<arrowsize name="tiny" value="1"/>-<dashstyle name="dashed" value="[2 2] 0"/>-<dashstyle name="dotted" value="[0.5 1] 0"/>-<dashstyle name="dash dotted" value="[4 2 1 2] 0"/>-<dashstyle name="dash dot dotted" value="[4 2 1 2 1 2] 0"/>-<gridsize name="1 pts" value="1"/>-<gridsize name="2 pts" value="2"/>-<opacity name="10%" value="0.1"/>-<opacity name="30%" value="0.3"/>-<opacity name="50%" value="0.5"/>-<opacity name="20%" value="0.2"/>-<opacity name="40%" value="0.4"/>-<opacity name="60%" value="0.6"/>-<opacity name="70%" value="0.7"/>-<opacity name="80%" value="0.8"/>-<opacity name="90%" value="0.9"/>-</ipestyle>-<page>-<layer name="alpha"/>-<layer name="beta"/>-<view layers="alpha beta" active="beta"/>-<path layer="alpha" stroke="black">-80 544 m-320 527 l-208 496 l-48 432 l-16 560 l-h-</path>-<path stroke="black">-80 544 m-208 496 l-</path>-<path layer="beta" stroke="black">-208 496 m-16 560 l-</path>-</page>-</ipe>
− test/Algorithms/Geometry/RedBlueSeparator/manual.ipe
@@ -1,355 +0,0 @@-<?xml version="1.0"?>-<!DOCTYPE ipe SYSTEM "ipe.dtd">-<ipe version="70206" creator="Ipe 7.2.7">-<info created="D:20190316210045" modified="D:20190316234250"/>-<ipestyle name="basic">-<symbol name="arrow/arc(spx)">-<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/farc(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/ptarc(spx)">-<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">-0 0 m--1 0.333 l--0.8 0 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/fptarc(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--0.8 0 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="mark/circle(sx)" transformations="translations">-<path fill="sym-stroke">-0.6 0 0 0.6 0 0 e-0.4 0 0 0.4 0 0 e-</path>-</symbol>-<symbol name="mark/disk(sx)" transformations="translations">-<path fill="sym-stroke">-0.6 0 0 0.6 0 0 e-</path>-</symbol>-<symbol name="mark/fdisk(sfx)" transformations="translations">-<group>-<path fill="sym-fill">-0.5 0 0 0.5 0 0 e-</path>-<path fill="sym-stroke" fillrule="eofill">-0.6 0 0 0.6 0 0 e-0.4 0 0 0.4 0 0 e-</path>-</group>-</symbol>-<symbol name="mark/box(sx)" transformations="translations">-<path fill="sym-stroke" fillrule="eofill">--0.6 -0.6 m-0.6 -0.6 l-0.6 0.6 l--0.6 0.6 l-h--0.4 -0.4 m-0.4 -0.4 l-0.4 0.4 l--0.4 0.4 l-h-</path>-</symbol>-<symbol name="mark/square(sx)" transformations="translations">-<path fill="sym-stroke">--0.6 -0.6 m-0.6 -0.6 l-0.6 0.6 l--0.6 0.6 l-h-</path>-</symbol>-<symbol name="mark/fsquare(sfx)" transformations="translations">-<group>-<path fill="sym-fill">--0.5 -0.5 m-0.5 -0.5 l-0.5 0.5 l--0.5 0.5 l-h-</path>-<path fill="sym-stroke" fillrule="eofill">--0.6 -0.6 m-0.6 -0.6 l-0.6 0.6 l--0.6 0.6 l-h--0.4 -0.4 m-0.4 -0.4 l-0.4 0.4 l--0.4 0.4 l-h-</path>-</group>-</symbol>-<symbol name="mark/cross(sx)" transformations="translations">-<group>-<path fill="sym-stroke">--0.43 -0.57 m-0.57 0.43 l-0.43 0.57 l--0.57 -0.43 l-h-</path>-<path fill="sym-stroke">--0.43 0.57 m-0.57 -0.43 l-0.43 -0.57 l--0.57 0.43 l-h-</path>-</group>-</symbol>-<symbol name="arrow/fnormal(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/pointed(spx)">-<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">-0 0 m--1 0.333 l--0.8 0 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/fpointed(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--0.8 0 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/linear(spx)">-<path stroke="sym-stroke" pen="sym-pen">--1 0.333 m-0 0 l--1 -0.333 l-</path>-</symbol>-<symbol name="arrow/fdouble(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h--1 0 m--2 0.333 l--2 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/double(spx)">-<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h--1 0 m--2 0.333 l--2 -0.333 l-h-</path>-</symbol>-<pen name="heavier" value="0.8"/>-<pen name="fat" value="1.2"/>-<pen name="ultrafat" value="2"/>-<symbolsize name="large" value="5"/>-<symbolsize name="small" value="2"/>-<symbolsize name="tiny" value="1.1"/>-<arrowsize name="large" value="10"/>-<arrowsize name="small" value="5"/>-<arrowsize name="tiny" value="3"/>-<color name="red" value="1 0 0"/>-<color name="green" value="0 1 0"/>-<color name="blue" value="0 0 1"/>-<color name="yellow" value="1 1 0"/>-<color name="orange" value="1 0.647 0"/>-<color name="gold" value="1 0.843 0"/>-<color name="purple" value="0.627 0.125 0.941"/>-<color name="gray" value="0.745"/>-<color name="brown" value="0.647 0.165 0.165"/>-<color name="navy" value="0 0 0.502"/>-<color name="pink" value="1 0.753 0.796"/>-<color name="seagreen" value="0.18 0.545 0.341"/>-<color name="turquoise" value="0.251 0.878 0.816"/>-<color name="violet" value="0.933 0.51 0.933"/>-<color name="darkblue" value="0 0 0.545"/>-<color name="darkcyan" value="0 0.545 0.545"/>-<color name="darkgray" value="0.663"/>-<color name="darkgreen" value="0 0.392 0"/>-<color name="darkmagenta" value="0.545 0 0.545"/>-<color name="darkorange" value="1 0.549 0"/>-<color name="darkred" value="0.545 0 0"/>-<color name="lightblue" value="0.678 0.847 0.902"/>-<color name="lightcyan" value="0.878 1 1"/>-<color name="lightgray" value="0.827"/>-<color name="lightgreen" value="0.565 0.933 0.565"/>-<color name="lightyellow" value="1 1 0.878"/>-<dashstyle name="dashed" value="[4] 0"/>-<dashstyle name="dotted" value="[1 3] 0"/>-<dashstyle name="dash dotted" value="[4 2 1 2] 0"/>-<dashstyle name="dash dot dotted" value="[4 2 1 2 1 2] 0"/>-<textsize name="large" value="\large"/>-<textsize name="Large" value="\Large"/>-<textsize name="LARGE" value="\LARGE"/>-<textsize name="huge" value="\huge"/>-<textsize name="Huge" value="\Huge"/>-<textsize name="small" value="\small"/>-<textsize name="footnote" value="\footnotesize"/>-<textsize name="tiny" value="\tiny"/>-<textstyle name="center" begin="\begin{center}" end="\end{center}"/>-<textstyle name="itemize" begin="\begin{itemize}" end="\end{itemize}"/>-<textstyle name="item" begin="\begin{itemize}\item{}" end="\end{itemize}"/>-<gridsize name="4 pts" value="4"/>-<gridsize name="8 pts (~3 mm)" value="8"/>-<gridsize name="16 pts (~6 mm)" value="16"/>-<gridsize name="32 pts (~12 mm)" value="32"/>-<gridsize name="10 pts (~3.5 mm)" value="10"/>-<gridsize name="20 pts (~7 mm)" value="20"/>-<gridsize name="14 pts (~5 mm)" value="14"/>-<gridsize name="28 pts (~10 mm)" value="28"/>-<gridsize name="56 pts (~20 mm)" value="56"/>-<anglesize name="90 deg" value="90"/>-<anglesize name="60 deg" value="60"/>-<anglesize name="45 deg" value="45"/>-<anglesize name="30 deg" value="30"/>-<anglesize name="22.5 deg" value="22.5"/>-<opacity name="10%" value="0.1"/>-<opacity name="30%" value="0.3"/>-<opacity name="50%" value="0.5"/>-<opacity name="75%" value="0.75"/>-<tiling name="falling" angle="-60" step="4" width="1"/>-<tiling name="rising" angle="30" step="4" width="1"/>-</ipestyle>-<ipestyle name="frank">-<arrowsize name="normal" value="5"/>-<arrowsize name="large" value="8"/>-<arrowsize name="huge" value="10"/>-<arrowsize name="small" value="3"/>-<arrowsize name="tiny" value="1"/>-<dashstyle name="dashed" value="[2 2] 0"/>-<dashstyle name="dotted" value="[0.5 1] 0"/>-<dashstyle name="dash dotted" value="[4 2 1 2] 0"/>-<dashstyle name="dash dot dotted" value="[4 2 1 2 1 2] 0"/>-<gridsize name="1 pts" value="1"/>-<gridsize name="2 pts" value="2"/>-<opacity name="10%" value="0.1"/>-<opacity name="30%" value="0.3"/>-<opacity name="50%" value="0.5"/>-<opacity name="20%" value="0.2"/>-<opacity name="40%" value="0.4"/>-<opacity name="60%" value="0.6"/>-<opacity name="70%" value="0.7"/>-<opacity name="80%" value="0.8"/>-<opacity name="90%" value="0.9"/>-</ipestyle>-<page>-<layer name="alpha"/>-<view layers="alpha" active="alpha"/>-<use layer="alpha" name="mark/disk(sx)" pos="176 688" size="normal" stroke="blue"/>-<use name="mark/disk(sx)" pos="224 672" size="normal" stroke="blue"/>-<use name="mark/disk(sx)" pos="160 656" size="normal" stroke="blue"/>-<use name="mark/disk(sx)" pos="208 624" size="normal" stroke="blue"/>-<use name="mark/disk(sx)" pos="400 688" size="normal" stroke="red"/>-<use name="mark/disk(sx)" pos="448 640" size="normal" stroke="red"/>-<use matrix="1 0 0 1 -43.6079 16.3284" name="mark/disk(sx)" pos="400 640" size="normal" stroke="red"/>-</page>-<page>-<layer name="alpha"/>-<view layers="alpha" active="alpha"/>-<use layer="alpha" name="mark/disk(sx)" pos="208 608" size="normal" stroke="red"/>-<use name="mark/disk(sx)" pos="224 640" size="normal" stroke="red"/>-<use matrix="1 0 0 1 0 1.54293" name="mark/disk(sx)" pos="288 608" size="normal" stroke="red"/>-<use matrix="1 0 0 1 21.7014 -12.8726" name="mark/disk(sx)" pos="224 608" size="normal" stroke="red"/>-<use name="mark/disk(sx)" pos="336 640" size="normal" stroke="red"/>-<use name="mark/disk(sx)" pos="320 688" size="normal" stroke="red"/>-<use name="mark/disk(sx)" pos="64 704" size="normal" stroke="blue"/>-<use name="mark/disk(sx)" pos="160 656" size="normal" stroke="blue"/>-<use name="mark/disk(sx)" pos="160 752" size="normal" stroke="blue"/>-<use name="mark/disk(sx)" pos="112 672" size="normal" stroke="blue"/>-<use name="mark/disk(sx)" pos="112 592" size="normal" stroke="blue"/>-<use name="mark/disk(sx)" pos="288 736" size="normal" stroke="blue"/>-</page>-<page>-<layer name="alpha"/>-<view layers="alpha" active="alpha"/>-<use layer="alpha" name="mark/cross(sx)" pos="137.831 733.813" size="normal" stroke="blue"/>-<use name="mark/cross(sx)" pos="230.904 721.563" size="normal" stroke="blue"/>-<use name="mark/cross(sx)" pos="150.255 624.633" size="normal" stroke="blue"/>-<use name="mark/cross(sx)" pos="85.1135 709.576" size="normal" stroke="blue"/>-<use name="mark/cross(sx)" pos="160.209 702.601" size="normal" stroke="blue"/>-<use name="mark/cross(sx)" pos="160.209 702.601" size="normal" stroke="blue"/>-<use name="mark/cross(sx)" pos="170.678 688.287" size="normal" stroke="blue"/>-<use name="mark/cross(sx)" pos="251.915 645.615" size="normal" stroke="blue"/>-<use name="mark/cross(sx)" pos="55.337 684.816" size="normal" stroke="blue"/>-<use name="mark/cross(sx)" pos="129.955 678.571" size="normal" stroke="blue"/>-<use name="mark/cross(sx)" pos="130.15 631.793" size="normal" stroke="blue"/>-<use name="mark/cross(sx)" pos="249.435 558.192" size="normal" stroke="blue"/>-<use name="mark/cross(sx)" pos="324.114 668.358" size="normal" stroke="blue"/>-<use name="mark/cross(sx)" pos="324.114 668.358" size="normal" stroke="blue"/>-<use name="mark/cross(sx)" pos="361.354 661.106" size="normal" stroke="blue"/>-<use name="mark/cross(sx)" pos="189.131 599.845" size="normal" stroke="blue"/>-<use name="mark/cross(sx)" pos="143.375 537.289" size="normal" stroke="blue"/>-<use name="mark/cross(sx)" pos="359.679 584.286" size="normal" stroke="red"/>-<use name="mark/cross(sx)" pos="396.828 627.4" size="normal" stroke="red"/>-<use name="mark/cross(sx)" pos="417.481 668.711" size="normal" stroke="red"/>-<use name="mark/cross(sx)" pos="467.45 598.096" size="normal" stroke="red"/>-<use matrix="1 0 0 1 -93.524 0.18083" name="mark/cross(sx)" pos="326.916 608.601" size="normal" stroke="red"/>-<use name="mark/cross(sx)" pos="338.842 545.777" size="normal" stroke="red"/>-<use name="mark/cross(sx)" pos="432.668 573.584" size="normal" stroke="red"/>-<use name="mark/cross(sx)" pos="357.521 629.624" size="normal" stroke="red"/>-<use name="mark/cross(sx)" pos="309.927 526.735" size="normal" stroke="red"/>-<use name="mark/cross(sx)" pos="417.855 527.98" size="normal" stroke="red"/>-<use name="mark/cross(sx)" pos="425.293 604.935" size="normal" stroke="red"/>-<use name="mark/cross(sx)" pos="482.54 641.657" size="normal" stroke="red"/>-</page>-<page>-<layer name="alpha"/>-<view layers="alpha" active="alpha"/>-<use layer="alpha" name="mark/disk(sx)" pos="71.295 646.994" size="normal" stroke="red"/>-<use name="mark/disk(sx)" pos="124.003 669.524" size="normal" stroke="red"/>-<use name="mark/disk(sx)" pos="158.117 593.965" size="normal" stroke="red"/>-<use name="mark/disk(sx)" pos="106.985 602.699" size="normal" stroke="red"/>-<use name="mark/disk(sx)" pos="130.801 646.957" size="normal" stroke="red"/>-<use name="mark/disk(sx)" pos="183.976 638.614" size="normal" stroke="red"/>-<use name="mark/disk(sx)" pos="268.842 528.238" size="normal" stroke="blue"/>-<use name="mark/disk(sx)" pos="303.35 581.718" size="normal" stroke="blue"/>-<use name="mark/disk(sx)" pos="353.58 636.762" size="normal" stroke="blue"/>-<use name="mark/disk(sx)" pos="288.989 633.613" size="normal" stroke="blue"/>-<use name="mark/disk(sx)" pos="325.76 613.53" size="normal" stroke="blue"/>-<use name="mark/disk(sx)" pos="337.81 597.8" size="normal" stroke="blue"/>-<use name="mark/disk(sx)" pos="245.135 580.319" size="normal" stroke="blue"/>-<use name="mark/disk(sx)" pos="168.779 515.317" size="normal" stroke="blue"/>-<use name="mark/disk(sx)" pos="116.706 526.039" size="normal" stroke="blue"/>-</page>-</ipe>
− test/Algorithms/Geometry/SmallestEnclosingDisk/manual.ipe
@@ -1,369 +0,0 @@-<?xml version="1.0"?>-<!DOCTYPE ipe SYSTEM "ipe.dtd">-<ipe version="70107" creator="Ipe 7.1.7">-<info created="D:20151023214323" modified="D:20160123195914"/>-<ipestyle name="basic">-<symbol name="arrow/arc(spx)">-<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/farc(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/ptarc(spx)">-<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">-0 0 m--1 0.333 l--0.8 0 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/fptarc(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--0.8 0 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="mark/circle(sx)" transformations="translations">-<path fill="sym-stroke">-0.6 0 0 0.6 0 0 e-0.4 0 0 0.4 0 0 e-</path>-</symbol>-<symbol name="mark/disk(sx)" transformations="translations">-<path fill="sym-stroke">-0.6 0 0 0.6 0 0 e-</path>-</symbol>-<symbol name="mark/fdisk(sfx)" transformations="translations">-<group>-<path fill="sym-fill">-0.5 0 0 0.5 0 0 e-</path>-<path fill="sym-stroke" fillrule="eofill">-0.6 0 0 0.6 0 0 e-0.4 0 0 0.4 0 0 e-</path>-</group>-</symbol>-<symbol name="mark/box(sx)" transformations="translations">-<path fill="sym-stroke" fillrule="eofill">--0.6 -0.6 m-0.6 -0.6 l-0.6 0.6 l--0.6 0.6 l-h--0.4 -0.4 m-0.4 -0.4 l-0.4 0.4 l--0.4 0.4 l-h-</path>-</symbol>-<symbol name="mark/square(sx)" transformations="translations">-<path fill="sym-stroke">--0.6 -0.6 m-0.6 -0.6 l-0.6 0.6 l--0.6 0.6 l-h-</path>-</symbol>-<symbol name="mark/fsquare(sfx)" transformations="translations">-<group>-<path fill="sym-fill">--0.5 -0.5 m-0.5 -0.5 l-0.5 0.5 l--0.5 0.5 l-h-</path>-<path fill="sym-stroke" fillrule="eofill">--0.6 -0.6 m-0.6 -0.6 l-0.6 0.6 l--0.6 0.6 l-h--0.4 -0.4 m-0.4 -0.4 l-0.4 0.4 l--0.4 0.4 l-h-</path>-</group>-</symbol>-<symbol name="mark/cross(sx)" transformations="translations">-<group>-<path fill="sym-stroke">--0.43 -0.57 m-0.57 0.43 l-0.43 0.57 l--0.57 -0.43 l-h-</path>-<path fill="sym-stroke">--0.43 0.57 m-0.57 -0.43 l-0.43 -0.57 l--0.57 0.43 l-h-</path>-</group>-</symbol>-<symbol name="arrow/fnormal(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/pointed(spx)">-<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">-0 0 m--1 0.333 l--0.8 0 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/fpointed(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--0.8 0 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/linear(spx)">-<path stroke="sym-stroke" pen="sym-pen">--1 0.333 m-0 0 l--1 -0.333 l-</path>-</symbol>-<symbol name="arrow/fdouble(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h--1 0 m--2 0.333 l--2 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/double(spx)">-<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h--1 0 m--2 0.333 l--2 -0.333 l-h-</path>-</symbol>-<pen name="heavier" value="0.8"/>-<pen name="fat" value="1.2"/>-<pen name="ultrafat" value="2"/>-<symbolsize name="large" value="5"/>-<symbolsize name="small" value="2"/>-<symbolsize name="tiny" value="1.1"/>-<arrowsize name="large" value="10"/>-<arrowsize name="small" value="5"/>-<arrowsize name="tiny" value="3"/>-<color name="red" value="1 0 0"/>-<color name="green" value="0 1 0"/>-<color name="blue" value="0 0 1"/>-<color name="yellow" value="1 1 0"/>-<color name="orange" value="1 0.647 0"/>-<color name="gold" value="1 0.843 0"/>-<color name="purple" value="0.627 0.125 0.941"/>-<color name="gray" value="0.745"/>-<color name="brown" value="0.647 0.165 0.165"/>-<color name="navy" value="0 0 0.502"/>-<color name="pink" value="1 0.753 0.796"/>-<color name="seagreen" value="0.18 0.545 0.341"/>-<color name="turquoise" value="0.251 0.878 0.816"/>-<color name="violet" value="0.933 0.51 0.933"/>-<color name="darkblue" value="0 0 0.545"/>-<color name="darkcyan" value="0 0.545 0.545"/>-<color name="darkgray" value="0.663"/>-<color name="darkgreen" value="0 0.392 0"/>-<color name="darkmagenta" value="0.545 0 0.545"/>-<color name="darkorange" value="1 0.549 0"/>-<color name="darkred" value="0.545 0 0"/>-<color name="lightblue" value="0.678 0.847 0.902"/>-<color name="lightcyan" value="0.878 1 1"/>-<color name="lightgray" value="0.827"/>-<color name="lightgreen" value="0.565 0.933 0.565"/>-<color name="lightyellow" value="1 1 0.878"/>-<dashstyle name="dashed" value="[4] 0"/>-<dashstyle name="dotted" value="[1 3] 0"/>-<dashstyle name="dash dotted" value="[4 2 1 2] 0"/>-<dashstyle name="dash dot dotted" value="[4 2 1 2 1 2] 0"/>-<textsize name="large" value="\large"/>-<textsize name="small" value="\small"/>-<textsize name="tiny" value="\tiny"/>-<textsize name="Large" value="\Large"/>-<textsize name="LARGE" value="\LARGE"/>-<textsize name="huge" value="\huge"/>-<textsize name="Huge" value="\Huge"/>-<textsize name="footnote" value="\footnotesize"/>-<textstyle name="center" begin="\begin{center}" end="\end{center}"/>-<textstyle name="itemize" begin="\begin{itemize}" end="\end{itemize}"/>-<textstyle name="item" begin="\begin{itemize}\item{}" end="\end{itemize}"/>-<gridsize name="4 pts" value="4"/>-<gridsize name="8 pts (~3 mm)" value="8"/>-<gridsize name="16 pts (~6 mm)" value="16"/>-<gridsize name="32 pts (~12 mm)" value="32"/>-<gridsize name="10 pts (~3.5 mm)" value="10"/>-<gridsize name="20 pts (~7 mm)" value="20"/>-<gridsize name="14 pts (~5 mm)" value="14"/>-<gridsize name="28 pts (~10 mm)" value="28"/>-<gridsize name="56 pts (~20 mm)" value="56"/>-<anglesize name="90 deg" value="90"/>-<anglesize name="60 deg" value="60"/>-<anglesize name="45 deg" value="45"/>-<anglesize name="30 deg" value="30"/>-<anglesize name="22.5 deg" value="22.5"/>-<tiling name="falling" angle="-60" step="4" width="1"/>-<tiling name="rising" angle="30" step="4" width="1"/>-</ipestyle>-<ipestyle name="frank">-<arrowsize name="normal" value="5"/>-<arrowsize name="large" value="8"/>-<arrowsize name="small" value="3"/>-<arrowsize name="tiny" value="1"/>-<arrowsize name="huge" value="10"/>-<dashstyle name="dashed" value="[2 2] 0"/>-<dashstyle name="dotted" value="[0.5 1] 0"/>-<dashstyle name="dash dotted" value="[4 2 1 2] 0"/>-<dashstyle name="dash dot dotted" value="[4 2 1 2 1 2] 0"/>-<gridsize name="1 pts" value="1"/>-<gridsize name="2 pts" value="2"/>-<opacity name="10%" value="0.1"/>-<opacity name="20%" value="0.2"/>-<opacity name="30%" value="0.3"/>-<opacity name="40%" value="0.4"/>-<opacity name="50%" value="0.5"/>-<opacity name="60%" value="0.6"/>-<opacity name="70%" value="0.7"/>-<opacity name="80%" value="0.8"/>-<opacity name="90%" value="0.9"/>-</ipestyle>-<page>-<layer name="alpha"/>-<layer name="beta"/>-<layer name="gamma"/>-<layer name="delta"/>-<view layers="alpha beta gamma delta" active="delta"/>-<use layer="alpha" name="mark/cross(sx)" pos="112 736" size="normal" stroke="black"/>-<use name="mark/cross(sx)" pos="336 640" size="normal" stroke="black"/>-<use name="mark/cross(sx)" pos="336 816" size="normal" stroke="black"/>-<use matrix="1 0 0 1 6.13784 -3.9059" name="mark/disk(sx)" pos="304 784" size="normal" stroke="black"/>-<use matrix="1 0 0 1 4.44908 -4.21815" name="mark/disk(sx)" pos="320 736" size="normal" stroke="black"/>-<use matrix="1 0 0 1 0.586099 6.64103" name="mark/disk(sx)" pos="352 736" size="normal" stroke="black"/>-<path stroke="black">-129.39 0 0 129.39 241.143 728 e-</path>-<use name="mark/disk(sx)" pos="264.671 689.288" size="normal" stroke="black"/>-<use name="mark/disk(sx)" pos="222.264 731.137" size="normal" stroke="black"/>-<use name="mark/disk(sx)" pos="289.78 722.767" size="normal" stroke="black"/>-<use name="mark/disk(sx)" pos="215.01 683.15" size="normal" stroke="black"/>-<use name="mark/disk(sx)" pos="197.154 741.181" size="normal" stroke="black"/>-<use name="mark/disk(sx)" pos="194.365 766.848" size="normal" stroke="black"/>-<use name="mark/disk(sx)" pos="230.076 767.406" size="normal" stroke="black"/>-<use name="mark/disk(sx)" pos="155.864 708.26" size="normal" stroke="black"/>-<use name="mark/disk(sx)" pos="238.445 743.413" size="normal" stroke="black"/>-<use name="mark/disk(sx)" pos="280.294 767.964" size="normal" stroke="black"/>-<use name="mark/disk(sx)" pos="274.715 659.157" size="normal" stroke="black"/>-<use name="mark/disk(sx)" pos="221.148 609.496" size="normal" stroke="black"/>-<use name="mark/disk(sx)" pos="310.984 638.512" size="normal" stroke="black"/>-<use name="mark/disk(sx)" pos="223.38 649.671" size="normal" stroke="black"/>-<use name="mark/disk(sx)" pos="169.813 689.846" size="normal" stroke="black"/>-<use name="mark/disk(sx)" pos="201.618 709.934" size="normal" stroke="black"/>-<use layer="beta" name="mark/disk(sx)" pos="368 608" size="normal" stroke="red"/>-<use matrix="1 0 0 1 2.78993 -9.48576" name="mark/disk(sx)" pos="336 608" size="normal" stroke="red"/>-<use name="mark/disk(sx)" pos="352 592" size="normal" stroke="red"/>-<use matrix="1 0 0 1 10.0437 -7.8118" name="mark/disk(sx)" pos="368 576" size="normal" stroke="red"/>-<use matrix="1 0 0 1 2.78993 1.11597" name="mark/disk(sx)" pos="320 576" size="normal" stroke="red"/>-<use matrix="1 0 0 1 -8.36979 -11.1597" name="mark/disk(sx)" pos="352 576" size="normal" stroke="red"/>-<use matrix="1 0 0 1 30.6892 -15.0656" name="mark/disk(sx)" pos="400 608" size="normal" stroke="red"/>-<use name="mark/disk(sx)" pos="400 576" size="normal" stroke="red"/>-<use name="mark/disk(sx)" pos="304 560" size="normal" stroke="red"/>-<use name="mark/disk(sx)" pos="368 544" size="normal" stroke="red"/>-<use name="mark/cross(sx)" pos="288.737 510.098" size="normal" stroke="red"/>-<use name="mark/disk(sx)" pos="379.689 503.96" size="normal" stroke="red"/>-<use name="mark/disk(sx)" pos="409.82 541.903" size="normal" stroke="red"/>-<use name="mark/disk(sx)" pos="363.507 541.345" size="normal" stroke="red"/>-<use name="mark/disk(sx)" pos="437.719 527.954" size="normal" stroke="red"/>-<use name="mark/cross(sx)" pos="476.778 591.564" size="normal" stroke="red"/>-<use name="mark/disk(sx)" pos="403.682 564.223" size="normal" stroke="red"/>-<use name="mark/disk(sx)" pos="409.82 562.549" size="normal" stroke="red"/>-<use name="mark/disk(sx)" pos="414.284 563.107" size="normal" stroke="red"/>-<use name="mark/disk(sx)" pos="462.271 545.809" size="normal" stroke="red"/>-<use name="mark/disk(sx)" pos="450.553 567.013" size="normal" stroke="red"/>-<use name="mark/disk(sx)" pos="343.978 524.606" size="normal" stroke="red"/>-<path stroke="red">-102.465 0 0 102.465 382.758 550.831 e-</path>-<use layer="gamma" matrix="1 0 0 1 6.60054 4.12708" name="mark/disk(sx)" pos="368 608" size="normal" stroke="blue"/>-<use matrix="1 0 0 1 9.39047 -5.35868" name="mark/disk(sx)" pos="336 608" size="normal" stroke="blue"/>-<use matrix="1 0 0 1 6.60054 4.12708" name="mark/disk(sx)" pos="352 592" size="normal" stroke="blue"/>-<use matrix="1 0 0 1 16.6443 -3.68472" name="mark/disk(sx)" pos="368 576" size="normal" stroke="blue"/>-<use matrix="1 0 0 1 9.39047 5.24305" name="mark/disk(sx)" pos="320 576" size="normal" stroke="blue"/>-<use matrix="1 0 0 1 -1.76925 -7.03264" name="mark/disk(sx)" pos="352 576" size="normal" stroke="blue"/>-<use matrix="1 0 0 1 37.2898 -10.9385" name="mark/disk(sx)" pos="400 608" size="normal" stroke="blue"/>-<use matrix="1 0 0 1 6.60054 4.12708" name="mark/disk(sx)" pos="400 576" size="normal" stroke="blue"/>-<use matrix="1 0 0 1 6.60054 4.12708" name="mark/disk(sx)" pos="304 560" size="normal" stroke="blue"/>-<use matrix="1 0 0 1 6.60054 4.12708" name="mark/disk(sx)" pos="368 544" size="normal" stroke="blue"/>-<use matrix="1 0 0 1 6.60054 4.12708" name="mark/disk(sx)" pos="379.689 503.96" size="normal" stroke="blue"/>-<use matrix="1 0 0 1 6.60054 4.12708" name="mark/disk(sx)" pos="409.82 541.903" size="normal" stroke="blue"/>-<use matrix="1 0 0 1 6.60054 4.12708" name="mark/disk(sx)" pos="363.507 541.345" size="normal" stroke="blue"/>-<use matrix="1 0 0 1 6.60054 4.12708" name="mark/disk(sx)" pos="437.719 527.954" size="normal" stroke="blue"/>-<use matrix="1 0 0 1 6.60054 4.12708" name="mark/disk(sx)" pos="403.682 564.223" size="normal" stroke="blue"/>-<use matrix="1 0 0 1 6.60054 4.12708" name="mark/disk(sx)" pos="409.82 562.549" size="normal" stroke="blue"/>-<use matrix="1 0 0 1 6.60054 4.12708" name="mark/disk(sx)" pos="414.284 563.107" size="normal" stroke="blue"/>-<use matrix="1 0 0 1 6.60054 4.12708" name="mark/disk(sx)" pos="462.271 545.809" size="normal" stroke="blue"/>-<use matrix="1 0 0 1 6.60054 4.12708" name="mark/disk(sx)" pos="450.553 567.013" size="normal" stroke="blue"/>-<use matrix="1 0 0 1 6.60054 4.12708" name="mark/disk(sx)" pos="343.978 524.606" size="normal" stroke="blue"/>-<use layer="delta" name="mark/disk(sx)" pos="71.4684 472.509" size="normal" stroke="blue"/>-<use name="mark/disk(sx)" pos="90.3283 458.001" size="normal" stroke="blue"/>-<use name="mark/disk(sx)" pos="75.0953 453.649" size="normal" stroke="blue"/>-<use name="mark/disk(sx)" pos="101.209 426.084" size="normal" stroke="blue"/>-<use name="mark/disk(sx)" pos="45.3547 421.732" size="normal" stroke="blue"/>-<use name="mark/disk(sx)" pos="76.5461 421.007" size="normal" stroke="blue"/>-<use name="mark/disk(sx)" pos="56.9608 430.437" size="normal" stroke="blue"/>-<use name="mark/disk(sx)" pos="85.2506 433.338" size="normal" stroke="blue"/>-<use name="mark/disk(sx)" pos="113.541 435.514" size="normal" stroke="blue"/>-<use name="mark/disk(sx)" pos="75.0953 453.649" size="normal" stroke="blue"/>-<use name="mark/disk(sx)" pos="46.8054 454.374" size="normal" stroke="blue"/>-<use matrix="1 0 0 1 39.896 -3.62691" name="mark/disk(sx)" pos="75.0953 453.649" size="normal" stroke="blue"/>-<use name="mark/disk(sx)" pos="105.561 473.96" size="normal" stroke="blue"/>-<use name="mark/disk(sx)" pos="107.012 458.727" size="normal" stroke="blue"/>-<use name="mark/disk(sx)" pos="135.302 418.105" size="normal" stroke="blue"/>-<use matrix="1 0 0 1 4.52803 -3.42357" name="mark/disk(sx)" pos="101.209 426.084" size="normal" stroke="blue"/>-<use name="mark/disk(sx)" pos="90.2821 422.711" size="normal" stroke="blue"/>-<use name="mark/disk(sx)" pos="118.434 461.101" size="normal" stroke="blue"/>-<use matrix="1 0 0 1 5.59154 0.698943" name="mark/disk(sx)" pos="57.5231 446.257" size="normal" stroke="blue"/>-<use name="mark/disk(sx)" pos="68.9116 432.574" size="normal" stroke="blue"/>-</page>-</ipe>
− test/Data/Geometry/Polygon/Convex/convexTests.ipe
@@ -1,308 +0,0 @@-<?xml version="1.0"?>-<!DOCTYPE ipe SYSTEM "ipe.dtd">-<ipe version="70107" creator="Ipe 7.2.2">-<info created="D:20160608222645" modified="D:20160611094216"/>-<ipestyle name="basic">-<symbol name="arrow/arc(spx)">-<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/farc(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/ptarc(spx)">-<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">-0 0 m--1 0.333 l--0.8 0 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/fptarc(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--0.8 0 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="mark/circle(sx)" transformations="translations">-<path fill="sym-stroke">-0.6 0 0 0.6 0 0 e-0.4 0 0 0.4 0 0 e-</path>-</symbol>-<symbol name="mark/disk(sx)" transformations="translations">-<path fill="sym-stroke">-0.6 0 0 0.6 0 0 e-</path>-</symbol>-<symbol name="mark/fdisk(sfx)" transformations="translations">-<group>-<path fill="sym-fill">-0.5 0 0 0.5 0 0 e-</path>-<path fill="sym-stroke" fillrule="eofill">-0.6 0 0 0.6 0 0 e-0.4 0 0 0.4 0 0 e-</path>-</group>-</symbol>-<symbol name="mark/box(sx)" transformations="translations">-<path fill="sym-stroke" fillrule="eofill">--0.6 -0.6 m-0.6 -0.6 l-0.6 0.6 l--0.6 0.6 l-h--0.4 -0.4 m-0.4 -0.4 l-0.4 0.4 l--0.4 0.4 l-h-</path>-</symbol>-<symbol name="mark/square(sx)" transformations="translations">-<path fill="sym-stroke">--0.6 -0.6 m-0.6 -0.6 l-0.6 0.6 l--0.6 0.6 l-h-</path>-</symbol>-<symbol name="mark/fsquare(sfx)" transformations="translations">-<group>-<path fill="sym-fill">--0.5 -0.5 m-0.5 -0.5 l-0.5 0.5 l--0.5 0.5 l-h-</path>-<path fill="sym-stroke" fillrule="eofill">--0.6 -0.6 m-0.6 -0.6 l-0.6 0.6 l--0.6 0.6 l-h--0.4 -0.4 m-0.4 -0.4 l-0.4 0.4 l--0.4 0.4 l-h-</path>-</group>-</symbol>-<symbol name="mark/cross(sx)" transformations="translations">-<group>-<path fill="sym-stroke">--0.43 -0.57 m-0.57 0.43 l-0.43 0.57 l--0.57 -0.43 l-h-</path>-<path fill="sym-stroke">--0.43 0.57 m-0.57 -0.43 l-0.43 -0.57 l--0.57 0.43 l-h-</path>-</group>-</symbol>-<symbol name="arrow/fnormal(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/pointed(spx)">-<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">-0 0 m--1 0.333 l--0.8 0 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/fpointed(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--0.8 0 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/linear(spx)">-<path stroke="sym-stroke" pen="sym-pen">--1 0.333 m-0 0 l--1 -0.333 l-</path>-</symbol>-<symbol name="arrow/fdouble(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h--1 0 m--2 0.333 l--2 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/double(spx)">-<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h--1 0 m--2 0.333 l--2 -0.333 l-h-</path>-</symbol>-<pen name="heavier" value="0.8"/>-<pen name="fat" value="1.2"/>-<pen name="ultrafat" value="2"/>-<symbolsize name="large" value="5"/>-<symbolsize name="small" value="2"/>-<symbolsize name="tiny" value="1.1"/>-<arrowsize name="large" value="10"/>-<arrowsize name="small" value="5"/>-<arrowsize name="tiny" value="3"/>-<color name="red" value="1 0 0"/>-<color name="green" value="0 1 0"/>-<color name="blue" value="0 0 1"/>-<color name="yellow" value="1 1 0"/>-<color name="orange" value="1 0.647 0"/>-<color name="gold" value="1 0.843 0"/>-<color name="purple" value="0.627 0.125 0.941"/>-<color name="gray" value="0.745"/>-<color name="brown" value="0.647 0.165 0.165"/>-<color name="navy" value="0 0 0.502"/>-<color name="pink" value="1 0.753 0.796"/>-<color name="seagreen" value="0.18 0.545 0.341"/>-<color name="turquoise" value="0.251 0.878 0.816"/>-<color name="violet" value="0.933 0.51 0.933"/>-<color name="darkblue" value="0 0 0.545"/>-<color name="darkcyan" value="0 0.545 0.545"/>-<color name="darkgray" value="0.663"/>-<color name="darkgreen" value="0 0.392 0"/>-<color name="darkmagenta" value="0.545 0 0.545"/>-<color name="darkorange" value="1 0.549 0"/>-<color name="darkred" value="0.545 0 0"/>-<color name="lightblue" value="0.678 0.847 0.902"/>-<color name="lightcyan" value="0.878 1 1"/>-<color name="lightgray" value="0.827"/>-<color name="lightgreen" value="0.565 0.933 0.565"/>-<color name="lightyellow" value="1 1 0.878"/>-<dashstyle name="dashed" value="[4] 0"/>-<dashstyle name="dotted" value="[1 3] 0"/>-<dashstyle name="dash dotted" value="[4 2 1 2] 0"/>-<dashstyle name="dash dot dotted" value="[4 2 1 2 1 2] 0"/>-<textsize name="large" value="\large"/>-<textsize name="Large" value="\Large"/>-<textsize name="LARGE" value="\LARGE"/>-<textsize name="huge" value="\huge"/>-<textsize name="Huge" value="\Huge"/>-<textsize name="small" value="\small"/>-<textsize name="footnote" value="\footnotesize"/>-<textsize name="tiny" value="\tiny"/>-<textstyle name="center" begin="\begin{center}" end="\end{center}"/>-<textstyle name="itemize" begin="\begin{itemize}" end="\end{itemize}"/>-<textstyle name="item" begin="\begin{itemize}\item{}" end="\end{itemize}"/>-<gridsize name="4 pts" value="4"/>-<gridsize name="8 pts (~3 mm)" value="8"/>-<gridsize name="16 pts (~6 mm)" value="16"/>-<gridsize name="32 pts (~12 mm)" value="32"/>-<gridsize name="10 pts (~3.5 mm)" value="10"/>-<gridsize name="20 pts (~7 mm)" value="20"/>-<gridsize name="14 pts (~5 mm)" value="14"/>-<gridsize name="28 pts (~10 mm)" value="28"/>-<gridsize name="56 pts (~20 mm)" value="56"/>-<anglesize name="90 deg" value="90"/>-<anglesize name="60 deg" value="60"/>-<anglesize name="45 deg" value="45"/>-<anglesize name="30 deg" value="30"/>-<anglesize name="22.5 deg" value="22.5"/>-<opacity name="10%" value="0.1"/>-<opacity name="30%" value="0.3"/>-<opacity name="50%" value="0.5"/>-<opacity name="75%" value="0.75"/>-<tiling name="falling" angle="-60" step="4" width="1"/>-<tiling name="rising" angle="30" step="4" width="1"/>-</ipestyle>-<ipestyle name="frank">-<arrowsize name="normal" value="5"/>-<arrowsize name="large" value="8"/>-<arrowsize name="huge" value="10"/>-<arrowsize name="small" value="3"/>-<arrowsize name="tiny" value="1"/>-<dashstyle name="dashed" value="[2 2] 0"/>-<dashstyle name="dotted" value="[0.5 1] 0"/>-<dashstyle name="dash dotted" value="[4 2 1 2] 0"/>-<dashstyle name="dash dot dotted" value="[4 2 1 2 1 2] 0"/>-<gridsize name="1 pts" value="1"/>-<gridsize name="2 pts" value="2"/>-<opacity name="10%" value="0.1"/>-<opacity name="30%" value="0.3"/>-<opacity name="50%" value="0.5"/>-<opacity name="20%" value="0.2"/>-<opacity name="40%" value="0.4"/>-<opacity name="60%" value="0.6"/>-<opacity name="70%" value="0.7"/>-<opacity name="80%" value="0.8"/>-<opacity name="90%" value="0.9"/>-</ipestyle>-<page>-<layer name="alpha"/>-<layer name="beta"/>-<view layers="alpha beta" active="beta"/>-<path layer="alpha" stroke="black">-144 720 m-224 768 l-368 672 l-320 592 l-240 544 l-112 528 l-96 640 l-h-</path>-<path stroke="black">-224 656 m-352 784 l-416 816 l-544 800 l-576 752 l-592 720 l-592 672 l-576 640 l-544 608 l-480 560 l-400 544 l-320 544 l-272 560 l-240 608 l-h-</path>-</page>-</ipe>
− test/Data/Geometry/Polygon/star_shaped.ipe
@@ -1,339 +0,0 @@-<?xml version="1.0"?>-<!DOCTYPE ipe SYSTEM "ipe.dtd">-<ipe version="70206" creator="Ipe 7.2.7">-<info created="D:20190310121058" modified="D:20190310122053"/>-<ipestyle name="basic">-<symbol name="arrow/arc(spx)">-<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/farc(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/ptarc(spx)">-<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">-0 0 m--1 0.333 l--0.8 0 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/fptarc(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--0.8 0 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="mark/circle(sx)" transformations="translations">-<path fill="sym-stroke">-0.6 0 0 0.6 0 0 e-0.4 0 0 0.4 0 0 e-</path>-</symbol>-<symbol name="mark/disk(sx)" transformations="translations">-<path fill="sym-stroke">-0.6 0 0 0.6 0 0 e-</path>-</symbol>-<symbol name="mark/fdisk(sfx)" transformations="translations">-<group>-<path fill="sym-fill">-0.5 0 0 0.5 0 0 e-</path>-<path fill="sym-stroke" fillrule="eofill">-0.6 0 0 0.6 0 0 e-0.4 0 0 0.4 0 0 e-</path>-</group>-</symbol>-<symbol name="mark/box(sx)" transformations="translations">-<path fill="sym-stroke" fillrule="eofill">--0.6 -0.6 m-0.6 -0.6 l-0.6 0.6 l--0.6 0.6 l-h--0.4 -0.4 m-0.4 -0.4 l-0.4 0.4 l--0.4 0.4 l-h-</path>-</symbol>-<symbol name="mark/square(sx)" transformations="translations">-<path fill="sym-stroke">--0.6 -0.6 m-0.6 -0.6 l-0.6 0.6 l--0.6 0.6 l-h-</path>-</symbol>-<symbol name="mark/fsquare(sfx)" transformations="translations">-<group>-<path fill="sym-fill">--0.5 -0.5 m-0.5 -0.5 l-0.5 0.5 l--0.5 0.5 l-h-</path>-<path fill="sym-stroke" fillrule="eofill">--0.6 -0.6 m-0.6 -0.6 l-0.6 0.6 l--0.6 0.6 l-h--0.4 -0.4 m-0.4 -0.4 l-0.4 0.4 l--0.4 0.4 l-h-</path>-</group>-</symbol>-<symbol name="mark/cross(sx)" transformations="translations">-<group>-<path fill="sym-stroke">--0.43 -0.57 m-0.57 0.43 l-0.43 0.57 l--0.57 -0.43 l-h-</path>-<path fill="sym-stroke">--0.43 0.57 m-0.57 -0.43 l-0.43 -0.57 l--0.57 0.43 l-h-</path>-</group>-</symbol>-<symbol name="arrow/fnormal(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/pointed(spx)">-<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">-0 0 m--1 0.333 l--0.8 0 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/fpointed(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--0.8 0 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/linear(spx)">-<path stroke="sym-stroke" pen="sym-pen">--1 0.333 m-0 0 l--1 -0.333 l-</path>-</symbol>-<symbol name="arrow/fdouble(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h--1 0 m--2 0.333 l--2 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/double(spx)">-<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h--1 0 m--2 0.333 l--2 -0.333 l-h-</path>-</symbol>-<pen name="heavier" value="0.8"/>-<pen name="fat" value="1.2"/>-<pen name="ultrafat" value="2"/>-<symbolsize name="large" value="5"/>-<symbolsize name="small" value="2"/>-<symbolsize name="tiny" value="1.1"/>-<arrowsize name="large" value="10"/>-<arrowsize name="small" value="5"/>-<arrowsize name="tiny" value="3"/>-<color name="red" value="1 0 0"/>-<color name="green" value="0 1 0"/>-<color name="blue" value="0 0 1"/>-<color name="yellow" value="1 1 0"/>-<color name="orange" value="1 0.647 0"/>-<color name="gold" value="1 0.843 0"/>-<color name="purple" value="0.627 0.125 0.941"/>-<color name="gray" value="0.745"/>-<color name="brown" value="0.647 0.165 0.165"/>-<color name="navy" value="0 0 0.502"/>-<color name="pink" value="1 0.753 0.796"/>-<color name="seagreen" value="0.18 0.545 0.341"/>-<color name="turquoise" value="0.251 0.878 0.816"/>-<color name="violet" value="0.933 0.51 0.933"/>-<color name="darkblue" value="0 0 0.545"/>-<color name="darkcyan" value="0 0.545 0.545"/>-<color name="darkgray" value="0.663"/>-<color name="darkgreen" value="0 0.392 0"/>-<color name="darkmagenta" value="0.545 0 0.545"/>-<color name="darkorange" value="1 0.549 0"/>-<color name="darkred" value="0.545 0 0"/>-<color name="lightblue" value="0.678 0.847 0.902"/>-<color name="lightcyan" value="0.878 1 1"/>-<color name="lightgray" value="0.827"/>-<color name="lightgreen" value="0.565 0.933 0.565"/>-<color name="lightyellow" value="1 1 0.878"/>-<dashstyle name="dashed" value="[4] 0"/>-<dashstyle name="dotted" value="[1 3] 0"/>-<dashstyle name="dash dotted" value="[4 2 1 2] 0"/>-<dashstyle name="dash dot dotted" value="[4 2 1 2 1 2] 0"/>-<textsize name="large" value="\large"/>-<textsize name="Large" value="\Large"/>-<textsize name="LARGE" value="\LARGE"/>-<textsize name="huge" value="\huge"/>-<textsize name="Huge" value="\Huge"/>-<textsize name="small" value="\small"/>-<textsize name="footnote" value="\footnotesize"/>-<textsize name="tiny" value="\tiny"/>-<textstyle name="center" begin="\begin{center}" end="\end{center}"/>-<textstyle name="itemize" begin="\begin{itemize}" end="\end{itemize}"/>-<textstyle name="item" begin="\begin{itemize}\item{}" end="\end{itemize}"/>-<gridsize name="4 pts" value="4"/>-<gridsize name="8 pts (~3 mm)" value="8"/>-<gridsize name="16 pts (~6 mm)" value="16"/>-<gridsize name="32 pts (~12 mm)" value="32"/>-<gridsize name="10 pts (~3.5 mm)" value="10"/>-<gridsize name="20 pts (~7 mm)" value="20"/>-<gridsize name="14 pts (~5 mm)" value="14"/>-<gridsize name="28 pts (~10 mm)" value="28"/>-<gridsize name="56 pts (~20 mm)" value="56"/>-<anglesize name="90 deg" value="90"/>-<anglesize name="60 deg" value="60"/>-<anglesize name="45 deg" value="45"/>-<anglesize name="30 deg" value="30"/>-<anglesize name="22.5 deg" value="22.5"/>-<opacity name="10%" value="0.1"/>-<opacity name="30%" value="0.3"/>-<opacity name="50%" value="0.5"/>-<opacity name="75%" value="0.75"/>-<tiling name="falling" angle="-60" step="4" width="1"/>-<tiling name="rising" angle="30" step="4" width="1"/>-</ipestyle>-<ipestyle name="frank">-<arrowsize name="normal" value="5"/>-<arrowsize name="large" value="8"/>-<arrowsize name="huge" value="10"/>-<arrowsize name="small" value="3"/>-<arrowsize name="tiny" value="1"/>-<dashstyle name="dashed" value="[2 2] 0"/>-<dashstyle name="dotted" value="[0.5 1] 0"/>-<dashstyle name="dash dotted" value="[4 2 1 2] 0"/>-<dashstyle name="dash dot dotted" value="[4 2 1 2 1 2] 0"/>-<gridsize name="1 pts" value="1"/>-<gridsize name="2 pts" value="2"/>-<opacity name="10%" value="0.1"/>-<opacity name="30%" value="0.3"/>-<opacity name="50%" value="0.5"/>-<opacity name="20%" value="0.2"/>-<opacity name="40%" value="0.4"/>-<opacity name="60%" value="0.6"/>-<opacity name="70%" value="0.7"/>-<opacity name="80%" value="0.8"/>-<opacity name="90%" value="0.9"/>-</ipestyle>-<page>-<layer name="alpha"/>-<view layers="alpha" active="alpha"/>-<path layer="alpha" stroke="blue">-176 752 m-208 688 l-160 624 l-288 672 l-304 752 l-256 736 l-h-</path>-<path stroke="red">-384 784 m-448 624 l-368 576 l-512 624 l-448 704 l-560 672 l-528 576 l-592 688 l-h-</path>-<path stroke="red">-240 544 m-80 416 l-224 336 l-320 336 l-208 416 l-352 416 l-320 320 l-480 400 l-448 496 l-320 496 l-256 464 l-h-</path>-<path stroke="blue">-176 272 m-144 80 l-400 176 l-h-</path>-<path stroke="blue">-432 272 m-480 144 l-528 192 l-496 192 l-512 240 l-480 224 l-h-</path>-<path stroke="blue">-64 656 m-32 592 l-80 640 l-144 640 l-80 656 l-96 704 l-80 672 l-h-</path>-</page>-</ipe>
− test/Data/Geometry/arrangement.ipe
@@ -1,296 +0,0 @@-<?xml version="1.0"?>-<!DOCTYPE ipe SYSTEM "ipe.dtd">-<ipe version="70107" creator="Ipe 7.2.2">-<info created="D:20180731094955" modified="D:20180731094955"/>-<ipestyle name="basic">-<symbol name="arrow/arc(spx)">-<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/farc(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/ptarc(spx)">-<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">-0 0 m--1 0.333 l--0.8 0 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/fptarc(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--0.8 0 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="mark/circle(sx)" transformations="translations">-<path fill="sym-stroke">-0.6 0 0 0.6 0 0 e-0.4 0 0 0.4 0 0 e-</path>-</symbol>-<symbol name="mark/disk(sx)" transformations="translations">-<path fill="sym-stroke">-0.6 0 0 0.6 0 0 e-</path>-</symbol>-<symbol name="mark/fdisk(sfx)" transformations="translations">-<group>-<path fill="sym-fill">-0.5 0 0 0.5 0 0 e-</path>-<path fill="sym-stroke" fillrule="eofill">-0.6 0 0 0.6 0 0 e-0.4 0 0 0.4 0 0 e-</path>-</group>-</symbol>-<symbol name="mark/box(sx)" transformations="translations">-<path fill="sym-stroke" fillrule="eofill">--0.6 -0.6 m-0.6 -0.6 l-0.6 0.6 l--0.6 0.6 l-h--0.4 -0.4 m-0.4 -0.4 l-0.4 0.4 l--0.4 0.4 l-h-</path>-</symbol>-<symbol name="mark/square(sx)" transformations="translations">-<path fill="sym-stroke">--0.6 -0.6 m-0.6 -0.6 l-0.6 0.6 l--0.6 0.6 l-h-</path>-</symbol>-<symbol name="mark/fsquare(sfx)" transformations="translations">-<group>-<path fill="sym-fill">--0.5 -0.5 m-0.5 -0.5 l-0.5 0.5 l--0.5 0.5 l-h-</path>-<path fill="sym-stroke" fillrule="eofill">--0.6 -0.6 m-0.6 -0.6 l-0.6 0.6 l--0.6 0.6 l-h--0.4 -0.4 m-0.4 -0.4 l-0.4 0.4 l--0.4 0.4 l-h-</path>-</group>-</symbol>-<symbol name="mark/cross(sx)" transformations="translations">-<group>-<path fill="sym-stroke">--0.43 -0.57 m-0.57 0.43 l-0.43 0.57 l--0.57 -0.43 l-h-</path>-<path fill="sym-stroke">--0.43 0.57 m-0.57 -0.43 l-0.43 -0.57 l--0.57 0.43 l-h-</path>-</group>-</symbol>-<symbol name="arrow/fnormal(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/pointed(spx)">-<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">-0 0 m--1 0.333 l--0.8 0 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/fpointed(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--0.8 0 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/linear(spx)">-<path stroke="sym-stroke" pen="sym-pen">--1 0.333 m-0 0 l--1 -0.333 l-</path>-</symbol>-<symbol name="arrow/fdouble(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h--1 0 m--2 0.333 l--2 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/double(spx)">-<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h--1 0 m--2 0.333 l--2 -0.333 l-h-</path>-</symbol>-<pen name="heavier" value="0.8"/>-<pen name="fat" value="1.2"/>-<pen name="ultrafat" value="2"/>-<symbolsize name="large" value="5"/>-<symbolsize name="small" value="2"/>-<symbolsize name="tiny" value="1.1"/>-<arrowsize name="large" value="10"/>-<arrowsize name="small" value="5"/>-<arrowsize name="tiny" value="3"/>-<color name="red" value="1 0 0"/>-<color name="green" value="0 1 0"/>-<color name="blue" value="0 0 1"/>-<color name="yellow" value="1 1 0"/>-<color name="orange" value="1 0.647 0"/>-<color name="gold" value="1 0.843 0"/>-<color name="purple" value="0.627 0.125 0.941"/>-<color name="gray" value="0.745"/>-<color name="brown" value="0.647 0.165 0.165"/>-<color name="navy" value="0 0 0.502"/>-<color name="pink" value="1 0.753 0.796"/>-<color name="seagreen" value="0.18 0.545 0.341"/>-<color name="turquoise" value="0.251 0.878 0.816"/>-<color name="violet" value="0.933 0.51 0.933"/>-<color name="darkblue" value="0 0 0.545"/>-<color name="darkcyan" value="0 0.545 0.545"/>-<color name="darkgray" value="0.663"/>-<color name="darkgreen" value="0 0.392 0"/>-<color name="darkmagenta" value="0.545 0 0.545"/>-<color name="darkorange" value="1 0.549 0"/>-<color name="darkred" value="0.545 0 0"/>-<color name="lightblue" value="0.678 0.847 0.902"/>-<color name="lightcyan" value="0.878 1 1"/>-<color name="lightgray" value="0.827"/>-<color name="lightgreen" value="0.565 0.933 0.565"/>-<color name="lightyellow" value="1 1 0.878"/>-<dashstyle name="dashed" value="[4] 0"/>-<dashstyle name="dotted" value="[1 3] 0"/>-<dashstyle name="dash dotted" value="[4 2 1 2] 0"/>-<dashstyle name="dash dot dotted" value="[4 2 1 2 1 2] 0"/>-<textsize name="large" value="\large"/>-<textsize name="Large" value="\Large"/>-<textsize name="LARGE" value="\LARGE"/>-<textsize name="huge" value="\huge"/>-<textsize name="Huge" value="\Huge"/>-<textsize name="small" value="\small"/>-<textsize name="footnote" value="\footnotesize"/>-<textsize name="tiny" value="\tiny"/>-<textstyle name="center" begin="\begin{center}" end="\end{center}"/>-<textstyle name="itemize" begin="\begin{itemize}" end="\end{itemize}"/>-<textstyle name="item" begin="\begin{itemize}\item{}" end="\end{itemize}"/>-<gridsize name="4 pts" value="4"/>-<gridsize name="8 pts (~3 mm)" value="8"/>-<gridsize name="16 pts (~6 mm)" value="16"/>-<gridsize name="32 pts (~12 mm)" value="32"/>-<gridsize name="10 pts (~3.5 mm)" value="10"/>-<gridsize name="20 pts (~7 mm)" value="20"/>-<gridsize name="14 pts (~5 mm)" value="14"/>-<gridsize name="28 pts (~10 mm)" value="28"/>-<gridsize name="56 pts (~20 mm)" value="56"/>-<anglesize name="90 deg" value="90"/>-<anglesize name="60 deg" value="60"/>-<anglesize name="45 deg" value="45"/>-<anglesize name="30 deg" value="30"/>-<anglesize name="22.5 deg" value="22.5"/>-<opacity name="10%" value="0.1"/>-<opacity name="30%" value="0.3"/>-<opacity name="50%" value="0.5"/>-<opacity name="75%" value="0.75"/>-<tiling name="falling" angle="-60" step="4" width="1"/>-<tiling name="rising" angle="30" step="4" width="1"/>-</ipestyle>-<ipestyle name="frank">-<arrowsize name="normal" value="5"/>-<arrowsize name="large" value="8"/>-<arrowsize name="huge" value="10"/>-<arrowsize name="small" value="3"/>-<arrowsize name="tiny" value="1"/>-<dashstyle name="dashed" value="[2 2] 0"/>-<dashstyle name="dotted" value="[0.5 1] 0"/>-<dashstyle name="dash dotted" value="[4 2 1 2] 0"/>-<dashstyle name="dash dot dotted" value="[4 2 1 2 1 2] 0"/>-<gridsize name="1 pts" value="1"/>-<gridsize name="2 pts" value="2"/>-<opacity name="10%" value="0.1"/>-<opacity name="30%" value="0.3"/>-<opacity name="50%" value="0.5"/>-<opacity name="20%" value="0.2"/>-<opacity name="40%" value="0.4"/>-<opacity name="60%" value="0.6"/>-<opacity name="70%" value="0.7"/>-<opacity name="80%" value="0.8"/>-<opacity name="90%" value="0.9"/>-</ipestyle>-<page>-<layer name="alpha"/>-<view layers="alpha" active="alpha"/>-<path layer="alpha" stroke="black">-80 560 m-368 800 l-</path>-<path stroke="black">-160 768 m-416 608 l-</path>-<path stroke="black">-80 624 m-400 672 l-</path>-<path matrix="0.857143 0 0 1.3 32 -172.8" stroke="black">-224 576 m-336 736 l-</path>-</page>-</ipe>
− test/Data/Geometry/arrangement.ipe.out.ipe
@@ -1,247 +0,0 @@-<?xml version="1.0" encoding="UTF-8"?>-<ipe version="70005" creator="HGeometry"><ipestyle name="basic">-<color name="red" value="1 0 0"/>-<color name="green" value="0 1 0"/>-<color name="blue" value="0 0 1"/>-<color name="yellow" value="1 1 0"/>-<color name="orange" value="1 0.647 0"/>-<color name="gold" value="1 0.843 0"/>-<color name="purple" value="0.627 0.125 0.941"/>-<color name="gray" value="0.745 0.745 0.745"/>-<color name="brown" value="0.647 0.165 0.165"/>-<color name="navy" value="0 0 0.502"/>-<color name="pink" value="1 0.753 0.796"/>-<color name="seagreen" value="0.18 0.545 0.341"/>-<color name="turquoise" value="0.251 0.878 0.816"/>-<color name="violet" value="0.933 0.51 0.933"/>-<color name="darkblue" value="0 0 0.545"/>-<color name="darkcyan" value="0 0.545 0.545"/>-<color name="darkgray" value="0.663 0.663 0.663"/>-<color name="darkgreen" value="0 0.392 0"/>-<color name="darkmagenta" value="0.545 0 0.545"/>-<color name="darkorange" value="1 0.549 0"/>-<color name="darkred" value="0.545 0 0"/>-<color name="lightblue" value="0.678 0.847 0.902"/>-<color name="lightcyan" value="0.878 1 1"/>-<color name="lightgray" value="0.827 0.827 0.827"/>-<color name="lightgreen" value="0.565 0.933 0.565"/>-<color name="lightyellow" value="1 1 0.878"/>-<dashstyle name="dashed" value="[4] 0"/>-<dashstyle name="dotted" value="[1 3] 0"/>-<dashstyle name="dash dotted" value="[4 2 1 2] 0"/>-<dashstyle name="dash dot dotted" value="[4 2 1 2 1 2] 0"/>-<pen name="heavier" value="0.8"/>-<pen name="fat" value="1.2"/>-<pen name="ultrafat" value="2"/>-<textsize name="large" value="\large"/>-<textsize name="Large" value="\Large"/>-<textsize name="LARGE" value="\LARGE"/>-<textsize name="huge" value="\huge"/>-<textsize name="Huge" value="\Huge"/>-<textsize name="small" value="\small"/>-<textsize name="footnote" value="\footnotesize"/>-<textsize name="tiny" value="\tiny"/>-<symbolsize name="small" value="2"/>-<symbolsize name="tiny" value="1.1"/>-<symbolsize name="large" value="5"/>-<arrowsize name="small" value="5"/>-<arrowsize name="tiny" value="3"/>-<arrowsize name="large" value="10"/>-<gridsize name="4 pts" value="4"/>-<gridsize name="8 pts (~3 mm)" value="8"/>-<gridsize name="16 pts (~6 mm)" value="16"/>-<gridsize name="32 pts (~12 mm)" value="32"/>-<gridsize name="10 pts (~3.5 mm)" value="10"/>-<gridsize name="20 pts (~7 mm)" value="20"/>-<gridsize name="14 pts (~5 mm)" value="14"/>-<gridsize name="28 pts (~10 mm)" value="28"/>-<gridsize name="56 pts (~20 mm)" value="56"/>-<anglesize name="90 deg" value="90"/>-<anglesize name="60 deg" value="60"/>-<anglesize name="45 deg" value="45"/>-<anglesize name="30 deg" value="30"/>-<anglesize name="22.5 deg" value="22.5"/>-<symbol name="mark/circle(sx)" transformations="translations">-<path fill="sym-stroke">-0.6 0 0 0.6 0 0 e 0.4 0 0 0.4 0 0 e-</path></symbol>-<symbol name="mark/disk(sx)" transformations="translations">-<path fill="sym-stroke">-0.6 0 0 0.6 0 0 e-</path></symbol>-<symbol name="mark/fdisk(sfx)" transformations="translations">-<group><path fill="sym-fill">-0.5 0 0 0.5 0 0 e-</path><path fill="sym-stroke" fillrule="eofill">-0.6 0 0 0.6 0 0 e 0.4 0 0 0.4 0 0 e-</path></group></symbol>-<symbol name="mark/box(sx)" transformations="translations">-<path fill="sym-stroke" fillrule="eofill">--0.6 -0.6 m 0.6 -0.6 l 0.6 0.6 l -0.6 0.6 l h--0.4 -0.4 m 0.4 -0.4 l 0.4 0.4 l -0.4 0.4 l h</path></symbol>-<symbol name="mark/square(sx)" transformations="translations">-<path fill="sym-stroke">--0.6 -0.6 m 0.6 -0.6 l 0.6 0.6 l -0.6 0.6 l h</path></symbol>-<symbol name="mark/fsquare(sfx)" transformations="translations">-<group><path fill="sym-fill">--0.5 -0.5 m 0.5 -0.5 l 0.5 0.5 l -0.5 0.5 l h</path>-<path fill="sym-stroke" fillrule="eofill">--0.6 -0.6 m 0.6 -0.6 l 0.6 0.6 l -0.6 0.6 l h--0.4 -0.4 m 0.4 -0.4 l 0.4 0.4 l -0.4 0.4 l h</path></group></symbol>-<symbol name="mark/cross(sx)" transformations="translations">-<group><path fill="sym-stroke">--0.43 -0.57 m 0.57 0.43 l 0.43 0.57 l -0.57 -0.43 l h</path>-<path fill="sym-stroke">--0.43 0.57 m 0.57 -0.43 l 0.43 -0.57 l -0.57 0.43 l h</path>-</group></symbol>-<symbol name="arrow/arc(spx)">-<path pen="sym-pen" stroke="sym-stroke" fill="sym-stroke">-0 0 m -1.0 0.333 l -1.0 -0.333 l h</path></symbol>-<symbol name="arrow/farc(spx)">-<path pen="sym-pen" stroke="sym-stroke" fill="white">-0 0 m -1.0 0.333 l -1.0 -0.333 l h</path></symbol>-<symbol name="arrow/ptarc(spx)">-<path pen="sym-pen" stroke="sym-stroke" fill="sym-stroke">-0 0 m -1.0 0.333 l -0.8 0 l -1.0 -0.333 l h</path></symbol>-<symbol name="arrow/fptarc(spx)">-<path pen="sym-pen" stroke="sym-stroke" fill="white">-0 0 m -1.0 0.333 l -0.8 0 l -1.0 -0.333 l h</path></symbol>-<symbol name="arrow/fnormal(spx)">-<path pen="sym-pen" stroke="sym-stroke" fill="white">-0 0 m -1.0 0.333 l -1.0 -0.333 l h</path></symbol>-<symbol name="arrow/pointed(spx)">-<path pen="sym-pen" stroke="sym-stroke" fill="sym-stroke">-0 0 m -1.0 0.333 l -0.8 0 l -1.0 -0.333 l h</path></symbol>-<symbol name="arrow/fpointed(spx)">-<path pen="sym-pen" stroke="sym-stroke" fill="white">-0 0 m -1.0 0.333 l -0.8 0 l -1.0 -0.333 l h</path></symbol>-<symbol name="arrow/linear(spx)">-<path pen="sym-pen" stroke="sym-stroke">--1.0 0.333 m 0 0 l -1.0 -0.333 l</path></symbol>-<symbol name="arrow/fdouble(spx)">-<path pen="sym-pen" stroke="sym-stroke" fill="white">-0 0 m -1.0 0.333 l -1.0 -0.333 l h--1 0 m -2.0 0.333 l -2.0 -0.333 l h-</path></symbol>-<symbol name="arrow/double(spx)">-<path pen="sym-pen" stroke="sym-stroke" fill="sym-stroke">-0 0 m -1.0 0.333 l -1.0 -0.333 l h--1 0 m -2.0 0.333 l -2.0 -0.333 l h-</path></symbol>-<tiling name="falling" angle="-60" width="1" step="4"/>-<tiling name="rising" angle="30" width="1" step="4"/>-<textstyle name="center" begin="\begin{center}" end="\end{center}"/>-<textstyle name="itemize" begin="\begin{itemize}" end="\end{itemize}"/>-<textstyle name="item" begin="\begin{itemize}\item{}" end="\end{itemize}"/>-</ipestyle><page><layer name="alpha"/><view layers="alpha" active="alpha"/><group><use pos="172.658536585365 637.048780487804" name="mark/disk(sx)"/><use pos="172.658536585365 637.215447154471" name="mark/disk(sx)"/><use pos="172.658536585365 637.898780487804" name="mark/disk(sx)"/><use pos="172.658536585365 746.000060937506" name="mark/disk(sx)"/><use pos="173.658536585365 638.048780487804" name="mark/disk(sx)"/><use pos="195.199902499989 746.000060937506" name="mark/disk(sx)"/><use pos="252.176396921200 637.048780487804" name="mark/disk(sx)"/><use pos="256.914285714285 707.428571428571" name="mark/disk(sx)"/><use pos="258.512437254286 650.776865588142" name="mark/disk(sx)"/><use pos="278.447793072843 693.970129329472" name="mark/disk(sx)"/><use pos="302.000073125007 745.000060937506" name="mark/disk(sx)"/><use pos="302.461611663469 746.000060937506" name="mark/disk(sx)"/><use pos="303.200073125007 746.000060937506" name="mark/disk(sx)"/><use pos="330.322580645161 661.548387096774" name="mark/disk(sx)"/><use pos="331.322580645161 637.048780487804" name="mark/disk(sx)"/><use pos="331.322580645161 660.923387096774" name="mark/disk(sx)"/><use pos="331.322580645161 661.698387096774" name="mark/disk(sx)"/><use pos="331.322580645161 746.000060937506" name="mark/disk(sx)"/><path>172.658536585365 637.215447154471 m-173.658536585365 638.048780487804 l-</path><path>173.658536585365 638.048780487804 m-256.914285714285 707.428571428571 l-</path><path>256.914285714285 707.428571428571 m-302.000073125007 745.000060937506 l-</path><path>302.000073125007 745.000060937506 m-303.200073125007 746.000060937506 l-</path><path>195.199902499989 746.000060937506 m-256.914285714285 707.428571428571 l-</path><path>256.914285714285 707.428571428571 m-278.447793072843 693.970129329472 l-</path><path>278.447793072843 693.970129329472 m-330.322580645161 661.548387096774 l-</path><path>330.322580645161 661.548387096774 m-331.322580645161 660.923387096774 l-</path><path>172.658536585365 637.898780487804 m-173.658536585365 638.048780487804 l-</path><path>173.658536585365 638.048780487804 m-258.512437254286 650.776865588142 l-</path><path>258.512437254286 650.776865588142 m-330.322580645161 661.548387096774 l-</path><path>330.322580645161 661.548387096774 m-331.322580645161 661.698387096774 l-</path><path>252.176396921200 637.048780487804 m-258.512437254286 650.776865588142 l-</path><path>258.512437254286 650.776865588142 m-278.447793072843 693.970129329472 l-</path><path>278.447793072843 693.970129329472 m-302.000073125007 745.000060937506 l-</path><path>302.000073125007 745.000060937506 m-302.461611663469 746.000060937506 l-</path><path>172.658536585365 746.000060937506 m-195.199902499989 746.000060937506 l-</path><path>195.199902499989 746.000060937506 m-302.461611663469 746.000060937506 l-</path><path>302.461611663469 746.000060937506 m-303.200073125007 746.000060937506 l-</path><path>303.200073125007 746.000060937506 m-331.322580645161 746.000060937506 l-</path><path>331.322580645161 746.000060937506 m-331.322580645161 661.698387096774 l-</path><path>331.322580645161 661.698387096774 m-331.322580645161 660.923387096774 l-</path><path>331.322580645161 660.923387096774 m-331.322580645161 637.048780487804 l-</path><path>331.322580645161 637.048780487804 m-252.176396921200 637.048780487804 l-</path><path>252.176396921200 637.048780487804 m-172.658536585365 637.048780487804 l-</path><path>172.658536585365 637.048780487804 m-172.658536585365 637.215447154471 l-</path><path>172.658536585365 637.215447154471 m-172.658536585365 637.898780487804 l-</path><path>172.658536585365 637.898780487804 m-172.658536585365 746.000060937506 l-</path><path>172.658536585365 637.215447154471 m-173.658536585365 638.048780487804 l-258.512437254286 650.776865588142 l-252.176396921200 637.048780487804 l-172.658536585365 637.048780487804 l-h-</path><path>172.658536585365 637.898780487804 m-173.658536585365 638.048780487804 l-172.658536585365 637.215447154471 l-h-</path><path>172.658536585365 746.000060937506 m-195.199902499989 746.000060937506 l-256.914285714285 707.428571428571 l-173.658536585365 638.048780487804 l-172.658536585365 637.898780487804 l-h-</path><path>256.914285714285 707.428571428571 m-278.447793072843 693.970129329472 l-258.512437254286 650.776865588142 l-173.658536585365 638.048780487804 l-h-</path><path>302.461611663469 746.000060937506 m-302.000073125007 745.000060937506 l-256.914285714285 707.428571428571 l-195.199902499989 746.000060937506 l-h-</path><path>258.512437254286 650.776865588142 m-330.322580645161 661.548387096774 l-331.322580645161 660.923387096774 l-331.322580645161 637.048780487804 l-252.176396921200 637.048780487804 l-h-</path><path>302.000073125007 745.000060937506 m-278.447793072843 693.970129329472 l-256.914285714285 707.428571428571 l-h-</path><path>278.447793072843 693.970129329472 m-330.322580645161 661.548387096774 l-258.512437254286 650.776865588142 l-h-</path><path>302.000073125007 745.000060937506 m-303.200073125007 746.000060937506 l-331.322580645161 746.000060937506 l-331.322580645161 661.698387096774 l-330.322580645161 661.548387096774 l-278.447793072843 693.970129329472 l-h-</path><path>302.461611663469 746.000060937506 m-303.200073125007 746.000060937506 l-302.000073125007 745.000060937506 l-h-</path><path>331.322580645161 661.698387096774 m-331.322580645161 660.923387096774 l-330.322580645161 661.548387096774 l-h-</path></group></page></ipe>
− test/Data/Geometry/pointInPolygon.ipe
@@ -1,311 +0,0 @@-<?xml version="1.0"?>-<!DOCTYPE ipe SYSTEM "ipe.dtd">-<ipe version="70107" creator="Ipe 7.1.7">-<info created="D:20150923215046" modified="D:20150924223742"/>-<ipestyle name="basic">-<symbol name="arrow/arc(spx)">-<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/farc(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/ptarc(spx)">-<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">-0 0 m--1 0.333 l--0.8 0 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/fptarc(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--0.8 0 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="mark/circle(sx)" transformations="translations">-<path fill="sym-stroke">-0.6 0 0 0.6 0 0 e-0.4 0 0 0.4 0 0 e-</path>-</symbol>-<symbol name="mark/disk(sx)" transformations="translations">-<path fill="sym-stroke">-0.6 0 0 0.6 0 0 e-</path>-</symbol>-<symbol name="mark/fdisk(sfx)" transformations="translations">-<group>-<path fill="sym-fill">-0.5 0 0 0.5 0 0 e-</path>-<path fill="sym-stroke" fillrule="eofill">-0.6 0 0 0.6 0 0 e-0.4 0 0 0.4 0 0 e-</path>-</group>-</symbol>-<symbol name="mark/box(sx)" transformations="translations">-<path fill="sym-stroke" fillrule="eofill">--0.6 -0.6 m-0.6 -0.6 l-0.6 0.6 l--0.6 0.6 l-h--0.4 -0.4 m-0.4 -0.4 l-0.4 0.4 l--0.4 0.4 l-h-</path>-</symbol>-<symbol name="mark/square(sx)" transformations="translations">-<path fill="sym-stroke">--0.6 -0.6 m-0.6 -0.6 l-0.6 0.6 l--0.6 0.6 l-h-</path>-</symbol>-<symbol name="mark/fsquare(sfx)" transformations="translations">-<group>-<path fill="sym-fill">--0.5 -0.5 m-0.5 -0.5 l-0.5 0.5 l--0.5 0.5 l-h-</path>-<path fill="sym-stroke" fillrule="eofill">--0.6 -0.6 m-0.6 -0.6 l-0.6 0.6 l--0.6 0.6 l-h--0.4 -0.4 m-0.4 -0.4 l-0.4 0.4 l--0.4 0.4 l-h-</path>-</group>-</symbol>-<symbol name="mark/cross(sx)" transformations="translations">-<group>-<path fill="sym-stroke">--0.43 -0.57 m-0.57 0.43 l-0.43 0.57 l--0.57 -0.43 l-h-</path>-<path fill="sym-stroke">--0.43 0.57 m-0.57 -0.43 l-0.43 -0.57 l--0.57 0.43 l-h-</path>-</group>-</symbol>-<symbol name="arrow/fnormal(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/pointed(spx)">-<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">-0 0 m--1 0.333 l--0.8 0 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/fpointed(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--0.8 0 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/linear(spx)">-<path stroke="sym-stroke" pen="sym-pen">--1 0.333 m-0 0 l--1 -0.333 l-</path>-</symbol>-<symbol name="arrow/fdouble(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h--1 0 m--2 0.333 l--2 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/double(spx)">-<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h--1 0 m--2 0.333 l--2 -0.333 l-h-</path>-</symbol>-<pen name="heavier" value="0.8"/>-<pen name="fat" value="1.2"/>-<pen name="ultrafat" value="2"/>-<symbolsize name="large" value="5"/>-<symbolsize name="small" value="2"/>-<symbolsize name="tiny" value="1.1"/>-<arrowsize name="large" value="10"/>-<arrowsize name="small" value="5"/>-<arrowsize name="tiny" value="3"/>-<color name="red" value="1 0 0"/>-<color name="green" value="0 1 0"/>-<color name="blue" value="0 0 1"/>-<color name="yellow" value="1 1 0"/>-<color name="orange" value="1 0.647 0"/>-<color name="gold" value="1 0.843 0"/>-<color name="purple" value="0.627 0.125 0.941"/>-<color name="gray" value="0.745"/>-<color name="brown" value="0.647 0.165 0.165"/>-<color name="navy" value="0 0 0.502"/>-<color name="pink" value="1 0.753 0.796"/>-<color name="seagreen" value="0.18 0.545 0.341"/>-<color name="turquoise" value="0.251 0.878 0.816"/>-<color name="violet" value="0.933 0.51 0.933"/>-<color name="darkblue" value="0 0 0.545"/>-<color name="darkcyan" value="0 0.545 0.545"/>-<color name="darkgray" value="0.663"/>-<color name="darkgreen" value="0 0.392 0"/>-<color name="darkmagenta" value="0.545 0 0.545"/>-<color name="darkorange" value="1 0.549 0"/>-<color name="darkred" value="0.545 0 0"/>-<color name="lightblue" value="0.678 0.847 0.902"/>-<color name="lightcyan" value="0.878 1 1"/>-<color name="lightgray" value="0.827"/>-<color name="lightgreen" value="0.565 0.933 0.565"/>-<color name="lightyellow" value="1 1 0.878"/>-<dashstyle name="dashed" value="[4] 0"/>-<dashstyle name="dotted" value="[1 3] 0"/>-<dashstyle name="dash dotted" value="[4 2 1 2] 0"/>-<dashstyle name="dash dot dotted" value="[4 2 1 2 1 2] 0"/>-<textsize name="large" value="\large"/>-<textsize name="Large" value="\Large"/>-<textsize name="LARGE" value="\LARGE"/>-<textsize name="huge" value="\huge"/>-<textsize name="Huge" value="\Huge"/>-<textsize name="small" value="\small"/>-<textsize name="footnote" value="\footnotesize"/>-<textsize name="tiny" value="\tiny"/>-<textstyle name="center" begin="\begin{center}" end="\end{center}"/>-<textstyle name="itemize" begin="\begin{itemize}" end="\end{itemize}"/>-<textstyle name="item" begin="\begin{itemize}\item{}" end="\end{itemize}"/>-<gridsize name="4 pts" value="4"/>-<gridsize name="8 pts (~3 mm)" value="8"/>-<gridsize name="16 pts (~6 mm)" value="16"/>-<gridsize name="32 pts (~12 mm)" value="32"/>-<gridsize name="10 pts (~3.5 mm)" value="10"/>-<gridsize name="20 pts (~7 mm)" value="20"/>-<gridsize name="14 pts (~5 mm)" value="14"/>-<gridsize name="28 pts (~10 mm)" value="28"/>-<gridsize name="56 pts (~20 mm)" value="56"/>-<anglesize name="90 deg" value="90"/>-<anglesize name="60 deg" value="60"/>-<anglesize name="45 deg" value="45"/>-<anglesize name="30 deg" value="30"/>-<anglesize name="22.5 deg" value="22.5"/>-<tiling name="falling" angle="-60" step="4" width="1"/>-<tiling name="rising" angle="30" step="4" width="1"/>-</ipestyle>-<ipestyle name="frank">-<arrowsize name="normal" value="5"/>-<arrowsize name="large" value="8"/>-<arrowsize name="huge" value="10"/>-<arrowsize name="small" value="3"/>-<arrowsize name="tiny" value="1"/>-<dashstyle name="dashed" value="[2 2] 0"/>-<dashstyle name="dotted" value="[0.5 1] 0"/>-<dashstyle name="dash dotted" value="[4 2 1 2] 0"/>-<dashstyle name="dash dot dotted" value="[4 2 1 2 1 2] 0"/>-<gridsize name="1 pts" value="1"/>-<gridsize name="2 pts" value="2"/>-<opacity name="10%" value="0.1"/>-<opacity name="20%" value="0.2"/>-<opacity name="30%" value="0.3"/>-<opacity name="40%" value="0.4"/>-<opacity name="50%" value="0.5"/>-<opacity name="60%" value="0.6"/>-<opacity name="70%" value="0.7"/>-<opacity name="80%" value="0.8"/>-<opacity name="90%" value="0.9"/>-</ipestyle>-<page>-<layer name="alpha"/>-<view layers="alpha" active="alpha"/>-<path layer="alpha" stroke="darkblue">-208 752 m-304 688 l-224 592 l-48 736 l-h-</path>-<use name="mark/disk(sx)" pos="128 704" size="normal" stroke="darkblue"/>-<use name="mark/disk(sx)" pos="192 672" size="normal" stroke="darkblue"/>-<use name="mark/disk(sx)" pos="192 720" size="normal" stroke="darkblue"/>-<use name="mark/box(sx)" pos="304 688" size="normal" stroke="black"/>-<use name="mark/cross(sx)" pos="352 736" size="normal" stroke="darkblue"/>-<use name="mark/cross(sx)" pos="352 704" size="normal" stroke="darkblue"/>-<path stroke="orange">-496 736 m-432 624 l-512 608 l-h-</path>-<use name="mark/box(sx)" pos="432 624" size="normal" stroke="orange"/>-<use name="mark/box(sx)" pos="512 608" size="normal" stroke="orange"/>-<use name="mark/box(sx)" pos="496 736" size="normal" stroke="orange"/>-<use name="mark/disk(sx)" pos="496 656" size="normal" stroke="orange"/>-<use name="mark/disk(sx)" pos="480 640" size="normal" stroke="orange"/>-<use name="mark/disk(sx)" pos="464 656" size="normal" stroke="orange"/>-<use name="mark/cross(sx)" pos="368 608" size="normal" stroke="orange"/>-<use name="mark/cross(sx)" pos="384 592" size="normal" stroke="orange"/>-<use name="mark/cross(sx)" pos="336 576" size="normal" stroke="orange"/>-<use name="mark/disk(sx)" pos="496 624" size="normal" stroke="orange"/>-<use name="mark/cross(sx)" pos="528 624" size="normal" stroke="orange"/>-<use name="mark/cross(sx)" pos="384 624" size="normal" stroke="orange"/>-<use name="mark/cross(sx)" pos="368 640" size="normal" stroke="orange"/>-<use name="mark/cross(sx)" pos="336 688" size="normal" stroke="darkblue"/>-<use name="mark/disk(sx)" pos="256 688" size="normal" stroke="darkblue"/>-<use name="mark/disk(sx)" pos="224 688" size="normal" stroke="darkblue"/>-</page>-</ipe>
− test/Data/Geometry/pointInTriangle.ipe
@@ -1,310 +0,0 @@-<?xml version="1.0"?>-<!DOCTYPE ipe SYSTEM "ipe.dtd">-<ipe version="70107" creator="Ipe 7.2.2">-<info created="D:20150923215046" modified="D:20180808120020"/>-<ipestyle name="basic">-<symbol name="arrow/arc(spx)">-<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/farc(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/ptarc(spx)">-<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">-0 0 m--1 0.333 l--0.8 0 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/fptarc(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--0.8 0 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="mark/circle(sx)" transformations="translations">-<path fill="sym-stroke">-0.6 0 0 0.6 0 0 e-0.4 0 0 0.4 0 0 e-</path>-</symbol>-<symbol name="mark/disk(sx)" transformations="translations">-<path fill="sym-stroke">-0.6 0 0 0.6 0 0 e-</path>-</symbol>-<symbol name="mark/fdisk(sfx)" transformations="translations">-<group>-<path fill="sym-fill">-0.5 0 0 0.5 0 0 e-</path>-<path fill="sym-stroke" fillrule="eofill">-0.6 0 0 0.6 0 0 e-0.4 0 0 0.4 0 0 e-</path>-</group>-</symbol>-<symbol name="mark/box(sx)" transformations="translations">-<path fill="sym-stroke" fillrule="eofill">--0.6 -0.6 m-0.6 -0.6 l-0.6 0.6 l--0.6 0.6 l-h--0.4 -0.4 m-0.4 -0.4 l-0.4 0.4 l--0.4 0.4 l-h-</path>-</symbol>-<symbol name="mark/square(sx)" transformations="translations">-<path fill="sym-stroke">--0.6 -0.6 m-0.6 -0.6 l-0.6 0.6 l--0.6 0.6 l-h-</path>-</symbol>-<symbol name="mark/fsquare(sfx)" transformations="translations">-<group>-<path fill="sym-fill">--0.5 -0.5 m-0.5 -0.5 l-0.5 0.5 l--0.5 0.5 l-h-</path>-<path fill="sym-stroke" fillrule="eofill">--0.6 -0.6 m-0.6 -0.6 l-0.6 0.6 l--0.6 0.6 l-h--0.4 -0.4 m-0.4 -0.4 l-0.4 0.4 l--0.4 0.4 l-h-</path>-</group>-</symbol>-<symbol name="mark/cross(sx)" transformations="translations">-<group>-<path fill="sym-stroke">--0.43 -0.57 m-0.57 0.43 l-0.43 0.57 l--0.57 -0.43 l-h-</path>-<path fill="sym-stroke">--0.43 0.57 m-0.57 -0.43 l-0.43 -0.57 l--0.57 0.43 l-h-</path>-</group>-</symbol>-<symbol name="arrow/fnormal(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/pointed(spx)">-<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">-0 0 m--1 0.333 l--0.8 0 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/fpointed(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--0.8 0 l--1 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/linear(spx)">-<path stroke="sym-stroke" pen="sym-pen">--1 0.333 m-0 0 l--1 -0.333 l-</path>-</symbol>-<symbol name="arrow/fdouble(spx)">-<path stroke="sym-stroke" fill="white" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h--1 0 m--2 0.333 l--2 -0.333 l-h-</path>-</symbol>-<symbol name="arrow/double(spx)">-<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">-0 0 m--1 0.333 l--1 -0.333 l-h--1 0 m--2 0.333 l--2 -0.333 l-h-</path>-</symbol>-<pen name="heavier" value="0.8"/>-<pen name="fat" value="1.2"/>-<pen name="ultrafat" value="2"/>-<symbolsize name="large" value="5"/>-<symbolsize name="small" value="2"/>-<symbolsize name="tiny" value="1.1"/>-<arrowsize name="large" value="10"/>-<arrowsize name="small" value="5"/>-<arrowsize name="tiny" value="3"/>-<color name="red" value="1 0 0"/>-<color name="green" value="0 1 0"/>-<color name="blue" value="0 0 1"/>-<color name="yellow" value="1 1 0"/>-<color name="orange" value="1 0.647 0"/>-<color name="gold" value="1 0.843 0"/>-<color name="purple" value="0.627 0.125 0.941"/>-<color name="gray" value="0.745"/>-<color name="brown" value="0.647 0.165 0.165"/>-<color name="navy" value="0 0 0.502"/>-<color name="pink" value="1 0.753 0.796"/>-<color name="seagreen" value="0.18 0.545 0.341"/>-<color name="turquoise" value="0.251 0.878 0.816"/>-<color name="violet" value="0.933 0.51 0.933"/>-<color name="darkblue" value="0 0 0.545"/>-<color name="darkcyan" value="0 0.545 0.545"/>-<color name="darkgray" value="0.663"/>-<color name="darkgreen" value="0 0.392 0"/>-<color name="darkmagenta" value="0.545 0 0.545"/>-<color name="darkorange" value="1 0.549 0"/>-<color name="darkred" value="0.545 0 0"/>-<color name="lightblue" value="0.678 0.847 0.902"/>-<color name="lightcyan" value="0.878 1 1"/>-<color name="lightgray" value="0.827"/>-<color name="lightgreen" value="0.565 0.933 0.565"/>-<color name="lightyellow" value="1 1 0.878"/>-<dashstyle name="dashed" value="[4] 0"/>-<dashstyle name="dotted" value="[1 3] 0"/>-<dashstyle name="dash dotted" value="[4 2 1 2] 0"/>-<dashstyle name="dash dot dotted" value="[4 2 1 2 1 2] 0"/>-<textsize name="large" value="\large"/>-<textsize name="Large" value="\Large"/>-<textsize name="LARGE" value="\LARGE"/>-<textsize name="huge" value="\huge"/>-<textsize name="Huge" value="\Huge"/>-<textsize name="small" value="\small"/>-<textsize name="footnote" value="\footnotesize"/>-<textsize name="tiny" value="\tiny"/>-<textstyle name="center" begin="\begin{center}" end="\end{center}"/>-<textstyle name="itemize" begin="\begin{itemize}" end="\end{itemize}"/>-<textstyle name="item" begin="\begin{itemize}\item{}" end="\end{itemize}"/>-<gridsize name="4 pts" value="4"/>-<gridsize name="8 pts (~3 mm)" value="8"/>-<gridsize name="16 pts (~6 mm)" value="16"/>-<gridsize name="32 pts (~12 mm)" value="32"/>-<gridsize name="10 pts (~3.5 mm)" value="10"/>-<gridsize name="20 pts (~7 mm)" value="20"/>-<gridsize name="14 pts (~5 mm)" value="14"/>-<gridsize name="28 pts (~10 mm)" value="28"/>-<gridsize name="56 pts (~20 mm)" value="56"/>-<anglesize name="90 deg" value="90"/>-<anglesize name="60 deg" value="60"/>-<anglesize name="45 deg" value="45"/>-<anglesize name="30 deg" value="30"/>-<anglesize name="22.5 deg" value="22.5"/>-<tiling name="falling" angle="-60" step="4" width="1"/>-<tiling name="rising" angle="30" step="4" width="1"/>-</ipestyle>-<ipestyle name="frank">-<arrowsize name="normal" value="5"/>-<arrowsize name="large" value="8"/>-<arrowsize name="huge" value="10"/>-<arrowsize name="small" value="3"/>-<arrowsize name="tiny" value="1"/>-<dashstyle name="dashed" value="[2 2] 0"/>-<dashstyle name="dotted" value="[0.5 1] 0"/>-<dashstyle name="dash dotted" value="[4 2 1 2] 0"/>-<dashstyle name="dash dot dotted" value="[4 2 1 2 1 2] 0"/>-<gridsize name="1 pts" value="1"/>-<gridsize name="2 pts" value="2"/>-<opacity name="10%" value="0.1"/>-<opacity name="30%" value="0.3"/>-<opacity name="50%" value="0.5"/>-<opacity name="20%" value="0.2"/>-<opacity name="40%" value="0.4"/>-<opacity name="60%" value="0.6"/>-<opacity name="70%" value="0.7"/>-<opacity name="80%" value="0.8"/>-<opacity name="90%" value="0.9"/>-</ipestyle>-<page>-<layer name="alpha"/>-<view layers="alpha" active="alpha"/>-<path layer="alpha" stroke="darkblue">-304 720 m-224 592 l-48 736 l-h-</path>-<use name="mark/disk(sx)" pos="128 704" size="normal" stroke="darkblue"/>-<use name="mark/disk(sx)" pos="192 672" size="normal" stroke="darkblue"/>-<use name="mark/disk(sx)" pos="192 720" size="normal" stroke="darkblue"/>-<use name="mark/box(sx)" pos="304 688" size="normal" stroke="black"/>-<use name="mark/cross(sx)" pos="352 736" size="normal" stroke="darkblue"/>-<use name="mark/cross(sx)" pos="352 704" size="normal" stroke="darkblue"/>-<path stroke="orange">-496 736 m-432 624 l-512 608 l-h-</path>-<use name="mark/box(sx)" pos="432 624" size="normal" stroke="orange"/>-<use name="mark/box(sx)" pos="512 608" size="normal" stroke="orange"/>-<use name="mark/box(sx)" pos="496 736" size="normal" stroke="orange"/>-<use name="mark/disk(sx)" pos="496 656" size="normal" stroke="orange"/>-<use name="mark/disk(sx)" pos="480 640" size="normal" stroke="orange"/>-<use name="mark/disk(sx)" pos="464 656" size="normal" stroke="orange"/>-<use name="mark/cross(sx)" pos="368 608" size="normal" stroke="orange"/>-<use name="mark/cross(sx)" pos="384 592" size="normal" stroke="orange"/>-<use name="mark/cross(sx)" pos="336 576" size="normal" stroke="orange"/>-<use name="mark/disk(sx)" pos="496 624" size="normal" stroke="orange"/>-<use name="mark/cross(sx)" pos="528 624" size="normal" stroke="orange"/>-<use name="mark/cross(sx)" pos="384 624" size="normal" stroke="orange"/>-<use name="mark/cross(sx)" pos="368 640" size="normal" stroke="orange"/>-<use name="mark/cross(sx)" pos="336 688" size="normal" stroke="darkblue"/>-<use name="mark/disk(sx)" pos="256 688" size="normal" stroke="darkblue"/>-<use name="mark/disk(sx)" pos="224 688" size="normal" stroke="darkblue"/>-</page>-</ipe>
− test/Data/PlaneGraph/myPlaneGraph.yaml
@@ -1,90 +0,0 @@-adjacencies:-- adj:- - - 4- - []- - - 2- - []- - - 1- - []- - - 3- - []- id: 0- loc:- - 0- - 0- vData:- - []- - []- - []- - []-- adj:- - - 2- - []- - - 3- - []- - - 0- - []- id: 1- loc:- - 10- - 10- vData:- - []- - []- - []-- adj:- - - 1- - []- - - 0- - []- - - 4- - []- id: 2- loc:- - 12- - 10- vData:- - []- - []- - []-- adj:- - - 0- - []- - - 1- - []- id: 3- loc:- - 13- - 20- vData:- - []- - []-- adj:- - - 2- - []- - - 0- - []- id: 4- loc:- - 20- - 5- vData:- - []- - []-faces:-- fData: []- incidentEdge:- - 0- - 4-- fData: []- incidentEdge:- - 0- - 2-- fData: []- incidentEdge:- - 0- - 1-- fData: []- incidentEdge:- - 0- - 3
− test/Data/PlaneGraph/small.yaml
@@ -1,58 +0,0 @@-ajacencies:-- adj:- - - 2- - 0->2- - - 1- - 0->1- - - 3- - 0->3- id: 0- loc:- - 0- - 0- vData: 0-- adj:- - - 0- - 1->0- - - 2- - 1->2- - - 3- - 1->3- id: 1- loc:- - 2- - 2- vData: 1-- adj:- - - 0- - 2->0- - - 1- - 2->1- id: 2- loc:- - 2- - 0- vData: 2-- adj:- - - 0- - 3->0- - - 1- - 3->1- id: 3- loc:- - -1- - 4- vData: 3-faces:-- fData: OuterFace- incidentEdge:- - 0- - 2-- fData: A- incidentEdge:- - 0- - 1-- fData: B- incidentEdge:- - 0- - 3
− test/Data/PlaneGraph/testsegs.png
binary file changed (56081 → absent bytes)