| /* |
| * 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.threed; |
| |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.Comparator; |
| import java.util.List; |
| import java.util.ListIterator; |
| |
| import org.apache.commons.geometry.core.precision.DoublePrecisionContext; |
| import org.apache.commons.geometry.euclidean.AbstractLinecastPoint; |
| |
| /** Class representing intersections resulting from linecast operations in Euclidean |
| * 3D space. This class contains the intersection point along with the boundary normal |
| * of the target at the point of intersection. |
| * @see Linecastable3D |
| */ |
| public class LinecastPoint3D extends AbstractLinecastPoint<Vector3D, Vector3D.Unit, Line3D> { |
| |
| /** Comparator that sorts intersection instances by increasing abscissa order. If two abscissa |
| * values are equal, the comparison uses {@link Vector3D#COORDINATE_ASCENDING_ORDER} with the |
| * intersection normals. |
| */ |
| public static final Comparator<LinecastPoint3D> ABSCISSA_ORDER = (a, b) -> { |
| int cmp = Double.compare(a.getAbscissa(), b.getAbscissa()); |
| if (cmp == 0) { |
| cmp = Vector3D.COORDINATE_ASCENDING_ORDER.compare(a.getNormal(), b.getNormal()); |
| } |
| return cmp; |
| }; |
| |
| /** Construct a new instance from its components. |
| * @param point intersection point |
| * @param normal normal of the target boundary at the intersection point |
| * @param line intersecting line |
| */ |
| public LinecastPoint3D(final Vector3D point, final Vector3D normal, final Line3D line) { |
| super(point, normal.normalize(), line); |
| } |
| |
| /** Return true if this instance should be considered equivalent to the argument, using the |
| * given precision context for comparison. Instances are considered equivalent if they have |
| * equivalent points, normals, and lines. |
| * @param other other point to compare with |
| * @param precision context to use for the comparison |
| * @return true if this instance should be considered equivalent to the argument |
| */ |
| public boolean eq(final LinecastPoint3D other, final DoublePrecisionContext precision) { |
| return getLine().eq(other.getLine(), precision) && |
| getPoint().eq(other.getPoint(), precision) && |
| getNormal().eq(other.getNormal(), precision); |
| } |
| |
| /** Sort the given list of linecast points by increasing abscissa value and filter to remove |
| * duplicate entries (as determined by the {@link #eq(LinecastPoint3D, DoublePrecisionContext)} method). |
| * The argument is modified. |
| * @param pts list of points to sort and filter |
| */ |
| public static void sortAndFilter(final List<LinecastPoint3D> pts) { |
| Collections.sort(pts, ABSCISSA_ORDER); |
| |
| double currentAbscissa = Double.POSITIVE_INFINITY; |
| final List<LinecastPoint3D> abscissaList = new ArrayList<>(); |
| |
| final ListIterator<LinecastPoint3D> it = pts.listIterator(); |
| LinecastPoint3D pt; |
| while (it.hasNext()) { |
| pt = it.next(); |
| if (!pt.getLine().getPrecision().eq(currentAbscissa, pt.getAbscissa())) { |
| // new abscissa value |
| currentAbscissa = pt.getAbscissa(); |
| abscissaList.clear(); |
| |
| abscissaList.add(pt); |
| } else if (containsEq(pt, abscissaList)) { |
| // duplicate found for this abscissa value |
| it.remove(); |
| } else { |
| // not a duplicate |
| abscissaList.add(pt); |
| } |
| } |
| } |
| |
| /** Return true if the given linecast point is equivalent to any of those in the given list. |
| * @param pt point to test |
| * @param list list to test against |
| * @return true if the given linecast point is equivalent to any of those in the given list |
| */ |
| private static boolean containsEq(final LinecastPoint3D pt, final List<LinecastPoint3D> list) { |
| final DoublePrecisionContext precision = pt.getLine().getPrecision(); |
| |
| for (LinecastPoint3D listPt : list) { |
| if (listPt.eq(pt, precision)) { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| } |