4

I have a complicated polygon in the 2d plane, that is an RegionIntersection of RegionUnion of triangles.

Finally, I want to calculate it's Area. Unfortunatly, the Area is really slow. I am not sure why, but presumably because it calculates the result analytically.

I have an example that represents the shapes I am dealing with:

TotalTime = 0;
For[cc = 1, cc <= 50, cc++,
  (* Reconstructing roughly the shapes I am using *)
  BoundIntersect = RegionIntersection[
    RegionDifference[Triangle[RandomReal[{-0.2, 0.2}, {3, 2}]], 
     Polygon[RandomReal[{-0.2, 0.2}, {3, 2}]]], 
    RegionUnion[Triangle[RandomReal[{-0.2, 0.2}, {3, 2}]], 
     Triangle[RandomReal[{-0.2, 0.2}, {3, 2}]], 
     Triangle[RandomReal[{-0.2, 0.2}, {3, 2}]], 
     Triangle[RandomReal[{-0.2, 0.2}, {3, 2}]], 
     Triangle[RandomReal[{-0.2, 0.2}, {3, 2}]]]];

  CurrentTime = AbsoluteTime[];
  BoundaryIntersectRatio = Area[BoundIntersect];
  TotalTime += (AbsoluteTime[] - CurrentTime);
  ];
Print["Total Time: " <> ToString[TotalTime] <> " sec."];

Can you speed it up? In particular, error-ratios in the order of $10^{-4}$ are tolerable.


Update (25.12.2019):

A fair comparison (100 iterations with same polygons for each method):

  1. Henrik Schumacher's method using undocumented Graphics`PolygonUtils function: 0.75005 sec.
  2. Alx's suggestion using BoundaryDiscretizeRegion: 5.03149 sec.
  3. My original method: 24.50163 sec.

Result: Speedup of >factor 30! And learned about undocumented function that i can use all over my code. Fantastic, thank you!

Mario Krenn
  • 2,172
  • 15
  • 35
  • 1
    Maybe some speed-up can be obtained with BoundaryDiscretizeRegion: Area@RegionIntersection[BoundaryDiscretizeRegion@RegionDifference[...],BoundaryDiscretizeRegion@RegionUnion[...]]. – Alx Dec 24 '19 at 02:32
  • You can try one of the implemenations of the shoelace formula: https://mathematica.stackexchange.com/a/207903/280 – Alexey Popkov Dec 24 '19 at 09:10

1 Answers1

2

These undocumented functions do the job almost two orders of magnitude faster:

BoundIntersect = Graphics`PolygonUtils`PolygonIntersection[
    Graphics`PolygonUtils`PolygonComplement @@ (Polygon /@ 
       RandomReal[{-0.2, 0.2}, {2, 3, 2}]),
    Graphics`PolygonUtils`PolygonCombine[
     Polygon /@ RandomReal[{-0.2, 0.2}, {5, 3, 2}]]
    ];
Graphics`PolygonUtils`PolygonArea[BoundIntersect]
Henrik Schumacher
  • 106,770
  • 7
  • 179
  • 309
  • Area[BoundIntersect] returns different result than Graphics`PolygonUtils`PolygonArea[BoundIntersect]. Why? – Alexey Popkov Dec 24 '19 at 08:57
  • Good point. I also observed this. Probably some sign errors. But Area[BoundaryDiscretizeRegion@BoundIntersect] returns the same result as Graphics`PolygonUtils`PolygonArea[BoundIntersect], so I am quite confident that this result is true. Of course, this requires some further testing... – Henrik Schumacher Dec 24 '19 at 09:03
  • Thanks this is great! How do you find about undocumented functions? And how do you get more infos about this specific one? – Mario Krenn Dec 26 '19 at 00:53
  • 1
    Well, they are undocumented, so you hardly can find out. What I did to find it: You can search all Mathematica contexts for a symbol that has Polygon in its name by evaluating ?*`Polygon*. Then I saw that the context Graphics`PolygonUtils might contain quite useful functions (see ?Graphics`PolygonUtils`*) The rest is just trying out different ways to call the functions in order to figure out the correct syntax. This works more often than one might expected. – Henrik Schumacher Dec 26 '19 at 08:45
  • Those undocumented are usually often backends to the more fleshed-out built-in functions. Often, they lack all the fancy argument processing capabilities, but this leads not seldomly to higher performance. IHowever, IIRC, the functions from the context Graphics`PolygonUtils predate all the Region-related functions. – Henrik Schumacher Dec 26 '19 at 08:49