View Javadoc

    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
    19  import java.util.ArrayList;
    20  import java.util.List;
    21  import java.util.Objects;
    22  import java.util.stream.Collectors;
    23  import java.util.stream.Stream;
    24
    25  /** Class that performs linecast operations against arbitrary {@link BoundarySource2D}
    26   * instances. This class performs a brute-force computation of the intersections of the
    27   * line or line subset against all boundaries. Some data structures may support more
    28   * efficient algorithms and should therefore prefer those instead.
    29   */
    30  final class BoundarySourceLinecaster2D implements Linecastable2D {
    31
    32      /** The boundary source instance providing boundaries for the linecast operation. */
    33      private final BoundarySource2D boundarySrc;
    34
    35      /** Construct a new instance for linecasting against the given boundary source.
    36       * @param boundarySrc boundary source to linecast against.
    37       */
    38      BoundarySourceLinecaster2D(final BoundarySource2D boundarySrc) {
    39          this.boundarySrc = boundarySrc;
    40      }
    41
    42      /** {@inheritDoc} */
    43      @Override
    44      public List<LinecastPoint2D> linecast(final LineConvexSubset subset) {
    45          try (Stream<LinecastPoint2D> stream = getIntersectionStream(subset)) {
    46
    47              final List<LinecastPoint2D> results = stream.collect(Collectors.toCollection(ArrayList::new));
    48              LinecastPoint2D.sortAndFilter(results);
    49
    50              return results;
    51          }
    52      }
    53
    54      /** {@inheritDoc} */
    55      @Override
    56      public LinecastPoint2D linecastFirst(final LineConvexSubset subset) {
    57          try (Stream<LinecastPoint2D> stream = getIntersectionStream(subset)) {
    58              return stream.min(LinecastPoint2D.ABSCISSA_ORDER)
    59                      .orElse(null);
    60          }
    61      }
    62
    63      /** Return a stream containing intersections between the boundary source and the
    64       * given line subset.
    65       * @param subset line subset to intersect
    66       * @return a stream containing linecast intersections
    67       */
    68      private Stream<LinecastPoint2D> getIntersectionStream(final LineConvexSubset subset) {
    69          return boundarySrc.boundaryStream()
    70                  .map(boundary -> computeIntersection(boundary, subset))
    71                  .filter(Objects::nonNull);
    72      }
    73
    74      /** Compute the intersection between a boundary line subset and linecast intersecting line subset. Null is
    75       * returned if no intersection is discovered.
    76       * @param boundary boundary from the boundary source
    77       * @param subset line subset to intersect with
    78       * @return the linecast intersection between the two arguments or null if there is no such
    79       *      intersection
    80       */
    81      private LinecastPoint2D computeIntersection(final LineConvexSubset boundary, final LineConvexSubset subset) {
    82          final Vector2D intersectionPt = boundary.intersection(subset);
    83
    84          if (intersectionPt != null) {
    85              final Vector2D normal = boundary.getLine().getOffsetDirection();
    86
    87              return new LinecastPoint2D(intersectionPt, normal, subset.getLine());
    88          }
    89
    90          return null; // no intersection
    91      }
    92  }