BoundarySourceLinecaster3D.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;

  18. import java.util.ArrayList;
  19. import java.util.List;
  20. import java.util.Objects;
  21. import java.util.stream.Collectors;
  22. import java.util.stream.Stream;

  23. import org.apache.commons.geometry.euclidean.threed.line.LineConvexSubset3D;
  24. import org.apache.commons.geometry.euclidean.threed.line.LinecastPoint3D;
  25. import org.apache.commons.geometry.euclidean.threed.line.Linecastable3D;

  26. /** Class that performs linecast operations against arbitrary {@link BoundarySource3D}
  27.  * instances. This class performs a brute-force computation of the intersections of the
  28.  * line or line convex subset against all boundaries. Some data structures may support more
  29.  * efficient algorithms and should therefore prefer those instead.
  30.  */
  31. final class BoundarySourceLinecaster3D implements Linecastable3D {

  32.     /** The boundary source instance providing boundaries for the linecast operation. */
  33.     private final BoundarySource3D boundarySrc;

  34.     /** Construct a new instance for linecasting against the given boundary source.
  35.      * @param boundarySrc boundary source to linecast against.
  36.      */
  37.     BoundarySourceLinecaster3D(final BoundarySource3D boundarySrc) {
  38.         this.boundarySrc = boundarySrc;
  39.     }

  40.     /** {@inheritDoc} */
  41.     @Override
  42.     public List<LinecastPoint3D> linecast(final LineConvexSubset3D subset) {
  43.         try (Stream<LinecastPoint3D> stream = getIntersectionStream(subset)) {

  44.             final List<LinecastPoint3D> results = stream.collect(Collectors.toCollection(ArrayList::new));
  45.             LinecastPoint3D.sortAndFilter(results);

  46.             return results;
  47.         }
  48.     }

  49.     /** {@inheritDoc} */
  50.     @Override
  51.     public LinecastPoint3D linecastFirst(final LineConvexSubset3D subset) {
  52.         try (Stream<LinecastPoint3D> stream = getIntersectionStream(subset)) {
  53.             return stream.min(LinecastPoint3D.ABSCISSA_ORDER)
  54.                     .orElse(null);
  55.         }
  56.     }

  57.     /** Return a stream containing intersections between the boundary source and the
  58.      * given line convex subset.
  59.      * @param subset line subset to intersect
  60.      * @return a stream containing linecast intersections
  61.      */
  62.     private Stream<LinecastPoint3D> getIntersectionStream(final LineConvexSubset3D subset) {
  63.         return boundarySrc.boundaryStream()
  64.                 .map(boundary -> computeIntersection(boundary, subset))
  65.                 .filter(Objects::nonNull);
  66.     }

  67.     /** Compute the intersection between a boundary plane subset and line subset. Null is
  68.      * returned if no intersection is discovered.
  69.      * @param planeSubset plane subset from the boundary source
  70.      * @param lineSubset line subset to intersect with
  71.      * @return the linecast intersection between the two arguments or null if there is no such
  72.      *      intersection
  73.      */
  74.     private LinecastPoint3D computeIntersection(final PlaneConvexSubset planeSubset,
  75.             final LineConvexSubset3D lineSubset) {
  76.         final Vector3D intersectionPt = planeSubset.intersection(lineSubset);

  77.         if (intersectionPt != null) {
  78.             final Vector3D normal = planeSubset.getPlane().getNormal();

  79.             return new LinecastPoint3D(intersectionPt, normal, lineSubset.getLine());
  80.         }

  81.         return null; // no intersection
  82.     }
  83. }