Giter VIP home page Giter VIP logo

noinia / hgeometry Goto Github PK

View Code? Open in Web Editor NEW
121.0 7.0 40.0 246.44 MB

HGeometry is a library for computing with geometric objects in Haskell. It defines basic geometric types and primitives, and it implements some geometric data structures and algorithms. The main two focusses are: (1) Strong type safety, and (2) implementations of geometric algorithms and data structures that have good asymptotic running time guarantees.

Haskell 99.81% Shell 0.03% HTML 0.17%
haskell geometric-algorithms computational-geometry geometry

hgeometry's Introduction

HGeometry

GitHub Workflow Status Hackage API docs coverage

HGeometry is a library for computing with geometric objects such as points, line segments, and polygons, in Haskell. It defines basic geometric types and primitive operations on these types (for example functions to test or compute the intersection of two line segments), and it implements some geometric data structures and algorithms. The main two focusses are:

  1. To provide idiomatic implementations of geometric algorithms and data structures that have good asymptotic running time guarantees, and
  2. Strong type safety.

Please note that first aspect --implementing good algorithms and data structures-- is much of a work in progress. Only a few algorithms have been implemented, and most likely they can use some improvements.

HGeometry Packages

HGeometry currently consists of three packages:

  • hgeometry-combinatorial,

    which defines the non-geometric (i.e. combinatorial) data types, data structures, and algorithms.

  • hgeometry,

    which defines the actual geometric algorithms and data structures, and

  • hgeometry-examples

    which defines some examples that showcase using hgeometry.

The hgeometry package itself actually consists of several libraries:

  • hgeometry

    The main library that defines the actual algorithms and data structures.

  • hgeometry:vector

    Defines length annotated Vector types and typeclasses. The hgeometry-point library depends on this.

  • hgeometry:point

    Defines types and typeclasses representing points in space, and basic operations on points.

  • hgeometry:kernel

    Defines other geometric "constant complexity" geometric types and primitives. For example lines, halfspaces, line segments, balls, circles, rectangles etc.

  • hgeometry:ipe

    Defines functions for reading, writing, and manipulating ipe files and the geometric objects therein.

  • hgeometry:svg

    Defines functions for writing the geometry types to svg files.

Examples

The hgeometry-examples provides some examples of using the library.

Available Geometric Algorithms and Data Structures

This is a brief overview of some of the main available algorithms in HGeometry. Refer to the haddocks for more details. HGeometry contains algorithms for computing

  • the convex hull of $n$ points in $\mathbb{R}^2$. In particular,

    • worst case optimal $O(n\log n)$ time implementations of Graham scan and Divide and Conquer,
    • an output sensitive $O(nh)$ time Jarvis March, and
    • a QuickHull implementation (which has worst case complexity $O(n^2)$ )

    Furtheremore, an optimal linear time algorithm for when the points are the vertices of a convex polygon.

  • the closest pair among $n$ points in $\mathbb{R}^2$

    • $O(n\log n)$ time using divide and conquer
  • the intersections among a set of $n$ line segments in $\mathbb{R}^2$.

    • The algorithm runs in $O((n+k)\log n)$ time, where $k$ is the output size.
    • Alternatively, one can of course also compute all intersections in $O(n^2)$ time (which may be better if $k$ is large).
  • the Minkowski sum of two convex polygons. The algorithm runs in optimal $O(n+m)$ time, where $n$ and $m$ are the sizes of the polygons.

  • if a point lies in a polygon. In particular,

    • in linear time for simple polygons, and
    • in $O(\log n)$ time for convex polygons.
  • tangents and extremal points in a polygon In particular,

    • in $O(\log n)$ time for convex polygons, and
    • in linear time in simple polygons.
  • a simplification of a polyline. In particular, an implementation of

    • the Imai-Iri algorithm, and
    • the well-known Douglas Peucker algorithm.

HGeometry also contains an implementation of some geometric data structures. In particular,

  • A one dimensional Interval Tree. The base tree is static.
  • A one dimensional Segment Tree. The base tree is static.

Avoiding Floating-point issues

All geometry types are parameterized by a numerical type r. It is well known that Floating-point arithmetic and Geometric algorithms don't go well together; 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 most algorithms it is sufficient if the type r is Fractional. Hence, you can use an exact number type such as Data.Ratio.Rational or HGeometry.Number.Real.Rational (which is essentially just a Rational with a friendlier Show instance).

Interval Arithmetic (to speed up our computations) is one of the things on the main things on the TODO list.

Working with additional data

In many applications we do not just have geometric data, e.g. Point d rs or Polygon rs, but instead, these types have some additional properties, like a color, size, thickness, elevation, or whatever. We use typeclasses to make sure it is easy to use the functions with custom geometric types that store such additional fields. For example, the 2d convex hull algorithms have type:

convexHull :: (Ord r, Num r, Point_ point 2 r) => NonEmpty point -> ConvexPolygon point

