All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.commons.math3.geometry.partitioning.RegionFactory Maven / Gradle / Ivy

Go to download

The Math project is a library of lightweight, self-contained mathematics and statistics components addressing the most common practical problems not immediately available in the Java programming language or commons-lang.

There is a newer version: 3.6.1
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.commons.math3.geometry.partitioning;

import org.apache.commons.math3.geometry.Space;

/** This class is a factory for {@link Region}.

 * @param  Type of the space.

 * @version $Id: RegionFactory.java 1244107 2012-02-14 16:17:55Z erans $
 * @since 3.0
 */
public class RegionFactory {

    /** Visitor removing internal nodes attributes. */
    private final NodesCleaner nodeCleaner;

    /** Simple constructor.
     */
    public RegionFactory() {
        nodeCleaner = new NodesCleaner();
    }

    /** Build a convex region from a collection of bounding hyperplanes.
     * @param hyperplanes collection of bounding hyperplanes
     * @return a new convex region, or null if the collection is empty
     */
    public Region buildConvex(final Hyperplane ... hyperplanes) {
        if ((hyperplanes == null) || (hyperplanes.length == 0)) {
            return null;
        }

        // use the first hyperplane to build the right class
        final Region region = hyperplanes[0].wholeSpace();

        // chop off parts of the space
        BSPTree node = region.getTree(false);
        node.setAttribute(Boolean.TRUE);
        for (final Hyperplane hyperplane : hyperplanes) {
            if (node.insertCut(hyperplane)) {
                node.setAttribute(null);
                node.getPlus().setAttribute(Boolean.FALSE);
                node = node.getMinus();
                node.setAttribute(Boolean.TRUE);
            }
        }

        return region;

    }

    /** Compute the union of two regions.
     * @param region1 first region (will be unusable after the operation as
     * parts of it will be reused in the new region)
     * @param region2 second region (will be unusable after the operation as
     * parts of it will be reused in the new region)
     * @return a new region, result of {@code region1 union region2}
     */
    public Region union(final Region region1, final Region region2) {
        final BSPTree tree =
            region1.getTree(false).merge(region2.getTree(false), new UnionMerger());
        tree.visit(nodeCleaner);
        return region1.buildNew(tree);
    }

    /** Compute the intersection of two regions.
     * @param region1 first region (will be unusable after the operation as
     * parts of it will be reused in the new region)
     * @param region2 second region (will be unusable after the operation as
     * parts of it will be reused in the new region)
     * @return a new region, result of {@code region1 intersection region2}
     */
    public Region intersection(final Region region1, final Region region2) {
        final BSPTree tree =
            region1.getTree(false).merge(region2.getTree(false), new IntersectionMerger());
        tree.visit(nodeCleaner);
        return region1.buildNew(tree);
    }

    /** Compute the symmetric difference (exclusive or) of two regions.
     * @param region1 first region (will be unusable after the operation as
     * parts of it will be reused in the new region)
     * @param region2 second region (will be unusable after the operation as
     * parts of it will be reused in the new region)
     * @return a new region, result of {@code region1 xor region2}
     */
    public Region xor(final Region region1, final Region region2) {
        final BSPTree tree =
            region1.getTree(false).merge(region2.getTree(false), new XorMerger());
        tree.visit(nodeCleaner);
        return region1.buildNew(tree);
    }

    /** Compute the difference of two regions.
     * @param region1 first region (will be unusable after the operation as
     * parts of it will be reused in the new region)
     * @param region2 second region (will be unusable after the operation as
     * parts of it will be reused in the new region)
     * @return a new region, result of {@code region1 minus region2}
     */
    public Region difference(final Region region1, final Region region2) {
        final BSPTree tree =
            region1.getTree(false).merge(region2.getTree(false), new DifferenceMerger());
        tree.visit(nodeCleaner);
        return region1.buildNew(tree);
    }

    /** Get the complement of the region (exchanged interior/exterior).
     * @param region region to complement, it will not modified, a new
     * region independent region will be built
     * @return a new region, complement of the specified one
     */
    public Region getComplement(final Region region) {
        return region.buildNew(recurseComplement(region.getTree(false)));
    }

