eu.mihosoft.vrl.v3d.Node Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of JavaCad Show documentation
Show all versions of JavaCad Show documentation
A Java based CSG Cad library
/**
* Node.java
*
* Copyright 2014-2014 Michael Hoffer [email protected]. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY Michael Hoffer [email protected] "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL Michael Hoffer [email protected] OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of Michael Hoffer
* [email protected].
*/
package eu.mihosoft.vrl.v3d;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
// TODO: Auto-generated Javadoc
/**
* Holds a node in a BSP tree. A BSP tree is built from a collection of polygons
* by picking a polygon to split along. That polygon (and all other coplanar
* polygons) are added directly to that node and the other polygons are added to
* the front and/or back subtrees. This is not a leafy BSP tree since there is
* no distinction between internal and leaf nodes.
*/
final class Node {
/**
* Polygons.
*/
private List polygons;
/**
* Plane used for BSP.
*/
private Plane plane;
/**
* Polygons in front of the plane.
*/
private Node front;
/**
* Polygons in back of the plane.
*/
private Node back;
private long maxDepth = -1;
/**
* Constructor.
*
* Creates a BSP node consisting of the specified polygons.
*
* @param polygons polygons
*/
public Node(List polygons) {
this.polygons = new ArrayList<>();
if (polygons != null) {
this.build(polygons);
}
}
/**
* Constructor. Creates a node without polygons.
*/
public Node() {
this(null);
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#clone()
*/
@Override
public Node clone() {
Node node = new Node();
node.plane = this.plane == null ? null : this.plane.clone();
node.front = this.front == null ? null : this.front.clone();
node.back = this.back == null ? null : this.back.clone();
// node.polygons = new ArrayList<>();
// polygons.parallelStream().forEach((Polygon p) -> {
// node.polygons.add(p.clone());
// });
Stream polygonStream;
if (polygons.size() > 200) {
polygonStream = polygons.parallelStream();
} else
polygonStream = polygons.stream();
node.polygons = polygonStream.map(p -> p.clone()).collect(Collectors.toList());
return node;
}
/**
* Converts solid space to empty space and vice verca.
*/
public void invert() {
Stream polygonStream;
if (polygons.size() > 200) {
polygonStream = polygons.parallelStream();
} else
polygonStream = polygons.stream();
polygonStream.forEach((polygon) -> {
polygon.flip();
});
if (this.plane == null && !polygons.isEmpty()) {
this.plane = polygons.get(0).plane.clone();
} else if (this.plane == null && polygons.isEmpty()) {
//System.err.println("Please fix me! I don't know what to do?");
throw new RuntimeException("Please fix me! I don't know what to do?");
// return;
}
this.plane.flip();
if (this.front != null) {
this.front.invert();
}
if (this.back != null) {
this.back.invert();
}
Node temp = this.front;
this.front = this.back;
this.back = temp;
}
/**
* Recursively removes all polygons in the {@link polygons} list that are
* contained within this BSP tree.
*
* Note: polygons are splitted if necessary.
*
* @param polygons the polygons to clip
*
* @return the cliped list of polygons
*/
private List clipPolygons(List polygons) {
if (this.plane == null) {
return new ArrayList<>(polygons);
}
List frontP = new ArrayList<>();
List backP = new ArrayList<>();
for (Polygon polygon : polygons) {
this.plane.splitPolygon(polygon, frontP, backP, frontP, backP);
}
if (this.front != null) {
frontP = this.front.clipPolygons(frontP);
}
if (this.back != null) {
backP = this.back.clipPolygons(backP);
} else {
backP = new ArrayList<>(0);
}
frontP.addAll(backP);
return frontP;
}
// Remove all polygons in this BSP tree that are inside the other BSP tree
// `bsp`.
/**
* Removes all polygons in this BSP tree that are inside the specified BSP tree
* ({@code bsp}).
*
* Note: polygons are splitted if necessary.
*
* @param bsp bsp that shall be used for clipping
*/
public void clipTo(Node bsp) {
this.polygons = bsp.clipPolygons(this.polygons);
if (this.front != null) {
this.front.clipTo(bsp);
}
if (this.back != null) {
this.back.clipTo(bsp);
}
}
/**
* Returns a list of all polygons in this BSP tree.
*
* @return a list of all polygons in this BSP tree
*/
public List allPolygons() {
List localPolygons = new ArrayList<>(this.polygons);
if (this.front != null) {
localPolygons.addAll(this.front.allPolygons());
// polygons = Utils.concat(polygons, this.front.allPolygons());
}
if (this.back != null) {
// polygons = Utils.concat(polygons, this.back.allPolygons());
localPolygons.addAll(this.back.allPolygons());
}
return localPolygons;
}
/**
* Build a BSP tree out of {@code polygons}. When called on an existing tree,
* the new polygons are filtered down to the bottom of the tree and become new
* nodes there. Each set of polygons is partitioned using the first polygon (no
* heuristic is used to pick a good split).
*
* @param polygons polygons used to build the BSP
*/
public final void build(List polygons) {
build(polygons, 0,polygons.size() );
}
/**
* Build a BSP tree out of {@code polygons}. When called on an existing tree,
* the new polygons are filtered down to the bottom of the tree and become new
* nodes there. Each set of polygons is partitioned using the first polygon (no
* heuristic is used to pick a good split).
*
* @param polygons polygons used to build the BSP
*/
public final void build(List polygons, long depth, long maxDepth) {
// if (depth > maxDepth) {
// throw new RuntimeException("Impossible Node depth " + depth + " with " + polygons.size() + " remaining max = "+maxDepth );
// }
// if (depth > 200) {
// System.out.println("Node depth " + depth + " with " + polygons.size() + " remaining ");
// Plane.setUseDebugger(true);
// } else {
// Plane.setUseDebugger(false);
// }
if (polygons.isEmpty()) {
return;
}
if (this.plane == null) {
this.plane = polygons.get(0).plane.clone();
}
//this.polygons.add(polygons.get(0));
List frontP = new ArrayList<>();
List backP = new ArrayList<>();
// parellel version does not work here
for(int i=0;i 0) {
if (this.front == null) {
this.front = new Node();
}
this.front.build(frontP, depth + 1,maxDepth);
}
if (backP.size() > 0) {
if (this.back == null) {
this.back = new Node();
}
this.back.build(backP, depth + 1,maxDepth);
}
}
}