evaluate() {
+
+ return plInternal;
+ }
+
+}
diff --git a/src/main/java/com/piro/bezier/ParseException.java b/src/main/java/com/piro/bezier/ParseException.java
new file mode 100644
index 00000000..5cad1778
--- /dev/null
+++ b/src/main/java/com/piro/bezier/ParseException.java
@@ -0,0 +1,129 @@
+/*
+
+ 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 com.piro.bezier;
+
+/**
+ * This class encapsulates a general parse error or warning.
+ *
+ * This class can contain basic error or warning information from
+ * either the parser or the application.
+ *
+ *
If the application needs to pass through other types of
+ * exceptions, it must wrap those exceptions in a ParseException.
+ *
+ * @author Stephane Hillion
+ * @version $Id: ParseException.java 475685 2006-11-16 11:16:05Z cam $
+ */
+public class ParseException extends RuntimeException {
+
+ /**
+ * @serial The embedded exception if tunnelling, or null.
+ */
+ protected Exception exception;
+
+ /**
+ * @serial The line number.
+ */
+ protected int lineNumber;
+
+ /**
+ * @serial The column number.
+ */
+ protected int columnNumber;
+
+ /**
+ * Creates a new ParseException.
+ * @param message The error or warning message.
+ * @param line The line of the last parsed character.
+ * @param column The column of the last parsed character.
+ */
+ public ParseException (String message, int line, int column) {
+ super(message);
+ exception = null;
+ lineNumber = line;
+ columnNumber = column;
+ }
+
+ /**
+ * Creates a new ParseException wrapping an existing exception.
+ *
+ *
The existing exception will be embedded in the new
+ * one, and its message will become the default message for
+ * the ParseException.
+ * @param e The exception to be wrapped in a ParseException.
+ */
+ public ParseException (Exception e) {
+ exception = e;
+ lineNumber = -1;
+ columnNumber = -1;
+ }
+
+ /**
+ * Creates a new ParseException from an existing exception.
+ *
+ *
The existing exception will be embedded in the new
+ * one, but the new exception will have its own message.
+ * @param message The detail message.
+ * @param e The exception to be wrapped in a SAXException.
+ */
+ public ParseException (String message, Exception e) {
+ super(message);
+ this.exception = e;
+ }
+
+ /**
+ * Return a detail message for this exception.
+ *
+ *
If there is a embedded exception, and if the ParseException
+ * has no detail message of its own, this method will return
+ * the detail message from the embedded exception.
+ * @return The error or warning message.
+ */
+ public String getMessage () {
+ String message = super.getMessage();
+
+ if (message == null && exception != null) {
+ return exception.getMessage();
+ } else {
+ return message;
+ }
+ }
+
+ /**
+ * Return the embedded exception, if any.
+ * @return The embedded exception, or null if there is none.
+ */
+ public Exception getException () {
+ return exception;
+ }
+
+ /**
+ * Returns the line of the last parsed character.
+ */
+ public int getLineNumber() {
+ return lineNumber;
+ }
+
+ /**
+ * Returns the column of the last parsed character.
+ */
+ public int getColumnNumber() {
+ return columnNumber;
+ }
+}
diff --git a/src/main/java/com/piro/bezier/PathHandler.java b/src/main/java/com/piro/bezier/PathHandler.java
new file mode 100644
index 00000000..a8e46b47
--- /dev/null
+++ b/src/main/java/com/piro/bezier/PathHandler.java
@@ -0,0 +1,262 @@
+/*
+
+ 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 com.piro.bezier;
+
+/**
+ * This interface must be implemented and then registred as the
+ * handler of a PathParser instance in order to be
+ * notified of parsing events.
+ *
+ * @author Stephane Hillion
+ * @version $Id: PathHandler.java 475685 2006-11-16 11:16:05Z cam $
+ */
+public interface PathHandler {
+ /**
+ * Invoked when the path starts.
+ * @exception ParseException if an error occured while processing the path
+ */
+ void startPath() throws ParseException;
+
+ /**
+ * Invoked when the path ends.
+ * @exception ParseException if an error occured while processing the path
+ */
+ void endPath() throws ParseException;
+
+ /**
+ * Invoked when a relative moveto command has been parsed.
+ *
Command : m
+ * @param x the relative x coordinate for the end point
+ * @param y the relative y coordinate for the end point
+ * @exception ParseException if an error occured while processing the path
+ */
+ void movetoRel(double x, double y) throws ParseException;
+
+ /**
+ * Invoked when an absolute moveto command has been parsed.
+ *
Command : M
+ * @param x the absolute x coordinate for the end point
+ * @param y the absolute y coordinate for the end point
+ * @exception ParseException if an error occured while processing the path
+ */
+ void movetoAbs(double x, double y) throws ParseException;
+
+ /**
+ * Invoked when a closepath has been parsed.
+ *
Command : z | Z
+ * @exception ParseException if an error occured while processing the path
+ */
+ void closePath() throws ParseException;
+
+ /**
+ * Invoked when a relative line command has been parsed.
+ *
Command : l
+ * @param x the relative x coordinates for the end point
+ * @param y the relative y coordinates for the end point
+ * @exception ParseException if an error occured while processing the path
+ */
+ void linetoRel(double x, double y) throws ParseException;
+
+ /**
+ * Invoked when an absolute line command has been parsed.
+ *
Command : L
+ * @param x the absolute x coordinate for the end point
+ * @param y the absolute y coordinate for the end point
+ * @exception ParseException if an error occured while processing the path
+ */
+ void linetoAbs(double x, double y) throws ParseException;
+
+ /**
+ * Invoked when an horizontal relative line command has been parsed.
+ *
Command : h
+ * @param x the relative X coordinate of the end point
+ * @exception ParseException if an error occured while processing the path
+ */
+ void linetoHorizontalRel(double x) throws ParseException;
+
+ /**
+ * Invoked when an horizontal absolute line command has been parsed.
+ *
Command : H
+ * @param x the absolute X coordinate of the end point
+ * @exception ParseException if an error occured while processing the path
+ */
+ void linetoHorizontalAbs(double x) throws ParseException;
+
+ /**
+ * Invoked when a vertical relative line command has been parsed.
+ *
Command : v
+ * @param y the relative Y coordinate of the end point
+ * @exception ParseException if an error occured while processing the path
+ */
+ void linetoVerticalRel(double y) throws ParseException;
+
+ /**
+ * Invoked when a vertical absolute line command has been parsed.
+ *
Command : V
+ * @param y the absolute Y coordinate of the end point
+ * @exception ParseException if an error occured while processing the path
+ */
+ void linetoVerticalAbs(double y) throws ParseException;
+
+ /**
+ * Invoked when a relative cubic bezier curve command has been parsed.
+ *
Command : c
+ * @param x1 the relative x coordinate for the first control point
+ * @param y1 the relative y coordinate for the first control point
+ * @param x2 the relative x coordinate for the second control point
+ * @param y2 the relative y coordinate for the second control point
+ * @param x the relative x coordinate for the end point
+ * @param y the relative y coordinate for the end point
+ * @exception ParseException if an error occured while processing the path
+ */
+ void curvetoCubicRel(double x1, double y1,
+ double x2, double y2,
+ double x, double y) throws ParseException;
+
+
+ /**
+ * Invoked when an absolute cubic bezier curve command has been parsed.
+ *
Command : C
+ * @param x1 the absolute x coordinate for the first control point
+ * @param y1 the absolute y coordinate for the first control point
+ * @param x2 the absolute x coordinate for the second control point
+ * @param y2 the absolute y coordinate for the second control point
+ * @param x the absolute x coordinate for the end point
+ * @param y the absolute y coordinate for the end point
+ * @exception ParseException if an error occured while processing the path
+ */
+ void curvetoCubicAbs(double x1, double y1,
+ double x2, double y2,
+ double x, double y) throws ParseException;
+
+ /**
+ * Invoked when a relative smooth cubic bezier curve command has
+ * been parsed. The first control point is assumed to be the
+ * reflection of the second control point on the previous command
+ * relative to the current point.
+ *
Command : s
+ * @param x2 the relative x coordinate for the second control point
+ * @param y2 the relative y coordinate for the second control point
+ * @param x the relative x coordinate for the end point
+ * @param y the relative y coordinate for the end point
+ * @exception ParseException if an error occured while processing the path
+ */
+ void curvetoCubicSmoothRel(double x2, double y2,
+ double x, double y) throws ParseException;
+
+ /**
+ * Invoked when an absolute smooth cubic bezier curve command has
+ * been parsed. The first control point is assumed to be the
+ * reflection of the second control point on the previous command
+ * relative to the current point.
+ *
Command : S
+ * @param x2 the absolute x coordinate for the second control point
+ * @param y2 the absolute y coordinate for the second control point
+ * @param x the absolute x coordinate for the end point
+ * @param y the absolute y coordinate for the end point
+ * @exception ParseException if an error occured while processing the path
+ */
+ void curvetoCubicSmoothAbs(double x2, double y2,
+ double x, double y) throws ParseException;
+
+ /**
+ * Invoked when a relative quadratic bezier curve command has been parsed.
+ *
Command : q
+ * @param x1 the relative x coordinate for the control point
+ * @param y1 the relative y coordinate for the control point
+ * @param x the relative x coordinate for the end point
+ * @param y the relative x coordinate for the end point
+ * @exception ParseException if an error occured while processing the path
+ */
+ void curvetoQuadraticRel(double x1, double y1,
+ double x, double y) throws ParseException;
+
+ /**
+ * Invoked when an absolute quadratic bezier curve command has been parsed.
+ *
Command : Q
+ * @param x1 the absolute x coordinate for the control point
+ * @param y1 the absolute y coordinate for the control point
+ * @param x the absolute x coordinate for the end point
+ * @param y the absolute x coordinate for the end point
+ * @exception ParseException if an error occured while processing the path
+ */
+ void curvetoQuadraticAbs(double x1, double y1,
+ double x, double y) throws ParseException;
+
+ /**
+ * Invoked when a relative smooth quadratic bezier curve command
+ * has been parsed. The control point is assumed to be the
+ * reflection of the control point on the previous command
+ * relative to the current point.
+ *
Command : t
+ * @param x the relative x coordinate for the end point
+ * @param y the relative y coordinate for the end point
+ * @exception ParseException if an error occured while processing the path
+ */
+ void curvetoQuadraticSmoothRel(double x, double y) throws ParseException;
+
+ /**
+ * Invoked when an absolute smooth quadratic bezier curve command
+ * has been parsed. The control point is assumed to be the
+ * reflection of the control point on the previous command
+ * relative to the current point.
+ *
Command : T
+ * @param x the absolute x coordinate for the end point
+ * @param y the absolute y coordinate for the end point
+ * @exception ParseException if an error occured while processing the path
+ */
+ void curvetoQuadraticSmoothAbs(double x, double y) throws ParseException;
+
+ /**
+ * Invoked when a relative elliptical arc command has been parsed.
+ *
Command : a
+ * @param rx the X axis radius for the ellipse
+ * @param ry the Y axis radius for the ellipse
+ * @param xAxisRotation the rotation angle in degrees for the ellipse's
+ * X-axis relative to the X-axis
+ * @param largeArcFlag the value of the large-arc-flag
+ * @param sweepFlag the value of the sweep-flag
+ * @param x the relative x coordinate for the end point
+ * @param y the relative y coordinate for the end point
+ * @exception ParseException if an error occured while processing the path
+ */
+ void arcRel(double rx, double ry,
+ double xAxisRotation,
+ boolean largeArcFlag, boolean sweepFlag,
+ double x, double y) throws ParseException;
+
+
+ /**
+ * Invoked when an absolute elliptical arc command has been parsed.
+ *
Command : A
+ * @param rx the X axis radius for the ellipse
+ * @param ry the Y axis radius for the ellipse
+ * @param xAxisRotation the rotation angle in degrees for the ellipse's
+ * X-axis relative to the X-axis
+ * @param largeArcFlag the value of the large-arc-flag
+ * @param sweepFlag the value of the sweep-flag
+ * @param x the absolute x coordinate for the end point
+ * @param y the absolute y coordinate for the end point
+ * @exception ParseException if an error occured while processing the path
+ */
+ void arcAbs(double rx, double ry,
+ double xAxisRotation,
+ boolean largeArcFlag, boolean sweepFlag,
+ double x, double y) throws ParseException;
+}
diff --git a/src/main/java/com/piro/bezier/Vector2.java b/src/main/java/com/piro/bezier/Vector2.java
new file mode 100644
index 00000000..d929a858
--- /dev/null
+++ b/src/main/java/com/piro/bezier/Vector2.java
@@ -0,0 +1,15 @@
+package com.piro.bezier;
+
+public class Vector2 {
+
+ public double x;
+ public double y;
+
+ public void set(double x, double y) {
+ this.x = x;
+ // Auto-generated method stub
+ this.y = y;
+
+ }
+
+}
diff --git a/src/main/java/eu/mihosoft/jcsg/Bounds.java b/src/main/java/eu/mihosoft/jcsg/Bounds.java
deleted file mode 100644
index f39ce50c..00000000
--- a/src/main/java/eu/mihosoft/jcsg/Bounds.java
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * To change this license header, choose License Headers in Project Properties.
- * To change this template file, choose Tools | Templates
- * and open the template in the editor.
- */
-package eu.mihosoft.jcsg;
-
-import eu.mihosoft.vvecmath.Vector3d;
-
-/**
- * Bounding box for CSGs.
- *
- * @author Michael Hoffer <info@michaelhoffer.de>
- */
-public class Bounds {
-
- private final Vector3d center;
- private final Vector3d bounds;
- private final Vector3d min;
- private final Vector3d max;
- private final CSG csg;
- private final Cube cube;
-
- /**
- * Constructor.
- *
- * @param min min x,y,z values
- * @param max max x,y,z values
- */
- public Bounds(Vector3d min, Vector3d max) {
- this.center = Vector3d.xyz(
- (max.x() + min.x()) / 2,
- (max.y() + min.y()) / 2,
- (max.z() + min.z()) / 2);
-
- this.bounds = Vector3d.xyz(
- Math.abs(max.x() - min.x()),
- Math.abs(max.y() - min.y()),
- Math.abs(max.z() - min.z()));
-
- this.min = min.clone();
- this.max = max.clone();
-
- cube = new Cube(center, bounds);
- csg = cube.toCSG();
- }
-
- @Override
- public Bounds clone() {
- return new Bounds(min.clone(), max.clone());
- }
-
- /**
- * Returns the position of the center.
- *
- * @return the center position
- */
- public Vector3d getCenter() {
- return center;
- }
-
- /**
- * Returns the bounds (width,height,depth).
- *
- * @return the bounds (width,height,depth)
- */
- public Vector3d getBounds() {
- return bounds;
- }
-
- /**
- * Returns this bounding box as csg.
- *
- * @return this bounding box as csg
- */
- public CSG toCSG() {
- return csg;
- }
-
- /**
- * Returns this bounding box as cube.
- *
- * @return this bounding box as cube
- */
- public Cube toCube() {
- return cube;
- }
-
- /**
- * Indicates whether the specified vertex is contained within this bounding
- * box (check includes box boundary).
- *
- * @param v vertex to check
- * @return {@code true} if the vertex is contained within this bounding box;
- * {@code false} otherwise
- */
- public boolean contains(Vertex v) {
- return contains(v.pos);
- }
-
- /**
- * Indicates whether the specified point is contained within this bounding
- * box (check includes box boundary).
- *
- * @param v vertex to check
- * @return {@code true} if the point is contained within this bounding box;
- * {@code false} otherwise
- */
- public boolean contains(Vector3d v) {
- boolean inX = min.x() <= v.x() && v.x() <= max.x();
- boolean inY = min.y() <= v.y() && v.y() <= max.y();
- boolean inZ = min.z() <= v.z() && v.z() <= max.z();
-
- return inX && inY && inZ;
- }
-
- /**
- * Indicates whether the specified polygon is contained within this bounding
- * box (check includes box boundary).
- *
- * @param p polygon to check
- * @return {@code true} if the polygon is contained within this bounding
- * box; {@code false} otherwise
- */
- public boolean contains(Polygon p) {
- return p.vertices.stream().allMatch(v -> contains(v));
- }
-
- /**
- * Indicates whether the specified polygon intersects with this bounding box
- * (check includes box boundary).
- *
- * @param p polygon to check
- * @return {@code true} if the polygon intersects this bounding box;
- * {@code false} otherwise
- * @deprecated not implemented yet
- */
- @Deprecated
- public boolean intersects(Polygon p) {
- throw new UnsupportedOperationException("Implementation missing!");
- }
-
- /**
- * Indicates whether the specified bounding box intersects with this
- * bounding box (check includes box boundary).
- *
- * @param b box to check
- * @return {@code true} if the bounding box intersects this bounding box;
- * {@code false} otherwise
- */
- public boolean intersects(Bounds b) {
-
- if (b.getMin().x() > this.getMax().x() || b.getMax().x() < this.getMin().x()) {
- return false;
- }
- if (b.getMin().y() > this.getMax().y() || b.getMax().y() < this.getMin().y()) {
- return false;
- }
- if (b.getMin().z() > this.getMax().z() || b.getMax().z() < this.getMin().z()) {
- return false;
- }
-
- return true;
-
- }
-
- /**
- * @return the min x,y,z values
- */
- public Vector3d getMin() {
- return min;
- }
-
- /**
- * @return the max x,y,z values
- */
- public Vector3d getMax() {
- return max;
- }
-
- @Override
- public String toString() {
- return "[center: " + center + ", bounds: " + bounds + "]";
- }
-
-}
diff --git a/src/main/java/eu/mihosoft/jcsg/CSG.java b/src/main/java/eu/mihosoft/jcsg/CSG.java
deleted file mode 100644
index f0e9fd31..00000000
--- a/src/main/java/eu/mihosoft/jcsg/CSG.java
+++ /dev/null
@@ -1,1183 +0,0 @@
-/**
- * CSG.java
- *
- * Copyright 2014-2014 Michael Hoffer . 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 "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 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
- * .
- */
-package eu.mihosoft.jcsg;
-
-import eu.mihosoft.vvecmath.Vector3d;
-import eu.mihosoft.vvecmath.Transform;
-import eu.mihosoft.jcsg.ext.quickhull3d.HullUtil;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-import javafx.scene.paint.Color;
-import javafx.scene.shape.TriangleMesh;
-
-/**
- * Constructive Solid Geometry (CSG).
- *
- * This implementation is a Java port of
- * https://github.com/evanw/csg.js/
- * with some additional features like polygon extrude, transformations etc.
- * Thanks to the author for creating the CSG.js library.
- *
- * Implementation Details
- *
- * All CSG operations are implemented in terms of two functions,
- * {@link Node#clipTo(Node)} and {@link Node#invert()},
- * which remove parts of a BSP tree inside another BSP tree and swap solid and
- * empty space, respectively. To find the union of {@code a} and {@code b}, we
- * want to remove everything in {@code a} inside {@code b} and everything in
- * {@code b} inside {@code a}, then combine polygons from {@code a} and
- * {@code b} into one solid:
- *
- *
- * a.clipTo(b);
- * b.clipTo(a);
- * a.build(b.allPolygons());
- *
- *
- * The only tricky part is handling overlapping coplanar polygons in both trees.
- * The code above keeps both copies, but we need to keep them in one tree and
- * remove them in the other tree. To remove them from {@code b} we can clip the
- * inverse of {@code b} against {@code a}. The code for union now looks like
- * this:
- *
- *
- * a.clipTo(b);
- * b.clipTo(a);
- * b.invert();
- * b.clipTo(a);
- * b.invert();
- * a.build(b.allPolygons());
- *
- *
- * Subtraction and intersection naturally follow from set operations. If union
- * is {@code A | B}, differenceion is {@code A - B = ~(~A | B)} and intersection
- * is {@code A & B =
- * ~(~A | ~B)} where {@code ~} is the complement operator.
- */
-public class CSG {
-
- private List polygons;
- private static OptType defaultOptType = OptType.NONE;
- private OptType optType = null;
- private PropertyStorage storage;
-
- private CSG() {
- storage = new PropertyStorage();
- }
-
- /**
- * Constructs a CSG from a list of {@link Polygon} instances.
- *
- * @param polygons polygons
- * @return a CSG instance
- */
- public static CSG fromPolygons(List polygons) {
-
- CSG csg = new CSG();
- csg.polygons = polygons;
-
- return csg;
- }
-
- /**
- * Constructs a CSG from the specified {@link Polygon} instances.
- *
- * @param polygons polygons
- * @return a CSG instance
- */
- public static CSG fromPolygons(Polygon... polygons) {
- return fromPolygons(Arrays.asList(polygons));
- }
-
- /**
- * Constructs a CSG from a list of {@link Polygon} instances.
- *
- * @param storage shared storage
- * @param polygons polygons
- * @return a CSG instance
- */
- public static CSG fromPolygons(PropertyStorage storage, List polygons) {
-
- CSG csg = new CSG();
- csg.polygons = polygons;
-
- csg.storage = storage;
-
- for (Polygon polygon : polygons) {
- polygon.setStorage(storage);
- }
-
- return csg;
- }
-
- /**
- * Constructs a CSG from the specified {@link Polygon} instances.
- *
- * @param storage shared storage
- * @param polygons polygons
- * @return a CSG instance
- */
- public static CSG fromPolygons(PropertyStorage storage, Polygon... polygons) {
- return fromPolygons(storage, Arrays.asList(polygons));
- }
-
- @Override
- public CSG clone() {
- CSG csg = new CSG();
-
- csg.setOptType(this.getOptType());
-
- // sequential code
-// csg.polygons = new ArrayList<>();
-// polygons.forEach((polygon) -> {
-// csg.polygons.add(polygon.clone());
-// });
- Stream polygonStream;
-
- if (polygons.size() > 200) {
- polygonStream = polygons.parallelStream();
- } else {
- polygonStream = polygons.stream();
- }
-
- csg.polygons = polygonStream.
- map((Polygon p) -> p.clone()).collect(Collectors.toList());
-
- return csg;
- }
-
- /**
- *
- * @return the polygons of this CSG
- */
- public List getPolygons() {
- return polygons;
- }
-
- /**
- * Defines the CSg optimization type.
- *
- * @param type optimization type
- * @return this CSG
- */
- public CSG optimization(OptType type) {
- this.setOptType(type);
- return this;
- }
-
- /**
- * Return a new CSG solid representing the union of this csg and the
- * specified csg.
- *
- * Note: Neither this csg nor the specified csg are weighted.
- *
- *
- * A.union(B)
- *
- * +-------+ +-------+
- * | | | |
- * | A | | |
- * | +--+----+ = | +----+
- * +----+--+ | +----+ |
- * | B | | |
- * | | | |
- * +-------+ +-------+
- *
- *
- *
- * @param csg other csg
- *
- * @return union of this csg and the specified csg
- */
- public CSG union(CSG csg) {
-
- switch (getOptType()) {
- case CSG_BOUND:
- return _unionCSGBoundsOpt(csg);
- case POLYGON_BOUND:
- return _unionPolygonBoundsOpt(csg);
- default:
-// return _unionIntersectOpt(csg);
- return _unionNoOpt(csg);
- }
- }
-
- /**
- * Returns a csg consisting of the polygons of this csg and the specified csg.
- *
- * The purpose of this method is to allow fast union operations for objects
- * that do not intersect.
- *
- * WARNING: this method does not apply the csg algorithms. Therefore,
- * please ensure that this csg and the specified csg do not intersect.
- *
- * @param csg csg
- *
- * @return a csg consisting of the polygons of this csg and the specified csg
- */
- public CSG dumbUnion(CSG csg) {
-
- CSG result = this.clone();
- CSG other = csg.clone();
-
- result.polygons.addAll(other.polygons);
-
- return result;
- }
-
- /**
- * Return a new CSG solid representing the union of this csg and the
- * specified csgs.
- *
- * Note: Neither this csg nor the specified csg are weighted.
- *
- *
- * A.union(B)
- *
- * +-------+ +-------+
- * | | | |
- * | A | | |
- * | +--+----+ = | +----+
- * +----+--+ | +----+ |
- * | B | | |
- * | | | |
- * +-------+ +-------+
- *
- *
- *
- * @param csgs other csgs
- *
- * @return union of this csg and the specified csgs
- */
- public CSG union(List csgs) {
-
- CSG result = this;
-
- for (CSG csg : csgs) {
- result = result.union(csg);
- }
-
- return result;
- }
-
- /**
- * Return a new CSG solid representing the union of this csg and the
- * specified csgs.
- *
- * Note: Neither this csg nor the specified csg are weighted.
- *
- *
- * A.union(B)
- *
- * +-------+ +-------+
- * | | | |
- * | A | | |
- * | +--+----+ = | +----+
- * +----+--+ | +----+ |
- * | B | | |
- * | | | |
- * +-------+ +-------+
- *
- *
- *
- * @param csgs other csgs
- *
- * @return union of this csg and the specified csgs
- */
- public CSG union(CSG... csgs) {
- return union(Arrays.asList(csgs));
- }
-
- /**
- * Returns the convex hull of this csg.
- *
- * @return the convex hull of this csg
- */
- public CSG hull() {
-
- return HullUtil.hull(this, storage);
- }
-
- /**
- * Returns the convex hull of this csg and the union of the specified csgs.
- *
- * @param csgs csgs
- * @return the convex hull of this csg and the specified csgs
- */
- public CSG hull(List csgs) {
-
- CSG csgsUnion = new CSG();
- csgsUnion.storage = storage;
- csgsUnion.optType = optType;
- csgsUnion.polygons = this.clone().polygons;
-
- csgs.stream().forEach((csg) -> {
- csgsUnion.polygons.addAll(csg.clone().polygons);
- });
-
- csgsUnion.polygons.forEach(p -> p.setStorage(storage));
- return csgsUnion.hull();
-
-// CSG csgsUnion = this;
-//
-// for (CSG csg : csgs) {
-// csgsUnion = csgsUnion.union(csg);
-// }
-//
-// return csgsUnion.hull();
- }
-
- /**
- * Returns the convex hull of this csg and the union of the specified csgs.
- *
- * @param csgs csgs
- * @return the convex hull of this csg and the specified csgs
- */
- public CSG hull(CSG... csgs) {
-
- return hull(Arrays.asList(csgs));
- }
-
- private CSG _unionCSGBoundsOpt(CSG csg) {
- System.err.println("WARNING: using " + CSG.OptType.NONE
- + " since other optimization types missing for union operation.");
- return _unionIntersectOpt(csg);
- }
-
- private CSG _unionPolygonBoundsOpt(CSG csg) {
- List inner = new ArrayList<>();
- List outer = new ArrayList<>();
-
- Bounds bounds = csg.getBounds();
-
- this.polygons.stream().forEach((p) -> {
- if (bounds.intersects(p.getBounds())) {
- inner.add(p);
- } else {
- outer.add(p);
- }
- });
-
- List allPolygons = new ArrayList<>();
-
- if (!inner.isEmpty()) {
- CSG innerCSG = CSG.fromPolygons(inner);
-
- allPolygons.addAll(outer);
- allPolygons.addAll(innerCSG._unionNoOpt(csg).polygons);
- } else {
- allPolygons.addAll(this.polygons);
- allPolygons.addAll(csg.polygons);
- }
-
- return CSG.fromPolygons(allPolygons).optimization(getOptType());
- }
-
- /**
- * Optimizes for intersection. If csgs do not intersect create a new csg
- * that consists of the polygon lists of this csg and the specified csg. In
- * this case no further space partitioning is performed.
- *
- * @param csg csg
- * @return the union of this csg and the specified csg
- */
- private CSG _unionIntersectOpt(CSG csg) {
- boolean intersects = false;
-
- Bounds bounds = csg.getBounds();
-
- for (Polygon p : polygons) {
- if (bounds.intersects(p.getBounds())) {
- intersects = true;
- break;
- }
- }
-
- List allPolygons = new ArrayList<>();
-
- if (intersects) {
- return _unionNoOpt(csg);
- } else {
- allPolygons.addAll(this.polygons);
- allPolygons.addAll(csg.polygons);
- }
-
- return CSG.fromPolygons(allPolygons).optimization(getOptType());
- }
-
- private CSG _unionNoOpt(CSG csg) {
- Node a = new Node(this.clone().polygons);
- Node b = new Node(csg.clone().polygons);
- a.clipTo(b);
- b.clipTo(a);
- b.invert();
- b.clipTo(a);
- b.invert();
- a.build(b.allPolygons());
- return CSG.fromPolygons(a.allPolygons()).optimization(getOptType());
- }
-
- /**
- * Return a new CSG solid representing the difference of this csg and the
- * specified csgs.
- *
- * Note: Neither this csg nor the specified csgs are weighted.
- *
- *
- * A.difference(B)
- *
- * +-------+ +-------+
- * | | | |
- * | A | | |
- * | +--+----+ = | +--+
- * +----+--+ | +----+
- * | B |
- * | |
- * +-------+
- *
- *
- * @param csgs other csgs
- * @return difference of this csg and the specified csgs
- */
- public CSG difference(List csgs) {
-
- if (csgs.isEmpty()) {
- return this.clone();
- }
-
- CSG csgsUnion = csgs.get(0);
-
- for (int i = 1; i < csgs.size(); i++) {
- csgsUnion = csgsUnion.union(csgs.get(i));
- }
-
- return difference(csgsUnion);
- }
-
- /**
- * Return a new CSG solid representing the difference of this csg and the
- * specified csgs.
- *
- * Note: Neither this csg nor the specified csgs are weighted.
- *
- *
- * A.difference(B)
- *
- * +-------+ +-------+
- * | | | |
- * | A | | |
- * | +--+----+ = | +--+
- * +----+--+ | +----+
- * | B |
- * | |
- * +-------+
- *
- *
- * @param csgs other csgs
- * @return difference of this csg and the specified csgs
- */
- public CSG difference(CSG... csgs) {
-
- return difference(Arrays.asList(csgs));
- }
-
- /**
- * Return a new CSG solid representing the difference of this csg and the
- * specified csg.
- *
- * Note: Neither this csg nor the specified csg are weighted.
- *
- *
- * A.difference(B)
- *
- * +-------+ +-------+
- * | | | |
- * | A | | |
- * | +--+----+ = | +--+
- * +----+--+ | +----+
- * | B |
- * | |
- * +-------+
- *
- *
- * @param csg other csg
- * @return difference of this csg and the specified csg
- */
- public CSG difference(CSG csg) {
-
- switch (getOptType()) {
- case CSG_BOUND:
- return _differenceCSGBoundsOpt(csg);
- case POLYGON_BOUND:
- return _differencePolygonBoundsOpt(csg);
- default:
- return _differenceNoOpt(csg);
- }
- }
-
- private CSG _differenceCSGBoundsOpt(CSG csg) {
- CSG b = csg;
-
- CSG a1 = this._differenceNoOpt(csg.getBounds().toCSG());
- CSG a2 = this.intersect(csg.getBounds().toCSG());
-
- return a2._differenceNoOpt(b)._unionIntersectOpt(a1).optimization(getOptType());
- }
-
- private CSG _differencePolygonBoundsOpt(CSG csg) {
- List inner = new ArrayList<>();
- List outer = new ArrayList<>();
-
- Bounds bounds = csg.getBounds();
-
- this.polygons.stream().forEach((p) -> {
- if (bounds.intersects(p.getBounds())) {
- inner.add(p);
- } else {
- outer.add(p);
- }
- });
-
- CSG innerCSG = CSG.fromPolygons(inner);
-
- List allPolygons = new ArrayList<>();
- allPolygons.addAll(outer);
- allPolygons.addAll(innerCSG._differenceNoOpt(csg).polygons);
-
- return CSG.fromPolygons(allPolygons).optimization(getOptType());
- }
-
- private CSG _differenceNoOpt(CSG csg) {
-
- Node a = new Node(this.clone().polygons);
- Node b = new Node(csg.clone().polygons);
-
- a.invert();
- a.clipTo(b);
- b.clipTo(a);
- b.invert();
- b.clipTo(a);
- b.invert();
- a.build(b.allPolygons());
- a.invert();
-
- CSG csgA = CSG.fromPolygons(a.allPolygons()).optimization(getOptType());
- return csgA;
- }
-
- /**
- * Return a new CSG solid representing the intersection of this csg and the
- * specified csg.
- *
- * Note: Neither this csg nor the specified csg are weighted.
- *
- *
- * A.intersect(B)
- *
- * +-------+
- * | |
- * | A |
- * | +--+----+ = +--+
- * +----+--+ | +--+
- * | B |
- * | |
- * +-------+
- * }
- *
- *
- * @param csg other csg
- * @return intersection of this csg and the specified csg
- */
- public CSG intersect(CSG csg) {
-
- Node a = new Node(this.clone().polygons);
- Node b = new Node(csg.clone().polygons);
- a.invert();
- b.clipTo(a);
- b.invert();
- a.clipTo(b);
- b.clipTo(a);
- a.build(b.allPolygons());
- a.invert();
- return CSG.fromPolygons(a.allPolygons()).optimization(getOptType());
- }
-
- /**
- * Return a new CSG solid representing the intersection of this csg and the
- * specified csgs.
- *
- * Note: Neither this csg nor the specified csgs are weighted.
- *
- *
- * A.intersect(B)
- *
- * +-------+
- * | |
- * | A |
- * | +--+----+ = +--+
- * +----+--+ | +--+
- * | B |
- * | |
- * +-------+
- * }
- *
- *
- * @param csgs other csgs
- * @return intersection of this csg and the specified csgs
- */
- public CSG intersect(List csgs) {
-
- if (csgs.isEmpty()) {
- return this.clone();
- }
-
- CSG csgsUnion = csgs.get(0);
-
- for (int i = 1; i < csgs.size(); i++) {
- csgsUnion = csgsUnion.union(csgs.get(i));
- }
-
- return intersect(csgsUnion);
- }
-
- /**
- * Return a new CSG solid representing the intersection of this csg and the
- * specified csgs.
- *
- * Note: Neither this csg nor the specified csgs are weighted.
- *
- *
- * A.intersect(B)
- *
- * +-------+
- * | |
- * | A |
- * | +--+----+ = +--+
- * +----+--+ | +--+
- * | B |
- * | |
- * +-------+
- * }
- *
- *
- * @param csgs other csgs
- * @return intersection of this csg and the specified csgs
- */
- public CSG intersect(CSG... csgs) {
-
- return intersect(Arrays.asList(csgs));
- }
-
- /**
- * Returns this csg in STL string format.
- *
- * @return this csg in STL string format
- */
- public String toStlString() {
- StringBuilder sb = new StringBuilder();
- toStlString(sb);
- return sb.toString();
- }
-
- /**
- * Returns this csg in STL string format.
- *
- * @param sb string builder
- *
- * @return the specified string builder
- */
- public StringBuilder toStlString(StringBuilder sb) {
- sb.append("solid v3d.csg\n");
- this.polygons.stream().forEach(
- (Polygon p) -> {
- p.toStlString(sb);
- });
- sb.append("endsolid v3d.csg\n");
- return sb;
- }
-
- public CSG color(Color c) {
-
- CSG result = this.clone();
-
- storage.set("material:color",
- "" + c.getRed()
- + " " + c.getGreen()
- + " " + c.getBlue());
-
- return result;
- }
-
- public ObjFile toObj() {
-
- StringBuilder objSb = new StringBuilder();
-
- objSb.append("mtllib " + ObjFile.MTL_NAME);
-
- objSb.append("# Group").append("\n");
- objSb.append("g v3d.csg\n");
-
- class PolygonStruct {
-
- PropertyStorage storage;
- List indices;
- String materialName;
-
- public PolygonStruct(PropertyStorage storage, List indices, String materialName) {
- this.storage = storage;
- this.indices = indices;
- this.materialName = materialName;
- }
- }
-
- List vertices = new ArrayList<>();
- List indices = new ArrayList<>();
-
- objSb.append("\n# Vertices\n");
-
- Map materialNames = new HashMap<>();
-
- int materialIndex = 0;
-
- for (Polygon p : polygons) {
- List polyIndices = new ArrayList<>();
-
- p.vertices.stream().forEach((v) -> {
- if (!vertices.contains(v)) {
- vertices.add(v);
- v.toObjString(objSb);
- polyIndices.add(vertices.size());
- } else {
- polyIndices.add(vertices.indexOf(v) + 1);
- }
- });
-
- if (!materialNames.containsKey(p.getStorage())) {
- materialIndex++;
- materialNames.put(p.getStorage(), materialIndex);
- p.getStorage().set("material:name", materialIndex);
- }
-
- indices.add(new PolygonStruct(
- p.getStorage(), polyIndices,
- "material-" + materialNames.get(p.getStorage())));
- }
-
- objSb.append("\n# Faces").append("\n");
-
- for (PolygonStruct ps : indices) {
-
- // add mtl info
- ps.storage.getValue("material:color").ifPresent(
- (v) -> objSb.append("usemtl ").append(ps.materialName).append("\n"));
-
- // we triangulate the polygon to ensure
- // compatibility with 3d printer software
- List pVerts = ps.indices;
- int index1 = pVerts.get(0);
- for (int i = 0; i < pVerts.size() - 2; i++) {
- int index2 = pVerts.get(i + 1);
- int index3 = pVerts.get(i + 2);
-
- objSb.append("f ").
- append(index1).append(" ").
- append(index2).append(" ").
- append(index3).append("\n");
- }
- }
-
- objSb.append("\n# End Group v3d.csg").append("\n");
-
- StringBuilder mtlSb = new StringBuilder();
-
- materialNames.keySet().forEach(s -> {
- if (s.contains("material:color")) {
- mtlSb.append("newmtl material-").append(s.getValue("material:name").get()).append("\n");
- mtlSb.append("Kd ").append(s.getValue("material:color").get()).append("\n");
- }
- });
-
- return new ObjFile(objSb.toString(), mtlSb.toString());
- }
-
- /**
- * Returns this csg in OBJ string format.
- *
- * @param sb string builder
- * @return the specified string builder
- */
- public StringBuilder toObjString(StringBuilder sb) {
- sb.append("# Group").append("\n");
- sb.append("g v3d.csg\n");
-
- class PolygonStruct {
-
- PropertyStorage storage;
- List indices;
- String materialName;
-
- public PolygonStruct(PropertyStorage storage, List indices, String materialName) {
- this.storage = storage;
- this.indices = indices;
- this.materialName = materialName;
- }
- }
-
- List vertices = new ArrayList<>();
- List indices = new ArrayList<>();
-
- sb.append("\n# Vertices\n");
-
- for (Polygon p : polygons) {
- List polyIndices = new ArrayList<>();
-
- p.vertices.stream().forEach((v) -> {
- if (!vertices.contains(v)) {
- vertices.add(v);
- v.toObjString(sb);
- polyIndices.add(vertices.size());
- } else {
- polyIndices.add(vertices.indexOf(v) + 1);
- }
- });
-
- }
-
- sb.append("\n# Faces").append("\n");
-
- for (PolygonStruct ps : indices) {
- // we triangulate the polygon to ensure
- // compatibility with 3d printer software
- List pVerts = ps.indices;
- int index1 = pVerts.get(0);
- for (int i = 0; i < pVerts.size() - 2; i++) {
- int index2 = pVerts.get(i + 1);
- int index3 = pVerts.get(i + 2);
-
- sb.append("f ").
- append(index1).append(" ").
- append(index2).append(" ").
- append(index3).append("\n");
- }
- }
-
- sb.append("\n# End Group v3d.csg").append("\n");
-
- return sb;
- }
-
- /**
- * Returns this csg in OBJ string format.
- *
- * @return this csg in OBJ string format
- */
- public String toObjString() {
- StringBuilder sb = new StringBuilder();
- return toObjString(sb).toString();
- }
-
- public CSG weighted(WeightFunction f) {
- return new Modifier(f).modified(this);
- }
-
- /**
- * Returns a transformed copy of this CSG.
- *
- * @param transform the transform to apply
- *
- * @return a transformed copy of this CSG
- */
- public CSG transformed(Transform transform) {
-
- if (polygons.isEmpty()) {
- return clone();
- }
-
- List newpolygons = this.polygons.stream().map(
- p -> p.transformed(transform)
- ).collect(Collectors.toList());
-
- CSG result = CSG.fromPolygons(newpolygons).optimization(getOptType());
-
- result.storage = storage;
-
- return result;
- }
-
-
- // TODO finish experiment (20.7.2014)
- public MeshContainer toJavaFXMesh() {
-
- return toJavaFXMeshSimple();
-
-// TODO test obj approach with multiple materials
-// try {
-// ObjImporter importer = new ObjImporter(toObj());
-//
-// List meshes = new ArrayList<>(importer.getMeshCollection());
-// return new MeshContainer(getBounds().getMin(), getBounds().getMax(),
-// meshes, new ArrayList<>(importer.getMaterialCollection()));
-// } catch (IOException ex) {
-// Logger.getLogger(CSG.class.getName()).log(Level.SEVERE, null, ex);
-// }
-// // we have no backup strategy for broken streams :(
-// return null;
- }
-
- /**
- * Returns the CSG as JavaFX triangle mesh.
- *
- * @return the CSG as JavaFX triangle mesh
- */
- public MeshContainer toJavaFXMeshSimple() {
-
- TriangleMesh mesh = new TriangleMesh();
-
- double minX = Double.POSITIVE_INFINITY;
- double minY = Double.POSITIVE_INFINITY;
- double minZ = Double.POSITIVE_INFINITY;
-
- double maxX = Double.NEGATIVE_INFINITY;
- double maxY = Double.NEGATIVE_INFINITY;
- double maxZ = Double.NEGATIVE_INFINITY;
-
- int counter = 0;
- for (Polygon p : getPolygons()) {
- if (p.vertices.size() >= 3) {
-
- // TODO: improve the triangulation?
- //
- // JavaOne requires triangular polygons.
- // If our polygon has more vertices, create
- // multiple triangles:
- Vertex firstVertex = p.vertices.get(0);
- for (int i = 0; i < p.vertices.size() - 2; i++) {
-
- if (firstVertex.pos.x() < minX) {
- minX = firstVertex.pos.x();
- }
- if (firstVertex.pos.y() < minY) {
- minY = firstVertex.pos.y();
- }
- if (firstVertex.pos.z() < minZ) {
- minZ = firstVertex.pos.z();
- }
-
- if (firstVertex.pos.x() > maxX) {
- maxX = firstVertex.pos.x();
- }
- if (firstVertex.pos.y() > maxY) {
- maxY = firstVertex.pos.y();
- }
- if (firstVertex.pos.z() > maxZ) {
- maxZ = firstVertex.pos.z();
- }
-
- mesh.getPoints().addAll(
- (float) firstVertex.pos.x(),
- (float) firstVertex.pos.y(),
- (float) firstVertex.pos.z());
-
- mesh.getTexCoords().addAll(0); // texture (not covered)
- mesh.getTexCoords().addAll(0);
-
- Vertex secondVertex = p.vertices.get(i + 1);
-
- if (secondVertex.pos.x() < minX) {
- minX = secondVertex.pos.x();
- }
- if (secondVertex.pos.y() < minY) {
- minY = secondVertex.pos.y();
- }
- if (secondVertex.pos.z() < minZ) {
- minZ = secondVertex.pos.z();
- }
-
- if (secondVertex.pos.x() > maxX) {
- maxX = firstVertex.pos.x();
- }
- if (secondVertex.pos.y() > maxY) {
- maxY = firstVertex.pos.y();
- }
- if (secondVertex.pos.z() > maxZ) {
- maxZ = firstVertex.pos.z();
- }
-
- mesh.getPoints().addAll(
- (float) secondVertex.pos.x(),
- (float) secondVertex.pos.y(),
- (float) secondVertex.pos.z());
-
- mesh.getTexCoords().addAll(0); // texture (not covered)
- mesh.getTexCoords().addAll(0);
-
- Vertex thirdVertex = p.vertices.get(i + 2);
-
- mesh.getPoints().addAll(
- (float) thirdVertex.pos.x(),
- (float) thirdVertex.pos.y(),
- (float) thirdVertex.pos.z());
-
- if (thirdVertex.pos.x() < minX) {
- minX = thirdVertex.pos.x();
- }
- if (thirdVertex.pos.y() < minY) {
- minY = thirdVertex.pos.y();
- }
- if (thirdVertex.pos.z() < minZ) {
- minZ = thirdVertex.pos.z();
- }
-
- if (thirdVertex.pos.x() > maxX) {
- maxX = firstVertex.pos.x();
- }
- if (thirdVertex.pos.y() > maxY) {
- maxY = firstVertex.pos.y();
- }
- if (thirdVertex.pos.z() > maxZ) {
- maxZ = firstVertex.pos.z();
- }
-
- mesh.getTexCoords().addAll(0); // texture (not covered)
- mesh.getTexCoords().addAll(0);
-
- mesh.getFaces().addAll(
- counter, // first vertex
- 0, // texture (not covered)
- counter + 1, // second vertex
- 0, // texture (not covered)
- counter + 2, // third vertex
- 0 // texture (not covered)
- );
- counter += 3;
- } // end for
- } // end if #verts >= 3
-
- } // end for polygon
-
- return new MeshContainer(
- Vector3d.xyz(minX, minY, minZ),
- Vector3d.xyz(maxX, maxY, maxZ), mesh);
- }
-
- /**
- * Returns the bounds of this csg.
- *
- * @return bouds of this csg
- */
- public Bounds getBounds() {
-
- if (polygons.isEmpty()) {
- return new Bounds(Vector3d.ZERO, Vector3d.ZERO);
- }
-
- double minX = Double.POSITIVE_INFINITY;
- double minY = Double.POSITIVE_INFINITY;
- double minZ = Double.POSITIVE_INFINITY;
-
- double maxX = Double.NEGATIVE_INFINITY;
- double maxY = Double.NEGATIVE_INFINITY;
- double maxZ = Double.NEGATIVE_INFINITY;
-
- for (Polygon p : getPolygons()) {
-
- for (int i = 0; i < p.vertices.size(); i++) {
-
- Vertex vert = p.vertices.get(i);
-
- if (vert.pos.x() < minX) {
- minX = vert.pos.x();
- }
- if (vert.pos.y() < minY) {
- minY = vert.pos.y();
- }
- if (vert.pos.z() < minZ) {
- minZ = vert.pos.z();
- }
-
- if (vert.pos.x() > maxX) {
- maxX = vert.pos.x();
- }
- if (vert.pos.y() > maxY) {
- maxY = vert.pos.y();
- }
- if (vert.pos.z() > maxZ) {
- maxZ = vert.pos.z();
- }
-
- } // end for vertices
-
- } // end for polygon
-
- return new Bounds(
- Vector3d.xyz(minX, minY, minZ),
- Vector3d.xyz(maxX, maxY, maxZ));
- }
-
- /**
- * @return the optType
- */
- private OptType getOptType() {
- return optType != null ? optType : defaultOptType;
- }
-
- /**
- * @param optType the optType to set
- */
- public static void setDefaultOptType(OptType optType) {
- defaultOptType = optType;
- }
-
- /**
- * @param optType the optType to set
- */
- public void setOptType(OptType optType) {
- this.optType = optType;
- }
-
- public static enum OptType {
-
- CSG_BOUND,
- POLYGON_BOUND,
- NONE
- }
-
-}
diff --git a/src/main/java/eu/mihosoft/jcsg/Edge.java b/src/main/java/eu/mihosoft/jcsg/Edge.java
deleted file mode 100644
index ac3d72ad..00000000
--- a/src/main/java/eu/mihosoft/jcsg/Edge.java
+++ /dev/null
@@ -1,740 +0,0 @@
-/**
- * Edge.java
- *
- * Copyright 2014-2016 Michael Hoffer . 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 "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 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
- * .
- */
-package eu.mihosoft.jcsg;
-
-import eu.mihosoft.vvecmath.Vector3d;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-import eu.mihosoft.jcsg.ext.org.poly2tri.PolygonUtil;
-
-/**
- *
- * @author miho
- */
-public class Edge {
-
- private final Vertex p1;
- private final Vertex p2;
- private final Vector3d direction;
-
- public Edge(Vertex p1, Vertex p2) {
- this.p1 = p1;
- this.p2 = p2;
-
- direction = p2.pos.minus(p1.pos).normalized();
- }
-
- /**
- * @return the p1
- */
- public Vertex getP1() {
- return p1;
- }
-
-// /**
-// * @param p1 the p1 to set
-// */
-// public void setP1(Vertex p1) {
-// this.p1 = p1;
-// }
- /**
- * @return the p2
- */
- public Vertex getP2() {
- return p2;
- }
-
-// /**
-// * @param p2 the p2 to set
-// */
-// public void setP2(Vertex p2) {
-// this.p2 = p2;
-// }
- public static List fromPolygon(Polygon poly) {
- List result = new ArrayList<>();
-
- for (int i = 0; i < poly.vertices.size(); i++) {
- Edge e = new Edge(poly.vertices.get(i), poly.vertices.get((i + 1) % poly.vertices.size()));
-
- result.add(e);
- }
-
- return result;
- }
-
- public static List toVertices(List edges) {
- return edges.stream().map(e -> e.p1).collect(Collectors.toList());
- }
-
- public static List toPoints(List edges) {
- return edges.stream().map(e -> e.p1.pos).collect(Collectors.toList());
- }
-
- private static Polygon toPolygon(List points, Plane plane) {
-
-// List points = edges.stream().().map(e -> e.p1.pos).
-// collect(Collectors.toList());
- Polygon p = Polygon.fromPoints(points);
-
- p.vertices.stream().forEachOrdered((vertex) -> {
- vertex.normal = plane.normal.clone();
- });
-
-// // we try to detect wrong orientation by comparing normals
-// if (p.plane.normal.angle(plane.normal) > 0.1) {
-// p.flip();
-// }
- return p;
- }
-
- public static List toPolygons(List boundaryEdges, Plane plane) {
-
- List boundaryPath = new ArrayList<>();
-
- boolean[] used = new boolean[boundaryEdges.size()];
- Edge edge = boundaryEdges.get(0);
- used[0] = true;
- while (true) {
- Edge finalEdge = edge;
-
- boundaryPath.add(finalEdge.p1.pos);
-
- int nextEdgeIndex = boundaryEdges.indexOf(boundaryEdges.stream().
- filter(e -> finalEdge.p2.equals(e.p1)).findFirst().get());
-
- if (used[nextEdgeIndex]) {
-// System.out.println("nexIndex: " + nextEdgeIndex);
- break;
- }
-// System.out.print("edge: " + edge.p2.pos);
- edge = boundaryEdges.get(nextEdgeIndex);
-// System.out.println("-> edge: " + edge.p1.pos);
- used[nextEdgeIndex] = true;
- }
-
- List result = new ArrayList<>();
-
- System.out.println("#bnd-path-length: " + boundaryPath.size());
-
- result.add(toPolygon(boundaryPath, plane));
-
- return result;
- }
-
- private static class Node {
-
- private Node parent;
- private final List children = new ArrayList<>();
- private final int index;
- private final T value;
- private boolean isHole;
-
- public Node(int index, T value) {
- this.index = index;
- this.value = value;
- }
-
- public void addChild(int index, T value) {
- children.add(new Node(index, value));
- }
-
- public List getChildren() {
- return this.children;
- }
-
- /**
- * @return the parent
- */
- public Node getParent() {
- return parent;
- }
-
- /**
- * @return the index
- */
- public int getIndex() {
- return index;
- }
-
- /**
- * @return the value
- */
- public T getValue() {
- return value;
- }
-
- @Override
- public int hashCode() {
- int hash = 7;
- hash = 67 * hash + this.index;
- return hash;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (obj == null) {
- return false;
- }
- if (getClass() != obj.getClass()) {
- return false;
- }
- final Node> other = (Node>) obj;
- if (this.index != other.index) {
- return false;
- }
- return true;
- }
-
- public int distanceToRoot() {
- int dist = 0;
-
- Node pNode = getParent();
-
- while (pNode != null) {
- dist++;
- pNode = getParent();
- }
-
- return dist;
- }
-
- /**
- * @return the isHole
- */
- public boolean isIsHole() {
- return isHole;
- }
-
- /**
- * @param isHole the isHole to set
- */
- public void setIsHole(boolean isHole) {
- this.isHole = isHole;
- }
-
- }
-
- public static final String KEY_POLYGON_HOLES = "jcsg:edge:polygon-holes";
-
- public static List boundaryPathsWithHoles(List boundaryPaths) {
-
- List result = boundaryPaths.stream().
- map(p -> p.clone()).collect(Collectors.toList());
-
- List> parents = new ArrayList<>();
- boolean[] isHole = new boolean[result.size()];
-
- for (int i = 0; i < result.size(); i++) {
- Polygon p1 = result.get(i);
- List parentsOfI = new ArrayList<>();
- parents.add(parentsOfI);
- for (int j = 0; j < result.size(); j++) {
- Polygon p2 = result.get(j);
- if (i != j) {
- if (p2.contains(p1)) {
- parentsOfI.add(j);
- }
- }
- }
- isHole[i] = parentsOfI.size() % 2 != 0;
- }
-
- int[] parent = new int[result.size()];
-
- for (int i = 0; i < parent.length; i++) {
- parent[i] = -1;
- }
-
- for (int i = 0; i < parents.size(); i++) {
- List par = parents.get(i);
-
- int max = 0;
- int maxIndex = 0;
- for (int pIndex : par) {
-
- int pSize = parents.get(pIndex).size();
-
- if (max < pSize) {
- max = pSize;
- maxIndex = pIndex;
- }
- }
-
- parent[i] = maxIndex;
-
- if (!isHole[maxIndex] && isHole[i]) {
-
- List holes;
-
- Optional> holesOpt = result.get(maxIndex).
- getStorage().getValue(KEY_POLYGON_HOLES);
-
- if (holesOpt.isPresent()) {
- holes = holesOpt.get();
- } else {
- holes = new ArrayList<>();
- result.get(maxIndex).getStorage().
- set(KEY_POLYGON_HOLES, holes);
- }
-
- holes.add(result.get(i));
- }
- }
-
- return result;
- }
-
- /**
- * Returns a list of all boundary paths.
- *
- * @param boundaryEdges boundary edges (all paths must be closed)
- * @return
- */
- private static List boundaryPaths(List boundaryEdges) {
- List result = new ArrayList<>();
-
- boolean[] used = new boolean[boundaryEdges.size()];
- int startIndex = 0;
- Edge edge = boundaryEdges.get(startIndex);
- used[startIndex] = true;
-
- startIndex = 1;
-
- while (startIndex > 0) {
- List boundaryPath = new ArrayList<>();
-
- while (true) {
- Edge finalEdge = edge;
-
- boundaryPath.add(finalEdge.p1.pos);
-
- System.out.print("edge: " + edge.p2.pos);
-
- Optional nextEdgeResult = boundaryEdges.stream().
- filter(e -> finalEdge.p2.equals(e.p1)).findFirst();
-
- if (!nextEdgeResult.isPresent()) {
- System.out.println("ERROR: unclosed path:"
- + " no edge found with " + finalEdge.p2);
- break;
- }
-
- Edge nextEdge = nextEdgeResult.get();
-
- int nextEdgeIndex = boundaryEdges.indexOf(nextEdge);
-
- if (used[nextEdgeIndex]) {
- break;
- }
-
- edge = nextEdge;
- System.out.println("-> edge: " + edge.p1.pos);
- used[nextEdgeIndex] = true;
- }
-
- if (boundaryPath.size() < 3) {
- break;
- }
-
- result.add(Polygon.fromPoints(boundaryPath));
- startIndex = nextUnused(used);
-
- if (startIndex > 0) {
- edge = boundaryEdges.get(startIndex);
- used[startIndex] = true;
- }
-
- }
-
- System.out.println("paths: " + result.size());
-
- return result;
- }
-
- /**
- * Returns the next unused index as specified in the given boolean array.
- *
- * @param usage the usage array
- * @return the next unused index or a value < 0 if all indices are used
- */
- private static int nextUnused(boolean[] usage) {
- for (int i = 0; i < usage.length; i++) {
- if (usage[i] == false) {
- return i;
- }
- }
-
- return -1;
- }
-
- public static List _toPolygons(List boundaryEdges, Plane plane) {
-
- List boundaryPath = new ArrayList<>();
-
- boolean[] used = new boolean[boundaryEdges.size()];
- Edge edge = boundaryEdges.get(0);
- used[0] = true;
- while (true) {
- Edge finalEdge = edge;
-
- boundaryPath.add(finalEdge.p1.pos);
-
- int nextEdgeIndex = boundaryEdges.indexOf(boundaryEdges.stream().
- filter(e -> finalEdge.p2.equals(e.p1)).findFirst().get());
-
- if (used[nextEdgeIndex]) {
-// System.out.println("nexIndex: " + nextEdgeIndex);
- break;
- }
-// System.out.print("edge: " + edge.p2.pos);
- edge = boundaryEdges.get(nextEdgeIndex);
-// System.out.println("-> edge: " + edge.p1.pos);
- used[nextEdgeIndex] = true;
- }
-
- List result = new ArrayList<>();
-
- System.out.println("#bnd-path-length: " + boundaryPath.size());
-
- result.add(toPolygon(boundaryPath, plane));
-
- return result;
- }
-
- /**
- * Determines whether the specified point lies on tthis edge.
- *
- * @param p point to check
- * @param TOL tolerance
- * @return true if the specified point lies on this line
- * segment; false otherwise
- */
- public boolean contains(Vector3d p, double TOL) {
-
- double x = p.x();
- double x1 = this.p1.pos.x();
- double x2 = this.p2.pos.x();
-
- double y = p.y();
- double y1 = this.p1.pos.y();
- double y2 = this.p2.pos.y();
-
- double z = p.z();
- double z1 = this.p1.pos.z();
- double z2 = this.p2.pos.z();
-
- double AB = Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1) + (z2 - z1) * (z2 - z1));
- double AP = Math.sqrt((x - x1) * (x - x1) + (y - y1) * (y - y1) + (z - z1) * (z - z1));
- double PB = Math.sqrt((x2 - x) * (x2 - x) + (y2 - y) * (y2 - y) + (z2 - z) * (z2 - z));
-
- return Math.abs(AB - (AP + PB)) < TOL;
- }
-
- /**
- * Determines whether the specified point lies on tthis edge.
- *
- * @param p point to check
- * @return true if the specified point lies on this line
- * segment; false otherwise
- */
- public boolean contains(Vector3d p) {
- return contains(p, Plane.EPSILON);
- }
-
- @Override
- public int hashCode() {
- int hash = 7;
- hash = 71 * hash + Objects.hashCode(this.p1);
- hash = 71 * hash + Objects.hashCode(this.p2);
- return hash;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (obj == null) {
- return false;
- }
- if (getClass() != obj.getClass()) {
- return false;
- }
- final Edge other = (Edge) obj;
- if (!(Objects.equals(this.p1, other.p1) || Objects.equals(this.p2, other.p1))) {
- return false;
- }
- if (!(Objects.equals(this.p2, other.p2) || Objects.equals(this.p1, other.p2))) {
- return false;
- }
- return true;
- }
-
- public Vector3d getDirection() {
- return direction;
- }
-
- /**
- * Returns the the point of this edge that is closest to the specified edge.
- *
- * NOTE: returns an empty optional if the edges are parallel
- *
- * @param e the edge to check
- * @return the the point of this edge that is closest to the specified edge
- */
- public Optional getClosestPoint(Edge e) {
-
- // algorithm from:
- // org.apache.commons.math3.geometry.euclidean.threed/Line.java.html
- Vector3d ourDir = getDirection();
-
- double cos = ourDir.dot(e.getDirection());
- double n = 1 - cos * cos;
-
- if (n < Plane.EPSILON) {
- // the lines are parallel
- return Optional.empty();
- }
-
- final Vector3d thisDelta = p2.pos.minus(p1.pos);
- final double norm2This = thisDelta.magnitudeSq();
-
- final Vector3d eDelta = e.p2.pos.minus(e.p1.pos);
- final double norm2E = eDelta.magnitudeSq();
-
- // line points above the origin
- Vector3d thisZero = p1.pos.plus(thisDelta.times(-p1.pos.dot(thisDelta) / norm2This));
- Vector3d eZero = e.p1.pos.plus(eDelta.times(-e.p1.pos.dot(eDelta) / norm2E));
-
- final Vector3d delta0 = eZero.minus(thisZero);
- final double a = delta0.dot(direction);
- final double b = delta0.dot(e.direction);
-
- Vector3d closestP = thisZero.plus(direction.times((a - b * cos) / n));
-
- if (!contains(closestP)) {
- if (closestP.minus(p1.pos).magnitudeSq()
- < closestP.minus(p2.pos).magnitudeSq()) {
- return Optional.of(p1.pos);
- } else {
- return Optional.of(p2.pos);
- }
- }
-
- return Optional.of(closestP);
- }
-
- /**
- * Returns the intersection point between this edge and the specified edge.
- *
- * NOTE: returns an empty optional if the edges are parallel or if
- * the intersection point is not inside the specified edge segment
- *
- * @param e edge to intersect
- * @return the intersection point between this edge and the specified edge
- */
- public Optional getIntersection(Edge e) {
- Optional closestPOpt = getClosestPoint(e);
-
- if (!closestPOpt.isPresent()) {
- // edges are parallel
- return Optional.empty();
- }
-
- Vector3d closestP = closestPOpt.get();
-
- if (e.contains(closestP)) {
- return closestPOpt;
- } else {
- // intersection point outside of segment
- return Optional.empty();
- }
- }
-
- public static List boundaryPolygons(CSG csg) {
- List result = new ArrayList<>();
-
- for (List polygonGroup : searchPlaneGroups(csg.getPolygons())) {
- result.addAll(boundaryPolygonsOfPlaneGroup(polygonGroup));
- }
-
- return result;
- }
-
- private static List boundaryEdgesOfPlaneGroup(List planeGroup) {
- List edges = new ArrayList<>();
-
- Stream pStream;
-
- if (planeGroup.size() > 200) {
- pStream = planeGroup.parallelStream();
- } else {
- pStream = planeGroup.stream();
- }
-
- pStream.map((p) -> Edge.fromPolygon(p)).forEach((pEdges) -> {
- edges.addAll(pEdges);
- });
-
- Stream edgeStream;
-
- if (edges.size() > 200) {
- edgeStream = edges.parallelStream();
- } else {
- edgeStream = edges.stream();
- }
-
- // find potential boundary edges, i.e., edges that occur once (freq=1)
- List potentialBoundaryEdges = new ArrayList<>();
- edgeStream.forEachOrdered((e) -> {
- int count = Collections.frequency(edges, e);
- if (count == 1) {
- potentialBoundaryEdges.add(e);
- }
- });
-
- // now find "false boundary" edges end remove them from the
- // boundary-edge-list
- //
- // thanks to Susanne Höllbacher for the idea :)
- Stream bndEdgeStream;
-
- if (potentialBoundaryEdges.size() > 200) {
- bndEdgeStream = potentialBoundaryEdges.parallelStream();
- } else {
- bndEdgeStream = potentialBoundaryEdges.stream();
- }
-
- List realBndEdges = bndEdgeStream.
- filter(be -> edges.stream().filter(
- e -> falseBoundaryEdgeSharedWithOtherEdge(be, e)
- ).count() == 0).collect(Collectors.toList());
-
- //
-// System.out.println("#bnd-edges: " + realBndEdges.size()
-// + ",#edges: " + edges.size()
-// + ", #del-bnd-edges: " + (boundaryEdges.size() - realBndEdges.size()));
- return realBndEdges;
- }
-
- private static List boundaryPolygonsOfPlaneGroup(
- List planeGroup) {
-
- List polygons = boundaryPathsWithHoles(
- boundaryPaths(boundaryEdgesOfPlaneGroup(planeGroup)));
-
- System.out.println("polygons: " + polygons.size());
-
- List result = new ArrayList<>(polygons.size());
-
- for (Polygon p : polygons) {
-
- Optional> holesOfPresult
- = p.
- getStorage().getValue(Edge.KEY_POLYGON_HOLES);
-
- if (!holesOfPresult.isPresent()) {
- result.add(p);
- } else {
- result.addAll(PolygonUtil.concaveToConvex(p));
- }
- }
-
- return result;
- }
-
- private static boolean falseBoundaryEdgeSharedWithOtherEdge(Edge fbe, Edge e) {
-
- // we don't consider edges with shared end-points since we are only
- // interested in "false-boundary-edge"-cases
- boolean sharedEndPoints = e.getP1().pos.equals(fbe.getP1().pos)
- || e.getP1().pos.equals(fbe.getP2().pos)
- || e.getP2().pos.equals(fbe.getP1().pos)
- || e.getP2().pos.equals(fbe.getP2().pos);
-
- if (sharedEndPoints) {
- return false;
- }
-
- return fbe.contains(e.getP1().pos) || fbe.contains(e.getP2().pos);
- }
-
- private static List> searchPlaneGroups(List polygons) {
- List> planeGroups = new ArrayList<>();
- boolean[] used = new boolean[polygons.size()];
- System.out.println("#polys: " + polygons.size());
- for (int pOuterI = 0; pOuterI < polygons.size(); pOuterI++) {
-
- if (used[pOuterI]) {
- continue;
- }
-
- Polygon pOuter = polygons.get(pOuterI);
-
- List otherPolysInPlane = new ArrayList<>();
-
- otherPolysInPlane.add(pOuter);
-
- for (int pInnerI = 0; pInnerI < polygons.size(); pInnerI++) {
-
- Polygon pInner = polygons.get(pInnerI);
-
- if (pOuter.equals(pInner)) {
- continue;
- }
-
- Vector3d nOuter = pOuter.plane.normal;
- Vector3d nInner = pInner.plane.normal;
-
- // TODO do we need radians or degrees?
- double angle = nOuter.angle(nInner);
-
-// System.out.println("angle: " + angle + " between " + pOuterI+" -> " + pInnerI);
- if (angle < 0.01 /*&& abs(pOuter.plane.dist - pInner.plane.dist) < 0.1*/) {
- otherPolysInPlane.add(pInner);
- used[pInnerI] = true;
- System.out.println("used: " + pOuterI + " -> " + pInnerI);
- }
- }
-
- if (!otherPolysInPlane.isEmpty()) {
- planeGroups.add(otherPolysInPlane);
- }
- }
- return planeGroups;
- }
-
-}
diff --git a/src/main/java/eu/mihosoft/jcsg/Extrude.java b/src/main/java/eu/mihosoft/jcsg/Extrude.java
deleted file mode 100644
index 1b0a32ba..00000000
--- a/src/main/java/eu/mihosoft/jcsg/Extrude.java
+++ /dev/null
@@ -1,247 +0,0 @@
-/**
- * Extrude.java
- *
- * Copyright 2014-2014 Michael Hoffer . 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 "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 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
- * .
- */
-package eu.mihosoft.jcsg;
-
-import eu.mihosoft.vvecmath.Vector3d;
-import eu.mihosoft.jcsg.ext.org.poly2tri.PolygonUtil;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Extrudes concave and convex polygons.
- *
- * @author Michael Hoffer <info@michaelhoffer.de>
- */
-public class Extrude {
-
- private Extrude() {
- throw new AssertionError("Don't instantiate me!", null);
- }
-
- /**
- * Extrudes the specified path (convex or concave polygon without holes or
- * intersections, specified in CCW) into the specified direction.
- *
- * @param dir direction
- * @param points path (convex or concave polygon without holes or
- * intersections)
- *
- * @return a CSG object that consists of the extruded polygon
- */
- public static CSG points(Vector3d dir, Vector3d... points) {
-
- return extrude(dir, Polygon.fromPoints(toCCW(Arrays.asList(points))));
- }
-
- /**
- * Extrudes the specified path (convex or concave polygon without holes or
- * intersections, specified in CCW) into the specified direction.
- *
- * @param dir direction
- * @param points path (convex or concave polygon without holes or
- * intersections)
- *
- * @return a CSG object that consists of the extruded polygon
- */
- public static CSG points(Vector3d dir, List points) {
-
- List newList = new ArrayList<>(points);
-
- return extrude(dir, Polygon.fromPoints(toCCW(newList)));
- }
-
- private static CSG extrude(Vector3d dir, Polygon polygon1) {
- List newPolygons = new ArrayList<>();
-
- if (dir.z()<0) {
- throw new IllegalArgumentException("z < 0 currently not supported for extrude: " + dir);
- }
-
- newPolygons.addAll(PolygonUtil.concaveToConvex(polygon1));
- Polygon polygon2 = polygon1.translated(dir);
-
- int numvertices = polygon1.vertices.size();
- for (int i = 0; i < numvertices; i++) {
-
- int nexti = (i + 1) % numvertices;
-
- Vector3d bottomV1 = polygon1.vertices.get(i).pos;
- Vector3d topV1 = polygon2.vertices.get(i).pos;
- Vector3d bottomV2 = polygon1.vertices.get(nexti).pos;
- Vector3d topV2 = polygon2.vertices.get(nexti).pos;
-
- List pPoints = Arrays.asList(bottomV2, topV2, topV1, bottomV1);
-
- newPolygons.add(Polygon.fromPoints(pPoints, polygon1.getStorage()));
-
- }
-
- polygon2 = polygon2.flipped();
- List topPolygons = PolygonUtil.concaveToConvex(polygon2);
-
- newPolygons.addAll(topPolygons);
-
- return CSG.fromPolygons(newPolygons);
-
- }
-
- static List toCCW(List points) {
-
- List result = new ArrayList<>(points);
-
- if (!isCCW(Polygon.fromPoints(result))) {
- Collections.reverse(result);
- }
-
- return result;
- }
-
- static List toCW(List points) {
-
- List result = new ArrayList<>(points);
-
- if (isCCW(Polygon.fromPoints(result))) {
- Collections.reverse(result);
- }
-
- return result;
- }
-
- public static boolean isCCW(Polygon polygon) {
- // thanks to Sepp Reiter for explaining me the algorithm!
-
- if (polygon.vertices.size() < 3) {
- throw new IllegalArgumentException("Only polygons with at least 3 vertices are supported!");
- }
-
- // search highest left vertex
- int highestLeftVertexIndex = 0;
- Vertex highestLeftVertex = polygon.vertices.get(0);
- for (int i = 0; i < polygon.vertices.size(); i++) {
- Vertex v = polygon.vertices.get(i);
-
- if (v.pos.y() > highestLeftVertex.pos.y()) {
- highestLeftVertex = v;
- highestLeftVertexIndex = i;
- } else if (v.pos.y() == highestLeftVertex.pos.y()
- && v.pos.x() < highestLeftVertex.pos.x()) {
- highestLeftVertex = v;
- highestLeftVertexIndex = i;
- }
- }
-
- // determine next and previous vertex indices
- int nextVertexIndex = (highestLeftVertexIndex + 1) % polygon.vertices.size();
- int prevVertexIndex = highestLeftVertexIndex - 1;
- if (prevVertexIndex < 0) {
- prevVertexIndex = polygon.vertices.size() - 1;
- }
- Vertex nextVertex = polygon.vertices.get(nextVertexIndex);
- Vertex prevVertex = polygon.vertices.get(prevVertexIndex);
-
- // edge 1
- double a1 = normalizedX(highestLeftVertex.pos, nextVertex.pos);
-
- // edge 2
- double a2 = normalizedX(highestLeftVertex.pos, prevVertex.pos);
-
- // select vertex with lowest x value
- int selectedVIndex;
-
- if (a2 > a1) {
- selectedVIndex = nextVertexIndex;
- } else {
- selectedVIndex = prevVertexIndex;
- }
-
- if (selectedVIndex == 0
- && highestLeftVertexIndex == polygon.vertices.size() - 1) {
- selectedVIndex = polygon.vertices.size();
- }
-
- if (highestLeftVertexIndex == 0
- && selectedVIndex == polygon.vertices.size() - 1) {
- highestLeftVertexIndex = polygon.vertices.size();
- }
-
- // indicates whether edge points from highestLeftVertexIndex towards
- // the sel index (ccw)
- return selectedVIndex > highestLeftVertexIndex;
- }
-
- private static double normalizedX(Vector3d v1, Vector3d v2) {
- Vector3d v2MinusV1 = v2.minus(v1);
-
- return v2MinusV1.dividedBy(v2MinusV1.magnitude()).times(Vector3d.X_ONE).x();
- }
-
-// public static void main(String[] args) {
-// System.out.println("1 CCW: " + isCCW(Polygon.fromPoints(
-// new Vector3d(-1, -1),
-// new Vector3d(0, -1),
-// new Vector3d(1, 0),
-// new Vector3d(1, 1)
-// )));
-//
-// System.out.println("3 CCW: " + isCCW(Polygon.fromPoints(
-// new Vector3d(1, 1),
-// new Vector3d(1, 0),
-// new Vector3d(0, -1),
-// new Vector3d(-1, -1)
-// )));
-//
-// System.out.println("2 CCW: " + isCCW(Polygon.fromPoints(
-// new Vector3d(0, -1),
-// new Vector3d(1, 0),
-// new Vector3d(1, 1),
-// new Vector3d(-1, -1)
-// )));
-//
-// System.out.println("4 CCW: " + isCCW(Polygon.fromPoints(
-// new Vector3d(-1, -1),
-// new Vector3d(-1, 1),
-// new Vector3d(0, 0)
-// )));
-//
-// System.out.println("5 CCW: " + isCCW(Polygon.fromPoints(
-// new Vector3d(0, 0),
-// new Vector3d(0, 1),
-// new Vector3d(0.5, 0.5),
-// new Vector3d(1, 1.1),
-// new Vector3d(1, 0)
-// )));
-// }
-}
diff --git a/src/main/java/eu/mihosoft/jcsg/Main.java b/src/main/java/eu/mihosoft/jcsg/Main.java
deleted file mode 100644
index da0830d6..00000000
--- a/src/main/java/eu/mihosoft/jcsg/Main.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/**
- * Main.java
- *
- * Copyright 2014-2014 Michael Hoffer . 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 "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 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
- * .
- */
-package eu.mihosoft.jcsg;
-
-import eu.mihosoft.vvecmath.Transform;
-import java.io.IOException;
-import java.nio.file.Paths;
-
-import javafx.scene.paint.Color;
-
-/**
- *
- * @author Michael Hoffer <info@michaelhoffer.de>
- */
-public class Main {
-
- public static void main(String[] args) throws IOException {
-
- // we use cube and sphere as base geometries
- CSG cube = new Cube(2).toCSG().color(Color.RED);
- CSG sphere = new Sphere(1.25).toCSG().color(Color.BLUE);
- CSG cyl = new Cylinder(0.5,3,16).toCSG().transformed(Transform.unity().translateZ(-1.5)).color(Color.GREEN);
- CSG cyl2 = cyl.transformed(Transform.unity().rotY(90));
- CSG cyl3 = cyl.transformed(Transform.unity().rotX(90));
-
- // perform union, difference and intersection
- CSG cubePlusSphere = cube.union(sphere);
- CSG cubeMinusSphere = cube.difference(sphere);
- CSG cubeIntersectSphere = cube.intersect(sphere);
- CSG cubeIntersectSphereCyl = cubeIntersectSphere.difference(cyl).difference(cyl2).difference(cyl3);
-
- // translate geometries to prevent overlapping
- CSG union = cube.
- union(sphere.transformed(Transform.unity().translateX(3))).
- union(cyl.transformed(Transform.unity().translateX(6))).
- union(cubePlusSphere.transformed(Transform.unity().translateX(9))).
- union(cubeMinusSphere.transformed(Transform.unity().translateX(12))).
- union(cubeIntersectSphere.transformed(Transform.unity().translateX(15))).
- union(cubeIntersectSphereCyl.transformed(Transform.unity().translateX(18)));
-
- FileUtil.write(Paths.get("sample.stl"), union.toStlString());
-
- union.toObj().toFiles(Paths.get("sample-color.obj"));
-
- }
-}
diff --git a/src/main/java/eu/mihosoft/jcsg/Matrix3d.java b/src/main/java/eu/mihosoft/jcsg/Matrix3d.java
deleted file mode 100644
index 397ac777..00000000
--- a/src/main/java/eu/mihosoft/jcsg/Matrix3d.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * To change this license header, choose License Headers in Project Properties.
- * To change this template file, choose Tools | Templates
- * and open the template in the editor.
- */
-package eu.mihosoft.jcsg;
-
-import eu.mihosoft.vvecmath.Vector3d;
-
-/**
- * 3D Matrix3d
- *
- * @author cpoliwoda
- */
-public class Matrix3d {
-
- public double m11, m12, m13;
- public double m21, m22, m23;
- public double m31, m32, m33;
-
- public static final Matrix3d ZERO = new Matrix3d(0, 0, 0, 0, 0, 0, 0, 0, 0);
- public static final Matrix3d UNITY = new Matrix3d(1, 0, 0, 0, 1, 0, 0, 0, 1);
-
- public Matrix3d(double m11, double m12, double m13,
- double m21, double m22, double m23,
- double m31, double m32, double m33) {
- this.m11 = m11;
- this.m12 = m12;
- this.m13 = m13;
- this.m21 = m21;
- this.m22 = m22;
- this.m23 = m23;
- this.m31 = m31;
- this.m32 = m32;
- this.m33 = m33;
- }
-
- @Override
- public String toString() {
- return "[" + m11 + ", " + m12 + ", " + m13 + "]\n"
- + "[" + m21 + ", " + m22 + ", " + m23 + "]\n"
- + "[" + m31 + ", " + m32 + ", " + m33 + "]";
- }
-
- /**
- * Returns the product of this matrix and the specified value.
- *
- * @param a the value
- *
- * Note: this matrix is not modified.
- *
- * @return the product of this matrix and the specified value
- */
- public Matrix3d times(double a) {
- return new Matrix3d(
- m11 * a, m12 * a, m13 * a,
- m21 * a, m22 * a, m23 * a,
- m31 * a, m32 * a, m33 * a);
- }
-
- /**
- * Returns the product of this matrix and the specified vector.
- *
- * @param a the vector
- *
- * Note: the vector is not modified.
- *
- * @return the product of this matrix and the specified vector
- */
- public Vector3d times(Vector3d a) {
- return Vector3d.xyz(
- m11 * a.x() + m12 * a.y() + m13 * a.z(),
- m21 * a.x() + m22 * a.y() + m23 * a.z(),
- m31 * a.x() + m32 * a.y() + m33 * a.z());
- }
-
- static double maxOf3Values(double[] values) {
-
- if (values[0] > values[1]) {
-
- if (values[0] > values[2]) {
- return (values[0]);
- } else {
- return (values[2]);
- }
-
- } else {
-
- if (values[1] > values[2]) {
- return (values[1]);
- } else {
- return (values[2]);
- }
-
- }
-
- }
-
-}
diff --git a/src/main/java/eu/mihosoft/jcsg/Node.java b/src/main/java/eu/mihosoft/jcsg/Node.java
deleted file mode 100644
index c88f2862..00000000
--- a/src/main/java/eu/mihosoft/jcsg/Node.java
+++ /dev/null
@@ -1,268 +0,0 @@
-/**
- * Node.java
- *
- * Copyright 2014-2014 Michael Hoffer . 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 "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 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
- * .
- */
-package eu.mihosoft.jcsg;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-/**
- * 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;
-
- /**
- * 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);
- }
-
- @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) {
-
- if (polygons.isEmpty()) return;
-
- if (this.plane == null) {
- this.plane = polygons.get(0).plane.clone();
- }
-
- polygons = polygons.stream().filter(p->p.isValid()).distinct().collect(Collectors.toList());
-
- List frontP = new ArrayList<>();
- List backP = new ArrayList<>();
-
- // parellel version does not work here
- polygons.forEach((polygon) -> {
- this.plane.splitPolygon(
- polygon, this.polygons, this.polygons, frontP, backP);
- });
-
- if (frontP.size() > 0) {
- if (this.front == null) {
- this.front = new Node();
- }
- this.front.build(frontP);
- }
- if (backP.size() > 0) {
- if (this.back == null) {
- this.back = new Node();
- }
- this.back.build(backP);
- }
- }
-}
diff --git a/src/main/java/eu/mihosoft/jcsg/Plane.java b/src/main/java/eu/mihosoft/jcsg/Plane.java
deleted file mode 100644
index 3ef82165..00000000
--- a/src/main/java/eu/mihosoft/jcsg/Plane.java
+++ /dev/null
@@ -1,198 +0,0 @@
-/**
- * Plane.java
- *
- * Copyright 2014-2014 Michael Hoffer . 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 "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 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
- * .
- */
-package eu.mihosoft.jcsg;
-
-// # class Plane
-import eu.mihosoft.vvecmath.Vector3d;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Represents a plane in 3D space.
- *
- * @author Michael Hoffer <info@michaelhoffer.de>
- */
-class Plane {
-
- /**
- * EPSILON is the tolerance used by {@link #splitPolygon(Polygon, java.util.List, java.util.List, java.util.List, java.util.List)
- * } to decide if a point is on the plane.
- */
- public static double EPSILON = 1e-8;
-
- /**
- * XY plane.
- */
- public static final Plane XY_PLANE = new Plane(Vector3d.Z_ONE, 1);
- /**
- * XZ plane.
- */
- public static final Plane XZ_PLANE = new Plane(Vector3d.Y_ONE, 1);
- /**
- * YZ plane.
- */
- public static final Plane YZ_PLANE = new Plane(Vector3d.X_ONE, 1);
-
- /**
- * Normal vector.
- */
- public Vector3d normal;
- /**
- * Distance to origin.
- */
- public double dist;
-
- /**
- * Constructor. Creates a new plane defined by its normal vector and the
- * distance to the origin.
- *
- * @param normal plane normal
- * @param dist distance from origin
- */
- public Plane(Vector3d normal, double dist) {
- this.normal = normal.normalized();
- this.dist = dist;
- }
-
- /**
- * Creates a plane defined by the the specified points.
- *
- * @param a first point
- * @param b second point
- * @param c third point
- * @return a plane
- */
- public static Plane createFromPoints(Vector3d a, Vector3d b, Vector3d c) {
- Vector3d n = b.minus(a).cross(c.minus(a)).normalized();
- return new Plane(n, n.dot(a));
- }
-
- @Override
- public Plane clone() {
- return new Plane(normal.clone(), dist);
- }
-
- /**
- * Flips this plane.
- */
- public void flip() {
- normal = normal.negated();
- dist = -dist;
- }
-
- /**
- * Splits a {@link Polygon} by this plane if needed. After that it puts the
- * polygons or the polygon fragments in the appropriate lists
- * ({@code front}, {@code back}). Coplanar polygons go into either
- * {@code coplanarFront}, {@code coplanarBack} depending on their
- * orientation with respect to this plane. Polygons in front or back of this
- * plane go into either {@code front} or {@code back}.
- *
- * @param polygon polygon to split
- * @param coplanarFront "coplanar front" polygons
- * @param coplanarBack "coplanar back" polygons
- * @param front front polygons
- * @param back back polgons
- */
- public void splitPolygon(
- Polygon polygon,
- List coplanarFront,
- List coplanarBack,
- List front,
- List back) {
- final int COPLANAR = 0;
- final int FRONT = 1;
- final int BACK = 2;
- final int SPANNING = 3; // == some in the FRONT + some in the BACK
-
- // Classify each point as well as the entire polygon into one of the
- // above four classes.
- int polygonType = 0;
- List types = new ArrayList<>(polygon.vertices.size());
- for (int i = 0; i < polygon.vertices.size(); i++) {
- double t = this.normal.dot(polygon.vertices.get(i).pos) - this.dist;
- int type = (t < -Plane.EPSILON) ? BACK : (t > Plane.EPSILON) ? FRONT : COPLANAR;
- polygonType |= type;
- types.add(type);
- }
-
- //System.out.println("> switching");
- // Put the polygon in the correct list, splitting it when necessary.
- switch (polygonType) {
- case COPLANAR:
- //System.out.println(" -> coplanar");
- (this.normal.dot(polygon.plane.normal) > 0 ? coplanarFront : coplanarBack).add(polygon);
- break;
- case FRONT:
- //System.out.println(" -> front");
- front.add(polygon);
- break;
- case BACK:
- //System.out.println(" -> back");
- back.add(polygon);
- break;
- case SPANNING:
- //System.out.println(" -> spanning");
- List f = new ArrayList<>();
- List b = new ArrayList<>();
- for (int i = 0; i < polygon.vertices.size(); i++) {
- int j = (i + 1) % polygon.vertices.size();
- int ti = types.get(i);
- int tj = types.get(j);
- Vertex vi = polygon.vertices.get(i);
- Vertex vj = polygon.vertices.get(j);
- if (ti != BACK) {
- f.add(vi);
- }
- if (ti != FRONT) {
- b.add(ti != BACK ? vi.clone() : vi);
- }
- if ((ti | tj) == SPANNING) {
- double t = (this.dist - this.normal.dot(vi.pos))
- / this.normal.dot(vj.pos.minus(vi.pos));
- Vertex v = vi.interpolate(vj, t);
- f.add(v);
- b.add(v.clone());
- }
- }
- if (f.size() >= 3) {
- front.add(new Polygon(f, polygon.getStorage()));
- }
- if (b.size() >= 3) {
- back.add(new Polygon(b, polygon.getStorage()));
- }
- break;
- }
- }
-}
diff --git a/src/main/java/eu/mihosoft/jcsg/Polygon.java b/src/main/java/eu/mihosoft/jcsg/Polygon.java
deleted file mode 100644
index e820a0db..00000000
--- a/src/main/java/eu/mihosoft/jcsg/Polygon.java
+++ /dev/null
@@ -1,605 +0,0 @@
-/**
- * Polygon.java
- *
- * Copyright 2014-2014 Michael Hoffer . 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 "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 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
- * .
- */
-package eu.mihosoft.jcsg;
-
-import eu.mihosoft.vvecmath.Vector3d;
-import eu.mihosoft.vvecmath.Transform;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import eu.mihosoft.jcsg.ext.org.poly2tri.PolygonUtil;
-
-/**
- * Represents a convex polygon.
- *
- * Each convex polygon has a {@code shared} property, which is shared between
- * all polygons that are clones of each other or where split from the same
- * polygon. This can be used to define per-polygon properties (such as surface
- * color).
- */
-public final class Polygon {
-
- /**
- * Polygon vertices
- */
- public final List vertices;
- /**
- * Shared property (can be used for shared color etc.).
- */
- private PropertyStorage shared;
- /**
- * Plane defined by this polygon.
- *
- * Note: uses first three vertices to define the plane.
- */
- public final Plane plane;
-
- void setStorage(PropertyStorage storage) {
- this.shared = storage;
- }
-
- /**
- * Decomposes the specified concave polygon into convex polygons.
- *
- * @param points the points that define the polygon
- * @return the decomposed concave polygon (list of convex polygons)
- */
- public static List fromConcavePoints(Vector3d... points) {
- Polygon p = fromPoints(points);
-
- return PolygonUtil.concaveToConvex(p);
- }
-
- /**
- * Decomposes the specified concave polygon into convex polygons.
- *
- * @param points the points that define the polygon
- * @return the decomposed concave polygon (list of convex polygons)
- */
- public static List fromConcavePoints(List points) {
- Polygon p = fromPoints(points);
-
- return PolygonUtil.concaveToConvex(p);
- }
-
- /**
- * Indicates whether this polyon is valid, i.e., if it
- * @return
- */
- public boolean isValid() {
- return valid;
- }
-
- private boolean valid = true;
-
- /**
- * Constructor. Creates a new polygon that consists of the specified
- * vertices.
- *
- * Note: the vertices used to initialize a polygon must be coplanar
- * and form a convex loop.
- *
- * @param vertices polygon vertices
- * @param shared shared property
- */
- public Polygon(List vertices, PropertyStorage shared) {
- this.vertices = vertices;
- this.shared = shared;
- this.plane = Plane.createFromPoints(
- vertices.get(0).pos,
- vertices.get(1).pos,
- vertices.get(2).pos);
-
- validateAndInit(vertices);
- }
-
- private void validateAndInit(List vertices1) {
- for (Vertex v : vertices1) {
- v.normal = plane.normal;
- }
- if (Vector3d.ZERO.equals(plane.normal)) {
- valid = false;
- System.err.println(
- "Normal is zero! Probably, duplicate points have been specified!\n\n"+toStlString());
-// throw new RuntimeException(
-// "Normal is zero! Probably, duplicate points have been specified!\n\n"+toStlString());
- }
-
- if(vertices.size()<3) {
- throw new RuntimeException(
- "Invalid polygon: at least 3 vertices expected, got: "
- + vertices.size());
- }
- }
-
- /**
- * Constructor. Creates a new polygon that consists of the specified
- * vertices.
- *
- * Note: the vertices used to initialize a polygon must be coplanar
- * and form a convex loop.
- *
- * @param vertices polygon vertices
- */
- public Polygon(List vertices) {
- this.vertices = vertices;
- this.plane = Plane.createFromPoints(
- vertices.get(0).pos,
- vertices.get(1).pos,
- vertices.get(2).pos);
-
- validateAndInit(vertices);
- }
-
- /**
- * Constructor. Creates a new polygon that consists of the specified
- * vertices.
- *
- * Note: the vertices used to initialize a polygon must be coplanar
- * and form a convex loop.
- *
- * @param vertices polygon vertices
- *
- */
- public Polygon(Vertex... vertices) {
- this(Arrays.asList(vertices));
- }
-
- @Override
- public Polygon clone() {
- List newVertices = new ArrayList<>();
- this.vertices.forEach((vertex) -> {
- newVertices.add(vertex.clone());
- });
- return new Polygon(newVertices, getStorage());
- }
-
- /**
- * Flips this polygon.
- *
- * @return this polygon
- */
- public Polygon flip() {
- vertices.forEach((vertex) -> {
- vertex.flip();
- });
- Collections.reverse(vertices);
-
- plane.flip();
-
- return this;
- }
-
- /**
- * Returns a flipped copy of this polygon.
- *
- * Note: this polygon is not modified.
- *
- * @return a flipped copy of this polygon
- */
- public Polygon flipped() {
- return clone().flip();
- }
-
- /**
- * Returns this polygon in STL string format.
- *
- * @return this polygon in STL string format
- */
- public String toStlString() {
- return toStlString(new StringBuilder()).toString();
- }
-
- /**
- * Returns this polygon in STL string format.
- *
- * @param sb string builder
- *
- * @return the specified string builder
- */
- public StringBuilder toStlString(StringBuilder sb) {
-
- if (this.vertices.size() >= 3) {
-
- // TODO: improve the triangulation?
- //
- // STL requires triangular polygons.
- // If our polygon has more vertices, create
- // multiple triangles:
- String firstVertexStl = this.vertices.get(0).toStlString();
- for (int i = 0; i < this.vertices.size() - 2; i++) {
- sb.
- append(" facet normal ").append(
- this.plane.normal.toStlString()).append("\n").
- append(" outer loop\n").
- append(" ").append(firstVertexStl).append("\n").
- append(" ");
- this.vertices.get(i + 1).toStlString(sb).append("\n").
- append(" ");
- this.vertices.get(i + 2).toStlString(sb).append("\n").
- append(" endloop\n").
- append(" endfacet\n");
- }
- }
-
- return sb;
- }
-
- /**
- * Translates this polygon.
- *
- * @param v the vector that defines the translation
- * @return this polygon
- */
- public Polygon translate(Vector3d v) {
- vertices.forEach((vertex) -> {
- vertex.pos = vertex.pos.plus(v);
- });
-
- Vector3d a = this.vertices.get(0).pos;
- Vector3d b = this.vertices.get(1).pos;
- Vector3d c = this.vertices.get(2).pos;
-
- this.plane.normal = b.minus(a).cross(c.minus(a));
-
- return this;
- }
-
- /**
- * Returns a translated copy of this polygon.
- *
- * Note: this polygon is not modified
- *
- * @param v the vector that defines the translation
- *
- * @return a translated copy of this polygon
- */
- public Polygon translated(Vector3d v) {
- return clone().translate(v);
- }
-
- /**
- * Applies the specified transformation to this polygon.
- *
- * Note: if the applied transformation performs a mirror operation
- * the vertex order of this polygon is reversed.
- *
- * @param transform the transformation to apply
- *
- * @return this polygon
- */
- public Polygon transform(Transform transform) {
-
- this.vertices.stream().forEach(
- (v) -> {
- v.transform(transform);
- }
- );
-
- Vector3d a = this.vertices.get(0).pos;
- Vector3d b = this.vertices.get(1).pos;
- Vector3d c = this.vertices.get(2).pos;
-
- this.plane.normal = b.minus(a).cross(c.minus(a)).normalized();
- this.plane.dist = this.plane.normal.dot(a);
-
- if (transform.isMirror()) {
- // the transformation includes mirroring. flip polygon
- flip();
-
- }
- return this;
- }
-
- /**
- * Returns a transformed copy of this polygon.
- *
- * Note: if the applied transformation performs a mirror operation
- * the vertex order of this polygon is reversed.
- *
- * Note: this polygon is not modified
- *
- * @param transform the transformation to apply
- * @return a transformed copy of this polygon
- */
- public Polygon transformed(Transform transform) {
- return clone().transform(transform);
- }
-
- /**
- * Creates a polygon from the specified point list.
- *
- * @param points the points that define the polygon
- * @param shared shared property storage
- * @return a polygon defined by the specified point list
- */
- public static Polygon fromPoints(List points,
- PropertyStorage shared) {
- return fromPoints(points, shared, null);
- }
-
- /**
- * Creates a polygon from the specified point list.
- *
- * @param points the points that define the polygon
- * @return a polygon defined by the specified point list
- */
- public static Polygon fromPoints(List points) {
- return fromPoints(points, new PropertyStorage(), null);
- }
-
- /**
- * Creates a polygon from the specified points.
- *
- * @param points the points that define the polygon
- * @return a polygon defined by the specified point list
- */
- public static Polygon fromPoints(Vector3d... points) {
- return fromPoints(Arrays.asList(points), new PropertyStorage(), null);
- }
-
- /**
- * Creates a polygon from the specified point list.
- *
- * @param points the points that define the polygon
- * @param shared
- * @param plane may be null
- * @return a polygon defined by the specified point list
- */
- private static Polygon fromPoints(
- List points, PropertyStorage shared, Plane plane) {
-
- Vector3d normal
- = (plane != null) ? plane.normal.clone() : null;
-
- if (normal == null) {
- normal = Plane.createFromPoints(
- points.get(0),
- points.get(1),
- points.get(2)).normal;
- }
-
- List vertices = new ArrayList<>();
-
- for (Vector3d p : points) {
- Vector3d vec = p.clone();
- Vertex vertex = new Vertex(vec, normal);
- vertices.add(vertex);
- }
-
- return new Polygon(vertices, shared);
- }
-
- /**
- * Returns the bounds of this polygon.
- *
- * @return bouds of this polygon
- */
- public Bounds getBounds() {
- double minX = Double.POSITIVE_INFINITY;
- double minY = Double.POSITIVE_INFINITY;
- double minZ = Double.POSITIVE_INFINITY;
-
- double maxX = Double.NEGATIVE_INFINITY;
- double maxY = Double.NEGATIVE_INFINITY;
- double maxZ = Double.NEGATIVE_INFINITY;
-
- for (int i = 0; i < vertices.size(); i++) {
-
- Vertex vert = vertices.get(i);
-
- if (vert.pos.x() < minX) {
- minX = vert.pos.x();
- }
- if (vert.pos.y() < minY) {
- minY = vert.pos.y();
- }
- if (vert.pos.z() < minZ) {
- minZ = vert.pos.z();
- }
-
- if (vert.pos.x() > maxX) {
- maxX = vert.pos.x();
- }
- if (vert.pos.y() > maxY) {
- maxY = vert.pos.y();
- }
- if (vert.pos.z() > maxZ) {
- maxZ = vert.pos.z();
- }
-
- } // end for vertices
-
- return new Bounds(
- Vector3d.xyz(minX, minY, minZ),
- Vector3d.xyz(maxX, maxY, maxZ));
- }
-
- public boolean contains(Vector3d p) {
- // taken from http://www.java-gaming.org/index.php?topic=26013.0
- // and http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
- double px = p.x();
- double py = p.y();
- boolean oddNodes = false;
- double x2 = vertices.get(vertices.size() - 1).pos.x();
- double y2 = vertices.get(vertices.size() - 1).pos.y();
- double x1, y1;
- for (int i = 0; i < vertices.size(); x2 = x1, y2 = y1, ++i) {
- x1 = vertices.get(i).pos.x();
- y1 = vertices.get(i).pos.y();
- if (((y1 < py) && (y2 >= py))
- || (y1 >= py) && (y2 < py)) {
- if ((py - y1) / (y2 - y1)
- * (x2 - x1) < (px - x1)) {
- oddNodes = !oddNodes;
- }
- }
- }
- return oddNodes;
- }
-
- public boolean contains(Polygon p) {
-
- for (Vertex v : p.vertices) {
- if (!contains(v.pos)) {
- return false;
- }
- }
-
- return true;
- }
-
-// private static List concaveToConvex(Polygon concave) {
-// List result = new ArrayList<>();
-//
-// Triangulation t = new Triangulation();
-//
-// double[] xv = new double[concave.vertices.size()];
-// double[] yv = new double[concave.vertices.size()];
-//
-// for(int i = 0; i < xv.length;i++) {
-// Vector3d pos = concave.vertices.get(i).pos;
-// xv[i] = pos.x;
-// yv[i] = pos.y;
-// }
-//
-// TriangleTri[] triangles = t.triangulatePolygon(xv, yv, xv.length);
-//
-// for(TriangleTri tr : triangles) {
-// double x1 = tr.x[0];
-// double x2 = tr.x[1];
-// double x3 = tr.x[2];
-// double y1 = tr.y[0];
-// double y2 = tr.y[1];
-// double y3 = tr.y[2];
-//
-// Vertex v1 = new Vertex(new Vector3d(x1, y1), new Vector3d(0, 0));
-// Vertex v2 = new Vertex(new Vector3d(x2, y2), new Vector3d(0, 0));
-// Vertex v3 = new Vertex(new Vector3d(x3, y3), new Vector3d(0, 0));
-//
-// result.add(new Polygon(v1,v2,v3));
-// }
-//
-// return result;
-// }
-// private static List concaveToConvex(Polygon concave) {
-// List result = new ArrayList<>();
-//
-// //convert polygon to convex polygons
-// EarClippingTriangulator clippingTriangulator = new EarClippingTriangulator();
-// double[] vertexArray = new double[concave.vertices.size() * 2];
-// for (int i = 0; i < vertexArray.length; i += 2) {
-// Vertex v = concave.vertices.get(i / 2);
-// vertexArray[i + 0] = v.pos.x;
-// vertexArray[i + 1] = v.pos.y;
-// }
-//
-// IntArray indices = clippingTriangulator.computeTriangles(vertexArray);
-//
-// System.out.println("indices: " + indices.size + ", vertices: " + vertexArray.length);
-//
-// for (double i : vertexArray) {
-// System.out.println("vertices: " + i);
-// }
-//
-// Vertex[] newPolygonVerts = new Vertex[3];
-//
-// int count = 0;
-// for (int i = 0; i < indices.size; i+=2) {
-// double x = vertexArray[indices.items[i]+0];
-// double y = vertexArray[indices.items[i]+1];
-//
-// Vector3d pos = new Vector3d(x, y);
-// Vertex v = new Vertex(pos, new Vector3d(0, 0, 0));
-//
-// System.out.println("writing vertex: " + (count));
-// newPolygonVerts[count] = v;
-//
-// if (count == 2) {
-// result.add(new Polygon(newPolygonVerts));
-// count = 0;
-// } else {
-// count++;
-// }
-// }
-//
-// System.out.println("---");
-//
-// for (Polygon p : result) {
-// System.out.println(p.toStlString());
-// }
-//
-// return result;
-//
-//// Point3d[] points = new Point3d[concave.vertices.size()];
-////
-//// for (int i = 0; i < points.length;i++) {
-//// Vector3d pos = concave.vertices.get(i).pos;
-//// points[i] = new Point3d(pos.x, pos.y, pos.z);
-//// }
-////
-//// QuickHull3D hull = new QuickHull3D();
-//// hull.build(points);
-////
-//// System.out.println("Vertices:");
-//// Point3d[] vertices = hull.getVertices();
-//// for (int i = 0; i < vertices.length; i++) {
-//// Point3d pnt = vertices[i];
-//// System.out.println(pnt.x + " " + pnt.y + " " + pnt.z);
-//// }
-////
-//// System.out.println("Faces:");
-//// int[][] faceIndices = hull.getFaces();
-//// for (int i = 0; i < faceIndices.length; i++) {
-//// for (int k = 0; k < faceIndices[i].length; k++) {
-//// System.out.print(faceIndices[i][k] + " ");
-//// }
-//// System.out.println("");
-//// }
-//
-//// return result;
-// }
- /**
- * @return the shared
- */
- public PropertyStorage getStorage() {
-
- if (shared == null) {
- shared = new PropertyStorage();
- }
-
- return shared;
- }
-}
diff --git a/src/main/java/eu/mihosoft/jcsg/Text3d.java b/src/main/java/eu/mihosoft/jcsg/Text3d.java
deleted file mode 100644
index ec6e959e..00000000
--- a/src/main/java/eu/mihosoft/jcsg/Text3d.java
+++ /dev/null
@@ -1,254 +0,0 @@
-///**
-// * Text3d.java
-// *
-// * Copyright 2014-2016 Michael Hoffer . 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 "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 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
-// * .
-// */
-//package eu.mihosoft.jcsg;
-//
-//import java.lang.reflect.Field;
-//import java.util.ArrayList;
-//import java.util.List;
-//import java.util.concurrent.CountDownLatch;
-//import java.util.logging.Level;
-//import java.util.logging.Logger;
-//import javafx.application.Platform;
-//import javafx.embed.swing.JFXPanel;
-//import javax.swing.SwingUtilities;
-//import org.fxyz.shapes.primitives.Text3DMesh;
-//import org.fxyz.shapes.primitives.TexturedMesh;
-//import org.fxyz.utils.MeshUtils;
-//
-///**
-// * 3d text primitive.
-// *
-// * @author Michael Hoffer
-// */
-//public class Text3d implements Primitive {
-//
-// private final PropertyStorage properties = new PropertyStorage();
-//
-// private final String text;
-// private String fontName;
-// private double size;
-// private double depth;
-// Text3DMesh t3dMesh;
-// private boolean noCenter;
-//
-// // 08.11.2016
-// // TODO report bug to FXyz authors
-// // factor by which we multiply text generation to minimize rendering errors
-// double scaleFactor = 100;
-//
-// /**
-// * Constructor.
-// *
-// * @param text text
-// */
-// public Text3d(String text) {
-// this(text, "Arial", 12, 1.0);
-// }
-//
-// /**
-// * Constructor.
-// *
-// * @param text text
-// * @param depth text depth (z thickness)
-// */
-// public Text3d(String text, double depth) {
-// this(text, "Arial", 12, depth);
-// }
-//
-// /**
-// * Constructor.
-// *
-// * @param text text
-// * @param fontName font name, e.g., "Arial"
-// * @param fontSize font size
-// * @param depth text depth (z thickness)
-// */
-// public Text3d(String text, String fontName, double fontSize, double depth) {
-// this.text = text;
-// this.fontName = fontName;
-// this.size = fontSize;
-// this.depth = depth;
-//
-// // scaled size and height (see scaleFactor docs)
-// int realSize = (int) (fontSize * scaleFactor);
-// double realHeight = depth * scaleFactor;
-//
-// invokeAndWait(() -> {
-// t3dMesh = new Text3DMesh(
-// text, fontName, realSize, false, realHeight, 0, 0);
-// });
-//
-// }
-//
-// @Override
-// public List toPolygons() {
-// return new MeshRetriever(this).toCSG(noCenter).getPolygons();
-// }
-//
-// @Override
-// public PropertyStorage getProperties() {
-// return properties;
-// }
-//
-// public Text3d noCenter() {
-// this.noCenter = true;
-//
-// return this;
-// }
-//
-// private static void invokeAndWait(Runnable action) {
-//
-// if (action == null) {
-// throw new NullPointerException("action");
-// }
-//
-// // run synchronously on JavaFX thread
-// if (Platform.isFxApplicationThread()) {
-// action.run();
-// return;
-// }
-//
-// // init JavaFX toolkit
-// Platform.setImplicitExit(true);
-//
-// setupJavaFX();
-//
-// // queue on JavaFX thread and wait for completion
-// final CountDownLatch doneLatch = new CountDownLatch(1);
-// Platform.runLater(() -> {
-// try {
-// action.run();
-// } finally {
-// doneLatch.countDown();
-// }
-// });
-//
-// try {
-// doneLatch.await();
-// } catch (InterruptedException e) {
-// // ignore exception
-// }
-// }
-//
-// private static void setupJavaFX() throws RuntimeException {
-// final CountDownLatch latch = new CountDownLatch(1);
-// SwingUtilities.invokeLater(() -> {
-// new JFXPanel(); // initializes JavaFX environment
-// latch.countDown();
-// });
-//
-// try {
-// latch.await();
-// } catch (InterruptedException e) {
-// throw new RuntimeException(e);
-// }
-// }
-//
-//}
-//
-//class MeshRetriever {
-//
-// private final Text3d t3dMesh;
-//
-// public MeshRetriever(Text3d t3dMesh) {
-// this.t3dMesh = t3dMesh;
-// }
-//
-// public CSG toCSG(boolean noCenter) {
-// List csgs = new ArrayList<>();
-//
-// CSG result = null;
-//
-// List meshes = getMeshes();
-//
-// for (int i = 0; i < meshes.size(); i++) {
-//
-// TexturedMesh mesh = meshes.get(i);
-//
-// CSG csg = MeshUtils.mesh2CSG(mesh);
-//
-// double xTransform = mesh.getTransforms().stream().
-// mapToDouble(tr -> tr.getTx()).sum();
-//
-// csg = csg.transformed(Transform.unity().translateX(xTransform));
-//
-// // rescale final mesh (see scaleFactor docs)
-// double xScale = 1.0 / t3dMesh.scaleFactor;
-// csg = csg.transformed(Transform.unity().
-// scale(xScale, -xScale, xScale));
-//
-// if (result == null) {
-// result = csg;
-// } else {
-// result = result.dumbUnion(csg);
-// }
-// }
-//
-// if (!noCenter) {
-// result = result.transformed(
-// Transform.unity().translate(
-// -result.getBounds().getBounds().x * 0.5,
-// -result.getBounds().getBounds().y * 0.5,
-// -result.getBounds().getBounds().z * 0.5)
-// );
-// }
-//
-// return result;
-// }
-//
-// public List getMeshes() {
-// try {
-// Field field = Text3DMesh.class.getDeclaredField("meshes");
-//
-// field.setAccessible(true);
-//
-// return (List) field.get(t3dMesh.t3dMesh);
-// } catch (NoSuchFieldException ex) {
-// Logger.getLogger(MeshRetriever.class.getName()).
-// log(Level.SEVERE, null, ex);
-// } catch (SecurityException ex) {
-// Logger.getLogger(MeshRetriever.class.getName()).
-// log(Level.SEVERE, null, ex);
-// } catch (IllegalArgumentException ex) {
-// Logger.getLogger(MeshRetriever.class.getName()).
-// log(Level.SEVERE, null, ex);
-// } catch (IllegalAccessException ex) {
-// Logger.getLogger(MeshRetriever.class.getName()).
-// log(Level.SEVERE, null, ex);
-// }
-//
-// return null;
-// }
-//
-//}
diff --git a/src/main/java/eu/mihosoft/jcsg/ext/imagej/STLLoader.java b/src/main/java/eu/mihosoft/jcsg/ext/imagej/STLLoader.java
deleted file mode 100644
index 93a7ea8e..00000000
--- a/src/main/java/eu/mihosoft/jcsg/ext/imagej/STLLoader.java
+++ /dev/null
@@ -1,176 +0,0 @@
-
-
-package eu.mihosoft.jcsg.ext.imagej;
-
-/**
- * Fork of
- * https://github.com/fiji/fiji/blob/master/src-plugins/3D_Viewer/src/main/java/customnode/STLLoader.java
- *
- * TODO: license unclear
- */
-
-import eu.mihosoft.vvecmath.ModifiableVector3d;
-import eu.mihosoft.vvecmath.Vector3d;
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileReader;
-import java.io.IOException;
-import java.text.DecimalFormat;
-import java.text.ParseException;
-import java.util.ArrayList;
-
-
-public class STLLoader {
-
-// /**
-// * Load the specified stl file and returns the result as a hash map, mapping
-// * the object names to the corresponding CustomMesh objects.
-// */
-// public static Map load(String stlfile)
-// throws IOException {
-// STLLoader sl = new STLLoader();
-// try {
-// sl.parse(stlfile);
-// } catch (RuntimeException e) {
-// System.out.println("error reading " + sl.name);
-// throw e;
-// }
-// return sl.meshes;
-// }
-//
-// private HashMap meshes;
- public STLLoader() {
- }
-
- String line;
- BufferedReader in;
-
- // attributes of the currently read mesh
- private ArrayList vertices = new ArrayList<>();
- private final ModifiableVector3d normal = Vector3d.zero().asModifiable(); //to be used for file checking
- private FileInputStream fis;
- private int triangles;
-// private DecimalFormat decimalFormat = new DecimalFormat("0.0E0");
-
-
-
- public ArrayList parse(File f) throws IOException {
- vertices.clear();
-
- // determine if this is a binary or ASCII STL
- // and send to the appropriate parsing method
- // Hypothesis 1: this is an ASCII STL
- BufferedReader br = new BufferedReader(new FileReader(f));
- String line = br.readLine();
- String[] words = line.trim().split("\\s+");
- if (line.indexOf('\0') < 0 && words[0].equalsIgnoreCase("solid")) {
- System.out.println("Looks like an ASCII STL");
- parseAscii(f);
- return vertices;
- }
-
- // Hypothesis 2: this is a binary STL
- FileInputStream fs = new FileInputStream(f);
-
- // bytes 80, 81, 82 and 83 form a little-endian int
- // that contains the number of triangles
- byte[] buffer = new byte[84];
- fs.read(buffer, 0, 84);
- triangles = (int) (((buffer[83] & 0xff) << 24)
- | ((buffer[82] & 0xff) << 16) | ((buffer[81] & 0xff) << 8) | (buffer[80] & 0xff));
- if (((f.length() - 84) / 50) == triangles) {
- System.out.println("Looks like a binary STL");
- parseBinary(f);
- return vertices;
- }
- System.err.println("File is not a valid STL");
-
- return vertices;
- }
-
- private void parseAscii(File f) {
- try {
- in = new BufferedReader(new FileReader(f));
- } catch (FileNotFoundException e) {
- e.printStackTrace();
- }
- vertices = new ArrayList<>();
- try {
- while ((line = in.readLine()) != null) {
- String[] numbers = line.trim().split("\\s+");
- if (numbers[0].equals("vertex")) {
- float x = parseFloat(numbers[1]);
- float y = parseFloat(numbers[2]);
- float z = parseFloat(numbers[3]);
- Vector3d vertex = Vector3d.xyz(x, y, z);
- vertices.add(vertex);
- } else if (numbers[0].equals("facet") && numbers[1].equals("normal")) {
- normal.setX(parseFloat(numbers[2]));
- normal.setY(parseFloat(numbers[3]));
- normal.setZ(parseFloat(numbers[4]));
- }
- }
- in.close();
- } catch (IOException e) {
- e.printStackTrace();
- } catch (ParseException e) {
- e.printStackTrace();
- }
- }
-
- private void parseBinary(File f) {
- vertices = new ArrayList();
- try {
- fis = new FileInputStream(f);
- for (int h = 0; h < 84; h++) {
- fis.read();// skip the header bytes
- }
- for (int t = 0; t < triangles; t++) {
- byte[] tri = new byte[50];
- for (int tb = 0; tb < 50; tb++) {
- tri[tb] = (byte) fis.read();
- }
- normal.setX(leBytesToFloat(tri[0], tri[1], tri[2], tri[3]));
- normal.setY(leBytesToFloat(tri[4], tri[5], tri[6], tri[7]));
- normal.setZ(leBytesToFloat(tri[8], tri[9], tri[10], tri[11]));
- for (int i = 0; i < 3; i++) {
- final int j = i * 12 + 12;
- float px = leBytesToFloat(tri[j], tri[j + 1], tri[j + 2],
- tri[j + 3]);
- float py = leBytesToFloat(tri[j + 4], tri[j + 5],
- tri[j + 6], tri[j + 7]);
- float pz = leBytesToFloat(tri[j + 8], tri[j + 9],
- tri[j + 10], tri[j + 11]);
- Vector3d p = Vector3d.xyz(px, py, pz);
- vertices.add(p);
- }
- }
- fis.close();
- } catch (FileNotFoundException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
-// private float parseFloat(String string) throws ParseException {
-// //E+05 -> E05, e+05 -> E05
-// string = string.replaceFirst("[eE]\\+", "E");
-// //E-05 -> E-05, e-05 -> E-05
-// string = string.replaceFirst("e\\-", "E-");
-// return decimalFormat.parse(string).floatValue();
-// }
-
- private float parseFloat(String string) throws ParseException {
-
- return Float.parseFloat(string);
- }
-
- private float leBytesToFloat(byte b0, byte b1, byte b2, byte b3) {
- return Float.intBitsToFloat((((b3 & 0xff) << 24) | ((b2 & 0xff) << 16)
- | ((b1 & 0xff) << 8) | (b0 & 0xff)));
- }
-
-}
diff --git a/src/main/java/eu/mihosoft/jcsg/ext/openjfx/importers/Optimizer.java b/src/main/java/eu/mihosoft/jcsg/ext/openjfx/importers/Optimizer.java
deleted file mode 100644
index 08446612..00000000
--- a/src/main/java/eu/mihosoft/jcsg/ext/openjfx/importers/Optimizer.java
+++ /dev/null
@@ -1,566 +0,0 @@
-/*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates.
- * All rights reserved. Use is subject to license terms.
- *
- * This file is available and licensed under the following license:
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * - 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.
- * - Neither the name of Oracle Corporation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "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 THE COPYRIGHT
- * OWNER 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.
- */
-package eu.mihosoft.jcsg.ext.openjfx.importers;
-
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import javafx.animation.Interpolator;
-import javafx.animation.KeyFrame;
-import javafx.animation.KeyValue;
-import javafx.animation.Timeline;
-import javafx.beans.property.Property;
-import javafx.beans.value.WritableValue;
-import javafx.collections.FXCollections;
-import javafx.collections.ObservableFloatArray;
-import javafx.collections.ObservableIntegerArray;
-import javafx.collections.ObservableList;
-import javafx.collections.transformation.SortedList;
-import javafx.geometry.Point2D;
-import javafx.geometry.Point3D;
-import javafx.scene.Group;
-import javafx.scene.Node;
-import javafx.scene.Parent;
-import javafx.scene.shape.MeshView;
-import javafx.scene.shape.TriangleMesh;
-import javafx.scene.transform.Transform;
-import javafx.util.Duration;
-
-/**
- * Optimizer to take 3D model and timeline loaded by one of the importers and do as much optimization on
- * the scene graph that was create as we can while still being able to play the given animation.
- */
-public class Optimizer {
-
- private Timeline timeline;
- private Node root;
- private Set bound = new HashSet<>();
- private List emptyParents = new ArrayList<>();
- private List meshViews = new ArrayList<>();
- private boolean convertToDiscrete = true;
-
- public Optimizer(Timeline timeline, Node root) {
- this(timeline, root, false);
- }
-
- public Optimizer(Timeline timeline, Node root, boolean convertToDiscrete) {
- this.timeline = timeline;
- this.root = root;
- this.convertToDiscrete = convertToDiscrete;
- }
-
- private int trRemoved, trTotal, groupsTotal, trCandidate, trEmpty;
-
- public void optimize() {
- trRemoved = 0;
- trTotal = 0;
- trCandidate = 0;
- trEmpty = 0;
- groupsTotal = 0;
- emptyParents.clear();
-
- parseTimeline();
- optimize(root);
- removeEmptyGroups();
- optimizeMeshes();
-
- System.out.printf("removed %d (%.2f%%) out of total %d transforms\n", trRemoved, 100d * trRemoved / trTotal, trTotal);
- System.out.printf("there are %d more multiplications that can be done of matrices that never change\n", trCandidate);
- System.out.printf("there are %d (%.2f%%) out of total %d groups with no transforms in them\n", trEmpty, 100d * trEmpty / groupsTotal, groupsTotal);
- }
-
- private void optimize(Node node) {
- ObservableList transforms = node.getTransforms();
- Iterator iterator = transforms.iterator();
- boolean prevIsStatic = false;
- while (iterator.hasNext()) {
- Transform transform = iterator.next();
- trTotal++;
- if (transform.isIdentity()) {
- if (timeline == null || !bound.contains(transform)) {
- iterator.remove();
- trRemoved++;
- }
- } else {
- if (timeline == null || !bound.contains(transform)) {
- if (prevIsStatic) {
- trCandidate++;
- }
- prevIsStatic = true;
- } else {
- prevIsStatic = false;
- }
- }
- }
- if (node instanceof Parent) {
- groupsTotal++;
- Parent p = (Parent) node;
- for (Node n : p.getChildrenUnmodifiable()) {
- optimize(n);
- }
- if (transforms.isEmpty()) {
- Parent parent = p.getParent();
- if (parent instanceof Group) {
- trEmpty++;
-// System.out.println("Empty group = " + node.getId());
- emptyParents.add(p);
- } else {
-// System.err.println("parent is not group = " + parent);
- }
- }
- }
- if (node instanceof MeshView) {
- meshViews.add((MeshView) node);
- }
- }
-
- private void optimizeMeshes() {
- optimizePoints();
- optimizeTexCoords();
- optimizeFaces();
- }
-
- private void optimizeFaces() {
- int total = 0, sameIndexes = 0, samePoints = 0, smallArea = 0;
- ObservableIntegerArray newFaces = FXCollections.observableIntegerArray();
- ObservableIntegerArray newFaceSmoothingGroups = FXCollections.observableIntegerArray();
- for (MeshView meshView : meshViews) {
- TriangleMesh mesh = (TriangleMesh) meshView.getMesh();
- ObservableIntegerArray faces = mesh.getFaces();
- ObservableIntegerArray faceSmoothingGroups = mesh.getFaceSmoothingGroups();
- ObservableFloatArray points = mesh.getPoints();
- newFaces.clear();
- newFaces.ensureCapacity(faces.size());
- newFaceSmoothingGroups.clear();
- newFaceSmoothingGroups.ensureCapacity(faceSmoothingGroups.size());
- int pointElementSize = mesh.getPointElementSize();
- int faceElementSize = mesh.getFaceElementSize();
- for (int i = 0; i < faces.size(); i += faceElementSize) {
- total++;
- int i1 = faces.get(i) * pointElementSize;
- int i2 = faces.get(i + 2) * pointElementSize;
- int i3 = faces.get(i + 4) * pointElementSize;
- if (i1 == i2 || i1 == i3 || i2 == i3) {
- sameIndexes++;
- continue;
- }
- Point3D p1 = new Point3D(points.get(i1), points.get(i1 + 1), points.get(i1 + 2));
- Point3D p2 = new Point3D(points.get(i2), points.get(i2 + 1), points.get(i2 + 2));
- Point3D p3 = new Point3D(points.get(i3), points.get(i3 + 1), points.get(i3 + 2));
- if (p1.equals(p2) || p1.equals(p3) || p2.equals(p3)) {
- samePoints++;
- continue;
- }
- double a = p1.distance(p2);
- double b = p2.distance(p3);
- double c = p3.distance(p1);
- double p = (a + b + c) / 2;
- double sqarea = p * (p - a) * (p - b) * (p - c);
-
- final float DEAD_FACE = 1.f/1024/1024/1024/1024; // taken from MeshNormal code
-
- if (sqarea < DEAD_FACE) {
- smallArea++;
-// System.out.printf("a = %e, b = %e, c = %e, sqarea = %e\n"
-// + "p1 = %s\np2 = %s\np3 = %s\n", a, b, c, sqarea, p1.toString(), p2.toString(), p3.toString());
- continue;
- }
- newFaces.addAll(faces, i, faceElementSize);
- int fIndex = i / faceElementSize;
- if (fIndex < faceSmoothingGroups.size()) {
- newFaceSmoothingGroups.addAll(faceSmoothingGroups.get(fIndex));
- }
- }
- faces.setAll(newFaces);
- faceSmoothingGroups.setAll(newFaceSmoothingGroups);
- faces.trimToSize();
- faceSmoothingGroups.trimToSize();
- }
- int badTotal = sameIndexes + samePoints + smallArea;
- System.out.printf("Removed %d (%.2f%%) faces with same point indexes, "
- + "%d (%.2f%%) faces with same points, "
- + "%d (%.2f%%) faces with small area. "
- + "Total %d (%.2f%%) bad faces out of %d total.\n",
- sameIndexes, 100d * sameIndexes / total,
- samePoints, 100d * samePoints / total,
- smallArea, 100d * smallArea / total,
- badTotal, 100d * badTotal / total, total);
- }
-
- private void optimizePoints() {
- int total = 0, duplicates = 0, check = 0;
-
- Map pp = new HashMap<>();
- ObservableIntegerArray reindex = FXCollections.observableIntegerArray();
- ObservableFloatArray newPoints = FXCollections.observableFloatArray();
-
- for (MeshView meshView : meshViews) {
- TriangleMesh mesh = (TriangleMesh) meshView.getMesh();
- ObservableFloatArray points = mesh.getPoints();
- int pointElementSize = mesh.getPointElementSize();
- int os = points.size() / pointElementSize;
-
- pp.clear();
- newPoints.clear();
- newPoints.ensureCapacity(points.size());
- reindex.clear();
- reindex.resize(os);
-
- for (int i = 0, oi = 0, ni = 0; i < points.size(); i += pointElementSize, oi++) {
- float x = points.get(i);
- float y = points.get(i + 1);
- float z = points.get(i + 2);
- Point3D p = new Point3D(x, y, z);
- Integer index = pp.get(p);
- if (index == null) {
- pp.put(p, ni);
- reindex.set(oi, ni);
- newPoints.addAll(x, y, z);
- ni++;
- } else {
- reindex.set(oi, index);
- }
- }
-
- int ns = newPoints.size() / pointElementSize;
-
- int d = os - ns;
- duplicates += d;
- total += os;
-
- points.setAll(newPoints);
- points.trimToSize();
-
- ObservableIntegerArray faces = mesh.getFaces();
- for (int i = 0; i < faces.size(); i += 2) {
- faces.set(i, reindex.get(faces.get(i)));
- }
-
-// System.out.printf("There are %d (%.2f%%) duplicate points out of %d total for mesh '%s'.\n",
-// d, 100d * d / os, os, meshView.getId());
-
- check += mesh.getPoints().size() / pointElementSize;
- }
- System.out.printf("There are %d (%.2f%%) duplicate points out of %d total.\n",
- duplicates, 100d * duplicates / total, total);
- System.out.printf("Now we have %d points.\n", check);
- }
-
- private void optimizeTexCoords() {
- int total = 0, duplicates = 0, check = 0;
-
- Map pp = new HashMap<>();
- ObservableIntegerArray reindex = FXCollections.observableIntegerArray();
- ObservableFloatArray newTexCoords = FXCollections.observableFloatArray();
-
- for (MeshView meshView : meshViews) {
- TriangleMesh mesh = (TriangleMesh) meshView.getMesh();
- ObservableFloatArray texcoords = mesh.getTexCoords();
- int texcoordElementSize = mesh.getTexCoordElementSize();
- int os = texcoords.size() / texcoordElementSize;
-
- pp.clear();
- newTexCoords.clear();
- newTexCoords.ensureCapacity(texcoords.size());
- reindex.clear();
- reindex.resize(os);
-
- for (int i = 0, oi = 0, ni = 0; i < texcoords.size(); i += texcoordElementSize, oi++) {
- float x = texcoords.get(i);
- float y = texcoords.get(i + 1);
- Point2D p = new Point2D(x, y);
- Integer index = pp.get(p);
- if (index == null) {
- pp.put(p, ni);
- reindex.set(oi, ni);
- newTexCoords.addAll(x, y);
- ni++;
- } else {
- reindex.set(oi, index);
- }
- }
-
- int ns = newTexCoords.size() / texcoordElementSize;
-
- int d = os - ns;
- duplicates += d;
- total += os;
-
- texcoords.setAll(newTexCoords);
- texcoords.trimToSize();
-
- ObservableIntegerArray faces = mesh.getFaces();
- for (int i = 1; i < faces.size(); i += 2) {
- faces.set(i, reindex.get(faces.get(i)));
- }
-
-// System.out.printf("There are %d (%.2f%%) duplicate texcoords out of %d total for mesh '%s'.\n",
-// d, 100d * d / os, os, meshView.getId());
-
- check += mesh.getTexCoords().size() / texcoordElementSize;
- }
- System.out.printf("There are %d (%.2f%%) duplicate texcoords out of %d total.\n",
- duplicates, 100d * duplicates / total, total);
- System.out.printf("Now we have %d texcoords.\n", check);
- }
-
- private void cleanUpRepeatingFramesAndValues() {
- ObservableList timelineKeyFrames = timeline.getKeyFrames().sorted(new KeyFrameComparator());
-// Timeline timeline;
- int kfTotal = timelineKeyFrames.size(), kfRemoved = 0;
- int kvTotal = 0, kvRemoved = 0;
- Map kfUnique = new HashMap<>();
- Map kvUnique = new HashMap<>();
- MapOfLists duplicates = new MapOfLists<>();
- Iterator iterator = timelineKeyFrames.iterator();
- while (iterator.hasNext()) {
- KeyFrame duplicate = iterator.next();
- KeyFrame original = kfUnique.put(duplicate.getTime(), duplicate);
- if (original != null) {
- kfRemoved++;
- iterator.remove(); // removing duplicate keyFrame
- duplicates.add(original, duplicate);
-
- kfUnique.put(duplicate.getTime(), original);
- }
- kvUnique.clear();
- for (KeyValue kvDup : duplicate.getValues()) {
- kvTotal++;
- KeyValue kvOrig = kvUnique.put(kvDup.getTarget(), kvDup);
- if (kvOrig != null) {
- kvRemoved++;
- if (!kvOrig.getEndValue().equals(kvDup.getEndValue()) && kvOrig.getTarget() == kvDup.getTarget()) {
- System.err.println("KeyValues set different values for KeyFrame " + duplicate.getTime() + ":"
- + "\n kvOrig = " + kvOrig + ", \nkvDup = " + kvDup);
- }
- }
- }
- }
- for (KeyFrame orig : duplicates.keySet()) {
- List keyValues = new ArrayList<>();
- for (KeyFrame dup : duplicates.get(orig)) {
- keyValues.addAll(dup.getValues());
- }
- timelineKeyFrames.set(timelineKeyFrames.indexOf(orig),
- new KeyFrame(orig.getTime(), keyValues.toArray(new KeyValue[keyValues.size()])));
- }
- System.out.printf("Removed %d (%.2f%%) duplicate KeyFrames out of total %d.\n",
- kfRemoved, 100d * kfRemoved / kfTotal, kfTotal);
- System.out.printf("Identified %d (%.2f%%) duplicate KeyValues out of total %d.\n",
- kvRemoved, 100d * kvRemoved / kvTotal, kvTotal);
- }
-
- private static class KeyInfo {
- KeyFrame keyFrame;
- KeyValue keyValue;
- boolean first;
-
- public KeyInfo(KeyFrame keyFrame, KeyValue keyValue) {
- this.keyFrame = keyFrame;
- this.keyValue = keyValue;
- first = false;
- }
-
- public KeyInfo(KeyFrame keyFrame, KeyValue keyValue, boolean first) {
- this.keyFrame = keyFrame;
- this.keyValue = keyValue;
- this.first = first;
- }
- }
-
- private static class MapOfLists extends HashMap> {
-
- public void add(K key, V value) {
- List p = get(key);
- if (p == null) {
- p = new ArrayList<>();
- put(key, p);
- }
- p.add(value);
- }
- }
-
- private void parseTimeline() {
- bound.clear();
- if (timeline == null) {
- return;
- }
-// cleanUpRepeatingFramesAndValues(); // we don't need it usually as timeline is initially correct
- SortedList sortedKeyFrames = timeline.getKeyFrames().sorted(new KeyFrameComparator());
- MapOfLists toRemove = new MapOfLists<>();
- Map prevValues = new HashMap<>();
- Map prevPrevValues = new HashMap<>();
- int kvTotal = 0;
- for (KeyFrame keyFrame : sortedKeyFrames) {
- for (KeyValue keyValue : keyFrame.getValues()) {
- WritableValue> target = keyValue.getTarget();
- KeyInfo prev = prevValues.get(target);
- kvTotal++;
- if (prev != null && prev.keyValue.getEndValue().equals(keyValue.getEndValue())) {
-// if (prev != null && (prev.keyValue.equals(keyValue) || (prev.first && prev.keyValue.getEndValue().equals(keyValue.getEndValue())))) {
- KeyInfo prevPrev = prevPrevValues.get(target);
- if ((prevPrev != null && prevPrev.keyValue.getEndValue().equals(keyValue.getEndValue()))
- || (prev.first && target.getValue().equals(prev.keyValue.getEndValue()))) {
- // All prevPrev, prev and current match, so prev can be removed
- // or prev is first and its value equals to the property existing value, so prev can be removed
- toRemove.add(prev.keyFrame, prev.keyValue);
- } else {
- prevPrevValues.put(target, prev);
-// KeyInfo oldKeyInfo = prevPrevValues.put(target, prev);
-// if (oldKeyInfo != null && oldKeyInfo.keyFrame.getTime().equals(prev.keyFrame.getTime())) {
-// System.err.println("prevPrev replaced more than once per keyFrame on " + target + "\n"
-// + "old = " + oldKeyInfo.keyFrame.getTime() + ", " + oldKeyInfo.keyValue + "\n"
-// + "new = " + prev.keyFrame.getTime() + ", " + prev.keyValue
-// );
-// }
- }
- }
- KeyInfo oldPrev = prevValues.put(target, new KeyInfo(keyFrame, keyValue, prev == null));
- if (oldPrev != null) prevPrevValues.put(target, oldPrev);
- }
- }
- // Deal with ending keyValues
- for (WritableValue target : prevValues.keySet()) {
- KeyInfo prev = prevValues.get(target);
- KeyInfo prevPrev = prevPrevValues.get(target);
- if (prevPrev != null && prevPrev.keyValue.getEndValue().equals(prev.keyValue.getEndValue())) {
- // prevPrev and prev match, so prev can be removed
- toRemove.add(prev.keyFrame, prev.keyValue);
- }
- }
- int kvRemoved = 0;
- int kfRemoved = 0, kfTotal = timeline.getKeyFrames().size(), kfSimplified = 0, kfNotRemoved = 0;
- // Removing unnecessary KeyValues and KeyFrames
- List newKeyValues = new ArrayList<>();
- for (int i = 0; i < timeline.getKeyFrames().size(); i++) {
- KeyFrame keyFrame = timeline.getKeyFrames().get(i);
- List keyValuesToRemove = toRemove.get(keyFrame);
- if (keyValuesToRemove != null) {
- newKeyValues.clear();
- for (KeyValue keyValue : keyFrame.getValues()) {
- if (keyValuesToRemove.remove(keyValue)) {
- kvRemoved++;
- } else {
- if (convertToDiscrete) {
- newKeyValues.add(new KeyValue((WritableValue)keyValue.getTarget(), keyValue.getEndValue(), Interpolator.DISCRETE));
- } else {
- newKeyValues.add(keyValue);
- }
- }
- }
- } else if (convertToDiscrete) {
- newKeyValues.clear();
- for (KeyValue keyValue : keyFrame.getValues()) {
- newKeyValues.add(new KeyValue((WritableValue)keyValue.getTarget(), keyValue.getEndValue(), Interpolator.DISCRETE));
- }
- }
- if (keyValuesToRemove != null || convertToDiscrete) {
- if (newKeyValues.isEmpty()) {
- if (keyFrame.getOnFinished() == null) {
- if (keyFrame.getName() != null) {
- System.err.println("Removed KeyFrame with name = " + keyFrame.getName());
- }
- timeline.getKeyFrames().remove(i);
- i--;
- kfRemoved++;
- continue; // for i
- } else {
- kfNotRemoved++;
- }
- } else {
- keyFrame = new KeyFrame(keyFrame.getTime(), keyFrame.getName(), keyFrame.getOnFinished(), newKeyValues);
- timeline.getKeyFrames().set(i, keyFrame);
- kfSimplified++;
- }
- }
- // collecting bound targets
- for (KeyValue keyValue : keyFrame.getValues()) {
- WritableValue> target = keyValue.getTarget();
- if (target instanceof Property) {
- Property p = (Property) target;
- Object bean = p.getBean();
- if (bean instanceof Transform) {
- bound.add((Transform) bean);
- } else {
- throw new UnsupportedOperationException("Bean is not transform, bean = " + bean);
- }
- } else {
- throw new UnsupportedOperationException("WritableValue is not property, can't identify what it changes, target = " + target);
- }
- }
- }
-// System.out.println("bound.size() = " + bound.size());
- System.out.printf("Removed %d (%.2f%%) repeating KeyValues out of total %d.\n", kvRemoved, 100d * kvRemoved / kvTotal, kvTotal);
- System.out.printf("Removed %d (%.2f%%) and simplified %d (%.2f%%) KeyFrames out of total %d. %d (%.2f%%) were not removed due to event handler attached.\n",
- kfRemoved, 100d * kfRemoved / kfTotal,
- kfSimplified, 100d * kfSimplified / kfTotal, kfTotal, kfNotRemoved, 100d * kfNotRemoved / kfTotal);
- int check = 0;
- for (KeyFrame keyFrame : timeline.getKeyFrames()) {
- check += keyFrame.getValues().size();
-// for (KeyValue keyValue : keyFrame.getValues()) {
-// if (keyValue.getInterpolator() != Interpolator.DISCRETE) {
-// throw new IllegalStateException();
-// }
-// }
- }
- System.out.printf("Now there are %d KeyValues and %d KeyFrames.\n", check, timeline.getKeyFrames().size());
- }
-
- private void removeEmptyGroups() {
- for (Parent p : emptyParents) {
- Parent parent = p.getParent();
- Group g = (Group) parent;
- g.getChildren().addAll(p.getChildrenUnmodifiable());
- g.getChildren().remove(p);
- }
- }
-
- private static class KeyFrameComparator implements Comparator {
-
- public KeyFrameComparator() {
- }
-
- @Override public int compare(KeyFrame o1, KeyFrame o2) {
-// int compareTo = o1.getTime().compareTo(o2.getTime());
-// if (compareTo == 0 && o1 != o2) {
-// System.err.println("those two KeyFrames are equal: o1 = " + o1.getTime() + " and o2 = " + o2.getTime());
-// }
- return o1.getTime().compareTo(o2.getTime());
- }
- }
-
-}
diff --git a/src/main/java/eu/mihosoft/jcsg/ext/org/poly2tri/AdvancingFront.java b/src/main/java/eu/mihosoft/jcsg/ext/org/poly2tri/AdvancingFront.java
deleted file mode 100644
index c565baf4..00000000
--- a/src/main/java/eu/mihosoft/jcsg/ext/org/poly2tri/AdvancingFront.java
+++ /dev/null
@@ -1,175 +0,0 @@
-/**
- * AdvancingFront.java
- *
- * Copyright 2014-2014 Michael Hoffer . 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 "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 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 .
- */
-
-package eu.mihosoft.jcsg.ext.org.poly2tri;
-/* Poly2Tri
- * Copyright (c) 2009-2010, Poly2Tri Contributors
- * http://code.google.com/p/poly2tri/
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * * 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.
- * * Neither the name of Poly2Tri nor the names of its contributors may be
- * used to endorse or promote products derived from this software without specific
- * prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "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 THE COPYRIGHT OWNER 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.
- */
-
-/**
- * @author Thomas ??? (thahlen@gmail.com)
- */
-class AdvancingFront {
-
- public AdvancingFrontNode head;
- public AdvancingFrontNode tail;
- protected AdvancingFrontNode search;
-
- public AdvancingFront(AdvancingFrontNode head, AdvancingFrontNode tail) {
- this.head = head;
- this.tail = tail;
- this.search = head;
- addNode(head);
- addNode(tail);
- }
-
- public void addNode(AdvancingFrontNode node) {
-// _searchTree.put( node.key, node );
- }
-
- public void removeNode(AdvancingFrontNode node) {
-// _searchTree.delete( node.key );
- }
-
- public String toString() {
- StringBuilder sb = new StringBuilder();
- AdvancingFrontNode node = head;
- while (node != tail) {
- sb.append(node.point.getX()).append("->");
- node = node.next;
- }
- sb.append(tail.point.getX());
- return sb.toString();
- }
-
- private final AdvancingFrontNode findSearchNode(double x) {
- // TODO: implement BST index
- return search;
- }
-
- /**
- * We use a balancing tree to locate a node smaller or equal to given key
- * value
- *
- * @param x
- * @return
- */
- public AdvancingFrontNode locateNode(TriangulationPoint point) {
- return locateNode(point.getX());
- }
-
- private AdvancingFrontNode locateNode(double x) {
- AdvancingFrontNode node = findSearchNode(x);
- if (x < node.value) {
- while ((node = node.prev) != null) {
- if (x >= node.value) {
- search = node;
- return node;
- }
- }
- } else {
- while ((node = node.next) != null) {
- if (x < node.value) {
- search = node.prev;
- return node.prev;
- }
- }
- }
- return null;
- }
-
- /**
- * This implementation will use simple node traversal algorithm to find a
- * point on the front
- *
- * @param point
- * @return
- */
- public AdvancingFrontNode locatePoint(final TriangulationPoint point) {
- final double px = point.getX();
- AdvancingFrontNode node = findSearchNode(px);
- final double nx = node.point.getX();
-
- if (px == nx) {
- if (point != node.point) {
- // We might have two nodes with same x value for a short time
- if (point == node.prev.point) {
- node = node.prev;
- } else if (point == node.next.point) {
- node = node.next;
- } else {
- throw new RuntimeException("Failed to find Node for given afront point");
-// node = null;
- }
- }
- } else if (px < nx) {
- while ((node = node.prev) != null) {
- if (point == node.point) {
- break;
- }
- }
- } else {
- while ((node = node.next) != null) {
- if (point == node.point) {
- break;
- }
- }
- }
- search = node;
- return node;
- }
-}
diff --git a/src/main/java/eu/mihosoft/jcsg/ext/org/poly2tri/AdvancingFrontIndex.java b/src/main/java/eu/mihosoft/jcsg/ext/org/poly2tri/AdvancingFrontIndex.java
deleted file mode 100644
index 5a1addb7..00000000
--- a/src/main/java/eu/mihosoft/jcsg/ext/org/poly2tri/AdvancingFrontIndex.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/**
- * AdvancingFrontIndex.java
- *
- * Copyright 2014-2014 Michael Hoffer . 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 "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 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 .
- */
-
-package eu.mihosoft.jcsg.ext.org.poly2tri;
-/* Poly2Tri
- * Copyright (c) 2009-2010, Poly2Tri Contributors
- * http://code.google.com/p/poly2tri/
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * * 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.
- * * Neither the name of Poly2Tri nor the names of its contributors may be
- * used to endorse or promote products derived from this software without specific
- * prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "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 THE COPYRIGHT OWNER 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.
- */
-class AdvancingFrontIndex
-{
- double _min,_max;
- IndexNode _root;
-
- public AdvancingFrontIndex( double min, double max, int depth )
- {
- if( depth > 5 ) depth = 5;
- _root = createIndex( depth );
- }
-
- private IndexNode createIndex( int n )
- {
- IndexNode node = null;
- if( n > 0 )
- {
- node = new IndexNode();
- node.bigger = createIndex( n-1 );
- node.smaller = createIndex( n-1 );
- }
- return node;
- }
-
- public A fetchAndRemoveIndex( A key )
- {
- return null;
- }
-
- public A fetchAndInsertIndex( A key )
- {
- return null;
- }
-
- class IndexNode
- {
- A value;
- IndexNode smaller;
- IndexNode bigger;
- double range;
- }
-}
diff --git a/src/main/java/eu/mihosoft/jcsg/ext/org/poly2tri/AdvancingFrontNode.java b/src/main/java/eu/mihosoft/jcsg/ext/org/poly2tri/AdvancingFrontNode.java
deleted file mode 100644
index 50743b72..00000000
--- a/src/main/java/eu/mihosoft/jcsg/ext/org/poly2tri/AdvancingFrontNode.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/**
- * AdvancingFrontNode.java
- *
- * Copyright 2014-2014 Michael Hoffer . 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 "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 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 .
- */
-
-package eu.mihosoft.jcsg.ext.org.poly2tri;
-/* Poly2Tri
- * Copyright (c) 2009-2010, Poly2Tri Contributors
- * http://code.google.com/p/poly2tri/
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * * 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.
- * * Neither the name of Poly2Tri nor the names of its contributors may be
- * used to endorse or promote products derived from this software without specific
- * prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "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 THE COPYRIGHT OWNER 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.
- */
-
-
-class AdvancingFrontNode
-{
- protected AdvancingFrontNode next = null;
- protected AdvancingFrontNode prev = null;
-
- protected final Double key; // XXX: BST
- protected final double value;
- protected final TriangulationPoint point;
- protected DelaunayTriangle triangle;
-
- public AdvancingFrontNode( TriangulationPoint point )
- {
- this.point = point;
- value = point.getX();
- key = Double.valueOf( value ); // XXX: BST
- }
-
- public AdvancingFrontNode getNext()
- {
- return next;
- }
-
- public AdvancingFrontNode getPrevious()
- {
- return prev;
- }
-
- public TriangulationPoint getPoint()
- {
- return point;
- }
-
- public DelaunayTriangle getTriangle()
- {
- return triangle;
- }
-
- public boolean hasNext()
- {
- return next != null;
- }
-
- public boolean hasPrevious()
- {
- return prev != null;
- }
-}
diff --git a/src/main/java/eu/mihosoft/jcsg/ext/org/poly2tri/AnyToXYTransform.java b/src/main/java/eu/mihosoft/jcsg/ext/org/poly2tri/AnyToXYTransform.java
deleted file mode 100644
index 13d631dd..00000000
--- a/src/main/java/eu/mihosoft/jcsg/ext/org/poly2tri/AnyToXYTransform.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/**
- * AnyToXYTransform.java
- *
- * Copyright 2014-2014 Michael Hoffer . 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 "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 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