diagrams / diagrams-contrib

User-contributed extensions to diagrams
BSD 3-Clause "New" or "Revised" License
27 stars 31 forks source link

union does not produce expected result when endpoints of a polygon overlap #77

Open bacchanalia opened 5 years ago

bacchanalia commented 5 years ago

In the following code ex4 unexpectedly produces an empty diagram.

{-# LANGUAGE TypeFamilies, FlexibleContexts #-}
import Diagrams.Prelude
import Diagrams.Backend.Cairo.CmdLine
import Diagrams.TwoD.Polygons
import qualified Diagrams.TwoD.Path.Boolean as B

rose n r1 r2 = polygon $ with
  & polyType   .~ PolyPolar (replicate n $ 1/8 @@ turn) (cycle [r1, r2])
  & polyOrient .~ NoOrient

roseWithNoOverlap = rose 7
roseWithOverlap   = rose 8

roseWithNoOverlapOrthoginal = roseWithNoOverlap 3 1
roseWithNoOverlapDiagonal   = roseWithNoOverlap 1 3
roseWithOverlapOrthoginal   = roseWithOverlap   3 1
roseWithOverlapDiagonal     = roseWithOverlap   1 3

ex d = stroke $ B.union Winding $ d <> circle 2

ex1, ex2, ex3, ex4, dia :: Diagram Cairo
ex1 = ex roseWithNoOverlapOrthoginal  -- works
ex2 = ex roseWithNoOverlapDiagonal    -- works: equiv to (ex1 # rotate (1/8 @@ turn))
ex3 = ex roseWithOverlapOrthoginal    -- works: equiv to ex1
ex4 = ex roseWithOverlapDiagonal      -- broken: produces nothing, expected quiv to ex2

dia = (ex1 ||| ex2) === (ex3 ||| ex4)
main = mainWith dia
byorgey commented 5 years ago

This may be related to https://github.com/kuribas/cubicbezier/issues/6 . I know there was another similar example where reversing one of the paths involved caused it to work --- does this example exhibit the same behavior?

bacchanalia commented 5 years ago

neither d or (circle 2) reversed neither d reversed d (circle 2) reversed circle both d and (circle 2) reversed both

byorgey commented 5 years ago

Weird!

fryguybob commented 5 years ago

The way paths are converted to be used with cubicbezier package leads to a tiny segment. I think this tiny segment (straight (V2 (-0.0) 4.440892098500626e-16)) is not handled well by cubicbezier. Boolean operations on non-convex polygons is super hard to get right in all the strange cases. This only gets harder with cubic segments. We could filter out tiny segments before handing off to cubicbezier.

What was the reason you switched to the "overlap" version again?

bacchanalia commented 5 years ago

I didn't switch back to the overlap version. I just figured: see weird behaviour, post weird behaviour. I ended up not using binary operations anyway because of the union of difference bug I hit, and instead went with slicing up my diagram at intersections.

fryguybob commented 5 years ago

I just figured: see weird behaviour, post weird behaviour.

Absolutely! I just was wondering if there was a need for that particular overlapped form in your workflow.