AbstractSubHyperplane.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      https://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */

  17. /*
  18.  * This is not the original file distributed by the Apache Software Foundation
  19.  * It has been modified by the Hipparchus project
  20.  */
  21. package org.hipparchus.geometry.partitioning;

  22. import java.util.HashMap;
  23. import java.util.Map;

  24. import org.hipparchus.geometry.Point;
  25. import org.hipparchus.geometry.Space;

  26. /** This class implements the dimension-independent parts of {@link SubHyperplane}.

  27.  * <p>sub-hyperplanes are obtained when parts of an {@link
  28.  * Hyperplane hyperplane} are chopped off by other hyperplanes that
  29.  * intersect it. The remaining part is a convex region. Such objects
  30.  * appear in {@link BSPTree BSP trees} as the intersection of a cut
  31.  * hyperplane with the convex region which it splits, the chopping
  32.  * hyperplanes are the cut hyperplanes closer to the tree root.</p>

  33.  * @param <S> Type of the space.
  34.  * @param <P> Type of the points in space.
  35.  * @param <H> Type of the hyperplane.
  36.  * @param <I> Type of the sub-hyperplane.
  37.  * @param <T> Type of the sub-space.
  38.  * @param <Q> Type of the points in sub-space.
  39.  * @param <F> Type of the hyperplane.
  40.  * @param <J> Type of the sub-hyperplane.

  41.  */
  42. public abstract class AbstractSubHyperplane<S extends Space,
  43.                                             P extends Point<S, P>,
  44.                                             H extends Hyperplane<S, P, H, I>,
  45.                                             I extends SubHyperplane<S, P, H, I>,
  46.                                             T extends Space, Q extends Point<T, Q>,
  47.                                             F extends Hyperplane<T, Q, F, J>,
  48.                                             J extends SubHyperplane<T, Q, F, J>>
  49.     implements SubHyperplane<S, P, H, I> {

  50.     /** Underlying hyperplane. */
  51.     private final H hyperplane;

  52.     /** Remaining region of the hyperplane. */
  53.     private final Region<T, Q, F, J> remainingRegion;

  54.     /** Build a sub-hyperplane from an hyperplane and a region.
  55.      * @param hyperplane underlying hyperplane
  56.      * @param remainingRegion remaining region of the hyperplane
  57.      */
  58.     protected AbstractSubHyperplane(final H hyperplane,
  59.                                     final Region<T, Q, F, J> remainingRegion) {
  60.         this.hyperplane      = hyperplane;
  61.         this.remainingRegion = remainingRegion;
  62.     }

  63.     /** Build a sub-hyperplane from an hyperplane and a region.
  64.      * @param hyper underlying hyperplane
  65.      * @param remaining remaining region of the hyperplane
  66.      * @return a new sub-hyperplane
  67.      */
  68.     protected abstract I buildNew(H hyper, Region<T, Q, F, J> remaining);

  69.     /** {@inheritDoc} */
  70.     @Override
  71.     public I copySelf() {
  72.         return buildNew(hyperplane.copySelf(), remainingRegion);
  73.     }

  74.     /** Get the underlying hyperplane.
  75.      * @return underlying hyperplane
  76.      */
  77.     @Override
  78.     public H getHyperplane() {
  79.         return hyperplane;
  80.     }

  81.     /** Get the remaining region of the hyperplane.
  82.      * <p>The returned region is expressed in the canonical hyperplane
  83.      * frame and has the hyperplane dimension. For example a chopped
  84.      * hyperplane in the 3D euclidean is a 2D plane and the
  85.      * corresponding region is a convex 2D polygon.</p>
  86.      * @return remaining region of the hyperplane
  87.      */
  88.     public Region<T, Q, F, J> getRemainingRegion() {
  89.         return remainingRegion;
  90.     }

  91.     /** {@inheritDoc} */
  92.     @Override
  93.     public double getSize() {
  94.         return remainingRegion.getSize();
  95.     }

  96.     /** {@inheritDoc} */
  97.     @Override
  98.     public I reunite(final I other) {
  99.         @SuppressWarnings("unchecked")
  100.         AbstractSubHyperplane<S, P, H, I, T, Q, F, J> o = (AbstractSubHyperplane<S, P, H, I, T, Q, F, J>) other;
  101.         return buildNew(hyperplane,
  102.                         new RegionFactory<T, Q, F, J>().union(remainingRegion, o.remainingRegion));
  103.     }

  104.     /** Apply a transform to the instance.
  105.      * <p>The instance must be a (D-1)-dimension sub-hyperplane with
  106.      * respect to the transform <em>not</em> a (D-2)-dimension
  107.      * sub-hyperplane the transform knows how to transform by
  108.      * itself. The transform will consist in transforming first the
  109.      * hyperplane and then the all region using the various methods
  110.      * provided by the transform.</p>
  111.      * @param transform D-dimension transform to apply
  112.      * @return the transformed instance
  113.      */
  114.     public I applyTransform(final Transform<S, P, H, I, T, Q, F, J> transform) {
  115.         final H tHyperplane = transform.apply(hyperplane);

  116.         // transform the tree, except for boundary attribute splitters
  117.         final Map<BSPTree<T, Q, F, J>, BSPTree<T, Q, F, J>> map = new HashMap<>();
  118.         final BSPTree<T, Q, F, J> tTree =
  119.             recurseTransform(remainingRegion.getTree(false), tHyperplane, transform, map);

  120.         // set up the boundary attributes splitters
  121.         for (final Map.Entry<BSPTree<T, Q, F, J>, BSPTree<T, Q, F, J>> entry : map.entrySet()) {
  122.             if (entry.getKey().getCut() != null) {
  123.                 @SuppressWarnings("unchecked")
  124.                 BoundaryAttribute<T, Q, F, J> original = (BoundaryAttribute<T, Q, F, J>) entry.getKey().getAttribute();
  125.                 if (original != null) {
  126.                     @SuppressWarnings("unchecked")
  127.                     BoundaryAttribute<T, Q, F, J> transformed = (BoundaryAttribute<T, Q, F, J>) entry.getValue().getAttribute();
  128.                     for (final BSPTree<T, Q, F, J> splitter : original.getSplitters()) {
  129.                         transformed.getSplitters().add(map.get(splitter));
  130.                     }
  131.                 }
  132.             }
  133.         }

  134.         return buildNew(tHyperplane, remainingRegion.buildNew(tTree));

  135.     }

  136.     /** Recursively transform a BSP-tree from a sub-hyperplane.
  137.      * @param node current BSP tree node
  138.      * @param transformed image of the instance hyperplane by the transform
  139.      * @param transform transform to apply
  140.      * @param map transformed nodes map
  141.      * @return a new tree
  142.      */
  143.     private BSPTree<T, Q, F, J> recurseTransform(final BSPTree<T, Q, F, J> node,
  144.                                                  final H transformed,
  145.                                                  final Transform<S, P, H, I, T, Q, F, J> transform,
  146.                                                  final Map<BSPTree<T, Q, F, J>, BSPTree<T, Q, F, J>> map) {

  147.         final BSPTree<T, Q, F, J> transformedNode;
  148.         if (node.getCut() == null) {
  149.             transformedNode = new BSPTree<>(node.getAttribute());
  150.         } else {

  151.             @SuppressWarnings("unchecked")
  152.             BoundaryAttribute<T, Q, F, J> attribute = (BoundaryAttribute<T, Q, F, J>) node.getAttribute();
  153.             if (attribute != null) {
  154.                 final J tPO = (attribute.getPlusOutside() == null) ?
  155.                     null : transform.apply(attribute.getPlusOutside(), hyperplane, transformed);
  156.                 final J tPI = (attribute.getPlusInside() == null) ?
  157.                     null : transform.apply(attribute.getPlusInside(), hyperplane, transformed);
  158.                 // we start with an empty list of splitters, it will be filled in out of recursion
  159.                 attribute = new BoundaryAttribute<>(tPO, tPI, new NodesSet<>());
  160.             }

  161.             transformedNode = new BSPTree<>(transform.apply(node.getCut(), hyperplane, transformed),
  162.                                             recurseTransform(node.getPlus(),  transformed, transform, map),
  163.                                             recurseTransform(node.getMinus(), transformed, transform, map),
  164.                                             attribute);
  165.         }

  166.         map.put(node, transformedNode);
  167.         return transformedNode;

  168.     }

  169.     /** {@inheritDoc} */
  170.     @Override
  171.     public abstract SplitSubHyperplane<S, P, H, I> split(H hyper);

  172.     /** {@inheritDoc} */
  173.     @Override
  174.     public boolean isEmpty() {
  175.         return remainingRegion.isEmpty();
  176.     }

  177. }