http://git-wip-us.apache.org/repos/asf/commons-math/blob/a7b4803f/src/main/java/org/apache/commons/math3/geometry/euclidean/threed/Plane.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/commons/math3/geometry/euclidean/threed/Plane.java b/src/main/java/org/apache/commons/math3/geometry/euclidean/threed/Plane.java deleted file mode 100644 index a63e806..0000000 --- a/src/main/java/org/apache/commons/math3/geometry/euclidean/threed/Plane.java +++ /dev/null @@ -1,527 +0,0 @@ -/* - * 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.euclidean.threed; - -import org.apache.commons.math3.exception.MathArithmeticException; -import org.apache.commons.math3.exception.util.LocalizedFormats; -import org.apache.commons.math3.geometry.Point; -import org.apache.commons.math3.geometry.Vector; -import org.apache.commons.math3.geometry.euclidean.oned.Euclidean1D; -import org.apache.commons.math3.geometry.euclidean.oned.Vector1D; -import org.apache.commons.math3.geometry.euclidean.twod.Euclidean2D; -import org.apache.commons.math3.geometry.euclidean.twod.PolygonsSet; -import org.apache.commons.math3.geometry.euclidean.twod.Vector2D; -import org.apache.commons.math3.geometry.partitioning.Embedding; -import org.apache.commons.math3.geometry.partitioning.Hyperplane; -import org.apache.commons.math3.util.FastMath; - -/** The class represent planes in a three dimensional space. - * @since 3.0 - */ -public class Plane implements Hyperplane<Euclidean3D>, Embedding<Euclidean3D, Euclidean2D> { - - /** Default value for tolerance. */ - private static final double DEFAULT_TOLERANCE = 1.0e-10; - - /** Offset of the origin with respect to the plane. */ - private double originOffset; - - /** Origin of the plane frame. */ - private Vector3D origin; - - /** First vector of the plane frame (in plane). */ - private Vector3D u; - - /** Second vector of the plane frame (in plane). */ - private Vector3D v; - - /** Third vector of the plane frame (plane normal). */ - private Vector3D w; - - /** Tolerance below which points are considered identical. */ - private final double tolerance; - - /** Build a plane normal to a given direction and containing the origin. - * @param normal normal direction to the plane - * @param tolerance tolerance below which points are considered identical - * @exception MathArithmeticException if the normal norm is too small - * @since 3.3 - */ - public Plane(final Vector3D normal, final double tolerance) - throws MathArithmeticException { - setNormal(normal); - this.tolerance = tolerance; - originOffset = 0; - setFrame(); - } - - /** Build a plane from a point and a normal. - * @param p point belonging to the plane - * @param normal normal direction to the plane - * @param tolerance tolerance below which points are considered identical - * @exception MathArithmeticException if the normal norm is too small - * @since 3.3 - */ - public Plane(final Vector3D p, final Vector3D normal, final double tolerance) - throws MathArithmeticException { - setNormal(normal); - this.tolerance = tolerance; - originOffset = -p.dotProduct(w); - setFrame(); - } - - /** Build a plane from three points. - * <p>The plane is oriented in the direction of - * {@code (p2-p1) ^ (p3-p1)}</p> - * @param p1 first point belonging to the plane - * @param p2 second point belonging to the plane - * @param p3 third point belonging to the plane - * @param tolerance tolerance below which points are considered identical - * @exception MathArithmeticException if the points do not constitute a plane - * @since 3.3 - */ - public Plane(final Vector3D p1, final Vector3D p2, final Vector3D p3, final double tolerance) - throws MathArithmeticException { - this(p1, p2.subtract(p1).crossProduct(p3.subtract(p1)), tolerance); - } - - /** Build a plane normal to a given direction and containing the origin. - * @param normal normal direction to the plane - * @exception MathArithmeticException if the normal norm is too small - * @deprecated as of 3.3, replaced with {@link #Plane(Vector3D, double)} - */ - @Deprecated - public Plane(final Vector3D normal) throws MathArithmeticException { - this(normal, DEFAULT_TOLERANCE); - } - - /** Build a plane from a point and a normal. - * @param p point belonging to the plane - * @param normal normal direction to the plane - * @exception MathArithmeticException if the normal norm is too small - * @deprecated as of 3.3, replaced with {@link #Plane(Vector3D, Vector3D, double)} - */ - @Deprecated - public Plane(final Vector3D p, final Vector3D normal) throws MathArithmeticException { - this(p, normal, DEFAULT_TOLERANCE); - } - - /** Build a plane from three points. - * <p>The plane is oriented in the direction of - * {@code (p2-p1) ^ (p3-p1)}</p> - * @param p1 first point belonging to the plane - * @param p2 second point belonging to the plane - * @param p3 third point belonging to the plane - * @exception MathArithmeticException if the points do not constitute a plane - * @deprecated as of 3.3, replaced with {@link #Plane(Vector3D, Vector3D, Vector3D, double)} - */ - @Deprecated - public Plane(final Vector3D p1, final Vector3D p2, final Vector3D p3) - throws MathArithmeticException { - this(p1, p2, p3, DEFAULT_TOLERANCE); - } - - /** Copy constructor. - * <p>The instance created is completely independant of the original - * one. A deep copy is used, none of the underlying object are - * shared.</p> - * @param plane plane to copy - */ - public Plane(final Plane plane) { - originOffset = plane.originOffset; - origin = plane.origin; - u = plane.u; - v = plane.v; - w = plane.w; - tolerance = plane.tolerance; - } - - /** Copy the instance. - * <p>The instance created is completely independant of the original - * one. A deep copy is used, none of the underlying objects are - * shared (except for immutable objects).</p> - * @return a new hyperplane, copy of the instance - */ - public Plane copySelf() { - return new Plane(this); - } - - /** Reset the instance as if built from a point and a normal. - * @param p point belonging to the plane - * @param normal normal direction to the plane - * @exception MathArithmeticException if the normal norm is too small - */ - public void reset(final Vector3D p, final Vector3D normal) throws MathArithmeticException { - setNormal(normal); - originOffset = -p.dotProduct(w); - setFrame(); - } - - /** Reset the instance from another one. - * <p>The updated instance is completely independant of the original - * one. A deep reset is used none of the underlying object is - * shared.</p> - * @param original plane to reset from - */ - public void reset(final Plane original) { - originOffset = original.originOffset; - origin = original.origin; - u = original.u; - v = original.v; - w = original.w; - } - - /** Set the normal vactor. - * @param normal normal direction to the plane (will be copied) - * @exception MathArithmeticException if the normal norm is too small - */ - private void setNormal(final Vector3D normal) throws MathArithmeticException { - final double norm = normal.getNorm(); - if (norm < 1.0e-10) { - throw new MathArithmeticException(LocalizedFormats.ZERO_NORM); - } - w = new Vector3D(1.0 / norm, normal); - } - - /** Reset the plane frame. - */ - private void setFrame() { - origin = new Vector3D(-originOffset, w); - u = w.orthogonal(); - v = Vector3D.crossProduct(w, u); - } - - /** Get the origin point of the plane frame. - * <p>The point returned is the orthogonal projection of the - * 3D-space origin in the plane.</p> - * @return the origin point of the plane frame (point closest to the - * 3D-space origin) - */ - public Vector3D getOrigin() { - return origin; - } - - /** Get the normalized normal vector. - * <p>The frame defined by ({@link #getU getU}, {@link #getV getV}, - * {@link #getNormal getNormal}) is a rigth-handed orthonormalized - * frame).</p> - * @return normalized normal vector - * @see #getU - * @see #getV - */ - public Vector3D getNormal() { - return w; - } - - /** Get the plane first canonical vector. - * <p>The frame defined by ({@link #getU getU}, {@link #getV getV}, - * {@link #getNormal getNormal}) is a rigth-handed orthonormalized - * frame).</p> - * @return normalized first canonical vector - * @see #getV - * @see #getNormal - */ - public Vector3D getU() { - return u; - } - - /** Get the plane second canonical vector. - * <p>The frame defined by ({@link #getU getU}, {@link #getV getV}, - * {@link #getNormal getNormal}) is a rigth-handed orthonormalized - * frame).</p> - * @return normalized second canonical vector - * @see #getU - * @see #getNormal - */ - public Vector3D getV() { - return v; - } - - /** {@inheritDoc} - * @since 3.3 - */ - public Point<Euclidean3D> project(Point<Euclidean3D> point) { - return toSpace(toSubSpace(point)); - } - - /** {@inheritDoc} - * @since 3.3 - */ - public double getTolerance() { - return tolerance; - } - - /** Revert the plane. - * <p>Replace the instance by a similar plane with opposite orientation.</p> - * <p>The new plane frame is chosen in such a way that a 3D point that had - * {@code (x, y)} in-plane coordinates and {@code z} offset with - * respect to the plane and is unaffected by the change will have - * {@code (y, x)} in-plane coordinates and {@code -z} offset with - * respect to the new plane. This means that the {@code u} and {@code v} - * vectors returned by the {@link #getU} and {@link #getV} methods are exchanged, - * and the {@code w} vector returned by the {@link #getNormal} method is - * reversed.</p> - */ - public void revertSelf() { - final Vector3D tmp = u; - u = v; - v = tmp; - w = w.negate(); - originOffset = -originOffset; - } - - /** Transform a space point into a sub-space point. - * @param vector n-dimension point of the space - * @return (n-1)-dimension point of the sub-space corresponding to - * the specified space point - */ - public Vector2D toSubSpace(Vector<Euclidean3D> vector) { - return toSubSpace((Point<Euclidean3D>) vector); - } - - /** Transform a sub-space point into a space point. - * @param vector (n-1)-dimension point of the sub-space - * @return n-dimension point of the space corresponding to the - * specified sub-space point - */ - public Vector3D toSpace(Vector<Euclidean2D> vector) { - return toSpace((Point<Euclidean2D>) vector); - } - - /** Transform a 3D space point into an in-plane point. - * @param point point of the space (must be a {@link Vector3D - * Vector3D} instance) - * @return in-plane point (really a {@link - * org.apache.commons.math3.geometry.euclidean.twod.Vector2D Vector2D} instance) - * @see #toSpace - */ - public Vector2D toSubSpace(final Point<Euclidean3D> point) { - final Vector3D p3D = (Vector3D) point; - return new Vector2D(p3D.dotProduct(u), p3D.dotProduct(v)); - } - - /** Transform an in-plane point into a 3D space point. - * @param point in-plane point (must be a {@link - * org.apache.commons.math3.geometry.euclidean.twod.Vector2D Vector2D} instance) - * @return 3D space point (really a {@link Vector3D Vector3D} instance) - * @see #toSubSpace - */ - public Vector3D toSpace(final Point<Euclidean2D> point) { - final Vector2D p2D = (Vector2D) point; - return new Vector3D(p2D.getX(), u, p2D.getY(), v, -originOffset, w); - } - - /** Get one point from the 3D-space. - * @param inPlane desired in-plane coordinates for the point in the - * plane - * @param offset desired offset for the point - * @return one point in the 3D-space, with given coordinates and offset - * relative to the plane - */ - public Vector3D getPointAt(final Vector2D inPlane, final double offset) { - return new Vector3D(inPlane.getX(), u, inPlane.getY(), v, offset - originOffset, w); - } - - /** Check if the instance is similar to another plane. - * <p>Planes are considered similar if they contain the same - * points. This does not mean they are equal since they can have - * opposite normals.</p> - * @param plane plane to which the instance is compared - * @return true if the planes are similar - */ - public boolean isSimilarTo(final Plane plane) { - final double angle = Vector3D.angle(w, plane.w); - return ((angle < 1.0e-10) && (FastMath.abs(originOffset - plane.originOffset) < 1.0e-10)) || - ((angle > (FastMath.PI - 1.0e-10)) && (FastMath.abs(originOffset + plane.originOffset) < 1.0e-10)); - } - - /** Rotate the plane around the specified point. - * <p>The instance is not modified, a new instance is created.</p> - * @param center rotation center - * @param rotation vectorial rotation operator - * @return a new plane - */ - public Plane rotate(final Vector3D center, final Rotation rotation) { - - final Vector3D delta = origin.subtract(center); - final Plane plane = new Plane(center.add(rotation.applyTo(delta)), - rotation.applyTo(w), tolerance); - - // make sure the frame is transformed as desired - plane.u = rotation.applyTo(u); - plane.v = rotation.applyTo(v); - - return plane; - - } - - /** Translate the plane by the specified amount. - * <p>The instance is not modified, a new instance is created.</p> - * @param translation translation to apply - * @return a new plane - */ - public Plane translate(final Vector3D translation) { - - final Plane plane = new Plane(origin.add(translation), w, tolerance); - - // make sure the frame is transformed as desired - plane.u = u; - plane.v = v; - - return plane; - - } - - /** Get the intersection of a line with the instance. - * @param line line intersecting the instance - * @return intersection point between between the line and the - * instance (null if the line is parallel to the instance) - */ - public Vector3D intersection(final Line line) { - final Vector3D direction = line.getDirection(); - final double dot = w.dotProduct(direction); - if (FastMath.abs(dot) < 1.0e-10) { - return null; - } - final Vector3D point = line.toSpace((Point<Euclidean1D>) Vector1D.ZERO); - final double k = -(originOffset + w.dotProduct(point)) / dot; - return new Vector3D(1.0, point, k, direction); - } - - /** Build the line shared by the instance and another plane. - * @param other other plane - * @return line at the intersection of the instance and the - * other plane (really a {@link Line Line} instance) - */ - public Line intersection(final Plane other) { - final Vector3D direction = Vector3D.crossProduct(w, other.w); - if (direction.getNorm() < 1.0e-10) { - return null; - } - final Vector3D point = intersection(this, other, new Plane(direction, tolerance)); - return new Line(point, point.add(direction), tolerance); - } - - /** Get the intersection point of three planes. - * @param plane1 first plane1 - * @param plane2 second plane2 - * @param plane3 third plane2 - * @return intersection point of three planes, null if some planes are parallel - */ - public static Vector3D intersection(final Plane plane1, final Plane plane2, final Plane plane3) { - - // coefficients of the three planes linear equations - final double a1 = plane1.w.getX(); - final double b1 = plane1.w.getY(); - final double c1 = plane1.w.getZ(); - final double d1 = plane1.originOffset; - - final double a2 = plane2.w.getX(); - final double b2 = plane2.w.getY(); - final double c2 = plane2.w.getZ(); - final double d2 = plane2.originOffset; - - final double a3 = plane3.w.getX(); - final double b3 = plane3.w.getY(); - final double c3 = plane3.w.getZ(); - final double d3 = plane3.originOffset; - - // direct Cramer resolution of the linear system - // (this is still feasible for a 3x3 system) - final double a23 = b2 * c3 - b3 * c2; - final double b23 = c2 * a3 - c3 * a2; - final double c23 = a2 * b3 - a3 * b2; - final double determinant = a1 * a23 + b1 * b23 + c1 * c23; - if (FastMath.abs(determinant) < 1.0e-10) { - return null; - } - - final double r = 1.0 / determinant; - return new Vector3D( - (-a23 * d1 - (c1 * b3 - c3 * b1) * d2 - (c2 * b1 - c1 * b2) * d3) * r, - (-b23 * d1 - (c3 * a1 - c1 * a3) * d2 - (c1 * a2 - c2 * a1) * d3) * r, - (-c23 * d1 - (b1 * a3 - b3 * a1) * d2 - (b2 * a1 - b1 * a2) * d3) * r); - - } - - /** Build a region covering the whole hyperplane. - * @return a region covering the whole hyperplane - */ - public SubPlane wholeHyperplane() { - return new SubPlane(this, new PolygonsSet(tolerance)); - } - - /** Build a region covering the whole space. - * @return a region containing the instance (really a {@link - * PolyhedronsSet PolyhedronsSet} instance) - */ - public PolyhedronsSet wholeSpace() { - return new PolyhedronsSet(tolerance); - } - - /** Check if the instance contains a point. - * @param p point to check - * @return true if p belongs to the plane - */ - public boolean contains(final Vector3D p) { - return FastMath.abs(getOffset(p)) < 1.0e-10; - } - - /** Get the offset (oriented distance) of a parallel plane. - * <p>This method should be called only for parallel planes otherwise - * the result is not meaningful.</p> - * <p>The offset is 0 if both planes are the same, it is - * positive if the plane is on the plus side of the instance and - * negative if it is on the minus side, according to its natural - * orientation.</p> - * @param plane plane to check - * @return offset of the plane - */ - public double getOffset(final Plane plane) { - return originOffset + (sameOrientationAs(plane) ? -plane.originOffset : plane.originOffset); - } - - /** Get the offset (oriented distance) of a vector. - * @param vector vector to check - * @return offset of the vector - */ - public double getOffset(Vector<Euclidean3D> vector) { - return getOffset((Point<Euclidean3D>) vector); - } - - /** Get the offset (oriented distance) of a point. - * <p>The offset is 0 if the point is on the underlying hyperplane, - * it is positive if the point is on one particular side of the - * hyperplane, and it is negative if the point is on the other side, - * according to the hyperplane natural orientation.</p> - * @param point point to check - * @return offset of the point - */ - public double getOffset(final Point<Euclidean3D> point) { - return ((Vector3D) point).dotProduct(w) + originOffset; - } - - /** Check if the instance has the same orientation as another hyperplane. - * @param other other hyperplane to check against the instance - * @return true if the instance and the other hyperplane have - * the same orientation - */ - public boolean sameOrientationAs(final Hyperplane<Euclidean3D> other) { - return (((Plane) other).w).dotProduct(w) > 0.0; - } - -}
http://git-wip-us.apache.org/repos/asf/commons-math/blob/a7b4803f/src/main/java/org/apache/commons/math3/geometry/euclidean/threed/PolyhedronsSet.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/commons/math3/geometry/euclidean/threed/PolyhedronsSet.java b/src/main/java/org/apache/commons/math3/geometry/euclidean/threed/PolyhedronsSet.java deleted file mode 100644 index d41d133..0000000 --- a/src/main/java/org/apache/commons/math3/geometry/euclidean/threed/PolyhedronsSet.java +++ /dev/null @@ -1,539 +0,0 @@ -/* - * 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.euclidean.threed; - -import java.awt.geom.AffineTransform; -import java.util.Collection; - -import org.apache.commons.math3.geometry.Point; -import org.apache.commons.math3.geometry.euclidean.oned.Euclidean1D; -import org.apache.commons.math3.geometry.euclidean.twod.Euclidean2D; -import org.apache.commons.math3.geometry.euclidean.twod.SubLine; -import org.apache.commons.math3.geometry.euclidean.twod.Vector2D; -import org.apache.commons.math3.geometry.partitioning.AbstractRegion; -import org.apache.commons.math3.geometry.partitioning.BSPTree; -import org.apache.commons.math3.geometry.partitioning.BSPTreeVisitor; -import org.apache.commons.math3.geometry.partitioning.BoundaryAttribute; -import org.apache.commons.math3.geometry.partitioning.Hyperplane; -import org.apache.commons.math3.geometry.partitioning.Region; -import org.apache.commons.math3.geometry.partitioning.RegionFactory; -import org.apache.commons.math3.geometry.partitioning.SubHyperplane; -import org.apache.commons.math3.geometry.partitioning.Transform; -import org.apache.commons.math3.util.FastMath; - -/** This class represents a 3D region: a set of polyhedrons. - * @since 3.0 - */ -public class PolyhedronsSet extends AbstractRegion<Euclidean3D, Euclidean2D> { - - /** Default value for tolerance. */ - private static final double DEFAULT_TOLERANCE = 1.0e-10; - - /** Build a polyhedrons set representing the whole real line. - * @param tolerance tolerance below which points are considered identical - * @since 3.3 - */ - public PolyhedronsSet(final double tolerance) { - super(tolerance); - } - - /** Build a polyhedrons set from a BSP tree. - * <p>The leaf nodes of the BSP tree <em>must</em> have a - * {@code Boolean} attribute representing the inside status of - * the corresponding cell (true for inside cells, false for outside - * cells). In order to avoid building too many small objects, it is - * recommended to use the predefined constants - * {@code Boolean.TRUE} and {@code Boolean.FALSE}</p> - * <p> - * This constructor is aimed at expert use, as building the tree may - * be a difficult task. It is not intended for general use and for - * performances reasons does not check thoroughly its input, as this would - * require walking the full tree each time. Failing to provide a tree with - * the proper attributes, <em>will</em> therefore generate problems like - * {@link NullPointerException} or {@link ClassCastException} only later on. - * This limitation is known and explains why this constructor is for expert - * use only. The caller does have the responsibility to provided correct arguments. - * </p> - * @param tree inside/outside BSP tree representing the region - * @param tolerance tolerance below which points are considered identical - * @since 3.3 - */ - public PolyhedronsSet(final BSPTree<Euclidean3D> tree, final double tolerance) { - super(tree, tolerance); - } - - /** Build a polyhedrons set from a Boundary REPresentation (B-rep). - * <p>The boundary is provided as a collection of {@link - * SubHyperplane sub-hyperplanes}. Each sub-hyperplane has the - * interior part of the region on its minus side and the exterior on - * its plus side.</p> - * <p>The boundary elements can be in any order, and can form - * several non-connected sets (like for example polyhedrons with holes - * or a set of disjoint polyhedrons considered as a whole). In - * fact, the elements do not even need to be connected together - * (their topological connections are not used here). However, if the - * boundary does not really separate an inside open from an outside - * open (open having here its topological meaning), then subsequent - * calls to the {@link Region#checkPoint(Point) checkPoint} method will - * not be meaningful anymore.</p> - * <p>If the boundary is empty, the region will represent the whole - * space.</p> - * @param boundary collection of boundary elements, as a - * collection of {@link SubHyperplane SubHyperplane} objects - * @param tolerance tolerance below which points are considered identical - * @since 3.3 - */ - public PolyhedronsSet(final Collection<SubHyperplane<Euclidean3D>> boundary, - final double tolerance) { - super(boundary, tolerance); - } - - /** Build a parallellepipedic box. - * @param xMin low bound along the x direction - * @param xMax high bound along the x direction - * @param yMin low bound along the y direction - * @param yMax high bound along the y direction - * @param zMin low bound along the z direction - * @param zMax high bound along the z direction - * @param tolerance tolerance below which points are considered identical - * @since 3.3 - */ - public PolyhedronsSet(final double xMin, final double xMax, - final double yMin, final double yMax, - final double zMin, final double zMax, - final double tolerance) { - super(buildBoundary(xMin, xMax, yMin, yMax, zMin, zMax, tolerance), tolerance); - } - - /** Build a polyhedrons set representing the whole real line. - * @deprecated as of 3.3, replaced with {@link #PolyhedronsSet(double)} - */ - @Deprecated - public PolyhedronsSet() { - this(DEFAULT_TOLERANCE); - } - - /** Build a polyhedrons set from a BSP tree. - * <p>The leaf nodes of the BSP tree <em>must</em> have a - * {@code Boolean} attribute representing the inside status of - * the corresponding cell (true for inside cells, false for outside - * cells). In order to avoid building too many small objects, it is - * recommended to use the predefined constants - * {@code Boolean.TRUE} and {@code Boolean.FALSE}</p> - * @param tree inside/outside BSP tree representing the region - * @deprecated as of 3.3, replaced with {@link #PolyhedronsSet(BSPTree, double)} - */ - @Deprecated - public PolyhedronsSet(final BSPTree<Euclidean3D> tree) { - this(tree, DEFAULT_TOLERANCE); - } - - /** Build a polyhedrons set from a Boundary REPresentation (B-rep). - * <p>The boundary is provided as a collection of {@link - * SubHyperplane sub-hyperplanes}. Each sub-hyperplane has the - * interior part of the region on its minus side and the exterior on - * its plus side.</p> - * <p>The boundary elements can be in any order, and can form - * several non-connected sets (like for example polyhedrons with holes - * or a set of disjoint polyhedrons considered as a whole). In - * fact, the elements do not even need to be connected together - * (their topological connections are not used here). However, if the - * boundary does not really separate an inside open from an outside - * open (open having here its topological meaning), then subsequent - * calls to the {@link Region#checkPoint(Point) checkPoint} method will - * not be meaningful anymore.</p> - * <p>If the boundary is empty, the region will represent the whole - * space.</p> - * @param boundary collection of boundary elements, as a - * collection of {@link SubHyperplane SubHyperplane} objects - * @deprecated as of 3.3, replaced with {@link #PolyhedronsSet(Collection, double)} - */ - @Deprecated - public PolyhedronsSet(final Collection<SubHyperplane<Euclidean3D>> boundary) { - this(boundary, DEFAULT_TOLERANCE); - } - - /** Build a parallellepipedic box. - * @param xMin low bound along the x direction - * @param xMax high bound along the x direction - * @param yMin low bound along the y direction - * @param yMax high bound along the y direction - * @param zMin low bound along the z direction - * @param zMax high bound along the z direction - * @deprecated as of 3.3, replaced with {@link #PolyhedronsSet(double, double, - * double, double, double, double, double)} - */ - @Deprecated - public PolyhedronsSet(final double xMin, final double xMax, - final double yMin, final double yMax, - final double zMin, final double zMax) { - this(xMin, xMax, yMin, yMax, zMin, zMax, DEFAULT_TOLERANCE); - } - - /** Build a parallellepipedic box boundary. - * @param xMin low bound along the x direction - * @param xMax high bound along the x direction - * @param yMin low bound along the y direction - * @param yMax high bound along the y direction - * @param zMin low bound along the z direction - * @param zMax high bound along the z direction - * @param tolerance tolerance below which points are considered identical - * @return boundary tree - * @since 3.3 - */ - private static BSPTree<Euclidean3D> buildBoundary(final double xMin, final double xMax, - final double yMin, final double yMax, - final double zMin, final double zMax, - final double tolerance) { - if ((xMin >= xMax - tolerance) || (yMin >= yMax - tolerance) || (zMin >= zMax - tolerance)) { - // too thin box, build an empty polygons set - return new BSPTree<Euclidean3D>(Boolean.FALSE); - } - final Plane pxMin = new Plane(new Vector3D(xMin, 0, 0), Vector3D.MINUS_I, tolerance); - final Plane pxMax = new Plane(new Vector3D(xMax, 0, 0), Vector3D.PLUS_I, tolerance); - final Plane pyMin = new Plane(new Vector3D(0, yMin, 0), Vector3D.MINUS_J, tolerance); - final Plane pyMax = new Plane(new Vector3D(0, yMax, 0), Vector3D.PLUS_J, tolerance); - final Plane pzMin = new Plane(new Vector3D(0, 0, zMin), Vector3D.MINUS_K, tolerance); - final Plane pzMax = new Plane(new Vector3D(0, 0, zMax), Vector3D.PLUS_K, tolerance); - @SuppressWarnings("unchecked") - final Region<Euclidean3D> boundary = - new RegionFactory<Euclidean3D>().buildConvex(pxMin, pxMax, pyMin, pyMax, pzMin, pzMax); - return boundary.getTree(false); - } - - /** {@inheritDoc} */ - @Override - public PolyhedronsSet buildNew(final BSPTree<Euclidean3D> tree) { - return new PolyhedronsSet(tree, getTolerance()); - } - - /** {@inheritDoc} */ - @Override - protected void computeGeometricalProperties() { - - // compute the contribution of all boundary facets - getTree(true).visit(new FacetsContributionVisitor()); - - if (getSize() < 0) { - // the polyhedrons set as a finite outside - // surrounded by an infinite inside - setSize(Double.POSITIVE_INFINITY); - setBarycenter((Point<Euclidean3D>) Vector3D.NaN); - } else { - // the polyhedrons set is finite, apply the remaining scaling factors - setSize(getSize() / 3.0); - setBarycenter((Point<Euclidean3D>) new Vector3D(1.0 / (4 * getSize()), (Vector3D) getBarycenter())); - } - - } - - /** Visitor computing geometrical properties. */ - private class FacetsContributionVisitor implements BSPTreeVisitor<Euclidean3D> { - - /** Simple constructor. */ - public FacetsContributionVisitor() { - setSize(0); - setBarycenter((Point<Euclidean3D>) new Vector3D(0, 0, 0)); - } - - /** {@inheritDoc} */ - public Order visitOrder(final BSPTree<Euclidean3D> node) { - return Order.MINUS_SUB_PLUS; - } - - /** {@inheritDoc} */ - public void visitInternalNode(final BSPTree<Euclidean3D> node) { - @SuppressWarnings("unchecked") - final BoundaryAttribute<Euclidean3D> attribute = - (BoundaryAttribute<Euclidean3D>) node.getAttribute(); - if (attribute.getPlusOutside() != null) { - addContribution(attribute.getPlusOutside(), false); - } - if (attribute.getPlusInside() != null) { - addContribution(attribute.getPlusInside(), true); - } - } - - /** {@inheritDoc} */ - public void visitLeafNode(final BSPTree<Euclidean3D> node) { - } - - /** Add he contribution of a boundary facet. - * @param facet boundary facet - * @param reversed if true, the facet has the inside on its plus side - */ - private void addContribution(final SubHyperplane<Euclidean3D> facet, final boolean reversed) { - - final Region<Euclidean2D> polygon = ((SubPlane) facet).getRemainingRegion(); - final double area = polygon.getSize(); - - if (Double.isInfinite(area)) { - setSize(Double.POSITIVE_INFINITY); - setBarycenter((Point<Euclidean3D>) Vector3D.NaN); - } else { - - final Plane plane = (Plane) facet.getHyperplane(); - final Vector3D facetB = plane.toSpace(polygon.getBarycenter()); - double scaled = area * facetB.dotProduct(plane.getNormal()); - if (reversed) { - scaled = -scaled; - } - - setSize(getSize() + scaled); - setBarycenter((Point<Euclidean3D>) new Vector3D(1.0, (Vector3D) getBarycenter(), scaled, facetB)); - - } - - } - - } - - /** Get the first sub-hyperplane crossed by a semi-infinite line. - * @param point start point of the part of the line considered - * @param line line to consider (contains point) - * @return the first sub-hyperplaned crossed by the line after the - * given point, or null if the line does not intersect any - * sub-hyperplaned - */ - public SubHyperplane<Euclidean3D> firstIntersection(final Vector3D point, final Line line) { - return recurseFirstIntersection(getTree(true), point, line); - } - - /** Get the first sub-hyperplane crossed by a semi-infinite line. - * @param node current node - * @param point start point of the part of the line considered - * @param line line to consider (contains point) - * @return the first sub-hyperplaned crossed by the line after the - * given point, or null if the line does not intersect any - * sub-hyperplaned - */ - private SubHyperplane<Euclidean3D> recurseFirstIntersection(final BSPTree<Euclidean3D> node, - final Vector3D point, - final Line line) { - - final SubHyperplane<Euclidean3D> cut = node.getCut(); - if (cut == null) { - return null; - } - final BSPTree<Euclidean3D> minus = node.getMinus(); - final BSPTree<Euclidean3D> plus = node.getPlus(); - final Plane plane = (Plane) cut.getHyperplane(); - - // establish search order - final double offset = plane.getOffset((Point<Euclidean3D>) point); - final boolean in = FastMath.abs(offset) < 1.0e-10; - final BSPTree<Euclidean3D> near; - final BSPTree<Euclidean3D> far; - if (offset < 0) { - near = minus; - far = plus; - } else { - near = plus; - far = minus; - } - - if (in) { - // search in the cut hyperplane - final SubHyperplane<Euclidean3D> facet = boundaryFacet(point, node); - if (facet != null) { - return facet; - } - } - - // search in the near branch - final SubHyperplane<Euclidean3D> crossed = recurseFirstIntersection(near, point, line); - if (crossed != null) { - return crossed; - } - - if (!in) { - // search in the cut hyperplane - final Vector3D hit3D = plane.intersection(line); - if (hit3D != null) { - final SubHyperplane<Euclidean3D> facet = boundaryFacet(hit3D, node); - if (facet != null) { - return facet; - } - } - } - - // search in the far branch - return recurseFirstIntersection(far, point, line); - - } - - /** Check if a point belongs to the boundary part of a node. - * @param point point to check - * @param node node containing the boundary facet to check - * @return the boundary facet this points belongs to (or null if it - * does not belong to any boundary facet) - */ - private SubHyperplane<Euclidean3D> boundaryFacet(final Vector3D point, - final BSPTree<Euclidean3D> node) { - final Vector2D point2D = ((Plane) node.getCut().getHyperplane()).toSubSpace((Point<Euclidean3D>) point); - @SuppressWarnings("unchecked") - final BoundaryAttribute<Euclidean3D> attribute = - (BoundaryAttribute<Euclidean3D>) node.getAttribute(); - if ((attribute.getPlusOutside() != null) && - (((SubPlane) attribute.getPlusOutside()).getRemainingRegion().checkPoint(point2D) == Location.INSIDE)) { - return attribute.getPlusOutside(); - } - if ((attribute.getPlusInside() != null) && - (((SubPlane) attribute.getPlusInside()).getRemainingRegion().checkPoint(point2D) == Location.INSIDE)) { - return attribute.getPlusInside(); - } - return null; - } - - /** Rotate the region around the specified point. - * <p>The instance is not modified, a new instance is created.</p> - * @param center rotation center - * @param rotation vectorial rotation operator - * @return a new instance representing the rotated region - */ - public PolyhedronsSet rotate(final Vector3D center, final Rotation rotation) { - return (PolyhedronsSet) applyTransform(new RotationTransform(center, rotation)); - } - - /** 3D rotation as a Transform. */ - private static class RotationTransform implements Transform<Euclidean3D, Euclidean2D> { - - /** Center point of the rotation. */ - private Vector3D center; - - /** Vectorial rotation. */ - private Rotation rotation; - - /** Cached original hyperplane. */ - private Plane cachedOriginal; - - /** Cached 2D transform valid inside the cached original hyperplane. */ - private Transform<Euclidean2D, Euclidean1D> cachedTransform; - - /** Build a rotation transform. - * @param center center point of the rotation - * @param rotation vectorial rotation - */ - public RotationTransform(final Vector3D center, final Rotation rotation) { - this.center = center; - this.rotation = rotation; - } - - /** {@inheritDoc} */ - public Vector3D apply(final Point<Euclidean3D> point) { - final Vector3D delta = ((Vector3D) point).subtract(center); - return new Vector3D(1.0, center, 1.0, rotation.applyTo(delta)); - } - - /** {@inheritDoc} */ - public Plane apply(final Hyperplane<Euclidean3D> hyperplane) { - return ((Plane) hyperplane).rotate(center, rotation); - } - - /** {@inheritDoc} */ - public SubHyperplane<Euclidean2D> apply(final SubHyperplane<Euclidean2D> sub, - final Hyperplane<Euclidean3D> original, - final Hyperplane<Euclidean3D> transformed) { - if (original != cachedOriginal) { - // we have changed hyperplane, reset the in-hyperplane transform - - final Plane oPlane = (Plane) original; - final Plane tPlane = (Plane) transformed; - final Vector3D p00 = oPlane.getOrigin(); - final Vector3D p10 = oPlane.toSpace((Point<Euclidean2D>) new Vector2D(1.0, 0.0)); - final Vector3D p01 = oPlane.toSpace((Point<Euclidean2D>) new Vector2D(0.0, 1.0)); - final Vector2D tP00 = tPlane.toSubSpace((Point<Euclidean3D>) apply(p00)); - final Vector2D tP10 = tPlane.toSubSpace((Point<Euclidean3D>) apply(p10)); - final Vector2D tP01 = tPlane.toSubSpace((Point<Euclidean3D>) apply(p01)); - final AffineTransform at = - new AffineTransform(tP10.getX() - tP00.getX(), tP10.getY() - tP00.getY(), - tP01.getX() - tP00.getX(), tP01.getY() - tP00.getY(), - tP00.getX(), tP00.getY()); - - cachedOriginal = (Plane) original; - cachedTransform = org.apache.commons.math3.geometry.euclidean.twod.Line.getTransform(at); - - } - return ((SubLine) sub).applyTransform(cachedTransform); - } - - } - - /** Translate the region by the specified amount. - * <p>The instance is not modified, a new instance is created.</p> - * @param translation translation to apply - * @return a new instance representing the translated region - */ - public PolyhedronsSet translate(final Vector3D translation) { - return (PolyhedronsSet) applyTransform(new TranslationTransform(translation)); - } - - /** 3D translation as a transform. */ - private static class TranslationTransform implements Transform<Euclidean3D, Euclidean2D> { - - /** Translation vector. */ - private Vector3D translation; - - /** Cached original hyperplane. */ - private Plane cachedOriginal; - - /** Cached 2D transform valid inside the cached original hyperplane. */ - private Transform<Euclidean2D, Euclidean1D> cachedTransform; - - /** Build a translation transform. - * @param translation translation vector - */ - public TranslationTransform(final Vector3D translation) { - this.translation = translation; - } - - /** {@inheritDoc} */ - public Vector3D apply(final Point<Euclidean3D> point) { - return new Vector3D(1.0, (Vector3D) point, 1.0, translation); - } - - /** {@inheritDoc} */ - public Plane apply(final Hyperplane<Euclidean3D> hyperplane) { - return ((Plane) hyperplane).translate(translation); - } - - /** {@inheritDoc} */ - public SubHyperplane<Euclidean2D> apply(final SubHyperplane<Euclidean2D> sub, - final Hyperplane<Euclidean3D> original, - final Hyperplane<Euclidean3D> transformed) { - if (original != cachedOriginal) { - // we have changed hyperplane, reset the in-hyperplane transform - - final Plane oPlane = (Plane) original; - final Plane tPlane = (Plane) transformed; - final Vector2D shift = tPlane.toSubSpace((Point<Euclidean3D>) apply(oPlane.getOrigin())); - final AffineTransform at = - AffineTransform.getTranslateInstance(shift.getX(), shift.getY()); - - cachedOriginal = (Plane) original; - cachedTransform = - org.apache.commons.math3.geometry.euclidean.twod.Line.getTransform(at); - - } - - return ((SubLine) sub).applyTransform(cachedTransform); - - } - - } - -}