6

I don't think there's a built in "RegionSimplify" for polyhedral Regions and derived akin to how Interval automatically simplifies its argument expression:

Interval[{0, 1}, {1, 2}]

and

Interval[{0, 1}]~IntervalUnion~Interval[{1, 2}]

yield

Interval[{0, 2}]

In contrast, RegionUnion remains unevaluated, even in 2D:

Line[{{0, 0}, {1, 0}}]~ RegionUnion ~ Line[{{1, 0}, {2, 0}}]

(* RegionUnion[Line[{{0, 0}, {1, 0}}], Line[{{1, 0}, {2, 0}}]] *) 

From

Rectangle[{0, 0}, {1, 1}] ~ RegionUnion ~ 
  Rectangle[{1, 0}, {2, 1}] // RegionBoundary // DiscretizeRegion

enter image description here

As expected, the Rectangles' common segment is not part of the output.

How to expose or compute the ideal normal form for 2D (at least) polyhedral Regions like these basic examples:

Overlapping lines:

Line[{{0, 0}, {2, 0}}]~ RegionUnion ~ Line[{{1, 0}, {3, 0}}] (* // RegionSimplify *)

(*  Line[{{0,0},{3,0}}] *)

Union of rectangles:

 Rectangle[{0, 0}, {1, 1}] ~ RegionUnion ~ 
      Rectangle[{1, 0}, {2, 1}] (* // RegionSimplify *)

(* Rectangle[{0, 0}, {2, 1}] *)

Boundary:

 Rectangle[{0, 0}, {1, 1}] ~ RegionUnion ~ 
      Rectangle[{1, 0}, {2, 1}] // RegionBoundary  (* // RegionSimplify *)

(* Line[{{0,0},{2,0},{2,1},{0,1},{0,0}}]  *)

The simplification should work for all 2D polyhedral regions including cones (which btw the current language does not support correctly):

ConicHullRegion[{{0, 0}}, {{1, 0}, {1, 1}}] ~RegionUnion ~ 
 ConicHullRegion[{{0, 0}}, {{0, 1}, {1, 1}}] (* // RegionSimplify *)

(* ConicHullRegion[{{0, 0}}, {{1, 0}, {0, 1}}] *)

For convex regions and convex-preserving operations (eg intersection) should suffice to consider the extreme set (vertices and rays), but in general regions aren't convex (and union doens't preserve it).

(Note: RegionIntersection of the same Rectangles hangs the kernel w/ msg: Last::nolast: "{} has a length of zero and no last element")

alancalvitti
  • 15,143
  • 3
  • 27
  • 92

2 Answers2

1
eps = 0.001;
repl = (z_Symbol == val_) :> 
   (val - eps/2 <= z <= val + eps/2);

r1 = Line[{{0, 0}, {1, 0}}];
r2 = Line[{{1, 0}, {2, 0}}];

r3 = ImplicitRegion[RegionMember[
     RegionUnion[r1, r2], {x, y}] //
    Simplify, {x, y}] /. repl

ImplicitRegion[(x | y) \[Element] Reals && -0.0005 <= y <= 0.0005 && 
  0 <= x <= 2, {x, y}]

r3 // DiscretizeRegion

enter image description here

r4 = Line[{{0, 0}, {2, 0}}];
r5 = Line[{{1, 0}, {3, 0}}];

r6 = ImplicitRegion[RegionMember[
     RegionUnion[r4, r5], {x, y}] //
    Simplify, {x, y}] /. repl

ImplicitRegion[(x | y) \[Element] Reals && -0.0005 <= y <= 0.0005 && 
  0 <= x <= 3, {x, y}]

r6 // DiscretizeRegion

enter image description here

r7 = Rectangle[{0, 0}, {1, 1}];
r8 = Rectangle[{1, 0}, {2, 1}];
r9 = RegionUnion[r7, r8];

RegionMember[r9, {x, y}] // Simplify

(x | y) \[Element] Reals && 0 <= x <= 2 && 0 <= y <= 1

r9 // DiscretizeRegion

enter image description here

r10 = Rectangle[{0, 0}, {1, 1}];
r11 = Rectangle[{1, 0}, {2, 1}];
r12 = RegionUnion[r10, r11];

RegionMember[r12, {x, y}] // Simplify

(x | y) \[Element] Reals && 0 <= x <= 2 && 0 <= y <= 1

r12 // DiscretizeRegion

enter image description here

n = 5;
rectangles = 
  Rectangle @@@ 
   Transpose[{RandomInteger[{0, 10}, {n, 2}], 
     RandomInteger[{11, 20}, {n, 2}]}];

Graphics[{Opacity[.25], rectangles}]

enter image description here

r13 = RegionUnion @@ rectangles;

RegionMember[r13, {x, y}]

(x | y) \[Element] 
  Reals && ((2 <= x <= 13 && 3 <= y <= 14) || (2 <= x <= 14 && 
     4 <= y <= 11) || (3 <= x <= 16 && 
     8 <= y <= 19) || (4 <= x <= 13 && 
     9 <= y <= 13) || (5 <= x <= 17 && 8 <= y <= 13))

r13 // DiscretizeRegion

enter image description here

EDIT: Example of disconnected regions

r14 = Rectangle[{0, 0}, {1, 1}];
r15 = Rectangle[{1.1, 1.1}, {1.6, 1.7}];
r16 = RegionUnion[r14, r15];

RegionMember[r16, {x, y}] // Simplify

(x | y) \[Element] 
  Reals && ((0 <= x <= 1 && 0 <= y <= 1) || (1.1 <= x <= 1.6 && 
     1.1 <= y <= 1.7))

r16 // DiscretizeRegion

enter image description here

SECOND EDIT: Additional example--regions with holes.

r1 = Rectangle[{0, 0}, {1, 1}];
r2 = Rectangle[{.25, .25}, {.5, .5}];
r3 = RegionDifference[r1, r2];
r4 = Disk[{1.5, 1.25}, .75];
r5 = Rectangle[{1.25, 1.25}, {1.75, 1.35}];
r6 = RegionDifference[r4, r5];
r7 = RegionUnion[r3, r6];

RegionMember[r7, {x, y}]

(x | y) [Element] Reals && (((-1.5 + x)^2 + (-1.25 + y)^2 <= 0.5625 && ! (1.25 <= x <= 1.75 && 1.25 <= y <= 1.35)) || (0 <= x <= 1 && 0 <= y <= 1 && ! (0.25 <= x <= 0.5 && 0.25 <= y <= 0.5)))

DiscretizeRegion[r7]

enter image description here

Bob Hanlon
  • 157,611
  • 7
  • 77
  • 198
0

(version 10) I made function lastUnion , firstUnion and RectangleRegionSimplify instead of RegionSimplify. I think you might want to make RectangleRegionSimplify.

lastUnion[coo_] := 
 Flatten[Replace[SplitBy [ coo, Last], {f_, ___, l_} -> {f, l}, 1], 1]
firstUnion[coo_] := 
 Flatten[Replace[SplitBy [ coo, First], {f_, ___, l_} -> {f, l}, 1], 1]
RectangleRegionSimplify[p__] := Module[{pts, rst},
  pts = MeshPrimitives[
     BoundaryDiscretizeRegion[
      DiscretizeRegion[RegionUnion@p], MaxCellMeasure -> \[Infinity]],
      2][[1, 1]];
  rst = Append[pts, First[pts]];
  rst = N[Rationalize[Chop[rst, 10^-6]], 5];
  rst // firstUnion // lastUnion // Rationalize // N // Line
]

And I made some sample Rectangle's as Region. Rectangle is not always Region, so I randomly selected those as Region.

n = 5;
data = Transpose[{RandomInteger[{0, 10}, {n, 2}], 
    RandomInteger[{11, 20}, {n, 2}]}];
fig1 = {ColorData["Atoms", "ColorList"][[1 ;; n]], 
    Rectangle @@@ data} // Transpose;
Graphics[{EdgeForm[Gray], Opacity[0.3], fig1}]

Blockquote

I think you can check for your code with following like this.

fig2 = RectangleRegionSimplify[RegionUnion @@ Rectangle @@@ data]

Line[{{4., 8.}, {5., 8.}, {5., 5.}, {7., 5.}, {7., 1.}, {12., 1.}, {12., 3.}, {16., 3.}, {16., 5.}, {19., 5.}, {19., 14.}, {15., 14.}, {15., 19.}, {4., 19.}, {4., 8.}}]

Graphics[{%, PointSize[Large], Red, Point @@ %}]

Blockquote

Caution

RegionQ[Rectangle[{0, 0}, {1, 3}]]

True

RegionQ[Rectangle[{2, 0}, {1, 3}]]

False

Junho Lee
  • 5,155
  • 1
  • 15
  • 33
  • Junho, it doesn't work on derived Regions, eg: Rectangle[{0, 0}, {2, 1}]~RegionUnion~ Rectangle[{1, 0}, {2, 2}]. Derived implies RegionQ[r]==True – alancalvitti Oct 01 '14 at 16:48
  • Applying Normal to BoundaryDiscretizeRegion is still a graphic. How to extract the line representation? Also note: ...// BoundaryDiscretizeRegion // RegionBoundary outputs many points that are not corners. – alancalvitti Oct 01 '14 at 17:06
  • as per the calendar counterexample, try rectangles whose union is not simply connected. Also, the method should work for all 2D polyhedra and derived regions. – alancalvitti Oct 03 '14 at 02:50
  • Your method fails if the union is not simply-connected, eg this "#" shape: data2 = {{{1, 0}, {2, 6}}, {{4, 0}, {5, 1}}, {{0, 1}, {6, 2}}, {{4, 0}, {5, 6}}, {{0, 4}, {6, 5}}} with msg: There is no simple cell representation for the specified cells of the BoundaryMeshRegion... – alancalvitti Oct 06 '14 at 17:15