In many cases you may not want to explicitly declare a new specific point type, but just "attach" an additional value (e.g. a color) to a point. You may want to use the Ext type (typically seen as (:+) from Heometry.Ext in such cases.

Build Instructions

HGeometry heavily relies on typeclasses to support polymorphic inputs. Therefore, if you are using this package, it is recommended to compile your package with GHC options -fspecialise-aggressively -fexpose-all-unfoldings to make sure GHC sufficiently specializes the calls. You can do so by adding the following to your executable/library stanza in your cabal file:

    ghc-options: -fspecialise-aggressively -fexpose-all-unfoldings

Not doing so may significantly impact the performance of your compiled code.

hgeometry's People

Contributors

noinia avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

hgeometry's Issues

Error installing with cabal from hackage

Installing hgeometry 0.8.0.0 using cabal and install fails with

[98 of 98] Compiling Test.QuickCheck.HGeometryInstances ( src/Test/QuickCheck/HGeometryInstances.hs, dist/dist-sandbox-f9cfa1d8/build/Test/QuickCheck/HGeometryInstances.o )

src/Test/QuickCheck/HGeometryInstances.hs:109:58: error:
    Ambiguous occurrence ‘Negative’
    It could refer to either ‘PlanarGraph.Negative’,
                             imported from ‘Data.PlanarGraph’ at src/Test/QuickCheck/HGeometryInstances.hs:21:1-33
                             (and originally defined at src/Data/PlanarGraph.hs:139:18-25)
                          or ‘Test.QuickCheck.Negative’,
                             imported from ‘Test.QuickCheck’ at src/Test/QuickCheck/HGeometryInstances.hs:28:1-32
                             (and originally defined in ‘Test.QuickCheck.Modifiers’)
    |
109 |   arbitrary = (\b -> if b then PlanarGraph.Positive else Negative) <$> arbitrary
    |                                                          ^^^^^^^^

Question on dependent types / Illegal type: `2'

Hi,

I'm trying to write a rotation function with a signature like:

rotate2d :: Double -> Transformation 2 Double

but I keep running into errors like

Illegal type: `2' Perhaps you intended to use DataKinds

Illegal kind signature: `2'
      Perhaps you intended to use KindSignatures

and so on. I see that hgeometry supports Data.Geometry.Vector.Vector 2 r but what is the right way to write something similar for my transformation that works with hgeometry?

Thanks

Splitting Up Components

There seems to be a lot accumulating in this library.
Would it be possible to split out some of the components?
I'm willing to help with this

A few good reasons to do this are:

  • There are getting to be a lot of dependencies that take a long time to compile
  • Your typed Sequences seem very useful outside of this project
  • The unused code is making my containers larger and more costly to run
  • Modular readers and writers for different geometry file formats like Ipe, DXF, DWG, SVG

I would need some help figuring out where the project should be cut apart at. Here are some places I see right now:

  • src/Graphics
  • src/Algorithms/{BinaryTree,Graph}
  • src/Data/Geometry/Ipe
  • src/Data/*Seq.hs
  • src/Data/UnBounded
  • examples/
  • probably a few more

Let me know if this seems reasonable.

Better visual debugging

Debugging the algorithms is sometimes a bit of a hassle since the show instances are quite verbose. Ideally we would have some way of showing/rendering some image that shows the geometry in question. The best thing we have so far is to render ipe or svg images. But since those parts are now in separate packages, that is sometimes a bit cumbersome as well.

Ideally the user/developer can click points/polygons/segments to show whatever data is associated with them. I'm not sure what the best way is to implement any of that. I've fiddled a bit with miso (some web framework) and reflex-sdl before to try and build some interactive application to this end. But both seem a mountain of work, nor am I sure how/what I would want precisely.

Any thoughts on how we could improve the situation?

Remove IPE from Tests

I have noticed that a lot of tests are dependent on .ipe data files. There seems to be nothing special about the data that couldn't be in the haskell test files. I propose having the data converted to the proper haskell geometry data type and placed in the correct test file.

This is a good idea because:

  • it removes the dependence on the Ipe modules
  • it the data file is changed the test will not be broken.

Orphan Instances Arbitrary

Would there be an advantage to declaring the Arbitrary instances from Test.QuickCheck.HGeometryInstances in the files that the types are declared in?

Comprehensive feature wishlist / brain dump.

Algorithms:

Infrastructure:

Test properties:

  • read . show == id for Point. Implemented in #64
  • read . show == id for Vector.
  • read . show == id for RealNumber. Add QC tests.
  • read . show == id for SimplePolygon and MultiPolygon. Implemented in #51
  • area p == area (connectHoles p)
  • connectHoles p doesn't add any self-intersections. Check with BentleyOttmann in O(n log n).
  • area p == sum (map area (triangulate p)) Implemented in #51
  • area p <= area (convexHull p)
  • extremes == extremesLinear. Implemented in #69

Library:

  • Don't use CircularSeq in Algorithms.Geometry.Tangents.Tangents.
  • Implement Data.Ext as a zero cost type family.
  • Inforced CCW vertex order in all polygons. Implemented in #52
  • O(1) vertex indexing in SimplePolygon. Implemented in #53
  • O(1) vertex indexing in MultiPolygon.
  • Safe constructor for SimplePolygon. Implemented in #74
  • Consistent Big-O notation. Implemented in #82
  • Bezier curve intersection. See bezier clipping and De Casteljau's algorithm. Copy code (BSD3) from cubicbezier.
    Finding exact intersections is hard. This is how they do it in CGAL: http://acg.cs.tau.ac.il/copy_of_projects/in-house-projects/arrangements-of-bezier-curves/p253-hanniel.pdf
    This way may be easier: https://cs.nyu.edu/exact/doc/subdiv1.pdf
    Geez, bezier intersection is hard: https://arxiv.org/pdf/2009.00811.pdf
    Bezier intersection is way too difficult. Much easier to linearise the curves and use normal line-segment intersection.
  • Bezier boolean operations: union, intersection, difference, exclusion.
  • Read/Write support for mesh file-formats. See meshio. Hm, maybe we only need support for WKT.

Branding:

  • hgeometry organization.
  • website on hgeometry.github.io and hgeometry.org/.com.
  • Benchmark against CGAL.

Incredible overview of Computation Geometry: Visibility Algorithms In The Plane

Another good overview: https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.48.2190&rep=rep1&type=pdf

Overview of intersection algorithms: https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.63.2041&rep=rep1&type=pdf

Handbook of Discrete and Computational Geometry: http://www.csun.edu/~ctoth/Handbook/HDCG3.html

PhD about numerical errors: https://tel.archives-ouvertes.fr/tel-03116750/document

linear package version

linear >= 1.20.8
seems too low coming from
hgeometry-combinatorial which imports unavailable
import Linear.Matrix (luSolve)

hgeometry-core

I'm working on extracting the core geometric types
https://github.com/BebeSparkelSparkel/hgeometry/tree/extract-core

I think the below belong in core

  • Boundary
  • Box
  • HalfLine
  • HyperPlane
  • Interval
  • Line
  • Point
  • PolyLine
  • Polygon
  • Properties.hs
  • SegmentTree.hs
  • SubLine
  • Transformation
  • Triangle
  • Vector

I am unsure if the below belong in core:

  • Slab
  • SegmentTree
  • KDTree
  • IntervalTree
  • Envelope
  • Duality
  • Arrangement
    • Not sure what to do with src/Data/Geometry/Arrangement since it depends on Data.Geometry.PlanarSubdivision. I don't think that PlanarSubdivision belongs in core, but let me know what you think.

hgeometry-combinatorial 0.12.0.1: doctests fail

This is the log. Looks like some kind of GHC bug actually, maybe someone else can make sense of this.
If you can't reproduce the failure exactly, I can check which precise build flags are used, this might be due
to enabled profiling.

src/Data/Double/Shaman.hs:23: failure in expression `sin pi == (0 :: SDouble 0)'
expected: *** Exception: Insufficient precision.
          ...
 but got: ghc: ^^ Could not load 'erf_log', dependency unresolved. See top entry above.
          ^


          ByteCodeLink: can't find label
          During interactive linking, GHCi couldn't find the following symbol:
            erf_log
          This may be due to you not asking GHCi to load extra object files,
          archives or DLLs needed by your current session.  Restart GHCi, specifying
          the missing library using the -L/path/to/object/dir and -lmissinglibname
          flags, or simply by naming the relevant files on the GHCi command line.
          Alternatively, this link failure might indicate a bug in GHCi.
          If you suspect the latter, please report this as a GHC bug:
            https://www.haskell.org/ghc/reportabug


src/Data/Double/Shaman.hs:82: failure in expression `significativeDigits 1'
expected: Infinity
 but got: ghc: ^^ Could not load 'erf_log', dependency unresolved. See top entry above.
          ^


          ByteCodeLink: can't find label
          During interactive linking, GHCi couldn't find the following symbol:
            erf_log
          This may be due to you not asking GHCi to load extra object files,
          archives or DLLs needed by your current session.  Restart GHCi, specifying
          the missing library using the -L/path/to/object/dir and -lmissinglibname
          flags, or simply by naming the relevant files on the GHCi command line.
          Alternatively, this link failure might indicate a bug in GHCi.
          If you suspect the latter, please report this as a GHC bug:
            https://www.haskell.org/ghc/reportabug

sqDistancetoArg

When I use sqDistanceToArg one of the points returned is not on the boundary of the polygon.

> let poly :: SimplePolygon () Rational; poly = (fromPoints . map ext) [point2 61 1500, point2 89 2200, point2 82.5 2200, point2 68 1950, point2 52.5 1500] in sqDistanceToArg (point2 70 2100) . supportingLine <$> outerBoundaryEdges poly
CSeq [(140625 % 626,Point2 [53195 % 626,1314225 % 626]),(10000 % 1,Point2 [70 % 1,2200 % 1]),(11222500 % 250841,Point2 [19233870 % 250841,526668950 % 250841]),(8122500 % 810961,Point2 [59332270 % 810961,1702929750 % 810961]),(360000 % 1,Point2 [70 % 1,1500 % 1])]

The point Point2 [70 % 1,1500 % 1] is not within the polygon, yet it is returned as the nearest point on a line.

Is this a bug?

use faster sorting algorithms?

See if switching to the sorting algorithms from vector-algorithms (over the merge-sort based List.sort) improves results on say convex hull, polygon triangulation etc.

Shorter module names.

Some module names are quite long (such as Algorithms.Geometry.WellSeparatedPairDecomposition.WSPD) and we're not being too consistent with the naming schemes. Sometimes we use an abbreviation (like Algorithms.Geometry.SoS and Algorithms.Geometry.EuclideanMST) and other times we write out the name in full. I suggest we use abbreviations when possible and also use more general groupings (eg. rename PolygonTriangulation to just Triangulation).

Specific changes I'm proposing:

  • Rename PolygonTriangulation to Triangulation.
  • Rename WellSeparatedPairDecomposition to WSPD (make it re-export Algorithms.Geometry.WellSeparatedPairDecomposition.WSPD and Algorithms.Geometry.WellSeparatedPairDecomposition.Types).
  • Rename LineSegmentIntersection to Intersection.
  • Rename PolyLineSimplification to Simplification.
  • Rename DelaunayTriangulation to Delaunay.
  • Rename Algorithms.Geometry.EuclideanMST.EuclideanMST to Algorithms.Geometry.EuclideanMST.

I'd also like to merge all of Algorithm.Geometry.PolygonTriangulation.* into Algorithm.Geometry.Triangulation.Monotone. Then Algorithm.Geometry.Triangulation should re-export a general triangulation function.

Deprecation schedule: I suggest we mark the old modules as deprecated and schedule them for removal in six months.

What do you think, @noinia?

[Feature request] More Box/Rectangle operations?

For working with Boxes / Rectangles, it might make sense to have concepts splitting a rectangle into 2, 4, or 9 subrectangles, and having concepts such as West/East, North/South, NorthWest, NorthEast, SouthWest, SouthEast, Center.

Wrong result from inPolygon when used with Double values

Hi,

using the inPolygon function with Double values sometimes returns wrong results while working correctly with (presumably) Integral values:

>>> (Point2 340000 5700000) `inPolygon` fromPoints [Point2 334882 5689376 :+ (), Point2 334882 5714648 :+ (), Point2 348981 5714648 :+ (), Point2 348981 5689376 :+ ()]
Inside -- OK
>>> (Point2 340000 5700000) `inPolygon` fromPoints [Point2 334882.785 5689376.404 :+ (), Point2 334882.785 5714648.124 :+ (), Point2 348981.954 5714648.124 :+ (), Point2 348981.954 5689376.404 :+ ()]
Outside -- Should be Inside!

Am I doing something wrong or is this a bug?

Thanks,
Martin

Delaunay triangulation

Hello. Im doing delaunay with random points in rational domain.
It works with 4 points. But with more points It mostly throws errors.
I also tried to do toPlaneGraph instead of toPlanarSubdivision and there are no errors
but the results does not seem correct (as if most of the points were ignored)
Tried both Naive and Dividie.
Ages ago I've reported problems with mutli polygon triangulation. Maybe that's similar problem.
Polygon triangulation works great for me so far with some pretty complex stuff I've thrown at it.

21> pointCount = 8
22> rvs <- replicateM pointCount (randomRIO (Point2 (-300) (-300), Point2 300 300))
23> ne = NE.fromList (ext . fmap (%(1::Integer)) <$> rvs)
24> trian = G.toPlanarSubdivision (Proxy :: Proxy ()) $ G.delaunayTriangulation ne
25> print (G.rawFacePolygons trian)
[(FaceId 1,Left SimplePolygon [Point2 (215 % 1) (242 % 1) :+ (),Point2 (127 % 1) (143 % 1) :+ (),Point2 (61 % 1) ((-84) % 1) :+ (),Point2 (217 % 1) ((-85) % 1) :+ (),Point2 (127 % 1) (143 % 1) :+ (),Point2 (215 % 1) (242 % 1) :+ (),Point2 (217 % 1) ((-85) % 1) :+ (),Point2 ((-40) % 1) ((-180) % 1) :+ (),Point2 ((-244) % 1) ((-202) % 1) :+ (),Point2 ((-278) % 1) (288 % 1) :+ ()] :+ ()),(FaceId 2,Left SimplePolygon [Point2 ((-244) % 1) ((-202) % 1) :+ (),Point2 ((-34) % 1) (2 % 1) :+ (),Point2 ((-40) % 1) ((-180) % 1) :+ (),Point2 (61 % 1) ((-84) % 1) :+ (),Point2 ((-34) % 1) (2 % 1) :+ (),Point2 ((-244) % 1) ((-202) % 1) :+ (),Point2 ((-40) % 1) ((-180) % 1) :+ (),Point2 ((-34) % 1) (2 % 1) :+ (),Point2 ((-278) % 1) (288 % 1) :+ ()] :+ ()),(FaceId 3,Left SimplePolygon [Point2 ((-34) % 1) (2 % 1) :+ (),Point2 (127 % 1) (143 % 1) :+ (),Point2 ((-278) % 1) (288 % 1) :+ ()] :+ ()),(FaceId 4,Left SimplePolygon [Point2 (217 % 1) ((-85) % 1) :+ (),Point2 (61 % 1) ((-84) % 1) :+ (),Point2 ((-40) % 1) ((-180) % 1) :+ ()] :+ ()),(FaceId 5,Left SimplePolygon [Point2 (61 % 1) ((-84) % 1) :+ (),Point2 (127 % 1) (143 % 1) :+ (),Point2 ((-34) % 1) (2 % 1) :+ ()] :+ ()),(FaceId 6,Left SimplePolygon *** Exception: (^?!): empty Fold
CallStack (from HasCallStack):
error, called at src/Control/Lens/Fold.hs:1310:28 in lens-4.18.1-IMnU2TgTkGFCqXrge7lTNW:Control.Lens.Fold
^?!, called at src/Data/PlanarGraph/Core.hs:435:32 in hgeometry-combinatorial-0.12.0.3-6MKt1QLJ2g4KHrJMCKbN5l:Data.PlanarGraph.Core

LineSegment Circle intersection

Hi.
Im trying to do some intersections.

45> circle = Ball.Circle (ext $ Point2 0 0) (1::Double)
46> segment r x = LineSegment (Closed . ext $ (Point2 0 0)) (Closed . ext $ (Point2 (r * cos x) (r * sin x)))
47> Data.Intersection.intersect (segment 1.0 (0.1::Double)) circle
{|Point2 0.9950041652780258 9.983341664682815e-2|}
48> Data.Intersection.intersect (segment 1.1 (0.1::Double)) circle
{|NoIntersection|}
49> Data.Intersection.intersect (segment 1.2 (0.1::Double)) circle
{|NoIntersection|}
50> Data.Intersection.intersect (segment 1.4 (0.1::Double)) circle
{|Point2 0.9950041652780258 9.983341664682815e-2|}
51> Data.Intersection.intersect (segment 1.5 (0.1::Double)) circle
{|Point2 0.9950041652780258 9.983341664682815e-2|}
52> Data.Intersection.intersect (segment 1.6 (0.1::Double)) circle
{|NoIntersection|}

0.12 release checklist

What should be done before releasing 0.12 of geometry?

  • Enumerate all exports.
  • Consistent Big-O haddock notation.
  • Finish https://hgeometry.org/ and add at least one video showcase.
  • update the readme to include the new algorithms, and maybe we should advocate Data.RealNumber.Rational a bit more
  • Merge the visibility polygon stuff ( since that actually includes some changes to the primitives as well)
  • Fix building the automatic documentation generating thing; seems that https://noinia.github.io/hgeometry/doc/ yields a 404 now?
  • make sure the hgeometry-examples build (we may want to add these to the CI) [1]

Connect Holes discussion

CGAL has an implementation of connect holes that cut straight up from each hole to the nearest wall.

I'd like to add something like:

connectHoles :: (Ord r, Num r, Fractional r) => MultiPolygon p r -> SimplePolygon () r
connectHoles = connectHolesLinear (Vector2 0 1)
connectHolesLinear :: (Ord r, Num r, Fractional r) => Vector 2 r -> MultiPolygon p r -> SimplePolygon () r

Those functions connect the maximum extreme point (given by the vector) of each hole in a straight line. The extra data p is lost, though, since cutting adds new nodes rather than just new edges.

Are there other algorithms for cutting out holes? Perhaps a faster algorithm if the polygon has been triangulated? Is there an efficient way of making the shortest cuts possible? Is there an efficient way of cutting out holes without adding new nodes?

Unboxed polygons.

The current representation of polygons as boxed vectors of points with extra data is very inefficient. A SimplePolygon () (Point 2 Double) requires 11 words of memory per element. That's 11*8=88 bytes per vertex. For such a polygon, storing the vertices as two unboxed arrays would reduce the memory requirements to 2 words per vertex. That's an improvement of 5.5x.

Matters get worse when Rational is used instead of Double. Looking at SimplePolygon () (Point 2 Rational), it requires 61 words per vertex. Assuming no sharing, a polygon with 1000 vertices would require ~0.5MiB of memory. If we stored Rationals as vectors of numerators and denominators, the memory overhead is reduced to 8 words per vertex; an improvement of ~7.5x.

Ok, so boxing is definitely a problem but what can we do about it? One option is to use unboxed arrays and require that all points and associated data must be an instance of Data.Vector.Unboxed.Unbox. Even if we wrote an instance for Unbox Rational, this would be painful. It would put a large burden on the user to only use unboxable numbers and associated data.

There's a second option that offers a middle ground. It allows us to mix unboxed and boxed types, picking optimized representations when possible and defaulting to boxed vectors when there are no better options.
The idea is very similar to how VectorFamilyF picks an optimal representation for d < 5 and then defaults to vector. Going down this path would add a constraint (eg Unpack r => ) to fromPoints and to the PointFunctor class. We would also have to delete the Functor, Bifunctor, Bifoldable, and Bitraversable instances. We'll still export the functions used by those instances but they'll have the constraint Unpack r.

You might ask, how is the Unpack r constraint any better than the Unbox r? Well, Unpack r is defined for all types. It'll use an unboxed representation for types like Double, Rational, (a,b), Point 2 r, etc. And it'll use a boxed representation for anything else like a -> b, [a], etc. The user will never have to write an instance of Unpack. In fact, it's not possible to add an instance to the type-class.

So, to recap: Boxed polygons use between 5 to 7 times more memory than unboxed polygons. We can force the use of unboxed types via Data.Vector.Unboxed. This prevents users from using boxed types in polygons.
My proposed solution: Use a closed-world type family to select unboxed vectors for primitive types and gracefully default to boxed vectors for all other types.

Benefits:

  • Dramatically lower memory overhead.
  • Runtimes of all algorithms should improve by a constant factor.
  • Data.Ext adds zero memory overhead.
  • Since points and meta data are stored in separate vectors, they can be modified separately. For example, dropMetadata :: Polygon t p r -> Polygon t () r will become O(1). Similarly, numberVertices won't have to read&write all the vertices, it just adds a new vector with vertex numbers.

Drawbacks:

  • Adds Unpack constraints to a lot of functions (but not all functions).
  • Functor, Bifunctor, Bifoldable, and Bitraversable will no longer be available.
  • Functions like convexPolygon will no longer benefit from sharing points.

What are your thoughts, @noinia? I'll write up a draft PR so we'll have something concrete to look at.

Github Actions CI

The CI setup with travis doesn't report back to github and that makes it difficult to see if PRs are passing or not. Would you (@noinia) be okay with also using Github Actions to build and run the test suite? I'd be willing to maintain it.

Data.Geometry.CircularSeq.isShiftOf algorithm

Is the Data.Geometry.CircularSeq.isShiftOf algorithm correct? For example:

c1 :: CSeq Int
c1 = fromList [1, 2, 1, 3]

c2 :: CSeq Int
c2 = rotateNL 2 c1

isShiftOf c1 c2
False

In:

-- | Test if the circular list is a cyclic shift of the second list.
-- Running time: O(n), where n is the size of the smallest list
isShiftOf         :: Eq a => CSeq a -> CSeq a -> Bool
xs `isShiftOf` ys = let rest = tail . F.toList . leftElements
                    in maybe False (\xs' -> rest xs' == rest ys) $
                       rotateTo (focus ys) xs

This seems to me to assume that if the focus of ys is in xs, then it is unique in xs.

Documentation on readthedocs.io

readthedocs.io hosts documentation written in markdown for free. I think it would be a good fit for documentation that goes beyond haddock.

@noinia I can configure it with github hooks if you add me as a collaborator.

Problem and questions about LineArrangement

I am currently trying to port some code I played with from Python that used CGAL bindings to Haskell and it looks like HGeometry has the algorithms I need, which are computing Line Arrangements and Convex Hulls.

import Linear.V2
import qualified Data.Geometry as HG 
import qualified Data.Geometry.Arrangement as HG
import Data.Proxy
import Data.Ext

segToHGLine (V2 x1 y1, V2 x2 y2) = HG.lineThrough (HG.Point2 x1 y1) (HG.Point2 x2 y2)

box = [((V2 0 0),(V2 0 1))
      ,((V2 0 1),(V2 1 1))
      ,((V2 1 1),(V2 1 0))
      ,((V2 1 0),(V2 0 0))
      ,((V2 0 0),(V2 1 1))
      ,((V2 1 0),(V2 0 1))
      ]
arr = HG.constructArrangement (Proxy :: Proxy ()) $ map ((:+ ()) . segToHGLine) box

Now this ends with an error "link: fromJust" when evaluating _unboundedIntersections in GHCI.

  1. Am I doing something wrong or is this a bug? I would have expected to get an arrangement that in some way contains the 4 triangles inside the box.

  2. What would be the easiest way to extract the polygons (as sequence of points) of the arrangement?

  3. With the CGAL bindings I could use line segments for arrangements. It does not look to me that this is possible with HGeometry yet, is this correct? Should I just use constructArrangementInBox with a sufficiently tight box that excludes intersections outside of the regions that I care for, as a workaround for the lacking support for segments?

Thanks in advance!

DelaunayTriangulation.DivideAndConquer sometimes loops forever/gets stuck

I’ve been working on a little project that uses hgeometry, and so far I’m loving the library. In using it, however, I’ve found some circumstances where the divide-and-conquer algorithm for Delaunay triangulation loops infinitely, such as when given these points:

Point2 [217.44781269876754,249.24741543498274] :+ 'a'
Point2 [237.91428506927295,105.8082929316906] :+ 'b'
Point2 [51.46936876163245,193.21960885915342] :+ 'c'
Point2 [172.55365082143922,2.8346743864823387] :+ 'd'
Point2 [250.55083565080437,93.13205719006257] :+ ‘e’

To reproduce:

  • git clone [email protected]:patrickt/voronoid.git
  • git checkout a2d95e00f4774b19b03c640442d7c52d3f871c49
  • cabal new-build
  • cabal new-run

Approximately 75% of the time, this will loop infinitely (or at least for a very long time). If it doesn’t, run it a few times.

I ran some profiling tests, and it appears to be stuck in Data.Geometry.Ball.disk. I’m new to the codebase so I wasn’t able to debug any further. For the time being I’m using the Naive module, which is good enough for my purposes, but I figured you’d want a bug report.

voronoid.prof.txt

Bug in 'maxInDirection'.

convexP :: ConvexPolygon () Rational
convexP = ConvexPolygon $ fromPoints $ map ext
  [Point2 4 3
  ,Point2 5 4
  ,Point2 6 5
  ,Point2 3 5
  ,Point2 1 4
  ]
direction :: Vector 2 Rational
direction = Vector2 (-1) (-1)
λ> maxInDirection direction convexP
*** Exception: isUpwards: no edge endpoint
CallStack (from HasCallStack):
  error, called at src/Data/Geometry/Polygon/Convex.hs:175:37 in hgeometry-0.11.0.0-inplace:Data.Geometry.Polygon.Convex

Found this after adding a quickcheck test for extremes.

Single source shortest path

I'd like to add implementation of the single source shortest path for simple polygons. This requires the dual of the triangulation of the polygon, though. I see that PlanarGraphs have a dual function but I'm at a loss of how to use it. Am I on the right path or should I compute the dual myself? Also, the difference between PlanarGraph and PlaneGraph. Is PlaneGraph a convenience wrapper around PlanarGraph?

stack.yaml versions

Does there really need to be different stack.yaml files for the different ghc versions?

Beginner-friendly tasks

1. Random, monotone polygons.

Done! PR: #95. Thank you @1ndy!

2. Ray-casting visibility polygon.

What?

Imagine that the edges of a polygon represents the walls of a room seen top-down. Standing at some point inside of the room, how much can you see and how much is obscured? The area you can see is called the "visibility polygon."

There are many advanced algorithms for computing the visibility polygon but we'll focus on the simplest, brute-force solution and solve the problem in O(n^2) time. This slow solution will be instrumental in writing and testing faster solutions.

How?

By shooting rays from a point of origin through each vertex, we'll know which edges are entirely visible, entirely obscured, or partially visible. The algorithm is described on Wikipedia.

Tests?

Pick a random point inside a random polygon and generate the visibility polygon. Now pick a second random point on the boundary of the original polygon. Draw a line between the two points and count the intersections. If there are no intersections, the second point must be in the visibility polygon. If there are intersections, the second point must not be in the visibility polygon.

Type signatures:

The final module should look something like this:

visibility :: SimplePolygon p r -> Point 2 r -> SimplePolygon () r

3. SSSP visibility polygon.

What?

Computing the visibility polygon from a corner is much easier than from an arbitrary point inside a polygon.

How?

HGeometry already has code for computing the single-source shortest-path tree. This SSSP tree can tell use which corners are occluded and, if so, which corner is occluding them. Shooting a ray from the point of origin through the occluding vertex can tell us how much of an edge is occluded.

The algorithm is explained exhaustively in this paper on page 218: https://doi.org/10.1007/BF01840360
The paper can be found for free on sci-hub.

There's a Haskell implementation available here: https://github.com/reanimate/reanimate/blob/5795a59d4481e5b506210cdf16ed9adec62f0ebf/src/Reanimate/Math/Polygon.hs#L704
It could serve as a good starting point.

Tests?

Same as in task 2 except we're only picking points from the polygon boundary.

Type signatures:

The final module should look something like this:

visibility :: SSSP -> SimplePolygon p r -> SimplePolygon p r

4. Pick a random point in polygon.

What?

It is often useful to uniformly sample points inside a polygon. This can be used for testing or when generating showcase animations.

How?

Sampling a random point from a triangle is quite simple. Polygons are more complex but, fortunately, we can reduce any polygon to a list of triangles. Picking a random point from a random triangle is close to being correct but it would favor small triangles over bigger triangles. We can correct for this by selecting larger triangles more frequently.

So, the algorithm would look like this:

  1. Break the polygon down into triangles.
  2. Assign a frequency to each triangle. The frequency is the area of the triangle over the area of the polygon. See fromList in MonadRandom: https://hackage.haskell.org/package/MonadRandom-0.1.3/docs/Control-Monad-Random.html
  3. Pick a triangle from the list.
  4. Sample a random point from the triangle.

Hint 1: TriangulateSpec.hs:31 has a function for splitting a polygon into triangles.
Hint 2: Neat way of uniformly sampling a triangle: https://jsfiddle.net/96fw5x8p/1/

For extra credit: Use a finger tree to sample uniformly in O(log n) rather than in O(n).

Tests?

Any randomly sampled point should be inside the polygon or on the border.

Type signatures:

The final functions should look something like this:

-- | O(n log n)
samplePolygon :: (RandomGen g, Random r, Fractional r) => Polygon t p r -> Rand g (Point 2 r)
-- | O(n) sampleConvex is optional.
sampleConvex :: (RandomGen g, Random r, Fractional r) => ConvexPolygon p r -> Rand g (Point 2 r)
-- | O(1)
sampleTriangle :: (RandomGen g, Random r, Fractional r) => Triangle 2 p r -> Rand g (Point 2 r)

-- | O(n log n)
toTriangles :: (Fractional r, Ord r) => Polygon t p r -> [Triangle 2 p r]

Separate testing for intersections from computing the actual intersections

I think I will want to move the 'intersect' function from the IsIntersectableWith class into its own 'HasIntersectionWith' class or so. As we saw recently, sometimes checking if segments intersect is easier (e.g. requires fewer constraints) than figuring out where those intersections are exactly. That is currently impossible to encode. Also, for "complicated" geometric shapes there may be many possible ways in which geometric objects intersect (including all sorts of degenerate situations). This way we can still concisely express that we can check for intersections (but maybe not bother listing all possible scenarios).

nextIncidentEdge on planar subdivisions

Update the docs for nextIncidentEdge, since it is apparently somewhat ambiguous what it is supposed to return. Moreover, given a dart d=u->v, it actually seems to return an edge incident to u rather than v.

0.5.1.0

Can we publish 0.5.1.0 to hackage?

Update to 8.4.1 and release?

The semigroup-monoid changes mean that this no longer compiles with new base. It would be nice to do a new release that was 8.4.1 compatible.

Release 0.12.0.2

Hi @noinia. Could you upload hgeometry-0.12.0.2 to hackage from the stable-0.12 branch? It moves a test-related executable to the hgeometry-test package which is required by stackage. Thanks.

hgeometry-ipe-0.11.0.0 fails to compile from Hackage

When attempting to build hgeometry-ipe-0.11.0.0 with GHC 8.8.4, it fails with the following errors:

$ cabal repl -b hgeometry-ipe -w /opt/ghc/8.8.4/bin/ghc
Resolving dependencies...
Build profile: -w ghc-8.8.4 -O1
In order, the following will be built (use -v for more details):
 - hgeometry-ipe-0.11.0.0 (lib) (requires build)
 - fake-package-0 (lib) (first run)
Starting     hgeometry-ipe-0.11.0.0 (lib)
Building     hgeometry-ipe-0.11.0.0 (lib)

Failed to build hgeometry-ipe-0.11.0.0.
Build log (
/home/ryanglscott/.cabal/logs/ghc-8.8.4/hgeometry-ipe-0.11.0.0-75e38cac99cded5c4995ee435cf7b5f129a87dd0c3eeaa413443b7664fde0190.log
):
Configuring library for hgeometry-ipe-0.11.0.0..
Preprocessing library for hgeometry-ipe-0.11.0.0..
Building library for hgeometry-ipe-0.11.0.0..
[ 1 of 22] Compiling Data.Geometry.Ipe.Layer ( src/Data/Geometry/Ipe/Layer.hs, dist/build/Data/Geometry/Ipe/Layer.o )
[ 2 of 22] Compiling Data.Geometry.Ipe.Literal ( src/Data/Geometry/Ipe/Literal.hs, dist/build/Data/Geometry/Ipe/Literal.o )
[ 3 of 22] Compiling Data.Geometry.Ipe.ParserPrimitives ( src/Data/Geometry/Ipe/ParserPrimitives.hs, dist/build/Data/Geometry/Ipe/ParserPrimitives.o )
[ 4 of 22] Compiling Data.Geometry.Ipe.Path ( src/Data/Geometry/Ipe/Path.hs, dist/build/Data/Geometry/Ipe/Path.o )
[ 5 of 22] Compiling Data.Geometry.Ipe.PathParser ( src/Data/Geometry/Ipe/PathParser.hs, dist/build/Data/Geometry/Ipe/PathParser.o )
[ 6 of 22] Compiling Data.Geometry.Ipe.Value ( src/Data/Geometry/Ipe/Value.hs, dist/build/Data/Geometry/Ipe/Value.o )
[ 7 of 22] Compiling Data.Geometry.Ipe.Color ( src/Data/Geometry/Ipe/Color.hs, dist/build/Data/Geometry/Ipe/Color.o )
[ 8 of 22] Compiling Data.Geometry.Ipe.Attributes ( src/Data/Geometry/Ipe/Attributes.hs, dist/build/Data/Geometry/Ipe/Attributes.o )
[ 9 of 22] Compiling Data.Geometry.Ipe.Content ( src/Data/Geometry/Ipe/Content.hs, dist/build/Data/Geometry/Ipe/Content.o )
[10 of 22] Compiling Data.Geometry.Ipe.Types ( src/Data/Geometry/Ipe/Types.hs, dist/build/Data/Geometry/Ipe/Types.o )
[11 of 22] Compiling Data.Geometry.Ipe.Matrix ( src/Data/Geometry/Ipe/Matrix.hs, dist/build/Data/Geometry/Ipe/Matrix.o )
[12 of 22] Compiling Data.Geometry.Ipe.Reader ( src/Data/Geometry/Ipe/Reader.hs, dist/build/Data/Geometry/Ipe/Reader.o )
[13 of 22] Compiling Data.Geometry.Ipe.FromIpe ( src/Data/Geometry/Ipe/FromIpe.hs, dist/build/Data/Geometry/Ipe/FromIpe.o )

src/Data/Geometry/Ipe/FromIpe.hs:1:1: error:
    solveWanteds: too many iterations (limit = 4)
      Unsolved: WC {wc_simple =
                      [W] $dImplicitPeano_a2MZF {2}:: Data.Geometry.Vector.VectorFamilyPeano.ImplicitPeano
                                                        s0 (CDictCan)
                      [WD] $dImplicitPeano_a2MZG {0}:: Data.Geometry.Vector.VectorFamilyPeano.ImplicitPeano
                                                         s0 (CDictCan)
                      [W] $dOrd_a2MZH {0}:: Ord s0 (CDictCan)
                      [D] _ {1}:: Ord extra0 (CDictCan(psc))
                      [D] _ {1}:: Ord (point0 d0 a0) (CDictCan(psc))
                      [WD] $dTraversable_a2LCY {0}:: Traversable
                                                       (Polygon 'Simple ()) (CDictCan)
                      [WD] $dAsAPoint_a2LDk {0}:: hgeometry-0.12.0.1:Data.Geometry.Point.Class.AsAPoint
                                                    point0 (CDictCan)
                      [W] $dIsBoxable_a2LEN {0}:: IsBoxable r (CDictCan)
                      [D] _ {1}:: IsBoxable (point0 d0 a0) (CDictCan)
                      [WD] $dArityPeano_a2MZI {0}:: Data.Vector.Fixed.Cont.ArityPeano
                                                      s0 (CDictCan)
                      [W] $dArityPeano_a2MZJ {3}:: Data.Vector.Fixed.Cont.ArityPeano
                                                     s0 (CDictCan)
                      [W] $dKnownNat_a2MZK {1}:: GHC.TypeNats.KnownNat s0 (CDictCan)
                      [WD] $dKnownNat_a2LDg {0}:: GHC.TypeNats.KnownNat d0 (CDictCan)
                      [WD] $dKnownNat_a2MZL {0}:: GHC.TypeNats.KnownNat s0 (CDictCan)
                      [W] $dKnownNat_a2MZM {3}:: GHC.TypeNats.KnownNat s0 (CDictCan)
                      [WD] $dEq_a2LDd {0}:: Eq a0 (CDictCan)
                      [D] _ {1}:: Eq extra0 (CDictCan)
                      [D] _ {1}:: Eq (point0 d0 a0) (CDictCan)
                      [D] _ {8}:: s0
                                  ~ 'Data.Vector.Fixed.Cont.S
                                      ('Data.Vector.Fixed.Cont.S
                                         'Data.Vector.Fixed.Cont.Z) (CNonCanonical)
                      [D] _ {6}:: s0 ~ 2 (CNonCanonical)
                      [D] _ {0}:: s0 ~ (point0 d0 a0 :+ extra0) (CNonCanonical)
                      [WD] hole{co_a2MZC} {6}:: s0 ~ 2 (CNonCanonical)
                      [WD] hole{co_a2MZt} {9}:: s0
                                                ~ 'Data.Vector.Fixed.Cont.S s1 (CNonCanonical)
                      [D] _ {4}:: s0 ~ (point0 d0 a0 :+ extra0) (CNonCanonical)
                      [W] hole{co_a2MZk} {6}:: s0 ~ r (CNonCanonical)
                      [WD] hole{co_a2MZe} {6}:: s0 ~ 'True (CNonCanonical)
                      [D] _ {6}:: s0
                                  ~ 'Data.Vector.Fixed.Cont.S
                                      ('Data.Vector.Fixed.Cont.S
                                         'Data.Vector.Fixed.Cont.Z) (CNonCanonical)
                      [WD] hole{co_a2MZb} {6}:: s0
                                                ~ 'Data.Vector.Fixed.Cont.S s1 (CNonCanonical)
                      [WD] hole{co_a2MZh} {6}:: s0 ~ 'True (CNonCanonical)
                      [D] _ {6}:: r ~ (point0 d0 a0 :+ extra0) (CNonCanonical)
                      [W] hole{co_a2LGq} {0}:: r
                                               ~ (point0 d0 a0 :+ extra0) (CNonCanonical)
                      [D] _ {6}:: s0 ~ 3 (CNonCanonical)
                      [D] _ {0}:: s0 ~ 2 (CNonCanonical)
                      [D] _ {6}:: s0
                                  ~ 'Data.Vector.Fixed.Cont.S
                                      ('Data.Vector.Fixed.Cont.S
                                         'Data.Vector.Fixed.Cont.Z) (CNonCanonical)
                      [D] _ {8}:: s0 ~ 2 (CNonCanonical)
                      [D] _ {8}:: s0 ~ 3 (CNonCanonical)
                    wc_impl =
                      Implic {
                        TcLevel = 3
                        Skolems = (d :: ghc-prim-0.5.3:GHC.Types.Nat)
                                  (d :: ghc-prim-0.5.3:GHC.Types.Nat)
                                  a
                                  (point :: ghc-prim-0.5.3:GHC.Types.Nat -> * -> *)
                                  (point :: ghc-prim-0.5.3:GHC.Types.Nat -> * -> *)
                                  extra
                                  extra
                        No-eqs = False
                        Status = Solved {Dead givens = []}
                        Given =
                          $dImplicitPeano_a2LxR :: Data.Geometry.Vector.VectorFamilyPeano.ImplicitPeano
                                                     (Data.Vector.Fixed.Cont.Peano d)
                          $dImplicitPeano_a2LxS :: Data.Geometry.Vector.VectorFamilyPeano.ImplicitPeano
                                                     (Data.Vector.Fixed.Cont.Peano d)
                          $dEq_a2LxT :: Eq a
                          $dArityPeano_a2LxU :: Data.Vector.Fixed.Cont.ArityPeano
                                                  (Data.Vector.Fixed.Cont.Peano
                                                     (Data.Geometry.Vector.VectorFamilyPeano.FromPeano
                                                        (Data.Vector.Fixed.Cont.Peano d)))
                          $dArityPeano_a2LxV :: Data.Vector.Fixed.Cont.ArityPeano
                                                  (Data.Vector.Fixed.Cont.Peano
                                                     (Data.Geometry.Vector.VectorFamilyPeano.FromPeano
                                                        (Data.Vector.Fixed.Cont.Peano d)))
                          $dKnownNat_a2LxW :: GHC.TypeNats.KnownNat d
                          $dKnownNat_a2LxX :: GHC.TypeNats.KnownNat
                                                (Data.Geometry.Vector.VectorFamilyPeano.FromPeano
                                                   (Data.Vector.Fixed.Cont.Peano d))
                          $dKnownNat_a2LxY :: GHC.TypeNats.KnownNat
                                                (Data.Geometry.Vector.VectorFamilyPeano.FromPeano
                                                   (Data.Vector.Fixed.Cont.Peano d))
                          $dKnownNat_a2LxZ :: GHC.TypeNats.KnownNat d
                          $dAsAPoint_a2Ly0 :: hgeometry-0.12.0.1:Data.Geometry.Point.Class.AsAPoint
                                                point
                          $dAsAPoint_a2Ly1 :: hgeometry-0.12.0.1:Data.Geometry.Point.Class.AsAPoint
                                                point
                          $d~_a2Ly2 :: Data.Vector.Fixed.Cont.Peano
                                         (Data.Geometry.Vector.VectorFamilyPeano.FromPeano
                                            (Data.Vector.Fixed.Cont.Peano d)
                                          GHC.TypeNats.+ 1)
                                       ~ 'Data.Vector.Fixed.Cont.S
                                           (Data.Vector.Fixed.Cont.Peano
                                              (Data.Geometry.Vector.VectorFamilyPeano.FromPeano
                                                 (Data.Vector.Fixed.Cont.Peano d)))
                          $d~_a2Ly3 :: (2 GHC.TypeNats.<=? d) ~ 'True
                          $d~_a2Ly4 :: (2 GHC.TypeNats.<=? d) ~ 'True
                          $d~_a2Ly5 :: Data.Vector.Fixed.Cont.Peano
                                         (Data.Geometry.Vector.VectorFamilyPeano.FromPeano
                                            (Data.Vector.Fixed.Cont.Peano d)
                                          GHC.TypeNats.+ 1)
                                       ~ 'Data.Vector.Fixed.Cont.S
                                           (Data.Vector.Fixed.Cont.Peano
                                              (Data.Geometry.Vector.VectorFamilyPeano.FromPeano
                                                 (Data.Vector.Fixed.Cont.Peano d)))
                        Wanted = WC {}
                        Binds = EvBindsVar<a2Lx3>
                        the inferred type of
                          isV :: (Data.Geometry.Vector.VectorFamilyPeano.ImplicitPeano
                                    (Data.Vector.Fixed.Cont.Peano d1),
                                  Data.Geometry.Vector.VectorFamilyPeano.ImplicitPeano
                                    (Data.Vector.Fixed.Cont.Peano d),
                                  Eq a,
                                  Data.Vector.Fixed.Cont.ArityPeano
                                    (Data.Vector.Fixed.Cont.Peano
                                       (Data.Geometry.Vector.VectorFamilyPeano.FromPeano
                                          (Data.Vector.Fixed.Cont.Peano d))),
                                  Data.Vector.Fixed.Cont.ArityPeano
                                    (Data.Vector.Fixed.Cont.Peano
                                       (Data.Geometry.Vector.VectorFamilyPeano.FromPeano
                                          (Data.Vector.Fixed.Cont.Peano d1))),
                                  GHC.TypeNats.KnownNat d,
                                  GHC.TypeNats.KnownNat
                                    (Data.Geometry.Vector.VectorFamilyPeano.FromPeano
                                       (Data.Vector.Fixed.Cont.Peano d)),
                                  GHC.TypeNats.KnownNat
                                    (Data.Geometry.Vector.VectorFamilyPeano.FromPeano
                                       (Data.Vector.Fixed.Cont.Peano d1)),
                                  GHC.TypeNats.KnownNat d1,
                                  hgeometry-0.12.0.1:Data.Geometry.Point.Class.AsAPoint point,
                                  hgeometry-0.12.0.1:Data.Geometry.Point.Class.AsAPoint point1,
                                  Data.Vector.Fixed.Cont.Peano
                                    (Data.Geometry.Vector.VectorFamilyPeano.FromPeano
                                       (Data.Vector.Fixed.Cont.Peano d)
                                     GHC.TypeNats.+ 1)
                                  ~ 'Data.Vector.Fixed.Cont.S
                                      (Data.Vector.Fixed.Cont.Peano
                                         (Data.Geometry.Vector.VectorFamilyPeano.FromPeano
                                            (Data.Vector.Fixed.Cont.Peano d))),
                                  (2 GHC.TypeNats.<=? d) ~ 'True, (2 GHC.TypeNats.<=? d1) ~ 'True,
                                  Data.Vector.Fixed.Cont.Peano
                                    (Data.Geometry.Vector.VectorFamilyPeano.FromPeano
                                       (Data.Vector.Fixed.Cont.Peano d1)
                                     GHC.TypeNats.+ 1)
                                  ~ 'Data.Vector.Fixed.Cont.S
                                      (Data.Vector.Fixed.Cont.Peano
                                         (Data.Geometry.Vector.VectorFamilyPeano.FromPeano
                                            (Data.Vector.Fixed.Cont.Peano d1)))) =>
                                 p1 -> p3 -> Bool }
                      Implic {
                        TcLevel = 3
                        Skolems = (d :: ghc-prim-0.5.3:GHC.Types.Nat)
                                  (d :: ghc-prim-0.5.3:GHC.Types.Nat)
                                  a
                                  (point :: ghc-prim-0.5.3:GHC.Types.Nat -> * -> *)
                                  (point :: ghc-prim-0.5.3:GHC.Types.Nat -> * -> *)
                                  extra
                                  extra
                        No-eqs = False
                        Status = Solved {Dead givens = []}
                        Given =
                          $dImplicitPeano_a2LB0 :: Data.Geometry.Vector.VectorFamilyPeano.ImplicitPeano
                                                     (Data.Vector.Fixed.Cont.Peano d)
                          $dImplicitPeano_a2LB1 :: Data.Geometry.Vector.VectorFamilyPeano.ImplicitPeano
                                                     (Data.Vector.Fixed.Cont.Peano d)
                          $dEq_a2LB2 :: Eq a
                          $dArityPeano_a2LB3 :: Data.Vector.Fixed.Cont.ArityPeano
                                                  (Data.Vector.Fixed.Cont.Peano
                                                     (Data.Geometry.Vector.VectorFamilyPeano.FromPeano
                                                        (Data.Vector.Fixed.Cont.Peano d)))
                          $dArityPeano_a2LB4 :: Data.Vector.Fixed.Cont.ArityPeano
                                                  (Data.Vector.Fixed.Cont.Peano
                                                     (Data.Geometry.Vector.VectorFamilyPeano.FromPeano
                                                        (Data.Vector.Fixed.Cont.Peano d)))
                          $dKnownNat_a2LB5 :: GHC.TypeNats.KnownNat d
                          $dKnownNat_a2LB6 :: GHC.TypeNats.KnownNat
                                                (Data.Geometry.Vector.VectorFamilyPeano.FromPeano
                                                   (Data.Vector.Fixed.Cont.Peano d))
                          $dKnownNat_a2LB7 :: GHC.TypeNats.KnownNat
                                                (Data.Geometry.Vector.VectorFamilyPeano.FromPeano
                                                   (Data.Vector.Fixed.Cont.Peano d))
                          $dKnownNat_a2LB8 :: GHC.TypeNats.KnownNat d
                          $dAsAPoint_a2LB9 :: hgeometry-0.12.0.1:Data.Geometry.Point.Class.AsAPoint
                                                point
                          $dAsAPoint_a2LBa :: hgeometry-0.12.0.1:Data.Geometry.Point.Class.AsAPoint
                                                point
                          $d~_a2LBb :: Data.Vector.Fixed.Cont.Peano
                                         (Data.Geometry.Vector.VectorFamilyPeano.FromPeano
                                            (Data.Vector.Fixed.Cont.Peano d)
                                          GHC.TypeNats.+ 1)
                                       ~ 'Data.Vector.Fixed.Cont.S
                                           (Data.Vector.Fixed.Cont.Peano
                                              (Data.Geometry.Vector.VectorFamilyPeano.FromPeano
                                                 (Data.Vector.Fixed.Cont.Peano d)))
                          $d~_a2LBc :: (1 GHC.TypeNats.<=? d) ~ 'True
                          $d~_a2LBd :: (1 GHC.TypeNats.<=? d) ~ 'True
                          $d~_a2LBe :: Data.Vector.Fixed.Cont.Peano
                                         (Data.Geometry.Vector.VectorFamilyPeano.FromPeano
                                            (Data.Vector.Fixed.Cont.Peano d)
                                          GHC.TypeNats.+ 1)
                                       ~ 'Data.Vector.Fixed.Cont.S
                                           (Data.Vector.Fixed.Cont.Peano
                                              (Data.Geometry.Vector.VectorFamilyPeano.FromPeano
                                                 (Data.Vector.Fixed.Cont.Peano d)))
                        Wanted = WC {}
                        Binds = EvBindsVar<a2LAd>
                        the inferred type of
                          isH :: (Data.Geometry.Vector.VectorFamilyPeano.ImplicitPeano
                                    (Data.Vector.Fixed.Cont.Peano d1),
                                  Data.Geometry.Vector.VectorFamilyPeano.ImplicitPeano
                                    (Data.Vector.Fixed.Cont.Peano d),
                                  Eq a,
                                  Data.Vector.Fixed.Cont.ArityPeano
                                    (Data.Vector.Fixed.Cont.Peano
                                       (Data.Geometry.Vector.VectorFamilyPeano.FromPeano
                                          (Data.Vector.Fixed.Cont.Peano d))),
                                  Data.Vector.Fixed.Cont.ArityPeano
                                    (Data.Vector.Fixed.Cont.Peano
                                       (Data.Geometry.Vector.VectorFamilyPeano.FromPeano
                                          (Data.Vector.Fixed.Cont.Peano d1))),
                                  GHC.TypeNats.KnownNat d,
                                  GHC.TypeNats.KnownNat
                                    (Data.Geometry.Vector.VectorFamilyPeano.FromPeano
                                       (Data.Vector.Fixed.Cont.Peano d)),
                                  GHC.TypeNats.KnownNat
                                    (Data.Geometry.Vector.VectorFamilyPeano.FromPeano
                                       (Data.Vector.Fixed.Cont.Peano d1)),
                                  GHC.TypeNats.KnownNat d1,
                                  hgeometry-0.12.0.1:Data.Geometry.Point.Class.AsAPoint point,
                                  hgeometry-0.12.0.1:Data.Geometry.Point.Class.AsAPoint point1,
                                  Data.Vector.Fixed.Cont.Peano
                                    (Data.Geometry.Vector.VectorFamilyPeano.FromPeano
                                       (Data.Vector.Fixed.Cont.Peano d)
                                     GHC.TypeNats.+ 1)
                                  ~ 'Data.Vector.Fixed.Cont.S
                                      (Data.Vector.Fixed.Cont.Peano
                                         (Data.Geometry.Vector.VectorFamilyPeano.FromPeano
                                            (Data.Vector.Fixed.Cont.Peano d))),
                                  (1 GHC.TypeNats.<=? d) ~ 'True, (1 GHC.TypeNats.<=? d1) ~ 'True,
                                  Data.Vector.Fixed.Cont.Peano
                                    (Data.Geometry.Vector.VectorFamilyPeano.FromPeano
                                       (Data.Vector.Fixed.Cont.Peano d1)
                                     GHC.TypeNats.+ 1)
                                  ~ 'Data.Vector.Fixed.Cont.S
                                      (Data.Vector.Fixed.Cont.Peano
                                         (Data.Geometry.Vector.VectorFamilyPeano.FromPeano
                                            (Data.Vector.Fixed.Cont.Peano d1)))) =>
                                 p1 -> p3 -> Bool }
                      Implic {
                        TcLevel = 3
                        Skolems = r
                        No-eqs = True
                        Status = Solved {Dead givens = []}
                        Given =
                          $dNum_a2LHC :: Num r
                          $dEq_a2LHD :: Eq r
                        Wanted = WC {}
                        Binds = EvBindsVar<a2LHy>
                        the inferred type of
                          rectToPath :: (Num r, Eq r) => Rectangle p0 r0 -> c0 }}
      Set limit with -fconstraint-solver-iterations=n; n=0 for no limit
  |
1 | {-# LANGUAGE OverloadedStrings #-}
  | ^

src/Data/Geometry/Ipe/FromIpe.hs:110:60: error:
    • Couldn't match expected type ‘point0 d0 a0 :+ extra0’
                  with actual type ‘r’
      ‘r’ is a rigid type variable bound by
        the type signature for:
          _asRectangle :: forall r.
                          (Num r, Ord r) =>
                          Prism' (Path r) (Rectangle () r)
        at src/Data/Geometry/Ipe/FromIpe.hs:101:1-76
    • In the second argument of ‘isH’, namely ‘a’
      In the second argument of ‘(&&)’, namely ‘isH d a’
      In the second argument of ‘(&&)’, namely ‘isV c d && isH d a’
    • Relevant bindings include
        d :: r (bound at src/Data/Geometry/Ipe/FromIpe.hs:110:16)
        c :: r (bound at src/Data/Geometry/Ipe/FromIpe.hs:110:14)
        b :: r (bound at src/Data/Geometry/Ipe/FromIpe.hs:110:12)
        a :: r (bound at src/Data/Geometry/Ipe/FromIpe.hs:110:10)
        pg :: SimplePolygon () r
          (bound at src/Data/Geometry/Ipe/FromIpe.hs:108:12)
        asRect :: SimplePolygon () r -> Maybe (Rectangle () r)
          (bound at src/Data/Geometry/Ipe/FromIpe.hs:108:5)
        (Some bindings suppressed; use -fmax-relevant-binds=N or -fno-max-relevant-binds)
    |
110 |         [a,b,c,d] | isV a b && isH b c && isV c d && isH d a -> Just (boundingBoxList' [a,c])
    |                                                            ^

src/Data/Geometry/Ipe/FromIpe.hs:167:53: error:
    • Couldn't match type ‘Polygon 'Simple () r’
                     with ‘hgeometry-0.12.0.1:Data.Geometry.Polygon.Core.Vertices
                             (Point 2 r :+ ())’
      Expected type: hgeometry-0.12.0.1:Data.Geometry.Polygon.Core.Vertices
                       (Point 2 r :+ ())
        Actual type: SimplePolygon () r
    • In the first argument of ‘SimplePolygon’, namely ‘vs’
      In the first argument of ‘(:|)’, namely ‘(SimplePolygon vs)’
      In the second argument of ‘($)’, namely ‘(SimplePolygon vs) :| hs’
    • Relevant bindings include
        hs :: [SimplePolygon () r]
          (bound at src/Data/Geometry/Ipe/FromIpe.hs:166:32)
        vs :: SimplePolygon () r
          (bound at src/Data/Geometry/Ipe/FromIpe.hs:166:29)
        polygonToPath :: Polygon t () r -> Path r
          (bound at src/Data/Geometry/Ipe/FromIpe.hs:165:1)
    |
167 |                                    $ (SimplePolygon vs) :| hs
    |                                                     ^^

src/Data/Geometry/Ipe/FromIpe.hs:174:73: error:
    • Couldn't match type ‘hgeometry-0.12.0.1:Data.Geometry.Polygon.Core.Vertices
                             (Point 2 r :+ ())’
                     with ‘Polygon 'Simple () r’
      Expected type: SimplePolygon () r
        Actual type: hgeometry-0.12.0.1:Data.Geometry.Polygon.Core.Vertices
                       (Point 2 r :+ ())
    • In the first argument of ‘MultiPolygon’, namely ‘vs’
      In the second argument of ‘($)’, namely ‘MultiPolygon vs hs’
      In the expression: Just . Right $ MultiPolygon vs hs
    • Relevant bindings include
        hs :: [SimplePolygon () r]
          (bound at src/Data/Geometry/Ipe/FromIpe.hs:174:39)
        vs :: hgeometry-0.12.0.1:Data.Geometry.Polygon.Core.Vertices
                (Point 2 r :+ ())
          (bound at src/Data/Geometry/Ipe/FromIpe.hs:174:35)
        p :: Path r (bound at src/Data/Geometry/Ipe/FromIpe.hs:171:15)
        pathToPolygon :: Path r
                         -> Maybe (Either (SimplePolygon () r) (MultiPolygon () r))
          (bound at src/Data/Geometry/Ipe/FromIpe.hs:171:1)
    |
174 |                     SimplePolygon vs: hs -> Just . Right $ MultiPolygon vs hs
    |                                                                         ^^
cabal: Failed to build hgeometry-ipe-0.11.0.0 (which is required by
fake-package-0). See the build log above for details.

In case it is helpful, here are the dependencies that cabal is using, as reported by cabal -v:

Ready component graph:
    definite hgeometry-ipe-0.11.0.0-75e38cac99cded5c4995ee435cf7b5f129a87dd0c3eeaa413443b7664fde0190
        depends MonadRandom-0.5.2-1a8007d302d9501c676b006728faf9b7be2316d4e492d1c8e21500a6419ac1c1
        depends QuickCheck-2.14.2-5322feebbd11bef6111515381f41ca7d6573ca48b0e6bb87b674b81866a3bd63
        depends aeson-1.5.6.0-678ba89beb1ccc461a59e2f2f15dc7cd0d4aa562d2d68e96c6d223204b4c9e85
        depends base-4.13.0.0
        depends bifunctors-5.5.10-16321d0a808f52fc4995f6843166309bfe5c9af93e2ff3aee820fa4ffc3c7da1
        depends bytestring-0.10.10.1
        depends colour-2.3.5-36e5103cd485639440b80f705a675a65fe5dbc0b6f3cbe8068e3949423e459fd
        depends containers-0.6.2.1
        depends data-clist-0.1.2.3-ff108e3ff0eee76ec04205449f6d31c7f64eed00fafff14a47493a6cef109811
        depends deepseq-1.4.4.0
        depends dlist-1.0-d6b5d855d0bcae1a5528c078bd76caecbcfc92fe5e5745f635e6b06cbeb4967c
        depends fingertree-0.1.4.2-be7f270d4d507f9e19ac5ca0935e446ade88f0048a1ff24598820c5500786857
        depends fixed-vector-1.2.0.0-7375ecab5b25d563bad891d053a8ef65f6ed5851d603ab16bcc921e25908114f
        depends hexpat-0.20.13-c45602f21abfbd36d60b1392fde3666c11655bfae9ec24ff49b8f238caf23ebc
        depends hgeometry-0.12.0.1-58b08a8d2f81b8f901abce4a35b8730758bae6f389d0e49d43aeeb382edfcfcd
        depends hgeometry-combinatorial-0.12.0.1-cd77e3c85fabac6d9256414fca26fb61db14dab69567a4df4782a22ca76c0431
        depends lens-5.0.1-ad699f2631ff25b5a15890a626bbaf1570000fd9760775b077ff0ee9f4378fbe
        depends linear-1.21.5-4e942fbf7c36173d06f4a0f9c1d3c05d8de1cfb285cb8dc5dbce0c9a8d161580
        depends mtl-2.2.2
        depends parsec-3.1.14.0
        depends quickcheck-instances-0.3.25.2-b4bfb0cf6d749e100afe7cd268582deb33702044508ec9f2653cbc743a8e9621
        depends random-1.2.0-00764634d8a1b2874f13ca39a40464d39214f25dd481d12f12f5c40b7f887c49
        depends reflection-2.1.6-978a599e512e9ec2acecdaf4133dd59ea4b87fb0220ffb648fd59cb19e1da2e9
        depends semigroupoids-5.3.5-2c1b5dd493845615e3fdcb41e5fedb16f08649734c18b590ceae2c4b0995039b
        depends semigroups-0.19.1-776d2fc9d959aed6826f59130ea115c80d9f632af7b10a89a7917f72644ff7e8
        depends singletons-2.6-8b660d708a1a2dfc4c6b3d8e7ca7cfe3648ca36a5a14718a2a441963efb01dc8
        depends template-haskell-2.15.0.0
        depends text-1.2.4.0
        depends vector-0.12.2.0-5bfd0cd997e5c3ba9c1ad373f1c09d6f4326a42315148cd296903a351a302057
        depends vinyl-0.13.0-6c4e1bf5c520aeb48a3325e45532ccf4bce6ed1085acf20390edf832814d2ab7
        depends yaml-0.11.5.0-05bc287bb0dcd957fce31efb4bf68487469a78ddb15f305357422fcc003533f1

Unused code.

The zipper for rose trees (Data.Tree.Util) is not used anywhere in hgeometry. May I comment out such unused code, @noinia?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.