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.euclidean.threed; 018 019 import org.apache.commons.math3.geometry.euclidean.oned.Vector1D; 020 import org.apache.commons.math3.geometry.euclidean.twod.Euclidean2D; 021 import org.apache.commons.math3.geometry.euclidean.twod.Vector2D; 022 import org.apache.commons.math3.geometry.euclidean.twod.PolygonsSet; 023 import org.apache.commons.math3.geometry.partitioning.AbstractSubHyperplane; 024 import org.apache.commons.math3.geometry.partitioning.BSPTree; 025 import org.apache.commons.math3.geometry.partitioning.Hyperplane; 026 import org.apache.commons.math3.geometry.partitioning.Region; 027 import org.apache.commons.math3.geometry.partitioning.Side; 028 import org.apache.commons.math3.geometry.partitioning.SubHyperplane; 029 030 /** This class represents a sub-hyperplane for {@link Plane}. 031 * @version $Id: SubPlane.java 1416643 2012-12-03 19:37:14Z tn $ 032 * @since 3.0 033 */ 034 public class SubPlane extends AbstractSubHyperplane<Euclidean3D, Euclidean2D> { 035 036 /** Simple constructor. 037 * @param hyperplane underlying hyperplane 038 * @param remainingRegion remaining region of the hyperplane 039 */ 040 public SubPlane(final Hyperplane<Euclidean3D> hyperplane, 041 final Region<Euclidean2D> remainingRegion) { 042 super(hyperplane, remainingRegion); 043 } 044 045 /** {@inheritDoc} */ 046 @Override 047 protected AbstractSubHyperplane<Euclidean3D, Euclidean2D> buildNew(final Hyperplane<Euclidean3D> hyperplane, 048 final Region<Euclidean2D> remainingRegion) { 049 return new SubPlane(hyperplane, remainingRegion); 050 } 051 052 /** {@inheritDoc} */ 053 @Override 054 public Side side(Hyperplane<Euclidean3D> hyperplane) { 055 056 final Plane otherPlane = (Plane) hyperplane; 057 final Plane thisPlane = (Plane) getHyperplane(); 058 final Line inter = otherPlane.intersection(thisPlane); 059 060 if (inter == null) { 061 // the hyperplanes are parallel, 062 // any point can be used to check their relative position 063 final double global = otherPlane.getOffset(thisPlane); 064 return (global < -1.0e-10) ? Side.MINUS : ((global > 1.0e-10) ? Side.PLUS : Side.HYPER); 065 } 066 067 // create a 2D line in the otherPlane canonical 2D frame such that: 068 // - the line is the crossing line of the two planes in 3D 069 // - the line splits the otherPlane in two half planes with an 070 // orientation consistent with the orientation of the instance 071 // (i.e. the 3D half space on the plus side (resp. minus side) 072 // of the instance contains the 2D half plane on the plus side 073 // (resp. minus side) of the 2D line 074 Vector2D p = thisPlane.toSubSpace(inter.toSpace(Vector1D.ZERO)); 075 Vector2D q = thisPlane.toSubSpace(inter.toSpace(Vector1D.ONE)); 076 Vector3D crossP = Vector3D.crossProduct(inter.getDirection(), thisPlane.getNormal()); 077 if (crossP.dotProduct(otherPlane.getNormal()) < 0) { 078 final Vector2D tmp = p; 079 p = q; 080 q = tmp; 081 } 082 final org.apache.commons.math3.geometry.euclidean.twod.Line line2D = 083 new org.apache.commons.math3.geometry.euclidean.twod.Line(p, q); 084 085 // check the side on the 2D plane 086 return getRemainingRegion().side(line2D); 087 088 } 089 090 /** Split the instance in two parts by an hyperplane. 091 * @param hyperplane splitting hyperplane 092 * @return an object containing both the part of the instance 093 * on the plus side of the instance and the part of the 094 * instance on the minus side of the instance 095 */ 096 @Override 097 public SplitSubHyperplane<Euclidean3D> split(Hyperplane<Euclidean3D> hyperplane) { 098 099 final Plane otherPlane = (Plane) hyperplane; 100 final Plane thisPlane = (Plane) getHyperplane(); 101 final Line inter = otherPlane.intersection(thisPlane); 102 103 if (inter == null) { 104 // the hyperplanes are parallel 105 final double global = otherPlane.getOffset(thisPlane); 106 return (global < -1.0e-10) ? 107 new SplitSubHyperplane<Euclidean3D>(null, this) : 108 new SplitSubHyperplane<Euclidean3D>(this, null); 109 } 110 111 // the hyperplanes do intersect 112 Vector2D p = thisPlane.toSubSpace(inter.toSpace(Vector1D.ZERO)); 113 Vector2D q = thisPlane.toSubSpace(inter.toSpace(Vector1D.ONE)); 114 Vector3D crossP = Vector3D.crossProduct(inter.getDirection(), thisPlane.getNormal()); 115 if (crossP.dotProduct(otherPlane.getNormal()) < 0) { 116 final Vector2D tmp = p; 117 p = q; 118 q = tmp; 119 } 120 final SubHyperplane<Euclidean2D> l2DMinus = 121 new org.apache.commons.math3.geometry.euclidean.twod.Line(p, q).wholeHyperplane(); 122 final SubHyperplane<Euclidean2D> l2DPlus = 123 new org.apache.commons.math3.geometry.euclidean.twod.Line(q, p).wholeHyperplane(); 124 125 final BSPTree<Euclidean2D> splitTree = getRemainingRegion().getTree(false).split(l2DMinus); 126 final BSPTree<Euclidean2D> plusTree = getRemainingRegion().isEmpty(splitTree.getPlus()) ? 127 new BSPTree<Euclidean2D>(Boolean.FALSE) : 128 new BSPTree<Euclidean2D>(l2DPlus, new BSPTree<Euclidean2D>(Boolean.FALSE), 129 splitTree.getPlus(), null); 130 131 final BSPTree<Euclidean2D> minusTree = getRemainingRegion().isEmpty(splitTree.getMinus()) ? 132 new BSPTree<Euclidean2D>(Boolean.FALSE) : 133 new BSPTree<Euclidean2D>(l2DMinus, new BSPTree<Euclidean2D>(Boolean.FALSE), 134 splitTree.getMinus(), null); 135 136 return new SplitSubHyperplane<Euclidean3D>(new SubPlane(thisPlane.copySelf(), new PolygonsSet(plusTree)), 137 new SubPlane(thisPlane.copySelf(), new PolygonsSet(minusTree))); 138 139 } 140 141 }