001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.commons.math3.geometry.partitioning; 018 019 import org.apache.commons.math3.geometry.Space; 020 021 /** This class implements the dimension-independent parts of {@link SubHyperplane}. 022 023 * <p>sub-hyperplanes are obtained when parts of an {@link 024 * Hyperplane hyperplane} are chopped off by other hyperplanes that 025 * intersect it. The remaining part is a convex region. Such objects 026 * appear in {@link BSPTree BSP trees} as the intersection of a cut 027 * hyperplane with the convex region which it splits, the chopping 028 * hyperplanes are the cut hyperplanes closer to the tree root.</p> 029 030 * @param <S> Type of the embedding space. 031 * @param <T> Type of the embedded sub-space. 032 033 * @version $Id: AbstractSubHyperplane.java 1421448 2012-12-13 19:45:57Z tn $ 034 * @since 3.0 035 */ 036 public abstract class AbstractSubHyperplane<S extends Space, T extends Space> 037 implements SubHyperplane<S> { 038 039 /** Underlying hyperplane. */ 040 private final Hyperplane<S> hyperplane; 041 042 /** Remaining region of the hyperplane. */ 043 private final Region<T> remainingRegion; 044 045 /** Build a sub-hyperplane from an hyperplane and a region. 046 * @param hyperplane underlying hyperplane 047 * @param remainingRegion remaining region of the hyperplane 048 */ 049 protected AbstractSubHyperplane(final Hyperplane<S> hyperplane, 050 final Region<T> remainingRegion) { 051 this.hyperplane = hyperplane; 052 this.remainingRegion = remainingRegion; 053 } 054 055 /** Build a sub-hyperplane from an hyperplane and a region. 056 * @param hyper underlying hyperplane 057 * @param remaining remaining region of the hyperplane 058 * @return a new sub-hyperplane 059 */ 060 protected abstract AbstractSubHyperplane<S, T> buildNew(final Hyperplane<S> hyper, 061 final Region<T> remaining); 062 063 /** {@inheritDoc} */ 064 public AbstractSubHyperplane<S, T> copySelf() { 065 return buildNew(hyperplane, remainingRegion); 066 } 067 068 /** Get the underlying hyperplane. 069 * @return underlying hyperplane 070 */ 071 public Hyperplane<S> getHyperplane() { 072 return hyperplane; 073 } 074 075 /** Get the remaining region of the hyperplane. 076 * <p>The returned region is expressed in the canonical hyperplane 077 * frame and has the hyperplane dimension. For example a chopped 078 * hyperplane in the 3D euclidean is a 2D plane and the 079 * corresponding region is a convex 2D polygon.</p> 080 * @return remaining region of the hyperplane 081 */ 082 public Region<T> getRemainingRegion() { 083 return remainingRegion; 084 } 085 086 /** {@inheritDoc} */ 087 public double getSize() { 088 return remainingRegion.getSize(); 089 } 090 091 /** {@inheritDoc} */ 092 public AbstractSubHyperplane<S, T> reunite(final SubHyperplane<S> other) { 093 @SuppressWarnings("unchecked") 094 AbstractSubHyperplane<S, T> o = (AbstractSubHyperplane<S, T>) other; 095 return buildNew(hyperplane, 096 new RegionFactory<T>().union(remainingRegion, o.remainingRegion)); 097 } 098 099 /** Apply a transform to the instance. 100 * <p>The instance must be a (D-1)-dimension sub-hyperplane with 101 * respect to the transform <em>not</em> a (D-2)-dimension 102 * sub-hyperplane the transform knows how to transform by 103 * itself. The transform will consist in transforming first the 104 * hyperplane and then the all region using the various methods 105 * provided by the transform.</p> 106 * @param transform D-dimension transform to apply 107 * @return the transformed instance 108 */ 109 public AbstractSubHyperplane<S, T> applyTransform(final Transform<S, T> transform) { 110 final Hyperplane<S> tHyperplane = transform.apply(hyperplane); 111 final BSPTree<T> tTree = 112 recurseTransform(remainingRegion.getTree(false), tHyperplane, transform); 113 return buildNew(tHyperplane, remainingRegion.buildNew(tTree)); 114 } 115 116 /** Recursively transform a BSP-tree from a sub-hyperplane. 117 * @param node current BSP tree node 118 * @param transformed image of the instance hyperplane by the transform 119 * @param transform transform to apply 120 * @return a new tree 121 */ 122 private BSPTree<T> recurseTransform(final BSPTree<T> node, 123 final Hyperplane<S> transformed, 124 final Transform<S, T> transform) { 125 if (node.getCut() == null) { 126 return new BSPTree<T>(node.getAttribute()); 127 } 128 129 @SuppressWarnings("unchecked") 130 BoundaryAttribute<T> attribute = 131 (BoundaryAttribute<T>) node.getAttribute(); 132 if (attribute != null) { 133 final SubHyperplane<T> tPO = (attribute.getPlusOutside() == null) ? 134 null : transform.apply(attribute.getPlusOutside(), hyperplane, transformed); 135 final SubHyperplane<T> tPI = (attribute.getPlusInside() == null) ? 136 null : transform.apply(attribute.getPlusInside(), hyperplane, transformed); 137 attribute = new BoundaryAttribute<T>(tPO, tPI); 138 } 139 140 return new BSPTree<T>(transform.apply(node.getCut(), hyperplane, transformed), 141 recurseTransform(node.getPlus(), transformed, transform), 142 recurseTransform(node.getMinus(), transformed, transform), 143 attribute); 144 145 } 146 147 /** {@inheritDoc} */ 148 public abstract Side side(Hyperplane<S> hyper); 149 150 /** {@inheritDoc} */ 151 public abstract SplitSubHyperplane<S> split(Hyperplane<S> hyper); 152 153 /** {@inheritDoc} */ 154 public boolean isEmpty() { 155 return remainingRegion.isEmpty(); 156 } 157 158 }