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 */
017package org.apache.commons.math3.geometry.euclidean.threed;
018
019import org.apache.commons.math3.geometry.Point;
020import org.apache.commons.math3.geometry.euclidean.oned.Euclidean1D;
021import org.apache.commons.math3.geometry.euclidean.oned.Vector1D;
022import org.apache.commons.math3.geometry.euclidean.twod.Euclidean2D;
023import org.apache.commons.math3.geometry.euclidean.twod.PolygonsSet;
024import org.apache.commons.math3.geometry.euclidean.twod.Vector2D;
025import org.apache.commons.math3.geometry.partitioning.AbstractSubHyperplane;
026import org.apache.commons.math3.geometry.partitioning.BSPTree;
027import org.apache.commons.math3.geometry.partitioning.Hyperplane;
028import org.apache.commons.math3.geometry.partitioning.Region;
029import org.apache.commons.math3.geometry.partitioning.SubHyperplane;
030
031/** This class represents a sub-hyperplane for {@link Plane}.
032 * @since 3.0
033 */
034public 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    /** Split the instance in two parts by an hyperplane.
053     * @param hyperplane splitting hyperplane
054     * @return an object containing both the part of the instance
055     * on the plus side of the instance and the part of the
056     * instance on the minus side of the instance
057     */
058    @Override
059    public SplitSubHyperplane<Euclidean3D> split(Hyperplane<Euclidean3D> hyperplane) {
060
061        final Plane otherPlane = (Plane) hyperplane;
062        final Plane thisPlane  = (Plane) getHyperplane();
063        final Line  inter      = otherPlane.intersection(thisPlane);
064        final double tolerance = thisPlane.getTolerance();
065
066        if (inter == null) {
067            // the hyperplanes are parallel
068            final double global = otherPlane.getOffset(thisPlane);
069            if (global < -tolerance) {
070                return new SplitSubHyperplane<Euclidean3D>(null, this);
071            } else if (global > tolerance) {
072                return new SplitSubHyperplane<Euclidean3D>(this, null);
073            } else {
074                return new SplitSubHyperplane<Euclidean3D>(null, null);
075            }
076        }
077
078        // the hyperplanes do intersect
079        Vector2D p = thisPlane.toSubSpace((Point<Euclidean3D>) inter.toSpace((Point<Euclidean1D>) Vector1D.ZERO));
080        Vector2D q = thisPlane.toSubSpace((Point<Euclidean3D>) inter.toSpace((Point<Euclidean1D>) Vector1D.ONE));
081        Vector3D crossP = Vector3D.crossProduct(inter.getDirection(), thisPlane.getNormal());
082        if (crossP.dotProduct(otherPlane.getNormal()) < 0) {
083            final Vector2D tmp = p;
084            p           = q;
085            q           = tmp;
086        }
087        final SubHyperplane<Euclidean2D> l2DMinus =
088            new org.apache.commons.math3.geometry.euclidean.twod.Line(p, q, tolerance).wholeHyperplane();
089        final SubHyperplane<Euclidean2D> l2DPlus =
090            new org.apache.commons.math3.geometry.euclidean.twod.Line(q, p, tolerance).wholeHyperplane();
091
092        final BSPTree<Euclidean2D> splitTree = getRemainingRegion().getTree(false).split(l2DMinus);
093        final BSPTree<Euclidean2D> plusTree  = getRemainingRegion().isEmpty(splitTree.getPlus()) ?
094                                               new BSPTree<Euclidean2D>(Boolean.FALSE) :
095                                               new BSPTree<Euclidean2D>(l2DPlus, new BSPTree<Euclidean2D>(Boolean.FALSE),
096                                                                        splitTree.getPlus(), null);
097
098        final BSPTree<Euclidean2D> minusTree = getRemainingRegion().isEmpty(splitTree.getMinus()) ?
099                                               new BSPTree<Euclidean2D>(Boolean.FALSE) :
100                                                   new BSPTree<Euclidean2D>(l2DMinus, new BSPTree<Euclidean2D>(Boolean.FALSE),
101                                                                            splitTree.getMinus(), null);
102
103        return new SplitSubHyperplane<Euclidean3D>(new SubPlane(thisPlane.copySelf(), new PolygonsSet(plusTree, tolerance)),
104                                                   new SubPlane(thisPlane.copySelf(), new PolygonsSet(minusTree, tolerance)));
105
106    }
107
108}