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 }