RegionCutBoundary.java
/*
* 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.geometry.core.partitioning.bsp;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.geometry.core.Point;
import org.apache.commons.geometry.core.Sized;
import org.apache.commons.geometry.core.partitioning.HyperplaneConvexSubset;
/** Class representing the portion of an
* {@link AbstractRegionBSPTree.AbstractRegionNode AbstractRegionNode}'s cut that
* lies on the boundary of the region. Portions of the node cut may be oriented so
* that the plus side of the cut points toward the outside of the region
* ({@link #getOutsideFacing()}) and other portions toward the inside of the
* region ({@link #getInsideFacing()}). The inside-facing and outside-facing portions
* of the region boundary are represented as lists of disjoint hyperplane convex subsets,
* all originating from the same hyperplane convex subset forming the node cut.
*
* @param <P> Point implementation type
*/
public final class RegionCutBoundary<P extends Point<P>> implements Sized {
/** Portion of the cut oriented such that the plus side of the cut points to the inside of the region. */
private final List<HyperplaneConvexSubset<P>> insideFacing;
/** Portion of the cut oriented such that the plus side of the cut points to the outside of the region. */
private final List<HyperplaneConvexSubset<P>> outsideFacing;
/** Construct a new instance from the inside-facing and outside-facing portions of a node cut. The
* given lists are expected to be disjoint regions originating from the same hyperplane convex subset.
* No validation is performed.
* @param insideFacing the inside-facing portion of the node cut
* @param outsideFacing the outside-facing portion of the node cut
*/
RegionCutBoundary(final List<HyperplaneConvexSubset<P>> insideFacing,
final List<HyperplaneConvexSubset<P>> outsideFacing) {
this.insideFacing = insideFacing != null ?
Collections.unmodifiableList(insideFacing) :
Collections.emptyList();
this.outsideFacing = outsideFacing != null ?
Collections.unmodifiableList(outsideFacing) :
Collections.emptyList();
}
/** Get the portion of the cut with its plus side facing the inside of the region.
* @return the portion of the cut with its plus side facing the
* inside of the region
*/
public List<HyperplaneConvexSubset<P>> getInsideFacing() {
return insideFacing;
}
/** Get the portion of the cut with its plus side facing the outside of the region.
* @return the portion of the cut with its plus side facing the
* outside of the region
*/
public List<HyperplaneConvexSubset<P>> getOutsideFacing() {
return outsideFacing;
}
/** Get the total size of the cut boundary, including inside and outside facing components.
* @return the total size of the cut boundary, including inside and outside facing components
*/
@Override
public double getSize() {
return getTotalSize(insideFacing) + getTotalSize(outsideFacing);
}
/** Get the total size of all boundaries in the given list.
* @param boundaries boundaries to compute the size for
* @return the total size of all boundaries in the given list
*/
private double getTotalSize(final List<? extends HyperplaneConvexSubset<P>> boundaries) {
double total = 0.0;
for (final HyperplaneConvexSubset<P> boundary : boundaries) {
total += boundary.getSize();
if (Double.isInfinite(total)) {
return total;
}
}
return total;
}
/** Return the closest point to the argument in the inside and outside facing
* portions of the cut boundary.
* @param pt the reference point
* @return the point in the cut boundary closest to the reference point
* @see HyperplaneConvexSubset#closest(Point)
*/
public P closest(final P pt) {
P closest = null;
double closestDist = Double.POSITIVE_INFINITY;
final Iterator<HyperplaneConvexSubset<P>> insideIt = insideFacing.iterator();
final Iterator<HyperplaneConvexSubset<P>> outsideIt = outsideFacing.iterator();
HyperplaneConvexSubset<P> boundary;
P testPt;
double dist;
while (insideIt.hasNext() || outsideIt.hasNext()) {
boundary = insideIt.hasNext() ?
insideIt.next() :
outsideIt.next();
testPt = boundary.closest(pt);
dist = pt.distance(testPt);
if (closest == null || dist < closestDist) {
closest = testPt;
closestDist = dist;
}
}
return closest;
}
/** Return true if the given point is contained in the boundary, in either the
* inside facing portion or the outside facing portion.
* @param pt point to test
* @return true if the point is contained in the boundary
* @see HyperplaneConvexSubset#contains(Point)
*/
public boolean contains(final P pt) {
return containsInsideFacing(pt) || containsOutsideFacing(pt);
}
/** Return true if the given point is contained in the inside-facing portion of
* the region boundary.
* @param pt point to test
* @return true if the point is contained in the inside-facing portion of the region
* boundary
*/
public boolean containsInsideFacing(final P pt) {
return anyContains(pt, insideFacing);
}
/** Return true if the given point is contained in the outside-facing portion of the
* region boundary.
* @param pt point to test
* @return true if the point is contained in the outside-facing portion of the region
* boundary
*/
public boolean containsOutsideFacing(final P pt) {
return anyContains(pt, outsideFacing);
}
/** Return true if the point is contained in any of the given boundaries.
* @param pt point to test
* @param boundaries
* @return true if the point is contained in any of the given boundaries
*/
private boolean anyContains(final P pt, final List<? extends HyperplaneConvexSubset<P>> boundaries) {
for (final HyperplaneConvexSubset<P> boundary : boundaries) {
if (boundary.contains(pt)) {
return true;
}
}
return false;
}
}