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 }