HtmlSvgTestWriter.java
/*
* Copyright (c) 2016 Vivid Solutions.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* and Eclipse Distribution License v. 1.0 which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v20.html
* and the Eclipse Distribution License is available at
*
* http://www.eclipse.org/org/documents/edl-v10.php.
*/
package org.locationtech.jtstest.testbuilder.io;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Envelope;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jtstest.test.TestCaseList;
import org.locationtech.jtstest.test.Testable;
import org.locationtech.jtstest.testbuilder.geom.GeometryUtil;
import org.locationtech.jtstest.util.io.SVGWriter;
/**
* @version 1.7
*/
public class HtmlSvgTestWriter {
public static String writeTestSVG(TestCaseList testCaseList) {
HtmlSvgTestWriter writer = new HtmlSvgTestWriter();
return writer.write(testCaseList);
}
private SVGWriter svgWriter = new SVGWriter();
private int viewSize = 200;
public HtmlSvgTestWriter() {}
public String write(TestCaseList tcList) {
StringBuilder sb = new StringBuilder();
appendln(sb, "<html>");
writeStyles(sb);
appendln(sb, "<body>");
sb.append(defsMarkers());
for (int i = 0; i < tcList.size(); i++) {
Testable tc = tcList.get(i);
writeTest(i + 1, tc, sb);
}
appendln(sb, "</body></html>");
return sb.toString();
}
private static void writeStyles(StringBuilder sb) {
String styleA = HtmlUtil.styleClass(".geomA", style("vertexA", "#bbbbff", "#0000ff"));
String styleB = HtmlUtil.styleClass(".geomB", style("vertexB", "#ffbbbb", "#ff0000"));
sb.append(HtmlUtil.elem("head",
HtmlUtil.elem("style", styleA, styleB)));
}
private static String style(String vertexMarker, String clrFill, String clrStroke) {
return String.format(
"marker-end: url(#%s); marker-mid: url(#%s); fill:%s; fill-opacity:0.5; stroke:%s; stroke-width:1; stroke-opacity:1; stroke-miterlimit:4; stroke-linejoin:miter; stroke-linecap:square;"
, vertexMarker, vertexMarker, clrFill, clrStroke);
}
private static void appendln(StringBuilder sb, String s) {
sb.append(s);
sb.append("\n");
}
private static String defsMarkers() {
return "<svg xmlns='http://www.w3.org/2000/svg'>"
+ "\n<defs>"
+ "\n<marker id='vertexA' markerWidth='3' markerHeight='3' refX='1.5' refY='1.5'>"
+ "<circle cx='1.5' cy='1.5' r='1.5' stroke='none' fill='#0000af'/>"
+ "\n<marker id='vertexB' markerWidth='3' markerHeight='3' refX='1.5' refY='1.5'>"
+ "<circle cx='1.5' cy='1.5' r='1.5' stroke='none' fill='#af0000'/>"
+ "\n</marker>"
+ "\n</defs>"
+ "\n</svg>";
}
private void writeTest(int i, Testable tc, StringBuilder sb) {
writeTitle(i, tc, sb);
sb.append("<table><tr>");
sb.append("<td>");
sb.append(writeSvg(tc));
sb.append("</td>");
sb.append("<td>");
writeGeomText(sb , tc.getGeometry(0), "#0000a0");
appendln(sb,"<p>");
writeGeomText(sb , tc.getGeometry(1), "#a00000");
sb.append("</td>");
sb.append("</tr></table>\n");
sb.append("<hr />\n");
}
private void writeGeomText(StringBuilder sb, Geometry geom, String clr) {
if (geom == null) return;
String attr = String.format("style='color:%s'", clr);
sb.append( HtmlUtil.elemAttr("div", attr, HtmlUtil.elem("code", geom.toString())));
}
private void writeTitle(int i, Testable tc, StringBuilder sb) {
String desc = tc.getDescription();
String title = desc == null ? "" : ": " + desc;
sb.append(String.format(
"\n<h2>Case %d%s</h2>\n", i, title));
}
private String writeSvg(Testable testable) {
Geometry ga = testable.getGeometry(0);
Geometry gb = testable.getGeometry(1);
if (ga == null && gb == null) return "";
return write(ga, gb, testable.getName(), testable.getDescription() );
}
public String write(Geometry ga, Geometry gb, String name, String description) {
StringBuilder sb = new StringBuilder();
Envelope env = sceneEnv(ga, gb);
Coordinate centre = env.centre();
String wh = "width='" + viewSize + "' height='" + viewSize + "'";
String viewBox = env.getMinX() + " " + env.getMinY() + " " + env.getWidth() + " " + env.getHeight();
// transform to flip the Y axis to match SVG
String trans = String.format("translate(0 %f) scale( 1 -1 ) translate(0 %f)", centre.y, -centre.y);
sb.append("<svg " + wh + " viewBox='" + viewBox + "' version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'>\n");
String nameStr =name == null ? "" : name;
String descStr = description == null ? "" : description;
sb.append(" <desc>" + descStr + "</desc>\n");
sb.append(" <g transform='" + trans + "'>\n\n");
writeGeometryWithClass(sb, ga, "geomA");
writeGeometryWithClass(sb, gb, "geomB");
sb.append(" </g>\n");
sb.append("</svg>\n");
return sb.toString();
}
private static Envelope sceneEnv(Geometry ga, Geometry gb) {
Envelope env = new Envelope();
if (ga != null) env.expandToInclude(GeometryUtil.totalEnvelope(ga));
if (gb != null) env.expandToInclude(GeometryUtil.totalEnvelope(gb));
double envDiam = env.getDiameter();
env.expandBy(envDiam * 0.02);
return env;
}
private void writeGeometryWithClass(StringBuilder sb, Geometry g, String className ) {
if (g == null) return;
String gstyle = String.format("<g class='%s' >", className);
appendln(sb, gstyle);
appendln(sb, svgWriter.write(g));
appendln(sb, "</g>");
}
}