1 package eu.mihosoft.vrl.v3d.svg;
5 import org.apache.batik.anim.dom.SAXSVGDocumentFactory;
6 import org.apache.batik.anim.dom.SVGOMGElement;
7 import org.apache.batik.anim.dom.SVGOMImageElement;
8 import org.apache.batik.anim.dom.SVGOMPathElement;
9 import org.apache.batik.anim.dom.SVGOMPolylineElement;
11 import java.io.BufferedWriter;
13 import java.io.FileWriter;
14 import java.io.IOException;
16 import java.util.ArrayList;
17 import java.util.HashMap;
18 import java.util.List;
20 import javax.vecmath.Matrix4d;
22 import org.apache.batik.bridge.BridgeContext;
23 import org.apache.batik.bridge.DocumentLoader;
24 import org.apache.batik.bridge.GVTBuilder;
25 import org.apache.batik.bridge.UserAgent;
26 import org.apache.batik.bridge.UserAgentAdapter;
27 import org.apache.batik.dom.svg.SVGItem;
28 import org.apache.batik.util.XMLResourceDescriptor;
29 import org.w3c.dom.Document;
30 import org.w3c.dom.Node;
31 import org.w3c.dom.NodeList;
32 import org.w3c.dom.svg.SVGImageElement;
33 import org.w3c.dom.svg.SVGPathSegList;
34 import org.w3c.dom.svg.SVGPointList;
36 import com.piro.bezier.BezierPath;
37 import eu.mihosoft.vrl.v3d.CSG;
38 import eu.mihosoft.vrl.v3d.Edge;
39 import eu.mihosoft.vrl.v3d.Extrude;
40 import eu.mihosoft.vrl.v3d.Polygon;
41 import eu.mihosoft.vrl.v3d.Transform;
42 import eu.mihosoft.vrl.v3d.Vector3d;
43 import javafx.scene.paint.Color;
55 private HashMap<String,ArrayList<CSG>>
csgByLayers =
new HashMap<String, ArrayList<CSG>>();
56 private HashMap<Polygon,Color>
colors=
new HashMap<>();
67 private HashMap<String,Double>
units=
new HashMap<>();
78 private double toPx(String value) {
80 for(String key :
units.keySet()) {
81 if(value.endsWith(key)) {
82 String []split = value.split(key);
83 if(key.contentEquals(
"m")&& split.length>1) {
88 return Double.parseDouble(split[0])/
units.get(key);
91 return Double.parseDouble(value);
97 throw new RuntimeException(
"Scale must be real number");
106 return scale.doubleValue();
109 private double toMM(String value) {
110 Double px=
toPx(value);
116 public void onShape(
CSG newShape) {
131 class MetaPostPath2 {
132 private SVGOMPathElement pathElement;
133 private String transform;
143 public MetaPostPath2(Node pathNode) {
144 setPathNode(pathNode);
152 public String toCode() {
154 SVGOMPathElement pathElement = getPathElement();
155 SVGPathSegList pathList = pathElement.getNormalizedPathSegList();
158 int pathObjects = pathList.getNumberOfItems();
165 for (
int i = 0; i < pathObjects; i++) {
166 SVGItem item = (SVGItem) pathList.getItem(i);
167 String itemLine = String.format(
"%s%n", item.getValueAsString());
171 return sb.toString();
181 private void setPathNode(Node pathNode) {
182 this.pathElement = (SVGOMPathElement) pathNode;
191 private SVGOMPathElement getPathElement() {
192 return this.pathElement;
228 public SVGLoad(String data)
throws IOException {
229 File tmpsvg =
new File(System.getProperty(
"java.io.tmpdir") +
"/" + Math.random());
230 tmpsvg.createNewFile();
231 FileWriter fw =
new FileWriter(tmpsvg.getAbsoluteFile());
232 BufferedWriter bw =
new BufferedWriter(fw);
236 tmpsvg.deleteOnExit();
259 public static HashMap<String,List<Polygon>>
toPolygons(File f)
throws IOException {
260 return new SVGLoad(f.toURI()).toPolygons();
264 public HashMap<String,List<Polygon>>
toPolygons(
double resolution) {
268 }
catch (Exception e) {
280 public static ArrayList<CSG>
extrude(File f,
double thickness,
double resolution)
throws IOException {
290 public static ArrayList<CSG>
extrude(URI uri,
double thickness,
double resolution)
throws IOException {
296 NodeList pn =
getSVGDocument().getDocumentElement().getChildNodes();
298 String hval =
getSVGDocument().getDocumentElement().getAttribute(
"height");
299 String wval =
getSVGDocument().getDocumentElement().getAttribute(
"width");
300 String viewbox =
getSVGDocument().getDocumentElement().getAttribute(
"viewBox");
301 double viewW = Double.parseDouble(viewbox.split(
" ")[2]);
305 double value =viewW/
width;
308 }
catch (Throwable t) {
315 int pnCount = pn.getLength();
316 for (
int j = 0; j < pnCount; j++) {
317 Node item = pn.item(j);
319 if (SVGOMGElement.class.isInstance(item)) {
321 SVGOMGElement element = (SVGOMGElement) item;
322 loadGroup(element, resolution, startingFrame,
null);
323 }
if(SVGOMPathElement.class.isInstance(item) || SVGOMImageElement.class.isInstance(item)) {
325 loadPath(item, resolution, startingFrame,
"TOP");
326 }
catch (Throwable t) {
335 private void loadGroup(SVGOMGElement element,
double resolution,
Transform startingFrame, String encapsulatingLayer) {
336 Node transforms = element.getAttributes().getNamedItem(
"transform");
341 layername=element.getAttributeNS(
"http://www.inkscape.org/namespaces/inkscape",
"label");
342 if(layername==
null|| layername.length()==0)
343 throw new RuntimeException();
344 }
catch (Throwable t) {
347 if(layername==
null) {
348 layername=encapsulatingLayer;
354 NodeList children = element.getChildNodes();
355 for (
int i = 0; i < children.getLength(); i++) {
356 Node n = children.item(i);
357 if (SVGOMGElement.class.isInstance(n)) {
358 loadGroup((SVGOMGElement) n, resolution, newFrame,layername);
362 loadPath(n, resolution, newFrame,layername);
363 }
catch (Throwable t) {
372 if (transforms ==
null)
373 return startingFrame;
375 String transformValue = transforms.getNodeValue();
377 if (transformValue.contains(
"translate")) {
378 String[] transformValues = transformValue.replaceAll(
"translate",
"").replaceAll(
"\\(",
"")
379 .replaceAll(
"\\)",
"").split(
"\\,");
381 toPx(transformValues[1]), 0));
383 }
else if (transformValue.contains(
"rotate")) {
384 String[] rotvals = transformValue.replaceAll(
"rotate",
"").replaceAll(
"\\(",
"")
385 .replaceAll(
"\\)",
"").split(
"\\,");
386 newFrame= startingFrame.
inverse()
388 .
apply(startingFrame);
390 }
else if (transformValue.contains(
"scale")) {
391 String[] transformValues = transformValue.replaceAll(
"scale",
"").replaceAll(
"\\(",
"")
392 .replaceAll(
"\\)",
"").split(
"\\,");
394 double scalex =
toPx(transformValues[0]);
395 double scaley =
toPx(transformValues.length==2?transformValues[1]:transformValues[0]);
396 newFrame.
scale(scalex, scaley, 1);
398 }
else if (transformValue.contains(
"matrix")) {
399 String[] transformValues = transformValue.replaceAll(
"matrix",
"").replaceAll(
"\\(",
"")
400 .replaceAll(
"\\)",
"").split(
"\\,");
403 double a =
toPx(transformValues[0]);
404 double b =
toPx(transformValues[1]);
405 double c =
toPx(transformValues[2]);
406 double d =
toPx(transformValues[3]);
407 double e =
toPx(transformValues[4]);
408 double f =
toPx(transformValues[5]);
409 double elemenents[] = { a, c, 0, e, b, d, 0, f, 0, 0, 1, 0, 0, 0, 0, 1 };
417 private void loadPath(Node pathNode,
double resolution,
Transform startingFrame, String encapsulatingLayer) {
421 if (pathNode !=
null) {
427 newFrame = startingFrame;
429 Node transforms = pathNode.getAttributes().getNamedItem(
"transform");
431 }
catch(Exception ex) {
435 if(SVGOMPathElement.class.isInstance(pathNode)) {
453 String []style = pathNode.getAttributes().getNamedItem(
"style").getNodeValue().split(
";");
454 for(String s:style) {
455 if(s.startsWith(
"fill:")) {
456 String
string = s.split(
":")[1];
461 }
catch(java.lang.IllegalArgumentException ex) {
463 }
catch(Exception ex) {
468 String []style = pathNode.getAttributes().getNamedItem(
"style").getNodeValue().split(
";");
469 for(String s:style) {
470 if(s.startsWith(
"stroke:")) {
471 String
string = s.split(
":")[1];
476 }
catch(java.lang.IllegalArgumentException ex1) {
479 }
catch(Exception ex1) {
483 MetaPostPath2 mpp =
new MetaPostPath2(pathNode);
484 String code = mpp.toCode();
486 loadComposite(code, resolution, newFrame,encapsulatingLayer,c);
487 }
else if(SVGOMPolylineElement.class.isInstance(pathNode)) {
491 String []style = pathNode.getAttributes().getNamedItem(
"style").getNodeValue().split(
";");
492 for(String s:style) {
493 if(s.startsWith(
"fill:")) {
494 String
string = s.split(
":")[1];
499 }
catch(java.lang.IllegalArgumentException ex) {
501 }
catch(Exception ex) {
505 c=Color.web(pathNode.getAttributes().getNamedItem(
"stroke").getNodeValue());
506 }
catch(java.lang.IllegalArgumentException ex) {
508 }
catch(Exception ex) {
513 String []style = pathNode.getAttributes().getNamedItem(
"style").getNodeValue().split(
";");
514 for(String s:style) {
515 if(s.startsWith(
"stroke:")) {
516 String
string = s.split(
":")[1];
521 }
catch(java.lang.IllegalArgumentException ex1) {
524 }
catch(Exception ex1) {
531 SVGOMPolylineElement pathElement = (SVGOMPolylineElement)pathNode;
532 SVGPointList pathList = pathElement.getPoints();
535 int pathObjects = pathList.getNumberOfItems();
537 for (
int i = 0; i < pathObjects; i++) {
538 SVGItem item = (SVGItem) pathList.getItem(i);
539 String itemLine = String.format(
"%s%n", item.getValueAsString());
546 loadComposite(sb, resolution, newFrame,encapsulatingLayer,c);
547 }
else if(SVGOMImageElement.class.isInstance(pathNode)) {
548 SVGImageElement image = (SVGOMImageElement) pathNode;
550 double x=
toPx(image.getAttributes().getNamedItem(
"x").getNodeValue());
551 double y=
toPx(image.getAttributes().getNamedItem(
"y").getNodeValue());
552 double pheight=
toPx(image.getAttributes().getNamedItem(
"height").getNodeValue());
553 double pwidth=
toPx(image.getAttributes().getNamedItem(
"width").getNodeValue());
554 String []imageData =
null;
555 for(
int i=0;i<image.getAttributes().getLength();i++) {
556 Node n = image.getAttributes().item(i);
557 if(n.getNodeName().contains(
"href"))
559 imageData=n.getNodeValue().split(
"/");
561 }
catch (Exception e) {
570 }
catch (java.lang.ClassCastException ex){
572 System.out.println(
"Found "+pathNode.getClass());
580 private void loadComposite(String code,
double resolution,
Transform startingFrame, String encapsulatingLayer, Color c) {
582 int count = code.length() - code.replace(
"M",
"").length();
588 loadSingle(code, resolution, startingFrame,encapsulatingLayer, c);
589 }
catch (Exception ex) {
595 String[] pathParts = code.split(
"M");
597 for (
int i = 0; i < pathParts.length; i++) {
598 String sectionedPart =
"M" + pathParts[i];
600 if (sectionedPart.length() > 1) {
603 loadSingle(sectionedPart, resolution, startingFrame,encapsulatingLayer, c);
611 double runningTotal=0;
615 runningTotal+=e.getP1().pos.x*e.getP2().pos.y;
616 runningTotal-=e.getP2().pos.x*e.getP1().pos.y;
619 return runningTotal<0;
621 private void loadSingle(String code,
double resolution,
Transform startingFrame, String encapsulatingLayer, Color c) {
626 ArrayList<Vector3d> p = path.
evaluate();
628 point.transform(startingFrame);
631 point.transform(
new Transform().rotZ(-180));
632 point.transform(
new Transform().rotY(180));
649 ArrayList<String> layers=
new ArrayList<String>();
654 layers.add((String) key);
669 public HashMap<String,ArrayList<CSG>>
extrudeLayers(
double t,
double resolution, String targetLayer){
682 if(targetLayer!=
null)
683 if(!targetLayer.contentEquals(key))
706 public ArrayList<CSG>
extrude(
double t,
double resolution)
throws IOException {
709 HashMap<String,ArrayList<CSG>> layers =
extrudeLayers( t, resolution,
null);
710 ArrayList<CSG> all =
new ArrayList<CSG>();
711 for(String key:layers.keySet()) {
712 all.addAll(layers.get(key));
731 this.svgDocument = document;
752 UserAgent userAgent =
new UserAgentAdapter();
753 DocumentLoader loader =
new DocumentLoader(userAgent);
754 BridgeContext bridgeContext =
new BridgeContext(userAgent, loader);
755 bridgeContext.setDynamicState(BridgeContext.DYNAMIC);
758 (
new GVTBuilder()).build(bridgeContext, document);
771 String parser = XMLResourceDescriptor.getXMLParserClassName();
772 SAXSVGDocumentFactory factory =
new SAXSVGDocumentFactory(parser);
773 return factory.createDocument(uri.toString());
void parsePathString(String d)
ArrayList< Vector3d > evaluate()
static CSG unionAll(CSG... csgs)
CSG setColor(Color color)
static List< Edge > fromPolygon(Polygon poly)
static List< Vector3d > toCCW(List< Vector3d > points)
static IExtrusion getExtrusionEngine()
List< Vector3d > getPoints()
static Polygon fromPoints(List< Vector3d > points, PropertyStorage shared)
static ArrayList< CSG > extrude(URI uri, double thickness)
HashMap< String, List< Polygon > > polygonByLayers
HashMap< Polygon, Color > colors
ISVGLoadProgress getProgress()
Document createSVGDocument(URI uri)
HashMap< String, ArrayList< CSG > > extrudeLayers(double t, double resolution, String targetLayer)
CSG extrudeLayerToCSG(double t, String layer)
static final String GROUP_ELEMENT_NAME
ArrayList< CSG > extrude(double thickness)
ArrayList< CSG > extrudeLayer(double t, String layer)
void loadSingle(String code, double resolution, Transform startingFrame, String encapsulatingLayer, Color c)
static HashMap< String, List< Polygon > > toPolygons(File f)
HashMap< String, List< Polygon > > toPolygons(double resolution)
void setHolePolarity(boolean p)
void setProgress(ISVGLoadProgress progress)
void loadComposite(String code, double resolution, Transform startingFrame, String encapsulatingLayer, Color c)
void loadPath(Node pathNode, double resolution, Transform startingFrame, String encapsulatingLayer)
double toPx(String value)
void setSVGDocument(Document document)
static ISVGLoadProgress progressDefault
List< String > getLayers()
void setScale(double value)
boolean negativeThickness
HashMap< String, ArrayList< CSG > > extrudeLayers(double t)
void initSVGDOM(Document document)
HashMap< String, List< Polygon > > getPolygonByLayers()
Transform getNewframe(Transform startingFrame, Node transforms)
HashMap< String, Double > units
Document getSVGDocument()
static boolean isCCW(Polygon polygon)
HashMap< String, List< Polygon > > toPolygons()
ArrayList< CSG > extrude(double t, double resolution)
HashMap< String, ArrayList< CSG > > csgByLayers
void loadAllGroups(double resolution, Transform startingFrame)
static ISVGLoadProgress getProgressDefault()
static final String PATH_ELEMENT_NAME
static ArrayList< CSG > extrude(File f, double thickness, double resolution)
static ArrayList< CSG > extrude(URI uri, double thickness, double resolution)
static ArrayList< CSG > extrude(File f, double thickness)
ISVGLoadProgress progress
void loadGroup(SVGOMGElement element, double resolution, Transform startingFrame, String encapsulatingLayer)
double toMM(String value)
void setPolygonByLayers(HashMap< String, List< Polygon >> polygonByLayers)
CSG extrude(Vector3d dir, List< Vector3d > points)