    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.partitioning;
    018
    019    import org.apache.commons.math3.geometry.Space;
    020
    021    /** This class implements the dimension-independent parts of {@link SubHyperplane}.
    022
    023     * <p>sub-hyperplanes are obtained when parts of an {@link
    024     * Hyperplane hyperplane} are chopped off by other hyperplanes that
    025     * intersect it. The remaining part is a convex region. Such objects
    026     * appear in {@link BSPTree BSP trees} as the intersection of a cut
    027     * hyperplane with the convex region which it splits, the chopping
    028     * hyperplanes are the cut hyperplanes closer to the tree root.</p>
    029
    030     * @param <S> Type of the embedding space.
    031     * @param <T> Type of the embedded sub-space.
    032
    033     * @version $Id: AbstractSubHyperplane.java 1421448 2012-12-13 19:45:57Z tn $
    034     * @since 3.0
    035     */
    036    public abstract class AbstractSubHyperplane<S extends Space, T extends Space>
    037        implements SubHyperplane<S> {
    038
    039        /** Underlying hyperplane. */
    040        private final Hyperplane<S> hyperplane;
    041
    042        /** Remaining region of the hyperplane. */
    043        private final Region<T> remainingRegion;
    044
    045        /** Build a sub-hyperplane from an hyperplane and a region.
    046         * @param hyperplane underlying hyperplane
    047         * @param remainingRegion remaining region of the hyperplane
    048         */
    049        protected AbstractSubHyperplane(final Hyperplane<S> hyperplane,
    050                                        final Region<T> remainingRegion) {
    051            this.hyperplane      = hyperplane;
    052            this.remainingRegion = remainingRegion;
    053        }
    054
    055        /** Build a sub-hyperplane from an hyperplane and a region.
    056         * @param hyper underlying hyperplane
    057         * @param remaining remaining region of the hyperplane
    058         * @return a new sub-hyperplane
    059         */
    060        protected abstract AbstractSubHyperplane<S, T> buildNew(final Hyperplane<S> hyper,
    061                                                                final Region<T> remaining);
    062
    063        /** {@inheritDoc} */
    064        public AbstractSubHyperplane<S, T> copySelf() {
    065            return buildNew(hyperplane, remainingRegion);
    066        }
    067
    068        /** Get the underlying hyperplane.
    069         * @return underlying hyperplane
    070         */
    071        public Hyperplane<S> getHyperplane() {
    072            return hyperplane;
    073        }
    074
    075        /** Get the remaining region of the hyperplane.
    076         * <p>The returned region is expressed in the canonical hyperplane
    077         * frame and has the hyperplane dimension. For example a chopped
    078         * hyperplane in the 3D euclidean is a 2D plane and the
    079         * corresponding region is a convex 2D polygon.</p>
    080         * @return remaining region of the hyperplane
    081         */
    082        public Region<T> getRemainingRegion() {
    083            return remainingRegion;
    084        }
    085
    086        /** {@inheritDoc} */
    087        public double getSize() {
    088            return remainingRegion.getSize();
    089        }
    090
    091        /** {@inheritDoc} */
    092        public AbstractSubHyperplane<S, T> reunite(final SubHyperplane<S> other) {
    093            @SuppressWarnings("unchecked")
    094            AbstractSubHyperplane<S, T> o = (AbstractSubHyperplane<S, T>) other;
    095            return buildNew(hyperplane,
    096                            new RegionFactory<T>().union(remainingRegion, o.remainingRegion));
    097        }
    098
    099        /** Apply a transform to the instance.
    100         * <p>The instance must be a (D-1)-dimension sub-hyperplane with
    101         * respect to the transform <em>not</em> a (D-2)-dimension
    102         * sub-hyperplane the transform knows how to transform by
    103         * itself. The transform will consist in transforming first the
    104         * hyperplane and then the all region using the various methods
    105         * provided by the transform.</p>
    106         * @param transform D-dimension transform to apply
    107         * @return the transformed instance
    108         */
    109        public AbstractSubHyperplane<S, T> applyTransform(final Transform<S, T> transform) {
    110            final Hyperplane<S> tHyperplane = transform.apply(hyperplane);
    111            final BSPTree<T> tTree =
    112                recurseTransform(remainingRegion.getTree(false), tHyperplane, transform);
    113            return buildNew(tHyperplane, remainingRegion.buildNew(tTree));
    114        }
    115
    116        /** Recursively transform a BSP-tree from a sub-hyperplane.
    117         * @param node current BSP tree node
    118         * @param transformed image of the instance hyperplane by the transform
    119         * @param transform transform to apply
    120         * @return a new tree
    121         */
    122        private BSPTree<T> recurseTransform(final BSPTree<T> node,
    123                                            final Hyperplane<S> transformed,
    124                                            final Transform<S, T> transform) {
    125            if (node.getCut() == null) {
    126                return new BSPTree<T>(node.getAttribute());
    127            }
    128
    129            @SuppressWarnings("unchecked")
    130            BoundaryAttribute<T> attribute =
    131                (BoundaryAttribute<T>) node.getAttribute();
    132            if (attribute != null) {
    133                final SubHyperplane<T> tPO = (attribute.getPlusOutside() == null) ?
    134                    null : transform.apply(attribute.getPlusOutside(), hyperplane, transformed);
    135                final SubHyperplane<T> tPI = (attribute.getPlusInside() == null) ?
    136                    null : transform.apply(attribute.getPlusInside(), hyperplane, transformed);
    137                attribute = new BoundaryAttribute<T>(tPO, tPI);
    138            }
    139
    140            return new BSPTree<T>(transform.apply(node.getCut(), hyperplane, transformed),
    141                                  recurseTransform(node.getPlus(), transformed, transform),
    142                                  recurseTransform(node.getMinus(), transformed, transform),
    143                                  attribute);
    144
    145        }
    146
    147        /** {@inheritDoc} */
    148        public abstract Side side(Hyperplane<S> hyper);
    149
    150        /** {@inheritDoc} */
    151        public abstract SplitSubHyperplane<S> split(Hyperplane<S> hyper);
    152
    153        /** {@inheritDoc} */
    154        public boolean isEmpty() {
    155            return remainingRegion.isEmpty();
    156        }
    157
    158    }