LineSubset.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.euclidean.twod;
- import java.util.List;
- import org.apache.commons.geometry.core.RegionEmbedding;
- import org.apache.commons.geometry.core.RegionLocation;
- import org.apache.commons.geometry.core.partitioning.HyperplaneBoundedRegion;
- import org.apache.commons.geometry.core.partitioning.HyperplaneSubset;
- import org.apache.commons.geometry.core.partitioning.Split;
- import org.apache.commons.geometry.euclidean.oned.Vector1D;
- import org.apache.commons.numbers.core.Precision;
- /** Class representing a subset of points on a line in 2D Euclidean space. For example, line segments
- * and rays are line subsets. Line subsets may be finite or infinite.
- */
- public abstract class LineSubset implements HyperplaneSubset<Vector2D>, RegionEmbedding<Vector2D, Vector1D> {
- /** The line containing this instance. */
- private final Line line;
- /** Construct a new instance based on the given line.
- * @param line line forming the base of the instance
- */
- LineSubset(final Line line) {
- this.line = line;
- }
- /** Get the line containing this subset. This method is an alias
- * for {@link #getHyperplane()}.
- * @return the line containing this subset
- * @see #getHyperplane()
- */
- public Line getLine() {
- return getHyperplane();
- }
- /** {@inheritDoc} */
- @Override
- public Line getHyperplane() {
- return line;
- }
- /** {@inheritDoc} */
- @Override
- public Vector1D toSubspace(final Vector2D pt) {
- return line.toSubspace(pt);
- }
- /** Get a {@link Bounds2D} object defining an axis-aligned bounding box containing all
- * vertices for this subset. Null is returned if the subset is infinite or does not
- * contain any vertices.
- * @return the bounding box for this instance or null if no valid bounds could be determined
- */
- public abstract Bounds2D getBounds();
- /** {@inheritDoc} */
- @Override
- public abstract HyperplaneBoundedRegion<Vector1D> getSubspaceRegion();
- /** {@inheritDoc} */
- @Override
- public Vector2D toSpace(final Vector1D pt) {
- return line.toSpace(pt);
- }
- /** {@inheritDoc} */
- @Override
- public abstract List<LineConvexSubset> toConvex();
- /** {@inheritDoc} */
- @Override
- public RegionLocation classify(final Vector2D pt) {
- if (line.contains(pt)) {
- return classifyAbscissa(line.abscissa(pt));
- }
- return RegionLocation.OUTSIDE;
- }
- /** Get the unique intersection of this subset with the given line. Null is
- * returned if no unique intersection point exists (ie, the lines are
- * parallel or coincident) or the line does not intersect this instance.
- * @param inputLine line to intersect with this line subset
- * @return the unique intersection point between the line and this line subset
- * or null if no such point exists.
- * @see Line#intersection(Line)
- */
- public Vector2D intersection(final Line inputLine) {
- final Vector2D pt = line.intersection(inputLine);
- return (pt != null && contains(pt)) ? pt : null;
- }
- /** Get the unique intersection of this instance with the given line subset. Null
- * is returned if the lines containing the line subsets do not have a unique intersection
- * point (ie, they are parallel or coincident) or the intersection point is unique
- * but is not contained in both line subsets.
- * @param subset line subset to intersect with
- * @return the unique intersection point between this line subset and the argument or
- * null if no such point exists.
- * @see Line#intersection(Line)
- */
- public Vector2D intersection(final LineSubset subset) {
- final Vector2D pt = intersection(subset.getLine());
- return (pt != null && subset.contains(pt)) ? pt : null;
- }
- /** Return the object used to perform floating point comparisons, which is the
- * same object used by the underlying {@link Line}).
- * @return precision object used to perform floating point comparisons.
- */
- public Precision.DoubleEquivalence getPrecision() {
- return line.getPrecision();
- }
- /** Classify the given line abscissa value with respect to the subspace region.
- * @param abscissa the abscissa value to classify
- * @return the region location of the line abscissa value
- */
- abstract RegionLocation classifyAbscissa(double abscissa);
- /** Get a split result for cases where no intersection exists between the splitting line and the
- * line underlying the given line subset. This occurs when the two lines are parallel or coincident.
- * @param <T> Line subset type
- * @param splitter splitting line
- * @param subset line subset instance being split
- * @return return result of the non-intersecting split operation
- */
- <T extends LineSubset> Split<T> getNonIntersectingSplitResult(final Line splitter, final T subset) {
- // check which side of the splitter we lie on
- final double offset = splitter.offset(subset.getLine());
- final int comp = getPrecision().compare(offset, 0.0);
- if (comp < 0) {
- return new Split<>(subset, null);
- } else if (comp > 0) {
- return new Split<>(null, subset);
- } else {
- return new Split<>(null, null);
- }
- }
- /** Return true if the plus side of the given splitter line is facing in the positive direction
- * of this line.
- * @param splitterLine line splitting this instance
- * @return true if the plus side of the given line is facing in the positive direction of this
- * line
- */
- boolean splitterPlusIsPositiveFacing(final Line splitterLine) {
- return line.getOffsetDirection().dot(splitterLine.getDirection()) <= 0;
- }
- /** Create a split result for the given splitter line, given the low and high split portion of this
- * instance. The arguments are assigned to the split result's minus and plus properties based on the
- * relative orientation of the splitter line.
- * @param <T> Line subset type
- * @param splitter splitter line
- * @param low portion of the split result closest to negative infinity on this line
- * @param high portion of th split result closest to positive infinity on this line
- * @return a split result for the given splitter line.
- */
- <T extends LineSubset> Split<T> createSplitResult(final Line splitter, final T low, final T high) {
- return splitterPlusIsPositiveFacing(splitter) ?
- new Split<>(low, high) :
- new Split<>(high, low);
- }
- }