Added dump/parse utilities for BSP trees.
These utilities are for test and debug purposes only.
This commit is contained in:
parent
b4d2c75d39
commit
9744a812bd
|
@ -16,7 +16,11 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.commons.math3.geometry.euclidean.threed;
|
package org.apache.commons.math3.geometry.euclidean.threed;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.text.ParseException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.apache.commons.math3.exception.MathArithmeticException;
|
import org.apache.commons.math3.exception.MathArithmeticException;
|
||||||
import org.apache.commons.math3.exception.MathIllegalArgumentException;
|
import org.apache.commons.math3.exception.MathIllegalArgumentException;
|
||||||
|
@ -29,7 +33,9 @@ import org.apache.commons.math3.geometry.partitioning.BSPTree;
|
||||||
import org.apache.commons.math3.geometry.partitioning.BSPTreeVisitor;
|
import org.apache.commons.math3.geometry.partitioning.BSPTreeVisitor;
|
||||||
import org.apache.commons.math3.geometry.partitioning.BoundaryAttribute;
|
import org.apache.commons.math3.geometry.partitioning.BoundaryAttribute;
|
||||||
import org.apache.commons.math3.geometry.partitioning.Region;
|
import org.apache.commons.math3.geometry.partitioning.Region;
|
||||||
|
import org.apache.commons.math3.geometry.partitioning.RegionDumper;
|
||||||
import org.apache.commons.math3.geometry.partitioning.RegionFactory;
|
import org.apache.commons.math3.geometry.partitioning.RegionFactory;
|
||||||
|
import org.apache.commons.math3.geometry.partitioning.RegionParser;
|
||||||
import org.apache.commons.math3.geometry.partitioning.SubHyperplane;
|
import org.apache.commons.math3.geometry.partitioning.SubHyperplane;
|
||||||
import org.apache.commons.math3.util.FastMath;
|
import org.apache.commons.math3.util.FastMath;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
|
@ -307,6 +313,57 @@ public class PolyhedronsSetTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDumpParse() throws IOException, ParseException {
|
||||||
|
double tol=1e-8;
|
||||||
|
|
||||||
|
Vector3D[] verts=new Vector3D[8];
|
||||||
|
double xmin=-1,xmax=1;
|
||||||
|
double ymin=-1,ymax=1;
|
||||||
|
double zmin=-1,zmax=1;
|
||||||
|
verts[0]=new Vector3D(xmin,ymin,zmin);
|
||||||
|
verts[1]=new Vector3D(xmax,ymin,zmin);
|
||||||
|
verts[2]=new Vector3D(xmax,ymax,zmin);
|
||||||
|
verts[3]=new Vector3D(xmin,ymax,zmin);
|
||||||
|
verts[4]=new Vector3D(xmin,ymin,zmax);
|
||||||
|
verts[5]=new Vector3D(xmax,ymin,zmax);
|
||||||
|
verts[6]=new Vector3D(xmax,ymax,zmax);
|
||||||
|
verts[7]=new Vector3D(xmin,ymax,zmax);
|
||||||
|
//
|
||||||
|
int[][] faces=new int[12][];
|
||||||
|
faces[0]=new int[]{3,1,0}; // bottom (-z)
|
||||||
|
faces[1]=new int[]{1,3,2}; // bottom (-z)
|
||||||
|
faces[2]=new int[]{5,7,4}; // top (+z)
|
||||||
|
faces[3]=new int[]{7,5,6}; // top (+z)
|
||||||
|
faces[4]=new int[]{2,5,1}; // right (+x)
|
||||||
|
faces[5]=new int[]{5,2,6}; // right (+x)
|
||||||
|
faces[6]=new int[]{4,3,0}; // left (-x)
|
||||||
|
faces[7]=new int[]{3,4,7}; // left (-x)
|
||||||
|
faces[8]=new int[]{4,1,5}; // front (-y)
|
||||||
|
faces[9]=new int[]{1,4,0}; // front (-y)
|
||||||
|
faces[10]=new int[]{3,6,2}; // back (+y)
|
||||||
|
faces[11]=new int[]{6,3,7}; // back (+y)
|
||||||
|
//
|
||||||
|
Set<SubHyperplane<Euclidean3D>> pset=new HashSet<>();
|
||||||
|
for (int f=0; f<faces.length; f++) {
|
||||||
|
int[] vidx=faces[f];
|
||||||
|
Plane p=new Plane(verts[vidx[0]],verts[vidx[1]],verts[vidx[2]],tol);
|
||||||
|
Vector2D p0=p.toSubSpace(verts[vidx[0]]);
|
||||||
|
Vector2D p1=p.toSubSpace(verts[vidx[1]]);
|
||||||
|
Vector2D p2=p.toSubSpace(verts[vidx[2]]);
|
||||||
|
PolygonsSet lset=new PolygonsSet(tol,p0,p1,p2);
|
||||||
|
pset.add(new SubPlane(p,lset));
|
||||||
|
}
|
||||||
|
PolyhedronsSet polyset=new PolyhedronsSet(pset,tol);
|
||||||
|
Assert.assertEquals(8.0, polyset.getSize(), 1.0e-10);
|
||||||
|
Assert.assertEquals(24.0, polyset.getBoundarySize(), 1.0e-10);
|
||||||
|
String dump = RegionDumper.dump(polyset);
|
||||||
|
PolyhedronsSet parsed = RegionParser.parsePolyhedronsSet(dump);
|
||||||
|
Assert.assertEquals(8.0, parsed.getSize(), 1.0e-10);
|
||||||
|
Assert.assertEquals(24.0, parsed.getBoundarySize(), 1.0e-10);
|
||||||
|
Assert.assertTrue(new RegionFactory<Euclidean3D>().difference(polyset, parsed).isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
private void checkPoints(Region.Location expected, PolyhedronsSet tree, Vector3D[] points) {
|
private void checkPoints(Region.Location expected, PolyhedronsSet tree, Vector3D[] points) {
|
||||||
for (int i = 0; i < points.length; ++i) {
|
for (int i = 0; i < points.length; ++i) {
|
||||||
Assert.assertEquals(expected, tree.checkPoint(points[i]));
|
Assert.assertEquals(expected, tree.checkPoint(points[i]));
|
||||||
|
|
|
@ -0,0 +1,244 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.commons.math3.geometry.partitioning;
|
||||||
|
|
||||||
|
import java.util.Formatter;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import org.apache.commons.math3.geometry.Space;
|
||||||
|
import org.apache.commons.math3.geometry.euclidean.oned.Euclidean1D;
|
||||||
|
import org.apache.commons.math3.geometry.euclidean.oned.IntervalsSet;
|
||||||
|
import org.apache.commons.math3.geometry.euclidean.oned.OrientedPoint;
|
||||||
|
import org.apache.commons.math3.geometry.euclidean.oned.Vector1D;
|
||||||
|
import org.apache.commons.math3.geometry.euclidean.threed.Euclidean3D;
|
||||||
|
import org.apache.commons.math3.geometry.euclidean.threed.Plane;
|
||||||
|
import org.apache.commons.math3.geometry.euclidean.threed.PolyhedronsSet;
|
||||||
|
import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
|
||||||
|
import org.apache.commons.math3.geometry.euclidean.twod.Euclidean2D;
|
||||||
|
import org.apache.commons.math3.geometry.euclidean.twod.Line;
|
||||||
|
import org.apache.commons.math3.geometry.euclidean.twod.PolygonsSet;
|
||||||
|
import org.apache.commons.math3.geometry.euclidean.twod.Vector2D;
|
||||||
|
import org.apache.commons.math3.geometry.spherical.oned.ArcsSet;
|
||||||
|
import org.apache.commons.math3.geometry.spherical.oned.LimitAngle;
|
||||||
|
import org.apache.commons.math3.geometry.spherical.oned.Sphere1D;
|
||||||
|
import org.apache.commons.math3.geometry.spherical.twod.Circle;
|
||||||
|
import org.apache.commons.math3.geometry.spherical.twod.Sphere2D;
|
||||||
|
import org.apache.commons.math3.geometry.spherical.twod.SphericalPolygonsSet;
|
||||||
|
|
||||||
|
/** Class dumping a string representation of an {@link AbstractRegion}.
|
||||||
|
* <p>
|
||||||
|
* This class is intended for tests and debug purposes only.
|
||||||
|
* </p>
|
||||||
|
* @see RegionParser
|
||||||
|
* @since 3.5
|
||||||
|
*/
|
||||||
|
public class RegionDumper {
|
||||||
|
|
||||||
|
/** Private constructor for a utility class
|
||||||
|
*/
|
||||||
|
private RegionDumper() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get a string representation of an {@link ArcsSet}.
|
||||||
|
* @param arcsSet region to dump
|
||||||
|
* @return string representation of the region
|
||||||
|
*/
|
||||||
|
public static String dump(final ArcsSet arcsSet) {
|
||||||
|
final TreeDumper<Sphere1D> visitor = new TreeDumper<Sphere1D>("ArcsSet", arcsSet.getTolerance()) {
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
protected void formatHyperplane(final Hyperplane<Sphere1D> hyperplane) {
|
||||||
|
final LimitAngle h = (LimitAngle) hyperplane;
|
||||||
|
getFormatter().format("%22.15e %b %22.15e",
|
||||||
|
h.getLocation().getAlpha(), h.isDirect(), h.getTolerance());
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
arcsSet.getTree(false).visit(visitor);
|
||||||
|
return visitor.getDump();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get a string representation of a {@link SphericalPolygonsSet}.
|
||||||
|
* @param sphericalPolygonsSet region to dump
|
||||||
|
* @return string representation of the region
|
||||||
|
*/
|
||||||
|
public static String dump(final SphericalPolygonsSet sphericalPolygonsSet) {
|
||||||
|
final TreeDumper<Sphere2D> visitor = new TreeDumper<Sphere2D>("SphericalPolygonsSet", sphericalPolygonsSet.getTolerance()) {
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
protected void formatHyperplane(final Hyperplane<Sphere2D> hyperplane) {
|
||||||
|
final Circle h = (Circle) hyperplane;
|
||||||
|
getFormatter().format("%22.15e %22.15e %22.15e %22.15e",
|
||||||
|
h.getPole().getX(), h.getPole().getY(), h.getPole().getZ(),
|
||||||
|
h.getTolerance());
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
sphericalPolygonsSet.getTree(false).visit(visitor);
|
||||||
|
return visitor.getDump();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get a string representation of an {@link IntervalsSet}.
|
||||||
|
* @param intervalsSet region to dump
|
||||||
|
* @return string representation of the region
|
||||||
|
*/
|
||||||
|
public static String dump(final IntervalsSet intervalsSet) {
|
||||||
|
final TreeDumper<Euclidean1D> visitor = new TreeDumper<Euclidean1D>("IntervalsSet", intervalsSet.getTolerance()) {
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
protected void formatHyperplane(final Hyperplane<Euclidean1D> hyperplane) {
|
||||||
|
final OrientedPoint h = (OrientedPoint) hyperplane;
|
||||||
|
getFormatter().format("%22.15e %b %22.15e",
|
||||||
|
h.getLocation().getX(), h.isDirect(), h.getTolerance());
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
intervalsSet.getTree(false).visit(visitor);
|
||||||
|
return visitor.getDump();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get a string representation of a {@link PolygonsSet}.
|
||||||
|
* @param polygonsSet region to dump
|
||||||
|
* @return string representation of the region
|
||||||
|
*/
|
||||||
|
public static String dump(final PolygonsSet polygonsSet) {
|
||||||
|
final TreeDumper<Euclidean2D> visitor = new TreeDumper<Euclidean2D>("PolygonsSet", polygonsSet.getTolerance()) {
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
protected void formatHyperplane(final Hyperplane<Euclidean2D> hyperplane) {
|
||||||
|
final Line h = (Line) hyperplane;
|
||||||
|
final Vector2D p = h.toSpace(Vector1D.ZERO);
|
||||||
|
getFormatter().format("%22.15e %22.15e %22.15e %22.15e",
|
||||||
|
p.getX(), p.getY(), h.getAngle(), h.getTolerance());
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
polygonsSet.getTree(false).visit(visitor);
|
||||||
|
return visitor.getDump();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get a string representation of a {@link PolyhedronsSet}.
|
||||||
|
* @param polyhedronsSet region to dump
|
||||||
|
* @return string representation of the region
|
||||||
|
*/
|
||||||
|
public static String dump(final PolyhedronsSet polyhedronsSet) {
|
||||||
|
final TreeDumper<Euclidean3D> visitor = new TreeDumper<Euclidean3D>("PolyhedronsSet", polyhedronsSet.getTolerance()) {
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
protected void formatHyperplane(final Hyperplane<Euclidean3D> hyperplane) {
|
||||||
|
final Plane h = (Plane) hyperplane;
|
||||||
|
final Vector3D p = h.toSpace(Vector2D.ZERO);
|
||||||
|
getFormatter().format("%22.15e %22.15e %22.15e %22.15e %22.15e %22.15e %22.15e",
|
||||||
|
p.getX(), p.getY(), p.getZ(),
|
||||||
|
h.getNormal().getX(), h.getNormal().getY(), h.getNormal().getZ(),
|
||||||
|
h.getTolerance());
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
polyhedronsSet.getTree(false).visit(visitor);
|
||||||
|
return visitor.getDump();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Dumping visitor.
|
||||||
|
* @param <S> Type of the space.
|
||||||
|
*/
|
||||||
|
private abstract static class TreeDumper<S extends Space> implements BSPTreeVisitor<S> {
|
||||||
|
|
||||||
|
/** Builder for the string representation of the dumped tree. */
|
||||||
|
private final StringBuilder dump;
|
||||||
|
|
||||||
|
/** Formatter for strings. */
|
||||||
|
private final Formatter formatter;
|
||||||
|
|
||||||
|
/** Current indentation prefix. */
|
||||||
|
private String prefix;
|
||||||
|
|
||||||
|
/** Simple constructor.
|
||||||
|
* @param type type of the region to dump
|
||||||
|
* @param tolerance tolerance of the region
|
||||||
|
*/
|
||||||
|
public TreeDumper(final String type, final double tolerance) {
|
||||||
|
this.dump = new StringBuilder();
|
||||||
|
this.formatter = new Formatter(dump, Locale.US);
|
||||||
|
this.prefix = "";
|
||||||
|
formatter.format("%s%n", type);
|
||||||
|
formatter.format("tolerance %22.15e%n", tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get the string representation of the tree.
|
||||||
|
* @return string representation of the tree.
|
||||||
|
*/
|
||||||
|
public String getDump() {
|
||||||
|
return dump.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get the formatter to use.
|
||||||
|
* @return formatter to use
|
||||||
|
*/
|
||||||
|
protected Formatter getFormatter() {
|
||||||
|
return formatter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Format a string representation of the hyperplane underlying a cut sub-hyperplane.
|
||||||
|
* @param hyperplane hyperplane to format
|
||||||
|
*/
|
||||||
|
protected abstract void formatHyperplane(Hyperplane<S> hyperplane);
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public Order visitOrder(final BSPTree<S> node) {
|
||||||
|
return Order.SUB_MINUS_PLUS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public void visitInternalNode(final BSPTree<S> node) {
|
||||||
|
formatter.format("%s %s internal ", prefix, type(node));
|
||||||
|
formatHyperplane(node.getCut().getHyperplane());
|
||||||
|
formatter.format("%n");
|
||||||
|
prefix = prefix + " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public void visitLeafNode(final BSPTree<S> node) {
|
||||||
|
formatter.format("%s %s leaf %s%n",
|
||||||
|
prefix, type(node), node.getAttribute());
|
||||||
|
for (BSPTree<S> n = node;
|
||||||
|
n.getParent() != null && n == n.getParent().getPlus();
|
||||||
|
n = n.getParent()) {
|
||||||
|
prefix = prefix.substring(0, prefix.length() - 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get the type of the node.
|
||||||
|
* @param node node to check
|
||||||
|
* @return "plus " or "minus" depending on the node being the plus or minus
|
||||||
|
* child of its parent ("plus " is arbitrarily returned for the root node)
|
||||||
|
*/
|
||||||
|
private String type(final BSPTree<S> node) {
|
||||||
|
return (node.getParent() != null && node == node.getParent().getMinus()) ? "minus" : "plus ";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,303 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.commons.math3.geometry.partitioning;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.text.ParseException;
|
||||||
|
import java.util.StringTokenizer;
|
||||||
|
|
||||||
|
import org.apache.commons.math3.geometry.Space;
|
||||||
|
import org.apache.commons.math3.geometry.euclidean.oned.Euclidean1D;
|
||||||
|
import org.apache.commons.math3.geometry.euclidean.oned.IntervalsSet;
|
||||||
|
import org.apache.commons.math3.geometry.euclidean.oned.OrientedPoint;
|
||||||
|
import org.apache.commons.math3.geometry.euclidean.oned.Vector1D;
|
||||||
|
import org.apache.commons.math3.geometry.euclidean.threed.Euclidean3D;
|
||||||
|
import org.apache.commons.math3.geometry.euclidean.threed.Plane;
|
||||||
|
import org.apache.commons.math3.geometry.euclidean.threed.PolyhedronsSet;
|
||||||
|
import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
|
||||||
|
import org.apache.commons.math3.geometry.euclidean.twod.Euclidean2D;
|
||||||
|
import org.apache.commons.math3.geometry.euclidean.twod.Line;
|
||||||
|
import org.apache.commons.math3.geometry.euclidean.twod.PolygonsSet;
|
||||||
|
import org.apache.commons.math3.geometry.euclidean.twod.Vector2D;
|
||||||
|
import org.apache.commons.math3.geometry.spherical.oned.ArcsSet;
|
||||||
|
import org.apache.commons.math3.geometry.spherical.oned.LimitAngle;
|
||||||
|
import org.apache.commons.math3.geometry.spherical.oned.S1Point;
|
||||||
|
import org.apache.commons.math3.geometry.spherical.oned.Sphere1D;
|
||||||
|
import org.apache.commons.math3.geometry.spherical.twod.Circle;
|
||||||
|
import org.apache.commons.math3.geometry.spherical.twod.Sphere2D;
|
||||||
|
import org.apache.commons.math3.geometry.spherical.twod.SphericalPolygonsSet;
|
||||||
|
|
||||||
|
/** Class parsing a string representation of an {@link AbstractRegion}.
|
||||||
|
* <p>
|
||||||
|
* This class is intended for tests and debug purposes only.
|
||||||
|
* </p>
|
||||||
|
* @see RegionDumper
|
||||||
|
* @since 3.5
|
||||||
|
*/
|
||||||
|
public class RegionParser {
|
||||||
|
|
||||||
|
/** Private constructor for a utility class
|
||||||
|
*/
|
||||||
|
private RegionParser() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Parse a string representation of an {@link ArcsSet}.
|
||||||
|
* @param s string to parse
|
||||||
|
* @return parsed region
|
||||||
|
* @exception IOException if the string cannot be read
|
||||||
|
* @exception ParseException if the string cannot be parsed
|
||||||
|
*/
|
||||||
|
public static ArcsSet parseArcsSet(final String s)
|
||||||
|
throws IOException, ParseException {
|
||||||
|
final TreeBuilder<Sphere1D> builder = new TreeBuilder<Sphere1D>("ArcsSet", s) {
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
protected LimitAngle parseHyperplane()
|
||||||
|
throws IOException, ParseException {
|
||||||
|
return new LimitAngle(new S1Point(getNumber()), getBoolean(), getNumber());
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
return new ArcsSet(builder.getTree(), builder.getTolerance());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Parse a string representation of a {@link SphericalPolygonsSet}.
|
||||||
|
* @param s string to parse
|
||||||
|
* @return parsed region
|
||||||
|
* @exception IOException if the string cannot be read
|
||||||
|
* @exception ParseException if the string cannot be parsed
|
||||||
|
*/
|
||||||
|
public static SphericalPolygonsSet parseSphericalPolygonsSet(final String s)
|
||||||
|
throws IOException, ParseException {
|
||||||
|
final TreeBuilder<Sphere2D> builder = new TreeBuilder<Sphere2D>("SphericalPolygonsSet", s) {
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public Circle parseHyperplane()
|
||||||
|
throws IOException, ParseException {
|
||||||
|
return new Circle(new Vector3D(getNumber(), getNumber(), getNumber()), getNumber());
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
return new SphericalPolygonsSet(builder.getTree(), builder.getTolerance());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Parse a string representation of an {@link IntervalsSet}.
|
||||||
|
* @param s string to parse
|
||||||
|
* @return parsed region
|
||||||
|
* @exception IOException if the string cannot be read
|
||||||
|
* @exception ParseException if the string cannot be parsed
|
||||||
|
*/
|
||||||
|
public static IntervalsSet parseIntervalsSet(final String s)
|
||||||
|
throws IOException, ParseException {
|
||||||
|
final TreeBuilder<Euclidean1D> builder = new TreeBuilder<Euclidean1D>("IntervalsSet", s) {
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public OrientedPoint parseHyperplane()
|
||||||
|
throws IOException, ParseException {
|
||||||
|
return new OrientedPoint(new Vector1D(getNumber()), getBoolean(), getNumber());
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
return new IntervalsSet(builder.getTree(), builder.getTolerance());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Parse a string representation of a {@link PolygonsSet}.
|
||||||
|
* @param s string to parse
|
||||||
|
* @return parsed region
|
||||||
|
* @exception IOException if the string cannot be read
|
||||||
|
* @exception ParseException if the string cannot be parsed
|
||||||
|
*/
|
||||||
|
public static PolygonsSet parsePolygonsSet(final String s)
|
||||||
|
throws IOException, ParseException {
|
||||||
|
final TreeBuilder<Euclidean2D> builder = new TreeBuilder<Euclidean2D>("PolygonsSet", s) {
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public Line parseHyperplane()
|
||||||
|
throws IOException, ParseException {
|
||||||
|
return new Line(new Vector2D(getNumber(), getNumber()), getNumber(), getNumber());
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
return new PolygonsSet(builder.getTree(), builder.getTolerance());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Parse a string representation of a {@link PolyhedronsSet}.
|
||||||
|
* @param s string to parse
|
||||||
|
* @return parsed region
|
||||||
|
* @exception IOException if the string cannot be read
|
||||||
|
* @exception ParseException if the string cannot be parsed
|
||||||
|
*/
|
||||||
|
public static PolyhedronsSet parsePolyhedronsSet(final String s)
|
||||||
|
throws IOException, ParseException {
|
||||||
|
final TreeBuilder<Euclidean3D> builder = new TreeBuilder<Euclidean3D>("PolyhedronsSet", s) {
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public Plane parseHyperplane()
|
||||||
|
throws IOException, ParseException {
|
||||||
|
return new Plane(new Vector3D(getNumber(), getNumber(), getNumber()),
|
||||||
|
new Vector3D(getNumber(), getNumber(), getNumber()),
|
||||||
|
getNumber());
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
return new PolyhedronsSet(builder.getTree(), builder.getTolerance());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Local class for building an {@link AbstractRegion} tree.
|
||||||
|
* @param <S> Type of the space.
|
||||||
|
*/
|
||||||
|
private abstract static class TreeBuilder<S extends Space> {
|
||||||
|
|
||||||
|
/** Keyword for tolerance. */
|
||||||
|
private static final String TOLERANCE = "tolerance";
|
||||||
|
|
||||||
|
/** Keyword for internal nodes. */
|
||||||
|
private static final String INTERNAL = "internal";
|
||||||
|
|
||||||
|
/** Keyword for leaf nodes. */
|
||||||
|
private static final String LEAF = "leaf";
|
||||||
|
|
||||||
|
/** Keyword for plus children trees. */
|
||||||
|
private static final String PLUS = "plus";
|
||||||
|
|
||||||
|
/** Keyword for minus children trees. */
|
||||||
|
private static final String MINUS = "minus";
|
||||||
|
|
||||||
|
/** Keyword for true flags. */
|
||||||
|
private static final String TRUE = "true";
|
||||||
|
|
||||||
|
/** Keyword for false flags. */
|
||||||
|
private static final String FALSE = "false";
|
||||||
|
|
||||||
|
/** Tree root. */
|
||||||
|
private BSPTree<S> root;
|
||||||
|
|
||||||
|
/** Tolerance. */
|
||||||
|
private final double tolerance;
|
||||||
|
|
||||||
|
/** Tokenizer parsing string representation. */
|
||||||
|
private final StringTokenizer tokenizer;
|
||||||
|
|
||||||
|
/** Simple constructor.
|
||||||
|
* @param type type of the expected representation
|
||||||
|
* @param reader reader for the string representation
|
||||||
|
* @exception IOException if the string cannot be read
|
||||||
|
* @exception ParseException if the string cannot be parsed
|
||||||
|
*/
|
||||||
|
public TreeBuilder(final String type, final String s)
|
||||||
|
throws IOException, ParseException {
|
||||||
|
root = null;
|
||||||
|
tokenizer = new StringTokenizer(s);
|
||||||
|
getWord(type);
|
||||||
|
getWord(TOLERANCE);
|
||||||
|
tolerance = getNumber();
|
||||||
|
getWord(PLUS);
|
||||||
|
root = new BSPTree<S>();
|
||||||
|
parseTree(root);
|
||||||
|
if (tokenizer.hasMoreTokens()) {
|
||||||
|
throw new ParseException("unexpected " + tokenizer.nextToken(), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Parse a tree.
|
||||||
|
* @param node start node
|
||||||
|
* @exception IOException if the string cannot be read
|
||||||
|
* @exception ParseException if the string cannot be parsed
|
||||||
|
*/
|
||||||
|
private void parseTree(final BSPTree<S> node)
|
||||||
|
throws IOException, ParseException {
|
||||||
|
if (INTERNAL.equals(getWord(INTERNAL, LEAF))) {
|
||||||
|
// this is an internal node, it has a cut sub-hyperplane (stored as a whole hyperplane)
|
||||||
|
// then a minus tree, then a plus tree
|
||||||
|
node.insertCut(parseHyperplane());
|
||||||
|
getWord(MINUS);
|
||||||
|
parseTree(node.getMinus());
|
||||||
|
getWord(PLUS);
|
||||||
|
parseTree(node.getPlus());
|
||||||
|
} else {
|
||||||
|
// this is a leaf node, it has only an inside/outside flag
|
||||||
|
node.setAttribute(getBoolean());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get next word.
|
||||||
|
* @param allowed allowed values
|
||||||
|
* @return parsed word
|
||||||
|
* @exception IOException if the string cannot be read
|
||||||
|
* @exception ParseException if the string cannot be parsed
|
||||||
|
*/
|
||||||
|
protected String getWord(final String ... allowed)
|
||||||
|
throws IOException, ParseException {
|
||||||
|
final String token = tokenizer.nextToken();
|
||||||
|
for (final String a : allowed) {
|
||||||
|
if (a.equals(token)) {
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new ParseException(token + " != " + allowed[0], 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get next number.
|
||||||
|
* @return parsed number
|
||||||
|
* @exception IOException if the string cannot be read
|
||||||
|
* @exception NumberFormatException if the string cannot be parsed
|
||||||
|
*/
|
||||||
|
protected double getNumber()
|
||||||
|
throws IOException, NumberFormatException {
|
||||||
|
return Double.parseDouble(tokenizer.nextToken());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get next boolean.
|
||||||
|
* @return parsed boolean
|
||||||
|
* @exception IOException if the string cannot be read
|
||||||
|
* @exception ParseException if the string cannot be parsed
|
||||||
|
*/
|
||||||
|
protected boolean getBoolean()
|
||||||
|
throws IOException, ParseException {
|
||||||
|
return getWord(TRUE, FALSE).equals(TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get the built tree.
|
||||||
|
* @return built tree
|
||||||
|
*/
|
||||||
|
public BSPTree<S> getTree() {
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get the tolerance.
|
||||||
|
* @return tolerance
|
||||||
|
*/
|
||||||
|
public double getTolerance() {
|
||||||
|
return tolerance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Parse an hyperplane.
|
||||||
|
* @return next hyperplane from the stream
|
||||||
|
* @exception IOException if the string cannot be read
|
||||||
|
* @exception ParseException if the string cannot be parsed
|
||||||
|
*/
|
||||||
|
protected abstract Hyperplane<S> parseHyperplane()
|
||||||
|
throws IOException, ParseException;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue