Skip to content

Commit dcce1e3

Browse files
committed
fixes issue #42 for STL files : #42
1 parent cefce7f commit dcce1e3

File tree

2 files changed

+82
-71
lines changed

2 files changed

+82
-71
lines changed

src/main/java/eu/mihosoft/jcsg/CSG.java

Lines changed: 54 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,47 @@
11
/**
22
* CSG.java
33
*
4-
* Copyright 2014-2014 Michael Hoffer <info@michaelhoffer.de>. All rights
5-
* reserved.
4+
* Copyright 2014-2014 Michael Hoffer <info@michaelhoffer.de>. All rights reserved.
65
*
7-
* Redistribution and use in source and binary forms, with or without
8-
* modification, are permitted provided that the following conditions are met:
6+
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
7+
* following conditions are met:
98
*
10-
* 1. Redistributions of source code must retain the above copyright notice,
11-
* this list of conditions and the following disclaimer.
9+
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
10+
* disclaimer.
1211
*
13-
* 2. Redistributions in binary form must reproduce the above copyright notice,
14-
* this list of conditions and the following disclaimer in the documentation
15-
* and/or other materials provided with the distribution.
12+
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
13+
* following disclaimer in the documentation and/or other materials provided with the distribution.
1614
*
17-
* THIS SOFTWARE IS PROVIDED BY Michael Hoffer <info@michaelhoffer.de> "AS IS"
18-
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19-
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20-
* ARE DISCLAIMED. IN NO EVENT SHALL Michael Hoffer <info@michaelhoffer.de> OR
21-
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22-
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23-
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24-
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25-
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26-
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27-
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
15+
* THIS SOFTWARE IS PROVIDED BY Michael Hoffer <info@michaelhoffer.de> "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
16+
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17+
* DISCLAIMED. IN NO EVENT SHALL Michael Hoffer <info@michaelhoffer.de> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
18+
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20+
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
21+
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2822
*
29-
* The views and conclusions contained in the software and documentation are
30-
* those of the authors and should not be interpreted as representing official
31-
* policies, either expressed or implied, of Michael Hoffer
23+
* The views and conclusions contained in the software and documentation are those of the authors and should not be
24+
* interpreted as representing official policies, either expressed or implied, of Michael Hoffer
3225
* <info@michaelhoffer.de>.
3326
*/
3427
package eu.mihosoft.jcsg;
3528

29+
import static eu.mihosoft.jcsg.STL.file;
3630
import eu.mihosoft.vvecmath.Vector3d;
3731
import eu.mihosoft.vvecmath.Transform;
3832
import eu.mihosoft.jcsg.ext.quickhull3d.HullUtil;
33+
import java.io.BufferedWriter;
34+
import java.io.File;
35+
import java.io.FileWriter;
36+
import java.io.IOException;
3937

