    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    }