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