diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8c029aa7..f4d26d7b 100755 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -36,6 +36,22 @@ jobs: ls -al . sudo apt install gnupg1 + - name: start xvfb + run: + Xvfb :0 & + + - name: initialize the X11 DISPLAY variable + run: + export DISPLAY=:0 + + - name: Install libraries + run: | + sudo apt update + sudo apt install libgtk2.0-0 + + - name: Test with Gradle + run: xvfb-run -s '-screen 0 1024x768x24' ./gradlew test + - name: Publish package run: bash publish.sh env: diff --git a/src/main/java/com/neuronrobotics/javacad/JavaCadBuildInfo.java b/src/main/java/com/neuronrobotics/javacad/JavaCadBuildInfo.java index 807acd8f..1b635ee8 100644 --- a/src/main/java/com/neuronrobotics/javacad/JavaCadBuildInfo.java +++ b/src/main/java/com/neuronrobotics/javacad/JavaCadBuildInfo.java @@ -62,6 +62,10 @@ public static int getBuildVersion() { public static int[] getBuildInfo() { String s = getVersion(); String[] splits = s.split("[.]+"); + if (splits.length == 1) { + return new int[]{0, 0, 0}; + } + int[] rev = new int[3]; for (int i = 0; i < 3; i++) { rev[i] = new Integer(splits[i]); diff --git a/src/main/java/eu/mihosoft/vrl/v3d/CSG.java b/src/main/java/eu/mihosoft/vrl/v3d/CSG.java index a13f7a16..aa0dcb5a 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/CSG.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/CSG.java @@ -41,6 +41,7 @@ import eu.mihosoft.vrl.v3d.parametrics.LengthParameter; import eu.mihosoft.vrl.v3d.parametrics.Parameter; +import java.awt.Font; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -62,7 +63,6 @@ import javafx.scene.shape.CullFace; import javafx.scene.shape.DrawMode; import javafx.scene.shape.MeshView; -import javafx.scene.text.Font; import javafx.scene.transform.Affine; /** @@ -1257,7 +1257,7 @@ public CSG difference(CSG csg) { * @return the csg */ private CSG _differenceCSGBoundsOpt(CSG csg) { - CSG a1 = this._differenceNoOpt(csg.getBounds().toCSG()); + CSG a1 = this._differenceNoOpt(csg.getBounds().toCSG().setColor(csg.getColor())); CSG a2 = this.intersect(csg.getBounds().toCSG()); CSG result = a2._differenceNoOpt(csg)._unionIntersectOpt(a1).optimization(getOptType()); if (getName().length() != 0 && csg.getName().length() != 0) { @@ -2969,7 +2969,7 @@ public int getPrintBedIndex() { } public static CSG text(String text, double height, double fontSize) { - return text(text, height, fontSize, Font.getDefault().getName()); + return text(text, height, fontSize, Font.SANS_SERIF); } public static CSG text(String text, double height) { @@ -2977,15 +2977,8 @@ public static CSG text(String text, double height) { } public static CSG text(String text, double height, double fontSize, String fontType) { - javafx.scene.text.Font font = new javafx.scene.text.Font(fontType, fontSize); - if (!font.getName().toLowerCase().contains(fontType.toLowerCase())) { - String options = ""; - for (String name : javafx.scene.text.Font.getFontNames()) { - options += name + "\n"; - } - new Exception(options + "\nIs Not " + fontType + " instead got " + font.getName()).printStackTrace(); - } - ArrayList stuff = TextExtrude.text(height, text, font); + Font font = new Font(fontType, Font.PLAIN, (int)fontSize); + List stuff = TextExtrude.text(height, text, font); CSG back = null; for (int i = 0; i < stuff.size(); i++) { if (back == null) diff --git a/src/main/java/eu/mihosoft/vrl/v3d/Text3d.java b/src/main/java/eu/mihosoft/vrl/v3d/Text3d.java index 86440e30..8c00ac4d 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/Text3d.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/Text3d.java @@ -1,19 +1,19 @@ /** * Text3d.java - * + *

* Copyright 2014-2016 Michael Hoffer info@michaelhoffer.de. 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 info@michaelhoffer.de "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -25,7 +25,7 @@ * 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 @@ -35,73 +35,70 @@ import java.util.ArrayList; import java.util.List; +import java.awt.Font; +import java.util.logging.Level; +import java.util.logging.Logger; -import javafx.scene.text.Font; /** - * 3d text primitive. - * + * 3d text primitive. + * * @author Michael Hoffer info@michaelhoffer.de */ public class Text3d extends Primitive { - + private final static Logger LOGGER = Logger.getLogger(Text3d.class.getName()); private final PropertyStorage properties = new PropertyStorage(); - private final ArrayList letters = new ArrayList(); + private final List letters = new ArrayList<>(); + /** * Constructor. - * + * * @param text text */ public Text3d(String text) { - this(text, "Arial", 12, 1.0); + this(text, Font.SANS_SERIF, 12, 1.0); } /** * Constructor. - * - * @param text text + * + * @param text text * @param depth text depth (z thickness) */ public Text3d(String text, double depth) { - this(text, "Arial", 12, depth); + this(text, Font.SANS_SERIF, 12, depth); } /** - * Constructor. - * - * @param text text + * Constructor. + * + * @param text text * @param fontName font name, e.g., "Arial" * @param fontSize font size - * @param depth text depth (z thickness) + * @param depth text depth (z thickness) */ public Text3d(String text, String fontName, double fontSize, double depth) { + Font font = new Font(fontName, Font.PLAIN, (int) fontSize); + if (!font.getFamily().equalsIgnoreCase(fontName)) { + LOGGER.log(Level.INFO, String.format("Fontname '%s' was not found, defaulting to '%s'", fontName, font.getFamily())); + } - Font font = new Font(fontName, (int) fontSize); - if(!font.getName().toLowerCase().contains(fontName.toLowerCase())) { - String options = ""; - for(String name : javafx.scene.text.Font.getFontNames() ) { - options+=name+"\n"; - } - new Exception(options).printStackTrace(); - } - ArrayList tmp = TextExtrude.text( depth, text, font); - letters.clear(); - for (int i=0;i tmp = TextExtrude.text(depth, text, font); + letters.clear(); + for (int i = 0; i < tmp.size(); i++) { + letters.add(tmp.get(i) + .rotx(180) + .toZMin() + ); + } } @Override public List toPolygons() { - List poly =new ArrayList(); - for(CSG c:letters) { - poly.addAll(c.getPolygons()); - } - return poly; + List poly = new ArrayList<>(); + for (CSG c : letters) { + poly.addAll(c.getPolygons()); + } + return poly; } @Override diff --git a/src/main/java/eu/mihosoft/vrl/v3d/TextExtrude.java b/src/main/java/eu/mihosoft/vrl/v3d/TextExtrude.java index 0b50a234..2c7e70f6 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/TextExtrude.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/TextExtrude.java @@ -1,349 +1,152 @@ package eu.mihosoft.vrl.v3d; +import static com.neuronrobotics.javacad.JavaCadBuildInfo.isMac; +import java.awt.Font; +import java.awt.Graphics2D; +import java.awt.Shape; +import java.awt.font.GlyphVector; +import java.awt.geom.PathIterator; +import java.awt.image.BufferedImage; import java.util.ArrayList; -import java.util.HashSet; import java.util.List; - -import javafx.scene.shape.ClosePath; -import javafx.scene.shape.CubicCurveTo; -import javafx.scene.shape.LineTo; -import javafx.scene.shape.MoveTo; -import javafx.scene.shape.Path; -import javafx.scene.shape.PathElement; -import javafx.scene.shape.QuadCurveTo; -import javafx.scene.shape.Rectangle; -import javafx.scene.shape.Shape; -import javafx.scene.text.Font; -import javafx.scene.text.Text; -import java.util.stream.Collectors; import java.util.stream.IntStream; -import javafx.beans.property.DoubleProperty; -import javafx.beans.property.SimpleDoubleProperty; -import javafx.scene.paint.Color; -import javafx.scene.shape.Path; -import javafx.scene.shape.PathElement; -import javafx.scene.shape.MoveTo; -import javafx.scene.shape.LineTo; -import javafx.scene.shape.CubicCurveTo; -import javafx.scene.shape.QuadCurveTo; -import javafx.scene.shape.ClosePath; -import javafx.scene.text.Text; -import eu.mihosoft.vrl.v3d.Vector3d; -import java.util.*; -// TODO: Auto-generated Javadoc /** * The Class Text. */ - @SuppressWarnings("restriction") public class TextExtrude { - private static final String default_font = "FreeSerif"; - private final static int POINTS_CURVE = 10; - - private final String text; - // private List points; - // HashSet unique = new HashSet(); - private Vector3d p0; - private final List polis = new ArrayList<>(); - ArrayList sections = new ArrayList(); - ArrayList holes = new ArrayList(); - private double dir; - - class LineSegment { - - /* - * Given one single character in terms of Path, LineSegment stores a list of - * points that define the exterior of one of its polygons (!isHole). It can - * contain reference to one or several holes inside this polygon. Or it can - * define the perimeter of a hole (isHole), with no more holes inside. - */ - - private boolean hole; - private List points; - private Path path; - private Vector3d origen; - private List holes = new ArrayList<>(); - private String letter; - - public LineSegment(String text) { - letter = text; - } - - public String getLetter() { - return letter; - } - - public void setLetter(String letter) { - this.letter = letter; - } - - public boolean isHole() { - return hole; - } - - public void setHole(boolean isHole) { - this.hole = isHole; - } - - public List getPoints() { - return points; - } - - public void setPoints(List points) { - this.points = points; - } - - public Path getPath() { - return path; - } - - public void setPath(Path path) { - this.path = path; - } - - public Vector3d getOrigen() { - return origen; - } - - public void setOrigen(Vector3d origen) { - this.origen = origen; - } - - public List getHoles() { - return holes; - } - - public void setHoles(List holes) { - this.holes = holes; - } - - public void addHole(LineSegment hole) { - holes.add(hole); - } - - @Override - public String toString() { - return "Poly{" + "points=" + points + ", path=" + path + ", origen=" + origen + ", holes=" + holes + '}'; - } - } - - private TextExtrude(String text, Font font, double dir) { - if (dir <= 0) - throw new NumberFormatException("length can not be negative"); - this.dir = dir; - // points = new ArrayList<>(); - this.text = text; - Text textNode = new Text(text); - textNode.setFont(font); - - // Convert Text to Path - Path subtract = (Path) (Shape.subtract(textNode, new Rectangle(0, 0))); - List> outlines = extractOutlines(subtract); - double zOff = 0; - for (List points : outlines) { - boolean hole = Extrude.isCCW(Polygon.fromPoints(points)); - CSG newLetter = Extrude.points(new Vector3d(0, 0, dir), points).movez(zOff); - - if (!hole) - sections.add(newLetter); - else - holes.add(newLetter); - // zOff+=dir; - - } -// // Convert Path elements into lists of points defining the perimeter -// // (exterior or interior) -// subtract.getElements().forEach(this::getPoints); - - for (int i = 0; i < sections.size(); i++) { - for (CSG h : holes) { - try { - if (sections.get(i).touching(h)) { - // println "Hole found " - CSG nl = sections.get(i).difference(h); - - sections.set(i, nl); - } - } catch (Exception e) { - - } - } - } - } - - /** - * Extrudes the specified path (convex or concave polygon without holes or - * intersections, specified in CCW) into the specified direction. - * - * @param dir direction of extrusion - * @param text text - * @param font font configuration of the text - * - * @return a CSG object that consists of the extruded polygon - */ - @SuppressWarnings("restriction") - public static ArrayList text(double dir, String text, Font font) { - - TextExtrude te = new TextExtrude(text, font, dir); - - return te.sections; - } - - public List getLineSegment() { - return polis; - } - - public List getOffset() { - return polis.stream().sorted((p1, p2) -> (int) (p1.getOrigen().x - p2.getOrigen().x)) - .map(LineSegment::getOrigen).collect(Collectors.toList()); - } - -// Below is AI slop - private static final double CURVE_SEGMENTS = 3; // Number of segments to approximate curves - private static final double POINT_EPSILON = 0.0001; // Distance threshold for considering points equal - - /** - * Converts a JavaFX Text object into a list of cleaned vector lists - * representing the outlines - */ - public static List> extractOutlines(Path text) { - List> rawOutlines = extractRawOutlines(text); - List> cleanedOutlines = new ArrayList<>(); - - for (List outline : rawOutlines) { - List cleaned = cleanOutline(outline); - if (cleaned.size() >= 3) { // Only keep outlines with at least 3 points - cleanedOutlines.add(cleaned); - } - } - - return cleanedOutlines; - } - - /** - * Initial extraction of outlines from text - */ - private static List> extractRawOutlines(Path textPath) { - List> allOutlines = new ArrayList<>(); - - List currentPath = new ArrayList<>(); - Vector3d lastPoint = null; - - for (PathElement element : textPath.getElements()) { - if (element instanceof MoveTo) { - if (!currentPath.isEmpty()) { - allOutlines.add(new ArrayList<>(currentPath)); - currentPath.clear(); - } - MoveTo move = (MoveTo) element; - lastPoint = Vector3d.xyz(move.getX(), move.getY(), 0); - currentPath.add(lastPoint); - } else if (element instanceof LineTo) { - LineTo line = (LineTo) element; - lastPoint = Vector3d.xyz(line.getX(), line.getY(), 0); - currentPath.add(lastPoint); - } else if (element instanceof CubicCurveTo) { - CubicCurveTo curve = (CubicCurveTo) element; - List curvePoints = approximateCubicCurve(lastPoint, - Vector3d.xyz(curve.getControlX1(), curve.getControlY1(), 0), - Vector3d.xyz(curve.getControlX2(), curve.getControlY2(), 0), - Vector3d.xyz(curve.getX(), curve.getY(), 0)); - currentPath.addAll(curvePoints); - lastPoint = curvePoints.get(curvePoints.size() - 1); - } else if (element instanceof QuadCurveTo) { - QuadCurveTo curve = (QuadCurveTo) element; - List curvePoints = approximateQuadCurve(lastPoint, - Vector3d.xyz(curve.getControlX(), curve.getControlY(), 0), - Vector3d.xyz(curve.getX(), curve.getY(), 0)); - currentPath.addAll(curvePoints); - lastPoint = curvePoints.get(curvePoints.size() - 1); - } - } - - if (!currentPath.isEmpty()) { - allOutlines.add(currentPath); - } - - return allOutlines; - } - - /** - * Clean an outline by removing duplicate points and ensuring proper closure - */ - private static List cleanOutline(List outline) { - if (outline.isEmpty()) - return outline; - - List cleaned = new ArrayList<>(); - Vector3d prevPoint = null; - - // Process all points - for (Vector3d point : outline) { - if (prevPoint == null || !isNearlyEqual(prevPoint, point)) { - // Only add point if it's significantly different from the previous point - cleaned.add(point); - prevPoint = point; - } - } - // Remove redundant points that form zero-area triangles - return removeRedundantPoints(cleaned); - } - - /** - * Remove points that form zero-area triangles with their neighbors - */ - private static List removeRedundantPoints(List points) { - if (points.size() < 3) - return points; - - List result = new ArrayList<>(); - int size = points.size(); - - for (int i = 0; i < size; i++) { - Vector3d curr = points.get(i); - result.add(curr); - } - - return result; - } - - private static boolean isNearlyEqual(Vector3d v1, Vector3d v2) { - return v1.minus(v2).length() < POINT_EPSILON; - } - - // Bezier curve methods remain the same - private static List approximateCubicCurve(Vector3d start, Vector3d control1, Vector3d control2, - Vector3d end) { - List points = new ArrayList<>(); - for (double i = 1; i <= CURVE_SEGMENTS; i+=1) { - double t = (double) i / CURVE_SEGMENTS; - double x = cubicBezier(start.x, control1.x, control2.x, end.x, t); - double y = cubicBezier(start.y, control1.y, control2.y, end.y, t); - points.add(Vector3d.xyz(x, y, 0)); - } - return points; - } - - private static List approximateQuadCurve(Vector3d start, Vector3d control, Vector3d end) { - List points = new ArrayList<>(); - for (double i = 1; i <= CURVE_SEGMENTS; i+=1) { - double t = (double) i / CURVE_SEGMENTS; - double x = quadBezier(start.x, control.x, end.x, t); - double y = quadBezier(start.y, control.y, end.y, t); - points.add(Vector3d.xyz(x, y, 0)); - } - return points; - } - - private static double cubicBezier(double p0, double p1, double p2, double p3, double t) { - double mt = 1 - t; - return p0 * mt * mt * mt + 3 * p1 * mt * mt * t + 3 * p2 * mt * t * t + p3 * t * t * t; - } - - private static double quadBezier(double p0, double p1, double p2, double t) { - double mt = 1 - t; - return p0 * mt * mt + 2 * p1 * mt * t + p2 * t * t; - } - -} + private static final int CURVE_SEGMENTS = 3; + private final double dir; + private final List sections = new ArrayList<>(); + private final List holes = new ArrayList<>(); + private List points = new ArrayList<>(); + + private TextExtrude(String text, Font font, double dir) { + if (dir <= 0) + throw new NumberFormatException("length can not be negative"); + this.dir = dir; + + BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB); + Graphics2D g2 = img.createGraphics(); + GlyphVector glyphVector = font.createGlyphVector(g2.getFontRenderContext(), text); + Shape shape = glyphVector.getOutline(); + + + double[] coords = new double[8]; + PathIterator pathIterator = shape.getPathIterator(null); + Vector3d startPoint; + while (!pathIterator.isDone()) { + + int i = pathIterator.currentSegment(coords); + + switch (i) { + case PathIterator.SEG_MOVETO: + startPoint = new Vector3d(round(coords[0]), round(coords[1]), 0); + points.add(startPoint); + break; + + case PathIterator.SEG_LINETO: + points.add(new Vector3d(coords[0], coords[1], 0)); + break; + + case PathIterator.SEG_QUADTO: + expandQuadBezier(coords[0], coords[1], coords[2], coords[3]); + break; + + case PathIterator.SEG_CUBICTO: + expandCubicBezier(coords[0], coords[1], coords[2], coords[3], coords[4], coords[5]); + break; + + case PathIterator.SEG_CLOSE: + loadPoints(); + break; + + } + pathIterator.next(); + } + + + for (int i = 0; i < sections.size(); i++) { + for (CSG h : holes) { + try { + if (sections.get(i).touching(h)) { + CSG nl = sections.get(i).difference(h); + + sections.set(i, nl); + } + } catch (Exception e) { + + } + } + } + } + + private static double round(double value) { + return Math.round(value * 100000.0) / 100000.0; + } + + /** + * Extrudes the specified path (convex or concave polygon without holes or + * intersections, specified in CCW) into the specified direction. + * + * @param dir direction of extrusion + * @param text text + * @param font font configuration of the text + * @return a CSG object that consists of the extruded polygon + */ + @SuppressWarnings("restriction") + public static List text(double dir, String text, Font font) { + TextExtrude te = new TextExtrude(text, font, dir); + return te.sections; + } + + private void expandCubicBezier(double x1, double x2, double x3, double y1, double y2, double y3) { + Vector3d ini1 = points.get(points.size() - 1); + IntStream.rangeClosed(1, CURVE_SEGMENTS).forEach(index -> points.add(evalCubicBezier(x1, x2, x3, y1, y2, y3, ini1, ((double) index) / CURVE_SEGMENTS))); + } + + private void expandQuadBezier(double x1, double y1, double x2, double y2) { + final Vector3d start = points.get(points.size() - 1); + IntStream.rangeClosed(1, CURVE_SEGMENTS).forEach(index -> points.add(evalQuadBezier(start, x1, y1, x2, y2, ((double) index) / CURVE_SEGMENTS))); + } + + private void loadPoints() { + if (points.size() > 3) { + if (!isMac()) { + points.remove(points.size() - 1); + } + boolean isHole = !Extrude.isCCW(Polygon.fromPoints(points)); + CSG newLetter = Extrude.points(new Vector3d(0, 0, dir), points); + + if (!isHole) { + sections.add(newLetter); + } else { + holes.add(newLetter); + } + } + points = new ArrayList<>(); + } + + private Vector3d evalCubicBezier(double x1, double x2, double x3, double y1, double y2, double y3, Vector3d ini, double t) { + return new Vector3d((float) (Math.pow(1 - t, 3) * ini.x + + 3 * t * Math.pow(1 - t, 2) * x2 + + 3 * (1 - t) * t * t * x3 + + Math.pow(t, 3) * x1), + (float) (Math.pow(1 - t, 3) * ini.y + + 3 * t * Math.pow(1 - t, 2) * y2 + + 3 * (1 - t) * t * t * y3 + + Math.pow(t, 3) * y1), + 0f); + } + + private Vector3d evalQuadBezier(Vector3d startPoint, double x1, double y1, double x2, double y2, double t) { + return new Vector3d((float) (Math.pow(1 - t, 2) * startPoint.x + + 2 * (1 - t) * t * x1 + + Math.pow(t, 2) * x2), + (float) (Math.pow(1 - t, 2) * startPoint.y + + 2 * (1 - t) * t * y1 + + Math.pow(t, 2) * y2), + 0f); + } +} \ No newline at end of file diff --git a/src/test/java/eu/mihosoft/vrl/v3d/CSGTest.java b/src/test/java/eu/mihosoft/vrl/v3d/CSGTest.java index b6a829aa..c3f17eba 100644 --- a/src/test/java/eu/mihosoft/vrl/v3d/CSGTest.java +++ b/src/test/java/eu/mihosoft/vrl/v3d/CSGTest.java @@ -29,7 +29,7 @@ public void setColor_OnUnionCSGShouldRetainColorsOnPolygons() { .transformed(new Transform().translate(10, 0, 0)); CSG union = cube1.union(cube2); - assertEquals(CSG.getDefaultColor(), union.getColor()); + assertEquals("Expected the new object to get the color from the unioned object", Color.RED, union.getColor()); union.getPolygons().forEach(polygon -> { boolean isLeftCube = polygon.getPoints().stream().allMatch(p -> p.x <= 5); @@ -51,7 +51,7 @@ public void setColor_OnUnionedAndTriangulatedCSGShouldRetainColorsOnPolygons() { .transformed(new Transform().translate(10, 0, 0)); CSG union = cube1.union(cube2).triangulate(); - assertEquals(CSG.getDefaultColor(), union.getColor()); + assertEquals("Expected the new object to get the color from the unioned object", Color.RED, union.getColor()); union.getPolygons().forEach(polygon -> { boolean isLeftCube = polygon.getPoints().stream().allMatch(p -> p.x <= 5); @@ -86,7 +86,7 @@ public void setColor_OnUnionedCSGShouldChangeColorsOfAllPolygons() { .transformed(new Transform().translate(10, 0, 0)); CSG union = cube1.union(cube2); - assertEquals("Expected the new object to get the default color", CSG.getDefaultColor(), union.getColor()); + assertEquals("Expected the new object to get the color from the unioned object", Color.RED, union.getColor()); union.setColor(Color.BLUE); union.getPolygons().forEach(polygon -> { diff --git a/src/test/java/eu/mihosoft/vrl/v3d/Text3dTest.java b/src/test/java/eu/mihosoft/vrl/v3d/Text3dTest.java new file mode 100644 index 00000000..e2db341d --- /dev/null +++ b/src/test/java/eu/mihosoft/vrl/v3d/Text3dTest.java @@ -0,0 +1,32 @@ +package eu.mihosoft.vrl.v3d; + +import org.junit.Test; + +import java.io.IOException; +import java.nio.file.Paths; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; + +public class Text3dTest { + + @Test + public void textShouldGenerateCSG() throws IOException { + Text3d text = new Text3d("Hello world", 10); + FileUtil.write(Paths.get("exampleText.stl"), + text.toCSG().triangulate().toStlString()); + } + + @Test + public void textTriangulateShouldCreateSixFaces() { + CSG text = new Text3d("-", 1).toCSG().triangulate(); + assertEquals("We should have two triangles on each face", 12, text.getPolygons().size()); + } + + @Test + public void textWithUnknownFontShouldUseDefault() { + Text3d text = new Text3d("Hello world", "banana", 10, 10); + assertFalse(text.toPolygons().isEmpty()); + } + +} \ No newline at end of file diff --git a/src/test/java/eu/mihosoft/vrl/v3d/textTest.java b/src/test/java/eu/mihosoft/vrl/v3d/textTest.java deleted file mode 100644 index a68d80af..00000000 --- a/src/test/java/eu/mihosoft/vrl/v3d/textTest.java +++ /dev/null @@ -1,25 +0,0 @@ -package eu.mihosoft.vrl.v3d; - -import static org.junit.Assert.*; - -import java.io.IOException; -import java.nio.file.Paths; - -import org.junit.Test; - -import javafx.scene.text.Font; - -public class textTest { - - @Test - public void test() throws IOException { - //TextExtrude.text(10.0, "Hello", new Font("Helvedica", 18)); - //TextExtrude.text(10.0, "Hello World!", new Font("Times New Roman", 18)); - - CSG text = CSG.text("Hello world",10, 10,"Serif Regular"); - text=new Cube(180,40,10).toCSG().toZMin().toXMin().toYMin().movey(-5).difference(text); - FileUtil.write(Paths.get("exampleText.stl"), - text.toStlString()); - } - -}