6
$\begingroup$

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")

$\endgroup$
1
$\begingroup$
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

$\endgroup$
  • $\begingroup$ Did you try Union of Rectangles that isn't simply-connected? $\endgroup$ – alancalvitti Oct 5 '14 at 17:40
  • $\begingroup$ Added example of disconnected regions. $\endgroup$ – Bob Hanlon Oct 5 '14 at 18:57
  • $\begingroup$ Those components are simply connected. Try something w/ a hole in it. $\endgroup$ – alancalvitti Oct 6 '14 at 2:54
  • $\begingroup$ Added example with regions with holes. If this is not what you want, provide a specific example of what you do want. $\endgroup$ – Bob Hanlon Oct 6 '14 at 5:05
  • $\begingroup$ Your method using RegionMember and Simplify, unlike Junho's, seems robust to the more complex topologies but it doesn't yield the normal form, which is the minimal number of boundary points (for polytopes). $\endgroup$ – alancalvitti Oct 6 '14 at 17:21
0
$\begingroup$

(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

$\endgroup$
  • $\begingroup$ 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 $\endgroup$ – alancalvitti Oct 1 '14 at 16:48
  • $\begingroup$ 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. $\endgroup$ – alancalvitti Oct 1 '14 at 17:06
  • $\begingroup$ 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. $\endgroup$ – alancalvitti Oct 3 '14 at 2:50
  • $\begingroup$ 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... $\endgroup$ – alancalvitti Oct 6 '14 at 17:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.