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    *      https://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  
18  /*
19   * This is not the original file distributed by the Apache Software Foundation
20   * It has been modified by the Hipparchus project
21   */
22  package org.hipparchus.geometry.partitioning;
23  
24  import java.io.IOException;
25  import java.text.ParseException;
26  import java.util.StringTokenizer;
27  
28  import org.hipparchus.geometry.Space;
29  import org.hipparchus.geometry.euclidean.oned.Euclidean1D;
30  import org.hipparchus.geometry.euclidean.oned.IntervalsSet;
31  import org.hipparchus.geometry.euclidean.oned.OrientedPoint;
32  import org.hipparchus.geometry.euclidean.oned.Vector1D;
33  import org.hipparchus.geometry.euclidean.threed.Euclidean3D;
34  import org.hipparchus.geometry.euclidean.threed.Plane;
35  import org.hipparchus.geometry.euclidean.threed.PolyhedronsSet;
36  import org.hipparchus.geometry.euclidean.threed.Vector3D;
37  import org.hipparchus.geometry.euclidean.twod.Euclidean2D;
38  import org.hipparchus.geometry.euclidean.twod.Line;
39  import org.hipparchus.geometry.euclidean.twod.PolygonsSet;
40  import org.hipparchus.geometry.euclidean.twod.Vector2D;
41  import org.hipparchus.geometry.spherical.oned.ArcsSet;
42  import org.hipparchus.geometry.spherical.oned.LimitAngle;
43  import org.hipparchus.geometry.spherical.oned.S1Point;
44  import org.hipparchus.geometry.spherical.oned.Sphere1D;
45  import org.hipparchus.geometry.spherical.twod.Circle;
46  import org.hipparchus.geometry.spherical.twod.Sphere2D;
47  import org.hipparchus.geometry.spherical.twod.SphericalPolygonsSet;
48  
49  /** Class parsing a string representation of an {@link AbstractRegion}.
50   * <p>
51   * This class is intended for tests and debug purposes only.
52   * </p>
53   * @see RegionDumper
54   */
55  public class RegionParser {
56  
57      /** Private constructor for a utility class
58       */
59      private RegionParser() {
60      }
61  
62      /** Parse a string representation of an {@link ArcsSet}.
63       * @param s string to parse
64       * @return parsed region
65       * @exception IOException if the string cannot be read
66       * @exception ParseException if the string cannot be parsed
67       */
68      public static ArcsSet parseArcsSet(final String s)
69          throws IOException, ParseException {
70          final TreeBuilder<Sphere1D> builder = new TreeBuilder<Sphere1D>("ArcsSet", s) {
71  
72              /** {@inheritDoc} */
73              @Override
74              protected LimitAngle parseHyperplane()
75                  throws IOException, ParseException {
76                  return new LimitAngle(new S1Point(getNumber()), getBoolean(), getNumber());
77              }
78  
79          };
80          return new ArcsSet(builder.getTree(), builder.getTolerance());
81      }
82  
83      /** Parse a string representation of a {@link SphericalPolygonsSet}.
84       * @param s string to parse
85       * @return parsed region
86       * @exception IOException if the string cannot be read
87       * @exception ParseException if the string cannot be parsed
88       */
89      public static SphericalPolygonsSet parseSphericalPolygonsSet(final String s)
90          throws IOException, ParseException {
91          final TreeBuilder<Sphere2D> builder = new TreeBuilder<Sphere2D>("SphericalPolygonsSet", s) {
92  
93              /** {@inheritDoc} */
94              @Override
95              public Circle parseHyperplane()
96                  throws IOException, ParseException {
97                  return new Circle(new Vector3D(getNumber(), getNumber(), getNumber()), getNumber());
98              }
99  
100         };
101         return new SphericalPolygonsSet(builder.getTree(), builder.getTolerance());
102     }
103 
104     /** Parse a string representation of an {@link IntervalsSet}.
105      * @param s string to parse
106      * @return parsed region
107      * @exception IOException if the string cannot be read
108      * @exception ParseException if the string cannot be parsed
109      */
110     public static IntervalsSet parseIntervalsSet(final String s)
111         throws IOException, ParseException {
112         final TreeBuilder<Euclidean1D> builder = new TreeBuilder<Euclidean1D>("IntervalsSet", s) {
113 
114             /** {@inheritDoc} */
115             @Override
116             public OrientedPoint parseHyperplane()
117                 throws IOException, ParseException {
118                 return new OrientedPoint(new Vector1D(getNumber()), getBoolean(), getNumber());
119             }
120 
121         };
122         return new IntervalsSet(builder.getTree(), builder.getTolerance());
123     }
124 
125     /** Parse a string representation of a {@link PolygonsSet}.
126      * @param s string to parse
127      * @return parsed region
128      * @exception IOException if the string cannot be read
129      * @exception ParseException if the string cannot be parsed
130      */
131     public static PolygonsSet parsePolygonsSet(final String s)
132         throws IOException, ParseException {
133         final TreeBuilder<Euclidean2D> builder = new TreeBuilder<Euclidean2D>("PolygonsSet", s) {
134 
135             /** {@inheritDoc} */
136             @Override
137             public Line parseHyperplane()
138                 throws IOException, ParseException {
139                 return new Line(new Vector2D(getNumber(), getNumber()), getNumber(), getNumber());
140             }
141 
142         };
143         return new PolygonsSet(builder.getTree(), builder.getTolerance());
144     }
145 
146     /** Parse a string representation of a {@link PolyhedronsSet}.
147      * @param s string to parse
148      * @return parsed region
149      * @exception IOException if the string cannot be read
150      * @exception ParseException if the string cannot be parsed
151      */
152     public static PolyhedronsSet parsePolyhedronsSet(final String s)
153         throws IOException, ParseException {
154         final TreeBuilder<Euclidean3D> builder = new TreeBuilder<Euclidean3D>("PolyhedronsSet", s) {
155 
156             /** {@inheritDoc} */
157             @Override
158             public Plane parseHyperplane()
159                 throws IOException, ParseException {
160                 return new Plane(new Vector3D(getNumber(), getNumber(), getNumber()),
161                                  new Vector3D(getNumber(), getNumber(), getNumber()),
162                                  getNumber());
163             }
164 
165         };
166         return new PolyhedronsSet(builder.getTree(), builder.getTolerance());
167     }
168 
169     /** Local class for building an {@link AbstractRegion} tree.
170      * @param <S> Type of the space.
171      */
172     private abstract static class TreeBuilder<S extends Space> {
173 
174         /** Keyword for tolerance. */
175         private static final String TOLERANCE = "tolerance";
176 
177         /** Keyword for internal nodes. */
178         private static final String INTERNAL  = "internal";
179 
180         /** Keyword for leaf nodes. */
181         private static final String LEAF      = "leaf";
182 
183         /** Keyword for plus children trees. */
184         private static final String PLUS      = "plus";
185 
186         /** Keyword for minus children trees. */
187         private static final String MINUS     = "minus";
188 
189         /** Keyword for true flags. */
190         private static final String TRUE      = "true";
191 
192         /** Keyword for false flags. */
193         private static final String FALSE     = "false";
194 
195         /** Tree root. */
196         private BSPTree<S> root;
197 
198         /** Tolerance. */
199         private final double tolerance;
200 
201         /** Tokenizer parsing string representation. */
202         private final StringTokenizer tokenizer;
203 
204         /** Simple constructor.
205          * @param type type of the expected representation
206          * @param s string representation
207          * @exception IOException if the string cannot be read
208          * @exception ParseException if the string cannot be parsed
209          */
210         public TreeBuilder(final String type, final String s)
211             throws IOException, ParseException {
212             root = null;
213             tokenizer = new StringTokenizer(s);
214             getWord(type);
215             getWord(TOLERANCE);
216             tolerance = getNumber();
217             getWord(PLUS);
218             root = new BSPTree<S>();
219             parseTree(root);
220             if (tokenizer.hasMoreTokens()) {
221                 throw new ParseException("unexpected " + tokenizer.nextToken(), 0);
222             }
223         }
224 
225         /** Parse a tree.
226          * @param node start node
227          * @exception IOException if the string cannot be read
228          * @exception ParseException if the string cannot be parsed
229          */
230         private void parseTree(final BSPTree<S> node)
231             throws IOException, ParseException {
232             if (INTERNAL.equals(getWord(INTERNAL, LEAF))) {
233                 // this is an internal node, it has a cut sub-hyperplane (stored as a whole hyperplane)
234                 // then a minus tree, then a plus tree
235                 node.insertCut(parseHyperplane());
236                 getWord(MINUS);
237                 parseTree(node.getMinus());
238                 getWord(PLUS);
239                 parseTree(node.getPlus());
240             } else {
241                 // this is a leaf node, it has only an inside/outside flag
242                 node.setAttribute(getBoolean());
243             }
244         }
245 
246         /** Get next word.
247          * @param allowed allowed values
248          * @return parsed word
249          * @exception IOException if the string cannot be read
250          * @exception ParseException if the string cannot be parsed
251          */
252         protected String getWord(final String ... allowed)
253             throws IOException, ParseException {
254             final String token = tokenizer.nextToken();
255             for (final String a : allowed) {
256                 if (a.equals(token)) {
257                     return token;
258                 }
259             }
260             throw new ParseException(token + " != " + allowed[0], 0);
261         }
262 
263         /** Get next number.
264          * @return parsed number
265          * @exception IOException if the string cannot be read
266          * @exception NumberFormatException if the string cannot be parsed
267          */
268         protected double getNumber()
269             throws IOException, NumberFormatException {
270             return Double.parseDouble(tokenizer.nextToken());
271         }
272 
273         /** Get next boolean.
274          * @return parsed boolean
275          * @exception IOException if the string cannot be read
276          * @exception ParseException if the string cannot be parsed
277          */
278         protected boolean getBoolean()
279             throws IOException, ParseException {
280             return getWord(TRUE, FALSE).equals(TRUE);
281         }
282 
283         /** Get the built tree.
284          * @return built tree
285          */
286         public BSPTree<S> getTree() {
287             return root;
288         }
289 
290         /** Get the tolerance.
291          * @return tolerance
292          */
293         public double getTolerance() {
294             return tolerance;
295         }
296 
297         /** Parse an hyperplane.
298          * @return next hyperplane from the stream
299          * @exception IOException if the string cannot be read
300          * @exception ParseException if the string cannot be parsed
301          */
302         protected abstract Hyperplane<S> parseHyperplane()
303             throws IOException, ParseException;
304 
305     }
306 
307 }