View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.geometry.examples.tutorials.bsp;
18  
19  import java.io.File;
20  import java.util.HashMap;
21  import java.util.Map;
22  
23  import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
24  import org.apache.commons.geometry.core.precision.EpsilonDoublePrecisionContext;
25  import org.apache.commons.geometry.euclidean.twod.Bounds2D;
26  import org.apache.commons.geometry.euclidean.twod.Line;
27  import org.apache.commons.geometry.euclidean.twod.Lines;
28  import org.apache.commons.geometry.euclidean.twod.RegionBSPTree2D;
29  import org.apache.commons.geometry.euclidean.twod.RegionBSPTree2D.RegionNode2D;
30  import org.apache.commons.geometry.euclidean.twod.Vector2D;
31  
32  /** Class containing tutorial code for constructing a 2D BSP tree using
33   * a bottom-up approach.
34   */
35  public final class BottomUpBSPTreeConstruction {
36  
37      /** String defining the name format of output svg files. */
38      private static final String OUTPUT_FILE_FORMAT = "bu-cut-%d.svg";
39  
40      /** No instantiation. */
41      private BottomUpBSPTreeConstruction() {}
42  
43      /** Tutorial code entry point.
44       * @param args command arguments; if given, the first argument is used as the location of
45       *      output folder
46       */
47      public static void main(String[] args) {
48          File outputFolder = new File(args.length > 0 ? args[0] : ".");
49          BSPTreeSVGWriter svgWriter = new BSPTreeSVGWriter(Bounds2D.from(Vector2D.of(-8, -8), Vector2D.of(8, 8)));
50  
51          Map<RegionNode2D, String> nodeNames = new HashMap<>();
52          int cutCount = -1;
53  
54          // create a precision context for floating point comparisons
55          DoublePrecisionContext precision = new EpsilonDoublePrecisionContext(1e-6);
56  
57          // construct an empty tree
58          RegionBSPTree2D tree = RegionBSPTree2D.empty();
59  
60          Line rootCut = Lines.fromPointAndDirection(Vector2D.ZERO, Vector2D.Unit.PLUS_X, precision);
61          RegionNode2D a = tree.getRoot();
62  
63          nodeNames.put(a, "a");
64          svgWriter.write(tree, nodeNames, new File(outputFolder, String.format(OUTPUT_FILE_FORMAT, ++cutCount)));
65  
66          // add a single cut
67          a.cut(rootCut);
68  
69          RegionNode2D b = a.getMinus();
70          RegionNode2D c = a.getPlus();
71  
72          nodeNames.put(b, "b");
73          nodeNames.put(c, "c");
74          svgWriter.write(tree, nodeNames, new File(outputFolder, String.format(OUTPUT_FILE_FORMAT, ++cutCount)));
75  
76          // add another cut
77          b.insertCut(Lines.fromPoints(Vector2D.of(1, 0), Vector2D.of(-1, 1), precision));
78  
79          RegionNode2D d = b.getMinus();
80          RegionNode2D e = b.getPlus();
81  
82          nodeNames.put(d, "d");
83          nodeNames.put(e, "e");
84          svgWriter.write(tree, nodeNames, new File(outputFolder, String.format(OUTPUT_FILE_FORMAT, ++cutCount)));
85  
86          d.insertCut(Lines.fromPointAndDirection(Vector2D.of(-5, 1), Vector2D.Unit.MINUS_Y, precision));
87  
88          RegionNode2D f = d.getMinus();
89          RegionNode2D g = d.getPlus();
90  
91          nodeNames.put(f, "f");
92          nodeNames.put(g, "g");
93          svgWriter.write(tree, nodeNames, new File(outputFolder, String.format(OUTPUT_FILE_FORMAT, ++cutCount)));
94  
95          // other side
96          c.insertCut(Lines.fromPoints(Vector2D.of(-1, 0), Vector2D.of(1, -1), precision));
97  
98          RegionNode2D h = c.getMinus();
99          RegionNode2D i = c.getPlus();
100 
101         nodeNames.put(h, "h");
102         nodeNames.put(i, "i");
103         svgWriter.write(tree, nodeNames, new File(outputFolder, String.format(OUTPUT_FILE_FORMAT, ++cutCount)));
104 
105         h.insertCut(Lines.fromPointAndDirection(Vector2D.of(5, -1), Vector2D.Unit.PLUS_Y, precision));
106 
107         RegionNode2D j = h.getMinus();
108         RegionNode2D k = h.getPlus();
109 
110         nodeNames.put(j, "j");
111         nodeNames.put(k, "k");
112         svgWriter.write(tree, nodeNames, new File(outputFolder, String.format(OUTPUT_FILE_FORMAT, ++cutCount)));
113     }
114 }