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 * https://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 18 /* 19 * This is not the original file distributed by the Apache Software Foundation 20 * It has been modified by the Hipparchus project 21 */ 22 package org.hipparchus.geometry.partitioning; 23 24 import java.util.ArrayList; 25 import java.util.List; 26 27 import org.hipparchus.exception.MathRuntimeException; 28 import org.hipparchus.geometry.Point; 29 import org.hipparchus.geometry.Space; 30 31 /** Cut sub-hyperplanes characterization with respect to inside/outside cells. 32 * @see BoundaryBuilder 33 * @param <S> Type of the space. 34 * @param <P> Type of the points in space. 35 * @param <H> Type of the hyperplane. 36 * @param <I> Type of the sub-hyperplane. 37 */ 38 class Characterization<S extends Space, 39 P extends Point<S, P>, 40 H extends Hyperplane<S, P, H, I>, 41 I extends SubHyperplane<S, P, H, I>> { 42 43 /** Part of the cut sub-hyperplane that touch outside cells. */ 44 private I outsideTouching; 45 46 /** Part of the cut sub-hyperplane that touch inside cells. */ 47 private I insideTouching; 48 49 /** Nodes that were used to split the outside touching part. */ 50 private final NodesSet<S, P, H, I> outsideSplitters; 51 52 /** Nodes that were used to split the inside touching part. */ 53 private final NodesSet<S, P, H, I> insideSplitters; 54 55 /** Simple constructor. 56 * <p>Characterization consists in splitting the specified 57 * sub-hyperplane into several parts lying in inside and outside 58 * cells of the tree. The principle is to compute characterization 59 * twice for each cut sub-hyperplane in the tree, once on the plus 60 * node and once on the minus node. The parts that have the same flag 61 * (inside/inside or outside/outside) do not belong to the boundary 62 * while parts that have different flags (inside/outside or 63 * outside/inside) do belong to the boundary.</p> 64 * @param node current BSP tree node 65 * @param sub sub-hyperplane to characterize 66 */ 67 Characterization(final BSPTree<S, P, H, I> node, final I sub) { 68 outsideTouching = null; 69 insideTouching = null; 70 outsideSplitters = new NodesSet<>(); 71 insideSplitters = new NodesSet<>(); 72 characterize(node, sub, new ArrayList<>()); 73 } 74 75 /** Filter the parts of an hyperplane belonging to the boundary. 76 * <p>The filtering consist in splitting the specified 77 * sub-hyperplane into several parts lying in inside and outside 78 * cells of the tree. The principle is to call this method twice for 79 * each cut sub-hyperplane in the tree, once on the plus node and 80 * once on the minus node. The parts that have the same flag 81 * (inside/inside or outside/outside) do not belong to the boundary 82 * while parts that have different flags (inside/outside or 83 * outside/inside) do belong to the boundary.</p> 84 * @param node current BSP tree node 85 * @param sub sub-hyperplane to characterize 86 * @param splitters nodes that did split the current one 87 */ 88 private void characterize(final BSPTree<S, P, H, I> node, final I sub, 89 final List<BSPTree<S, P, H, I>> splitters) { 90 if (node.getCut() == null) { 91 // we have reached a leaf node 92 final boolean inside = (Boolean) node.getAttribute(); 93 if (inside) { 94 addInsideTouching(sub, splitters); 95 } else { 96 addOutsideTouching(sub, splitters); 97 } 98 } else { 99 final H hyperplane = node.getCut().getHyperplane(); 100 final SubHyperplane.SplitSubHyperplane<S, P, H, I> split = sub.split(hyperplane); 101 switch (split.getSide()) { 102 case PLUS: 103 characterize(node.getPlus(), sub, splitters); 104 break; 105 case MINUS: 106 characterize(node.getMinus(), sub, splitters); 107 break; 108 case BOTH: 109 splitters.add(node); 110 characterize(node.getPlus(), split.getPlus(), splitters); 111 characterize(node.getMinus(), split.getMinus(), splitters); 112 splitters.remove(splitters.size() - 1); 113 break; 114 default: 115 // this should not happen 116 throw MathRuntimeException.createInternalError(); 117 } 118 } 119 } 120 121 /** Add a part of the cut sub-hyperplane known to touch an outside cell. 122 * @param sub part of the cut sub-hyperplane known to touch an outside cell 123 * @param splitters sub-hyperplanes that did split the current one 124 */ 125 private void addOutsideTouching(final I sub, final List<BSPTree<S, P, H, I>> splitters) { 126 if (outsideTouching == null) { 127 outsideTouching = sub; 128 } else { 129 outsideTouching = outsideTouching.reunite(sub); 130 } 131 outsideSplitters.addAll(splitters); 132 } 133 134 /** Add a part of the cut sub-hyperplane known to touch an inside cell. 135 * @param sub part of the cut sub-hyperplane known to touch an inside cell 136 * @param splitters sub-hyperplanes that did split the current one 137 */ 138 private void addInsideTouching(final I sub, final List<BSPTree<S, P, H, I>> splitters) { 139 if (insideTouching == null) { 140 insideTouching = sub; 141 } else { 142 insideTouching = insideTouching.reunite(sub); 143 } 144 insideSplitters.addAll(splitters); 145 } 146 147 /** Check if the cut sub-hyperplane touches outside cells. 148 * @return true if the cut sub-hyperplane touches outside cells 149 */ 150 public boolean touchOutside() { 151 return outsideTouching != null && !outsideTouching.isEmpty(); 152 } 153 154 /** Get all the parts of the cut sub-hyperplane known to touch outside cells. 155 * @return parts of the cut sub-hyperplane known to touch outside cells 156 * (may be null or empty) 157 */ 158 public I outsideTouching() { 159 return outsideTouching; 160 } 161 162 /** Get the nodes that were used to split the outside touching part. 163 * <p> 164 * Splitting nodes are internal nodes (i.e. they have a non-null 165 * cut sub-hyperplane). 166 * </p> 167 * @return nodes that were used to split the outside touching part 168 */ 169 public NodesSet<S, P, H, I> getOutsideSplitters() { 170 return outsideSplitters; 171 } 172 173 /** Check if the cut sub-hyperplane touches inside cells. 174 * @return true if the cut sub-hyperplane touches inside cells 175 */ 176 public boolean touchInside() { 177 return insideTouching != null && !insideTouching.isEmpty(); 178 } 179 180 /** Get all the parts of the cut sub-hyperplane known to touch inside cells. 181 * @return parts of the cut sub-hyperplane known to touch inside cells 182 * (may be null or empty) 183 */ 184 public I insideTouching() { 185 return insideTouching; 186 } 187 188 /** Get the nodes that were used to split the inside touching part. 189 * <p> 190 * Splitting nodes are internal nodes (i.e. they have a non-null 191 * cut sub-hyperplane). 192 * </p> 193 * @return nodes that were used to split the inside touching part 194 */ 195 public NodesSet<S, P, H, I> getInsideSplitters() { 196 return insideSplitters; 197 } 198 199 }