4038
import java.util.ArrayList;
4139
import java.util.Arrays;
4240
import java.util.HashMap;
4341
import java.util.List;
4442
import java.util.Map;
43+
import java.util.logging.Level;
44+
import java.util.logging.Logger;
4545
import java.util.stream.Collectors;
4646
import java.util.stream.Stream;
4747
import javafx.scene.paint.Color;
@@ -53,29 +53,25 @@
5353
* This implementation is a Java port of
5454
* <a
5555
* href="https://github.com/evanw/csg.js/">https://github.com/evanw/csg.js/</a>
56-
* with some additional features like polygon extrude, transformations etc.
57-
* Thanks to the author for creating the CSG.js library.<br><br>
56+
* with some additional features like polygon extrude, transformations etc. Thanks to the author for creating the CSG.js
57+
* library.<br><br>
5858
*
5959
* <b>Implementation Details</b>
6060
*
61-
* All CSG operations are implemented in terms of two functions,
62-
* {@link Node#clipTo(Node)} and {@link Node#invert()}, which remove parts of a
63-
* BSP tree inside another BSP tree and swap solid and empty space,
64-
* respectively. To find the union of {@code a} and {@code b}, we want to remove
65-
* everything in {@code a} inside {@code b} and everything in {@code b} inside
66-
* {@code a}, then combine polygons from {@code a} and {@code b} into one solid:
61+
* All CSG operations are implemented in terms of two functions, {@link Node#clipTo(Node)} and {@link Node#invert()},
62+
* which remove parts of a BSP tree inside another BSP tree and swap solid and empty space, respectively. To find the
63+
* union of {@code a} and {@code b}, we want to remove everything in {@code a} inside {@code b} and everything in
64+
* {@code b} inside {@code a}, then combine polygons from {@code a} and {@code b} into one solid:
6765
*
6866
* <blockquote><pre>
6967
* a.clipTo(b);
7068
* b.clipTo(a);
7169
* a.build(b.allPolygons());
7270
* </pre></blockquote>
7371
*
74-
* The only tricky part is handling overlapping coplanar polygons in both trees.
75-
* The code above keeps both copies, but we need to keep them in one tree and
76-
* remove them in the other tree. To remove them from {@code b} we can clip the
77-
* inverse of {@code b} against {@code a}. The code for union now looks like
78-
* this:
72+
* The only tricky part is handling overlapping coplanar polygons in both trees. The code above keeps both copies, but
73+
* 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
74+
* inverse of {@code b} against {@code a}. The code for union now looks like this:
7975
*
8076
* <blockquote><pre>
8177
* a.clipTo(b);
@@ -86,9 +82,8 @@
8682
* a.build(b.allPolygons());
8783
* </pre></blockquote>
8884
*
89-
* Subtraction and intersection naturally follow from set operations. If union
90-
* is {@code A | B}, differenceion is {@code A - B = ~(~A | B)} and intersection
91-
* is {@code A & B =
85+
* Subtraction and intersection naturally follow from set operations. If union is {@code A | B}, differenceion is
86+
* {@code A - B = ~(~A | B)} and intersection is {@code A & B =
9287
* ~(~A | ~B)} where {@code ~} is the complement operator.
9388
*/
9489
public class CSG {
@@ -203,8 +198,7 @@ public CSG optimization(OptType type) {
203198
}
204199

205200
/**
206-
* Return a new CSG solid representing the union of this csg and the
207-
* specified csg.
201+
* Return a new CSG solid representing the union of this csg and the specified csg.
208202
*
209203
* <b>Note:</b> Neither this csg nor the specified csg are weighted.
210204
*
@@ -240,20 +234,17 @@ public CSG union(CSG csg) {
240234
}
241235

242236
/**
243-
* Returns a csg consisting of the polygons of this csg and the specified
244-
* csg.
237+
* Returns a csg consisting of the polygons of this csg and the specified csg.
245238
*
246-
* The purpose of this method is to allow fast union operations for objects
247-
* that do not intersect.
239+
* The purpose of this method is to allow fast union operations for objects that do not intersect.
248240
*
249241
* <p>
250-
* <b>WARNING:</b> this method does not apply the csg algorithms. Therefore,
251-
* please ensure that this csg and the specified csg do not intersect.
242+
* <b>WARNING:</b> this method does not apply the csg algorithms. Therefore, please ensure that this csg and the
243+
* specified csg do not intersect.
252244
*
253245
* @param csg csg
254246
*
255-
* @return a csg consisting of the polygons of this csg and the specified
256-
* csg
247+
* @return a csg consisting of the polygons of this csg and the specified csg
257248
*/
258249
public CSG dumbUnion(CSG csg) {
259250

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

268259
/**
269-
* Return a new CSG solid representing the union of this csg and the
270-
* specified csgs.
260+
* Return a new CSG solid representing the union of this csg and the specified csgs.
271261
*
272262
* <b>Note:</b> Neither this csg nor the specified csg are weighted.
273263
*
@@ -301,8 +291,7 @@ public CSG union(List<CSG> csgs) {
301291
}
302292

303293
/**
304-
* Return a new CSG solid representing the union of this csg and the
305-
* specified csgs.
294+
* Return a new CSG solid representing the union of this csg and the specified csgs.
306295
*
307296
* <b>Note:</b> Neither this csg nor the specified csg are weighted.
308297
*
@@ -414,9 +403,8 @@ private CSG _unionPolygonBoundsOpt(CSG csg) {
414403
}
415404

416405
/**
417-
* Optimizes for intersection. If csgs do not intersect create a new csg
418-
* that consists of the polygon lists of this csg and the specified csg. In
419-
* this case no further space partitioning is performed.
406+
* Optimizes for intersection. If csgs do not intersect create a new csg that consists of the polygon lists of this
407+
* csg and the specified csg. In this case no further space partitioning is performed.
420408
*
421409
* @param csg csg
422410
* @return the union of this csg and the specified csg
@@ -458,8 +446,7 @@ private CSG _unionNoOpt(CSG csg) {
458446
}
459447

460448
/**
461-
* Return a new CSG solid representing the difference of this csg and the
462-
* specified csgs.
449+
* Return a new CSG solid representing the difference of this csg and the specified csgs.
463450
*
464451
* <b>Note:</b> Neither this csg nor the specified csgs are weighted.
465452
*
@@ -495,8 +482,7 @@ public CSG difference(List<CSG> csgs) {
495482
}
496483

497484
/**
498-
* Return a new CSG solid representing the difference of this csg and the
499-
* specified csgs.
485+
* Return a new CSG solid representing the difference of this csg and the specified csgs.
500486
*
501487
* <b>Note:</b> Neither this csg nor the specified csgs are weighted.
502488
*
@@ -522,8 +508,7 @@ public CSG difference(CSG... csgs) {
522508
}
523509

524510
/**
525-
* Return a new CSG solid representing the difference of this csg and the
526-
* specified csg.
511+
* Return a new CSG solid representing the difference of this csg and the specified csg.
527512
*
528513
* <b>Note:</b> Neither this csg nor the specified csg are weighted.
529514
*
@@ -606,8 +591,7 @@ private CSG _differenceNoOpt(CSG csg) {
606591
}
607592

608593
/**
609-
* Return a new CSG solid representing the intersection of this csg and the
610-
* specified csg.
594+
* Return a new CSG solid representing the intersection of this csg and the specified csg.
611595
*
612596
* <b>Note:</b> Neither this csg nor the specified csg are weighted.
613597
*
@@ -643,8 +627,7 @@ public CSG intersect(CSG csg) {
643627
}
644628

645629
/**
646-
* Return a new CSG solid representing the intersection of this csg and the
647-
* specified csgs.
630+
* Return a new CSG solid representing the intersection of this csg and the specified csgs.
648631
*
649632
* <b>Note:</b> Neither this csg nor the specified csgs are weighted.
650633
*
@@ -681,8 +664,7 @@ public CSG intersect(List<CSG> csgs) {
681664
}
682665

683666
/**
684-
* Return a new CSG solid representing the intersection of this csg and the
685-
* specified csgs.
667+
* Return a new CSG solid representing the intersection of this csg and the specified csgs.
686668
*
687669
* <b>Note:</b> Neither this csg nor the specified csgs are weighted.
688670
*
@@ -719,6 +701,7 @@ public String toStlString() {
719701
return sb.toString();
720702
}
721703

704+
722705
/**
723706
* Returns this csg in STL string format.
724707
*
@@ -755,8 +738,8 @@ public ObjFile toObj() {
755738
}
756739

757740
public ObjFile toObj(int maxNumberOfVerts) {
758-
759-
if(maxNumberOfVerts != 3) {
741+
742+
if (maxNumberOfVerts != 3) {
760743
throw new UnsupportedOperationException(
761744
"maxNumberOfVerts > 3 not supported yet");
762745
}
@@ -1126,7 +1109,7 @@ public Bounds getBounds() {
11261109
if (polygons.isEmpty()) {
11271110
return new Bounds(Vector3d.ZERO, Vector3d.ZERO);
11281111
}
1129-
1112+
11301113
Vector3d initial = polygons.get(0).vertices.get(0).pos;
11311114

11321115
double minX = initial.x();

src/main/java/eu/mihosoft/jcsg/FileUtil.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@
3636
import java.nio.file.Files;
3737
import java.nio.file.Path;
3838
import java.nio.file.StandardOpenOption;
39+
import java.util.logging.Level;
40+
import java.util.logging.Logger;
3941

4042
/**
4143
* File util class.
@@ -74,4 +76,30 @@ public static void write(Path p, String s) throws IOException {
7476
public static String read(Path p) throws IOException {
7577
return new String(Files.readAllBytes(p), Charset.forName("UTF-8"));
7678
}
79+
80+
81+
/**
82+
* Saves the specified csg using STL ASCII format.
83+
*
84+
* @param path destination path
85+
* @param csg csg to save
86+
* @throws java.io.IOException
87+
*/
88+
public static void toStlFile(Path path, CSG csg) throws IOException {
89+
try (BufferedWriter out = Files.newBufferedWriter(path, Charset.forName("UTF-8"),
90+
StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) {
91+
92+
out.append("solid v3d.csg\n");
93+
csg.getPolygons().stream().forEach(
94+
(Polygon p) -> {
95+
try {
96+
out.append(p.toStlString());
97+
} catch (IOException ex) {
98+
Logger.getLogger(CSG.class.getName()).log(Level.SEVERE, null, ex);
99+
throw new RuntimeException(ex);
100+
}
101+
});
102+
out.append("endsolid v3d.csg\n");
103+
}
104+
}
77105
}

0 commit comments

Comments
 (0)