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    }