All Downloads are FREE. Search and download functionalities are using the official Maven repository.

repairability_test_files.NPEfix.NPEfix10.ten.NPEfix10_ten_t Maven / Gradle / Ivy

There is a newer version: 6.0.0
Show newest version
/*
 * 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.
 * @version $Id: PolyhedronsSet.java 1590254 2014-04-26 17:36:34Z luc $
 * @since 3.0
 */
public class PolyhedronsSet extends AbstractRegion {

    /** 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.
     * 

The leaf nodes of the BSP tree must 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}

*

* This constructor is aimed at expert use, as building the tree may * be a difficult taks. 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, will 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. *

* @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 tree, final double tolerance) { super(tree, tolerance); } /** Build a polyhedrons set from a Boundary REPresentation (B-rep). *

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.

*

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.

*

If the boundary is empty, the region will represent the whole * space.

* @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> 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. *

The leaf nodes of the BSP tree must 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}

* @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 tree) { this(tree, DEFAULT_TOLERANCE); } /** Build a polyhedrons set from a Boundary REPresentation (B-rep). *

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.

*

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.

*

If the boundary is empty, the region will represent the whole * space.

* @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> 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 buildBoundary(final double xMin, final double xMax, final double yMin, final double yMax, final double zMin, final double zMax, final double tolerance) { // FIX // if ((xMin >= xMax - tolerance) || (yMin >= yMax - tolerance) || (zMin >= zMax - tolerance)) { // // too thin box, build an empty polygons set // return new BSPTree(Boolean.FALSE); // } if ((xMin >= xMax - tolerance) || (yMin >= yMax - tolerance) || (zMin >= zMax - tolerance)) { // too thin box, build an empty polygons set return new BSPTree(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 boundary = new RegionFactory().buildConvex(pxMin, pxMax, pyMin, pyMax, pzMin, pzMax); return boundary.getTree(false); } /** {@inheritDoc} */ @Override public PolyhedronsSet buildNew(final BSPTree 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) Vector3D.NaN); } else { // the polyhedrons set is finite, apply the remaining scaling factors setSize(getSize() / 3.0); setBarycenter((Point) new Vector3D(1.0 / (4 * getSize()), (Vector3D) getBarycenter())); } } /** Visitor computing geometrical properties. */ private class FacetsContributionVisitor implements BSPTreeVisitor { /** Simple constructor. */ public FacetsContributionVisitor() { setSize(0); setBarycenter((Point) new Vector3D(0, 0, 0)); } /** {@inheritDoc} */ public Order visitOrder(final BSPTree node) { return Order.MINUS_SUB_PLUS; } /** {@inheritDoc} */ public void visitInternalNode(final BSPTree node) { @SuppressWarnings("unchecked") final BoundaryAttribute attribute = (BoundaryAttribute) node.getAttribute(); if (attribute.getPlusOutside() != null) { addContribution(attribute.getPlusOutside(), false); } if (attribute.getPlusInside() != null) { addContribution(attribute.getPlusInside(), true); } } /** {@inheritDoc} */ public void visitLeafNode(final BSPTree 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 facet, final boolean reversed) { final Region polygon = ((SubPlane) facet).getRemainingRegion(); final double area = polygon.getSize(); if (Double.isInfinite(area)) { setSize(Double.POSITIVE_INFINITY); setBarycenter((Point) 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) 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 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 recurseFirstIntersection(final BSPTree node, final Vector3D point, final Line line) { final SubHyperplane cut = node.getCut(); if (cut == null) { return null; } final BSPTree minus = node.getMinus(); final BSPTree plus = node.getPlus(); final Plane plane = (Plane) cut.getHyperplane(); // establish search order final double offset = plane.getOffset((Point) point); final boolean in = FastMath.abs(offset) < 1.0e-10; final BSPTree near; final BSPTree far; if (offset < 0) { near = minus; far = plus; } else { near = plus; far = minus; } if (in) { // search in the cut hyperplane final SubHyperplane facet = boundaryFacet(point, node); if (facet != null) { return facet; } } // search in the near branch final SubHyperplane 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 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 boundaryFacet(final Vector3D point, final BSPTree node) { final Vector2D point2D = ((Plane) node.getCut().getHyperplane()).toSubSpace((Point) point); @SuppressWarnings("unchecked") final BoundaryAttribute attribute = (BoundaryAttribute) 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. *

The instance is not modified, a new instance is created.

* @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 { /** 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 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 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 hyperplane) { return ((Plane) hyperplane).rotate(center, rotation); } /** {@inheritDoc} */ public SubHyperplane apply(final SubHyperplane sub, final Hyperplane original, final Hyperplane 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) new Vector2D(1.0, 0.0)); final Vector3D p01 = oPlane.toSpace((Point) new Vector2D(0.0, 1.0)); final Vector2D tP00 = tPlane.toSubSpace((Point) apply(p00)); final Vector2D tP10 = tPlane.toSubSpace((Point) apply(p10)); final Vector2D tP01 = tPlane.toSubSpace((Point) 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. *

The instance is not modified, a new instance is created.

* @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 { /** Translation vector. */ private Vector3D translation; /** Cached original hyperplane. */ private Plane cachedOriginal; /** Cached 2D transform valid inside the cached original hyperplane. */ private Transform cachedTransform; /** Build a translation transform. * @param translation translation vector */ public TranslationTransform(final Vector3D translation) { this.translation = translation; } /** {@inheritDoc} */ public Vector3D apply(final Point point) { return new Vector3D(1.0, (Vector3D) point, 1.0, translation); } /** {@inheritDoc} */ public Plane apply(final Hyperplane hyperplane) { return ((Plane) hyperplane).translate(translation); } /** {@inheritDoc} */ public SubHyperplane apply(final SubHyperplane sub, final Hyperplane original, final Hyperplane 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) 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); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy