/** Turns a List<CubicCurve2D.Float> into a SVG Element representing a sketch of that spline. */ Element splineToSketch(SVGDocument document, List<CubicCurve2D.Float> spline) { String svgNS = SVGDOMImplementation.SVG_NAMESPACE_URI; // <g> is an SVG group // TODO: add a random(ish) rotation to the group Element group = document.createElementNS(svgNS, "g"); // For each curve in the path, draw along it using a "brush". In // our case the brush is a simple circle, but this could be changed // to something more advanced. for (CubicCurve2D.Float curve : spline) { // TODO: magic number & step in loop guard for (double i = 0.0; i <= 1.0; i += 0.01) { Point2D result = evalParametric(curve, i); // Add random jitter at some random positive or negative // distance along the unit normal to the tangent of the // curve Point2D n = vectorUnitNormal(evalParametricTangent(curve, i)); float dx = (float) ((Math.random() - 0.5) * n.getX()); float dy = (float) ((Math.random() - 0.5) * n.getY()); Element brush = document.createElementNS(svgNS, "circle"); brush.setAttribute("cx", Double.toString(result.getX() + dx)); brush.setAttribute("cy", Double.toString(result.getY() + dy)); // TODO: magic number for circle radius brush.setAttribute("r", Double.toString(1.0)); brush.setAttribute("fill", "green"); brush.setAttributeNS(null, "z-index", Integer.toString(zOrder.CONTOUR.ordinal())); group.appendChild(brush); } } return group; }
/** * Draws a concreteDiagram as an SVG. * * <p>This approach is wholly declarative. It currently knows nothing about the on screen * rendering of the diagram. To make decisions based on the on screen rendering (such as better * label placement) we will, in future, have to build a GVT (from the Batik library) of the * SVGDocument. * * @returns An SVGDocument DOM structure representing the SVG. */ @Override public SVGDocument toSVG(ConcreteDiagram cd) { // Get a DOMImplementation. DOMImplementation domImpl = SVGDOMImplementation.getDOMImplementation(); // Create an instance of org.w3c.dom.Document. String svgNS = SVGDOMImplementation.SVG_NAMESPACE_URI; SVGDocument document = (SVGDocument) domImpl.createDocument(svgNS, "svg", null); // Get the root element (the 'svg' element). Element svgRoot = document.getDocumentElement(); // Set the width and height attributes on the root 'svg' element. svgRoot.setAttributeNS(null, "width", Integer.toString(cd.getSize())); svgRoot.setAttributeNS(null, "height", Integer.toString(cd.getSize())); // Draw the shaded zones for (ConcreteZone z : cd.getShadedZones()) { Element path = document.createElementNS(svgNS, "path"); path.setAttributeNS(null, "d", toSVGPath(z.getShape(cd.getBox()))); path.setAttributeNS(null, "fill", "#cccccc"); // grey path.setAttributeNS(null, "z-index", Integer.toString(zOrder.SHADING.ordinal())); svgRoot.appendChild(path); } // TODO: Concrete* should return themselves as DocumentFragments for (CircleContour c : cd.getCircles()) { // Draw the circle Element circle = document.createElementNS(svgNS, "circle"); circle.setAttributeNS(null, "cx", Double.toString(c.get_cx())); circle.setAttributeNS(null, "cy", Double.toString(c.get_cy())); circle.setAttributeNS(null, "r", Double.toString(c.get_radius())); circle.setAttributeNS(null, "z-index", Integer.toString(zOrder.CONTOUR.ordinal())); // Not pretty, but it works. Color strokeColor = c.color(); circle.setAttributeNS( null, "stroke", (null == strokeColor) ? "black" : "#" + toHexString(c.color())); circle.setAttributeNS(null, "stroke-width", "2"); circle.setAttributeNS(null, "fill", "none"); svgRoot.appendChild(circle); // TODO: Put this text in a path around the circle // alternatively come up with some better label placement // algorithm Element text = document.createElementNS(svgNS, "text"); text.setAttributeNS(null, "x", Double.toString(c.get_cx())); text.setAttributeNS(null, "y", Double.toString(c.get_cy() + c.get_radius())); text.setAttributeNS(null, "text-anchor", "middle"); text.setAttributeNS( null, "fill", (null == strokeColor) ? "black" : "#" + toHexString(c.color())); text.setAttributeNS(null, "z-index", Integer.toString(zOrder.LABEL.ordinal())); Text textNode = document.createTextNode(c.ac.getLabel().getLabel()); text.appendChild(textNode); svgRoot.appendChild(text); } for (ConcreteSpider cs : cd.getSpiders()) { for (ConcreteSpiderFoot f : cs.feet) { // Draw the foot Element circle = document.createElementNS(svgNS, "circle"); circle.setAttributeNS(null, "cx", Double.toString(f.getX())); circle.setAttributeNS(null, "cy", Double.toString(f.getY())); circle.setAttributeNS(null, "r", Double.toString(ConcreteSpiderFoot.FOOT_RADIUS)); circle.setAttributeNS(null, "z-index", Integer.toString(zOrder.SPIDER.ordinal())); circle.setAttributeNS(null, "stroke", "black"); circle.setAttributeNS(null, "stroke-width", "2"); circle.setAttributeNS(null, "fill", "black"); svgRoot.appendChild(circle); } for (ConcreteSpiderLeg l : cs.legs) { Element line = document.createElementNS(svgNS, "line"); line.setAttributeNS(null, "x1", Double.toString(l.from.getX())); line.setAttributeNS(null, "y1", Double.toString(l.from.getY())); line.setAttributeNS(null, "x2", Double.toString(l.to.getX())); line.setAttributeNS(null, "y2", Double.toString(l.to.getY())); line.setAttributeNS(null, "z-index", Integer.toString(zOrder.SPIDER.ordinal())); line.setAttributeNS(null, "stroke", "black"); line.setAttributeNS(null, "stroke-width", "2"); line.setAttributeNS(null, "fill", "black"); svgRoot.appendChild(line); } } return document; }