    /** Recursively build the complement of a BSP tree.
     * @param node current node of the original tree
     * @return new tree, complement of the node
     */
    private BSPTree recurseComplement(final BSPTree node) {
        if (node.getCut() == null) {
            return new BSPTree(((Boolean) node.getAttribute()) ? Boolean.FALSE : Boolean.TRUE);
        }

        @SuppressWarnings("unchecked")
        BoundaryAttribute attribute = (BoundaryAttribute) node.getAttribute();
        if (attribute != null) {
            final SubHyperplane plusOutside =
                (attribute.getPlusInside() == null) ? null : attribute.getPlusInside().copySelf();
            final SubHyperplane plusInside  =
                (attribute.getPlusOutside() == null) ? null : attribute.getPlusOutside().copySelf();
            attribute = new BoundaryAttribute(plusOutside, plusInside);
        }

        return new BSPTree(node.getCut().copySelf(),
                              recurseComplement(node.getPlus()),
                              recurseComplement(node.getMinus()),
                              attribute);

    }

    /** BSP tree leaf merger computing union of two regions. */
    private class UnionMerger implements BSPTree.LeafMerger {
        /** {@inheritDoc} */
        public BSPTree merge(final BSPTree leaf, final BSPTree tree,
                                final BSPTree parentTree,
                                final boolean isPlusChild, final boolean leafFromInstance) {
            if ((Boolean) leaf.getAttribute()) {
                // the leaf node represents an inside cell
                leaf.insertInTree(parentTree, isPlusChild);
                return leaf;
            }
            // the leaf node represents an outside cell
            tree.insertInTree(parentTree, isPlusChild);
            return tree;
        }
    }

    /** BSP tree leaf merger computing union of two regions. */
    private class IntersectionMerger implements BSPTree.LeafMerger {
        /** {@inheritDoc} */
        public BSPTree merge(final BSPTree leaf, final BSPTree tree,
                                final BSPTree parentTree,
                                final boolean isPlusChild, final boolean leafFromInstance) {
            if ((Boolean) leaf.getAttribute()) {
                // the leaf node represents an inside cell
                tree.insertInTree(parentTree, isPlusChild);
                return tree;
            }
            // the leaf node represents an outside cell
            leaf.insertInTree(parentTree, isPlusChild);
            return leaf;
        }
    }

    /** BSP tree leaf merger computing union of two regions. */
    private class XorMerger implements BSPTree.LeafMerger {
        /** {@inheritDoc} */
        public BSPTree merge(final BSPTree leaf, final BSPTree tree,
                                final BSPTree parentTree, final boolean isPlusChild,
                                final boolean leafFromInstance) {
            BSPTree t = tree;
            if ((Boolean) leaf.getAttribute()) {
                // the leaf node represents an inside cell
                t = recurseComplement(t);
            }
            t.insertInTree(parentTree, isPlusChild);
            return t;
        }
    }

    /** BSP tree leaf merger computing union of two regions. */
    private class DifferenceMerger implements BSPTree.LeafMerger {
        /** {@inheritDoc} */
        public BSPTree merge(final BSPTree leaf, final BSPTree tree,
                                final BSPTree parentTree, final boolean isPlusChild,
                                final boolean leafFromInstance) {
            if ((Boolean) leaf.getAttribute()) {
                // the leaf node represents an inside cell
                final BSPTree argTree =
                    recurseComplement(leafFromInstance ? tree : leaf);
                argTree.insertInTree(parentTree, isPlusChild);
                return argTree;
            }
            // the leaf node represents an outside cell
            final BSPTree instanceTree =
                leafFromInstance ? leaf : tree;
            instanceTree.insertInTree(parentTree, isPlusChild);
            return instanceTree;
        }
    }

    /** Visitor removing internal nodes attributes. */
    private class NodesCleaner implements  BSPTreeVisitor {

        /** {@inheritDoc} */
        public Order visitOrder(final BSPTree node) {
            return Order.PLUS_SUB_MINUS;
        }

        /** {@inheritDoc} */
        public void visitInternalNode(final BSPTree node) {
            node.setAttribute(null);
        }

        /** {@inheritDoc} */
        public void visitLeafNode(final BSPTree node) {
        }

    }

}