EdgesWithNodeInfoBuilder.java
/*
* Licensed to the Hipparchus project under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The Hipparchus project licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.hipparchus.geometry.spherical.twod;
import java.util.ArrayList;
import java.util.List;
import org.hipparchus.geometry.partitioning.AbstractSubHyperplane;
import org.hipparchus.geometry.partitioning.BSPTree;
import org.hipparchus.geometry.partitioning.BSPTreeVisitor;
import org.hipparchus.geometry.partitioning.BoundaryAttribute;
import org.hipparchus.geometry.partitioning.SubHyperplane;
import org.hipparchus.geometry.spherical.oned.Arc;
import org.hipparchus.geometry.spherical.oned.ArcsSet;
import org.hipparchus.geometry.spherical.oned.S1Point;
import org.hipparchus.geometry.spherical.oned.Sphere1D;
import org.hipparchus.util.FastMath;
/** Visitor building edges.
* @since 1.4
*/
class EdgesWithNodeInfoBuilder implements BSPTreeVisitor<Sphere2D> {
/** Tolerance for close nodes connection. */
private final double tolerance;
/** Built segments. */
private final List<EdgeWithNodeInfo> edges;
/** Simple constructor.
* @param tolerance below which points are consider to be identical
*/
EdgesWithNodeInfoBuilder(final double tolerance) {
this.tolerance = tolerance;
this.edges = new ArrayList<>();
}
/** {@inheritDoc} */
@Override
public Order visitOrder(final BSPTree<Sphere2D> node) {
return Order.MINUS_SUB_PLUS;
}
/** {@inheritDoc} */
@Override
public void visitInternalNode(final BSPTree<Sphere2D> node) {
@SuppressWarnings("unchecked")
final BoundaryAttribute<Sphere2D> attribute = (BoundaryAttribute<Sphere2D>) node.getAttribute();
final Iterable<BSPTree<Sphere2D>> splitters = attribute.getSplitters();
if (attribute.getPlusOutside() != null) {
addContribution(attribute.getPlusOutside(), node, splitters, false);
}
if (attribute.getPlusInside() != null) {
addContribution(attribute.getPlusInside(), node, splitters, true);
}
}
/** {@inheritDoc} */
@Override
public void visitLeafNode(final BSPTree<Sphere2D> node) {
}
/** Add the contribution of a boundary edge.
* @param sub boundary facet
* @param node node to which the edge belongs
* @param splitters splitters for the boundary facet
* @param reversed if true, the facet has the inside on its plus side
*/
private void addContribution(final SubHyperplane<Sphere2D> sub, final BSPTree<Sphere2D> node,
final Iterable<BSPTree<Sphere2D>> splitters,
final boolean reversed) {
final AbstractSubHyperplane<Sphere2D, Sphere1D> absSub =
(AbstractSubHyperplane<Sphere2D, Sphere1D>) sub;
final Circle circle = (Circle) sub.getHyperplane();
final List<Arc> arcs = ((ArcsSet) absSub.getRemainingRegion()).asList();
for (final Arc a : arcs) {
// find the 2D points
final Vertex startS = new Vertex(circle.toSpace(new S1Point(a.getInf())));
final Vertex endS = new Vertex(circle.toSpace(new S1Point(a.getSup())));
// recover the connectivity information
final BSPTree<Sphere2D> startN = selectClosest(startS.getLocation(), splitters);
final BSPTree<Sphere2D> endN = selectClosest(endS.getLocation(), splitters);
if (reversed) {
edges.add(new EdgeWithNodeInfo(endS, startS, a.getSize(), circle.getReverse(),
node, endN, startN));
} else {
edges.add(new EdgeWithNodeInfo(startS, endS, a.getSize(), circle,
node, startN, endN));
}
}
}
/** Select the node whose cut sub-hyperplane is closest to specified point.
* @param point reference point
* @param candidates candidate nodes
* @return node closest to point, or null if no node is closer than tolerance
*/
private BSPTree<Sphere2D> selectClosest(final S2Point point, final Iterable<BSPTree<Sphere2D>> candidates) {
if (point == null) {
return null;
}
BSPTree<Sphere2D> selected = null;
double min = Double.POSITIVE_INFINITY;
for (final BSPTree<Sphere2D> node : candidates) {
final double distance = FastMath.abs(node.getCut().getHyperplane().getOffset(point));
if (distance < min) {
selected = node;
min = distance;
}
}
return min <= tolerance ? selected : null;
}
/** Get the edges.
* @return built edges
*/
public List<EdgeWithNodeInfo> getEdges() {
return edges;
}
}