Skip to content

Commit

Permalink
fixes issue #42 for STL files : #42
Browse files Browse the repository at this point in the history
  • Loading branch information
miho committed Aug 18, 2017
1 parent cefce7f commit dcce1e3
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 71 deletions.
125 changes: 54 additions & 71 deletions src/main/java/eu/mihosoft/jcsg/CSG.java
Original file line number Diff line number Diff line change
@@ -1,47 +1,47 @@
/**
* CSG.java
*
* Copyright 2014-2014 Michael Hoffer <[email protected]>. All rights
* reserved.
* Copyright 2014-2014 Michael Hoffer <[email protected]>. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 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.
* 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.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY Michael Hoffer <[email protected]> "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL Michael Hoffer <[email protected]> OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* THIS SOFTWARE IS PROVIDED BY Michael Hoffer <[email protected]> "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL Michael Hoffer <[email protected]> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of Michael Hoffer
* The views and conclusions contained in the software and documentation are those of the authors and should not be
* interpreted as representing official policies, either expressed or implied, of Michael Hoffer
* <[email protected]>.
*/
package eu.mihosoft.jcsg;

import static eu.mihosoft.jcsg.STL.file;
import eu.mihosoft.vvecmath.Vector3d;
import eu.mihosoft.vvecmath.Transform;
import eu.mihosoft.jcsg.ext.quickhull3d.HullUtil;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javafx.scene.paint.Color;
Expand All @@ -53,29 +53,25 @@
* This implementation is a Java port of
* <a
* href="https://github.com/evanw/csg.js/">https://github.com/evanw/csg.js/</a>
* with some additional features like polygon extrude, transformations etc.
* Thanks to the author for creating the CSG.js library.<br><br>
* with some additional features like polygon extrude, transformations etc. Thanks to the author for creating the CSG.js
* library.<br><br>
*
* <b>Implementation Details</b>
*
* 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:
* 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:
*
* <blockquote><pre>
* a.clipTo(b);
* b.clipTo(a);
* a.build(b.allPolygons());
* </pre></blockquote>
*
* 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:
* 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:
*
* <blockquote><pre>
* a.clipTo(b);
Expand All @@ -86,9 +82,8 @@
* a.build(b.allPolygons());
* </pre></blockquote>
*
* 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 =
* 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 {
Expand Down Expand Up @@ -203,8 +198,7 @@ public CSG optimization(OptType type) {
}

/**
* Return a new CSG solid representing the union of this csg and the
* specified csg.
* Return a new CSG solid representing the union of this csg and the specified csg.
*
* <b>Note:</b> Neither this csg nor the specified csg are weighted.
*
Expand Down Expand Up @@ -240,20 +234,17 @@ public CSG union(CSG csg) {
}

/**
* Returns a csg consisting of the polygons of this csg and the specified
* 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.
* The purpose of this method is to allow fast union operations for objects that do not intersect.
*
* <p>
* <b>WARNING:</b> this method does not apply the csg algorithms. Therefore,
* please ensure that this csg and the specified csg do not intersect.
* <b>WARNING:</b> 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
* @return a csg consisting of the polygons of this csg and the specified csg
*/
public CSG dumbUnion(CSG csg) {

Expand All @@ -266,8 +257,7 @@ public CSG dumbUnion(CSG csg) {
}

/**
* Return a new CSG solid representing the union of this csg and the
* specified csgs.
* Return a new CSG solid representing the union of this csg and the specified csgs.
*
* <b>Note:</b> Neither this csg nor the specified csg are weighted.
*
Expand Down Expand Up @@ -301,8 +291,7 @@ public CSG union(List<CSG> csgs) {
}

/**
* Return a new CSG solid representing the union of this csg and the
* specified csgs.
* Return a new CSG solid representing the union of this csg and the specified csgs.
*
* <b>Note:</b> Neither this csg nor the specified csg are weighted.
*
Expand Down Expand Up @@ -414,9 +403,8 @@ private CSG _unionPolygonBoundsOpt(CSG csg) {
}

/**
* 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.
* 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
Expand Down Expand Up @@ -458,8 +446,7 @@ private CSG _unionNoOpt(CSG csg) {
}

/**
* Return a new CSG solid representing the difference of this csg and the
* specified csgs.
* Return a new CSG solid representing the difference of this csg and the specified csgs.
*
* <b>Note:</b> Neither this csg nor the specified csgs are weighted.
*
Expand Down Expand Up @@ -495,8 +482,7 @@ public CSG difference(List<CSG> csgs) {
}

/**
* Return a new CSG solid representing the difference of this csg and the
* specified csgs.
* Return a new CSG solid representing the difference of this csg and the specified csgs.
*
* <b>Note:</b> Neither this csg nor the specified csgs are weighted.
*
Expand All @@ -522,8 +508,7 @@ public CSG difference(CSG... csgs) {
}

/**
* Return a new CSG solid representing the difference of this csg and the
* specified csg.
* Return a new CSG solid representing the difference of this csg and the specified csg.
*
* <b>Note:</b> Neither this csg nor the specified csg are weighted.
*
Expand Down Expand Up @@ -606,8 +591,7 @@ private CSG _differenceNoOpt(CSG csg) {
}

/**
* Return a new CSG solid representing the intersection of this csg and the
* specified csg.
* Return a new CSG solid representing the intersection of this csg and the specified csg.
*
* <b>Note:</b> Neither this csg nor the specified csg are weighted.
*
Expand Down Expand Up @@ -643,8 +627,7 @@ public CSG intersect(CSG csg) {
}

/**
* Return a new CSG solid representing the intersection of this csg and the
* specified csgs.
* Return a new CSG solid representing the intersection of this csg and the specified csgs.
*
* <b>Note:</b> Neither this csg nor the specified csgs are weighted.
*
Expand Down Expand Up @@ -681,8 +664,7 @@ public CSG intersect(List<CSG> csgs) {
}

/**
* Return a new CSG solid representing the intersection of this csg and the
* specified csgs.
* Return a new CSG solid representing the intersection of this csg and the specified csgs.
*
* <b>Note:</b> Neither this csg nor the specified csgs are weighted.
*
Expand Down Expand Up @@ -719,6 +701,7 @@ public String toStlString() {
return sb.toString();
}


/**
* Returns this csg in STL string format.
*
Expand Down Expand Up @@ -755,8 +738,8 @@ public ObjFile toObj() {
}

public ObjFile toObj(int maxNumberOfVerts) {
if(maxNumberOfVerts != 3) {

if (maxNumberOfVerts != 3) {
throw new UnsupportedOperationException(
"maxNumberOfVerts > 3 not supported yet");
}
Expand Down Expand Up @@ -1126,7 +1109,7 @@ public Bounds getBounds() {
if (polygons.isEmpty()) {
return new Bounds(Vector3d.ZERO, Vector3d.ZERO);
}

Vector3d initial = polygons.get(0).vertices.get(0).pos;

double minX = initial.x();
Expand Down
28 changes: 28 additions & 0 deletions src/main/java/eu/mihosoft/jcsg/FileUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
* File util class.
Expand Down Expand Up @@ -74,4 +76,30 @@ public static void write(Path p, String s) throws IOException {
public static String read(Path p) throws IOException {
return new String(Files.readAllBytes(p), Charset.forName("UTF-8"));
}


/**
* Saves the specified csg using STL ASCII format.
*
* @param path destination path
* @param csg csg to save
* @throws java.io.IOException
*/
public static void toStlFile(Path path, CSG csg) throws IOException {
try (BufferedWriter out = Files.newBufferedWriter(path, Charset.forName("UTF-8"),
StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) {

out.append("solid v3d.csg\n");
csg.getPolygons().stream().forEach(
(Polygon p) -> {
try {
out.append(p.toStlString());
} catch (IOException ex) {
Logger.getLogger(CSG.class.getName()).log(Level.SEVERE, null, ex);
throw new RuntimeException(ex);
}
});
out.append("endsolid v3d.csg\n");
}
}
}

0 comments on commit dcce1e3

Please sign in to comment.