BoundarySourceLinecaster2D.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.twod;

  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. /** Class that performs linecast operations against arbitrary {@link BoundarySource2D}
  24.  * instances. This class performs a brute-force computation of the intersections of the
  25.  * line or line subset against all boundaries. Some data structures may support more
  26.  * efficient algorithms and should therefore prefer those instead.
  27.  */
  28. final class BoundarySourceLinecaster2D implements Linecastable2D {

  29.     /** The boundary source instance providing boundaries for the linecast operation. */
  30.     private final BoundarySource2D boundarySrc;

  31.     /** Construct a new instance for linecasting against the given boundary source.
  32.      * @param boundarySrc boundary source to linecast against.
  33.      */
  34.     BoundarySourceLinecaster2D(final BoundarySource2D boundarySrc) {
  35.         this.boundarySrc = boundarySrc;
  36.     }

  37.     /** {@inheritDoc} */
  38.     @Override
  39.     public List<LinecastPoint2D> linecast(final LineConvexSubset subset) {
  40.         try (Stream<LinecastPoint2D> stream = getIntersectionStream(subset)) {

  41.             final List<LinecastPoint2D> results = stream.collect(Collectors.toCollection(ArrayList::new));
  42.             LinecastPoint2D.sortAndFilter(results);

  43.             return results;
  44.         }
  45.     }

  46.     /** {@inheritDoc} */
  47.     @Override
  48.     public LinecastPoint2D linecastFirst(final LineConvexSubset subset) {
  49.         try (Stream<LinecastPoint2D> stream = getIntersectionStream(subset)) {
  50.             return stream.min(LinecastPoint2D.ABSCISSA_ORDER)
  51.                     .orElse(null);
  52.         }
  53.     }

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

  64.     /** Compute the intersection between a boundary line subset and linecast intersecting line subset. Null is
  65.      * returned if no intersection is discovered.
  66.      * @param boundary boundary from the boundary source
  67.      * @param subset line subset to intersect with
  68.      * @return the linecast intersection between the two arguments or null if there is no such
  69.      *      intersection
  70.      */
  71.     private LinecastPoint2D computeIntersection(final LineConvexSubset boundary, final LineConvexSubset subset) {
  72.         final Vector2D intersectionPt = boundary.intersection(subset);

  73.         if (intersectionPt != null) {
  74.             final Vector2D normal = boundary.getLine().getOffsetDirection();

  75.             return new LinecastPoint2D(intersectionPt, normal, subset.getLine());
  76.         }

  77.         return null; // no intersection
  78.     }
  79. }