LinecastPoint3D.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.apache.commons.geometry.euclidean.threed.line;

  18. import java.util.ArrayList;
  19. import java.util.Comparator;
  20. import java.util.List;
  21. import java.util.ListIterator;

  22. import org.apache.commons.geometry.euclidean.AbstractLinecastPoint;
  23. import org.apache.commons.geometry.euclidean.threed.Vector3D;
  24. import org.apache.commons.numbers.core.Precision;

  25. /** Class representing intersections resulting from linecast operations in Euclidean
  26.  * 3D space. This class contains the intersection point along with the boundary normal
  27.  * of the target at the point of intersection.
  28.  * @see Linecastable3D
  29.  */
  30. public class LinecastPoint3D extends AbstractLinecastPoint<Vector3D, Vector3D.Unit, Line3D>  {

  31.     /** Comparator that sorts intersection instances by increasing abscissa order. If two abscissa
  32.      * values are equal, the comparison uses {@link Vector3D#COORDINATE_ASCENDING_ORDER} with the
  33.      * intersection normals.
  34.      */
  35.     public static final Comparator<LinecastPoint3D> ABSCISSA_ORDER = (a, b) -> {
  36.         int cmp = Double.compare(a.getAbscissa(), b.getAbscissa());
  37.         if (cmp == 0) {
  38.             cmp = Vector3D.COORDINATE_ASCENDING_ORDER.compare(a.getNormal(), b.getNormal());
  39.         }
  40.         return cmp;
  41.     };

  42.     /** Construct a new instance from its components.
  43.      * @param point intersection point
  44.      * @param normal normal of the target boundary at the intersection point
  45.      * @param line intersecting line
  46.      */
  47.     public LinecastPoint3D(final Vector3D point, final Vector3D normal, final Line3D line) {
  48.         super(point, normal.normalize(), line);
  49.     }

  50.     /** Return true if this instance should be considered equivalent to the argument, using the
  51.      * given precision context for comparison. Instances are considered equivalent if they have
  52.      * equivalent points, normals, and lines.
  53.      * @param other other point to compare with
  54.      * @param precision context to use for the comparison
  55.      * @return true if this instance should be considered equivalent to the argument
  56.      */
  57.     public boolean eq(final LinecastPoint3D other, final Precision.DoubleEquivalence precision) {
  58.         return getLine().eq(other.getLine(), precision) &&
  59.                 getPoint().eq(other.getPoint(), precision) &&
  60.                 getNormal().eq(other.getNormal(), precision);
  61.     }

  62.     /** Sort the given list of linecast points by increasing abscissa value and filter to remove
  63.      * duplicate entries (as determined by the {@link #eq(LinecastPoint3D, Precision.DoubleEquivalence)} method).
  64.      * The argument is modified.
  65.      * @param pts list of points to sort and filter
  66.      */
  67.     public static void sortAndFilter(final List<LinecastPoint3D> pts) {
  68.         pts.sort(ABSCISSA_ORDER);

  69.         double currentAbscissa = Double.POSITIVE_INFINITY;
  70.         final List<LinecastPoint3D> abscissaList = new ArrayList<>();

  71.         final ListIterator<LinecastPoint3D> it = pts.listIterator();
  72.         LinecastPoint3D pt;
  73.         while (it.hasNext()) {
  74.             pt = it.next();
  75.             if (!pt.getLine().getPrecision().eq(currentAbscissa, pt.getAbscissa())) {
  76.                 // new abscissa value
  77.                 currentAbscissa = pt.getAbscissa();
  78.                 abscissaList.clear();

  79.                 abscissaList.add(pt);
  80.             } else if (containsEq(pt, abscissaList)) {
  81.                 // duplicate found for this abscissa value
  82.                 it.remove();
  83.             } else {
  84.                 // not a duplicate
  85.                 abscissaList.add(pt);
  86.             }
  87.         }
  88.     }

  89.     /** Return true if the given linecast point is equivalent to any of those in the given list.
  90.      * @param pt point to test
  91.      * @param list list to test against
  92.      * @return true if the given linecast point is equivalent to any of those in the given list
  93.      */
  94.     private static boolean containsEq(final LinecastPoint3D pt, final List<? extends LinecastPoint3D> list) {
  95.         final Precision.DoubleEquivalence precision = pt.getLine().getPrecision();

  96.         for (final LinecastPoint3D listPt : list) {
  97.             if (listPt.eq(pt, precision)) {
  98.                 return true;
  99.             }
  100.         }

  101.         return false;
  102.     }
  103. }