All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.geomajas.internal.rendering.DefaultSvgDocument Maven / Gradle / Ivy

/*
 * This file is part of Geomajas, a component framework for building
 * rich Internet applications (RIA) with sophisticated capabilities for the
 * display, analysis and management of geographic information.
 * It is a building block that allows developers to add maps
 * and other geographic data capabilities to their web applications.
 *
 * Copyright 2008-2010 Geosparc, http://www.geosparc.com, Belgium
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see .
 */
package org.geomajas.internal.rendering;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.GeometryCollection;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.LinearRing;
import com.vividsolutions.jts.geom.MultiLineString;
import com.vividsolutions.jts.geom.MultiPoint;
import com.vividsolutions.jts.geom.MultiPolygon;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.geom.Polygon;
import org.geomajas.geometry.Bbox;
import org.geomajas.global.ExceptionCode;
import org.geomajas.internal.rendering.writer.GraphicsWriter;
import org.geomajas.internal.rendering.writer.svg.geometry.GeometryCollectionWriter;
import org.geomajas.internal.rendering.writer.svg.geometry.LineStringWriter;
import org.geomajas.internal.rendering.writer.svg.geometry.MultiPointWriter;
import org.geomajas.internal.rendering.writer.svg.geometry.MultiPolygonWriter;
import org.geomajas.internal.rendering.writer.svg.geometry.BboxWriter;
import org.geomajas.internal.rendering.writer.svg.geometry.MultiLineStringWriter;
import org.geomajas.internal.rendering.writer.svg.geometry.PointWriter;
import org.geomajas.internal.rendering.writer.svg.geometry.PolygonWriter;
import org.geomajas.internal.util.WebSafeStringEncoder;
import org.geomajas.rendering.GraphicsDocument;
import org.geomajas.rendering.RenderException;

import java.io.IOException;
import java.io.Writer;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Stack;

/**
 * 

* GraphicsDocument implementation for writing VML documents. This document is * used when painting a tile's SVG in {@link org.geomajas.internal.layer.vector.GetTileStringContentStep}, * and the renderer specifies SVG. *

* * @author Pieter De Graef */ public class DefaultSvgDocument implements GraphicsDocument { /** * Default value for the number of digits after the fraction. */ protected static final int DEFAULT_MAX_DIGITS = 5; /** * A formatter for floating point values. Used when writing */ protected static DecimalFormat FORMATTER; /** * Little piece of code that sets initializes the formatter. */ static { Locale locale = new Locale("en", "US"); DecimalFormatSymbols decimalSymbols = new DecimalFormatSymbols(locale); decimalSymbols.setDecimalSeparator('.'); FORMATTER = new DecimalFormat(); FORMATTER.setDecimalFormatSymbols(decimalSymbols); // do not group FORMATTER.setGroupingSize(0); // do not show decimal SEPARATOR if it is not needed FORMATTER.setDecimalSeparatorAlwaysShown(false); FORMATTER.setDecimalFormatSymbols(null); // set default number of fraction digits FORMATTER.setMaximumFractionDigits(DEFAULT_MAX_DIGITS); // minimun fraction digits to 0 so they get not rendered if not needed FORMATTER.setMinimumFractionDigits(0); } private static Coordinate NULL_COORDINATE = new Coordinate(0, 0); /** * A map of all the writers that are needed to transform objects to SVG * code. These writers are implementations of GraphicsWriter * interface */ protected Map, GraphicsWriter> writers = new HashMap, GraphicsWriter>(); private Writer writer; private Stack elements = new Stack(); private boolean inAttribute; private String currentId; private String rootId; public DefaultSvgDocument(Writer writer) throws RenderException { this(writer, true); } public DefaultSvgDocument(Writer writer, boolean withSvgTag) throws RenderException { this.writer = writer; initDefaultWriters(); if (withSvgTag) { writeElement("svg", false); writeAttribute("xmlns", "http://www.w3.org/2000/svg"); writeAttribute("xmlns:hlink", "http://www.w3.org/1999/xlink"); } } public String toString() { return writer.toString(); } public void setMaximumFractionDigits(int numDigits) { FORMATTER.setMaximumFractionDigits(numDigits); } public void setMinimumFractionDigits(int numDigits) { FORMATTER.setMinimumFractionDigits(numDigits); } public void writeTextNode(String text) throws RenderException { try { checkState(false); if (!elements.empty()) { ElementState previous = elements.peek(); if (!previous.isOpened()) { writer.write(">"); previous.setOpened(true); } previous.setNeedsCloseTag(true); } writer.write(WebSafeStringEncoder.escapeHTML(text)); } catch (IOException ioe) { throw new RenderException(ioe, ExceptionCode.RENDER_DOCUMENT_IO_EXCEPTION); } } public void writeObject(Object o, boolean asChild) throws RenderException { Class c = o.getClass(); if (writers.containsKey(c)) { writers.get(c).writeObject(o, this, asChild); } else { throw new RenderException(ExceptionCode.RENDER_DOCUMENT_NO_REGISTERED_WRITER, o.getClass().getName()); } } public void writeAttribute(String name, double value) throws RenderException { writeAttribute(name, FORMATTER.format(value)); } public void writeAttribute(String name, String value) throws RenderException { try { checkState(false); writer.write(" " + name + "=" + "\"" + value + "\""); } catch (IOException ioe) { throw new RenderException(ioe, ExceptionCode.RENDER_DOCUMENT_IO_EXCEPTION); } } public void writeAttributeEnd() throws RenderException { try { checkState(true); writer.write("\""); inAttribute = false; } catch (IOException ioe) { throw new RenderException(ioe, ExceptionCode.RENDER_DOCUMENT_IO_EXCEPTION); } } public void writeAttributeStart(String name) throws RenderException { try { checkState(false); writer.write(" " + name + "=\""); inAttribute = true; } catch (IOException ioe) { throw new RenderException(ioe, ExceptionCode.RENDER_DOCUMENT_IO_EXCEPTION); } } public void writeElement(String name, boolean asChild) throws RenderException { try { checkState(false); if (!elements.empty()) { if (asChild) { ElementState previous = elements.peek(); if (!previous.isOpened()) { writer.write(">"); previous.setOpened(true); } previous.setNeedsCloseTag(true); } else { ElementState previous = elements.pop(); unwindId(); if (!previous.isOpened()) { writer.write(">"); } writer.write(""); } } writer.write("<" + name); elements.push(new ElementState(name)); } catch (IOException ioe) { throw new RenderException(ioe, ExceptionCode.RENDER_DOCUMENT_IO_EXCEPTION); } } public void closeElement() throws RenderException { try { checkState(false); if (!elements.empty()) { ElementState current = elements.pop(); if (current.needsCloseTag()) { if (!current.isOpened()) { writer.write(">"); } writer.write(""); } else { writer.write("/>"); } unwindId(); } } catch (IOException ioe) { throw new RenderException(ioe, ExceptionCode.RENDER_DOCUMENT_IO_EXCEPTION); } } public void writeClosedPathContent(Coordinate[] coords) throws RenderException { try { checkState(true); writePathContent(coords); writer.write('Z'); } catch (IOException ioe) { throw new RenderException(ioe, ExceptionCode.RENDER_DOCUMENT_IO_EXCEPTION); } } public void writePathContent(Coordinate[] coords) throws RenderException { try { checkState(true); writer.write('M'); Coordinate curr = roundCoordinate(coords[0]); writeCoordinate(curr); Coordinate prev = curr; int nCoords = coords.length; if (nCoords > 1) { writer.write('l'); for (int i = 1; i < nCoords; i++) { curr = coords[i]; Coordinate delta = new Coordinate(curr.x - prev.x, curr.y - prev.y); delta = roundCoordinate(delta); if (!delta.equals(NULL_COORDINATE) || i == 1) { writeCoordinate(delta); prev.x += delta.x; prev.y += delta.y; writer.write(' '); } } } } catch (IOException ioe) { throw new RenderException(ioe, ExceptionCode.RENDER_DOCUMENT_IO_EXCEPTION); } } public void flush() throws RenderException { try { if (!elements.empty()) { ElementState previous = elements.pop(); if (previous.needsCloseTag()) { writer.write(">"); } else { writer.write("/>"); } } while (!elements.empty()) { ElementState previous = elements.pop(); writer.write(""); } unwindId(); writer.flush(); } catch (IOException ioe) { throw new RenderException(ioe, ExceptionCode.RENDER_DOCUMENT_IO_EXCEPTION); } } public void setRootId(String rootId) { this.rootId = rootId; } public void registerWriter(Class c, GraphicsWriter writerToRegister) { writers.put(c, writerToRegister); } protected Coordinate roundCoordinate(Coordinate c) throws RenderException { return new Coordinate(roundDouble(c.x), roundDouble(c.y)); } protected void writeCoordinate(Coordinate c) throws IOException { writer.write(FORMATTER.format(c.x)); writer.write(' '); writer.write(FORMATTER.format(c.y)); } protected double roundDouble(double d) { int frac = FORMATTER.getMaximumFractionDigits(); double scale = Math.pow(10, frac); double result = d * scale; return Math.round(result) / scale; } private void checkState(boolean toCheck) throws RenderException { if (this.inAttribute != toCheck) { throw new RenderException(toCheck ? ExceptionCode.RENDER_DOCUMENT_EXPECTED_ATTRIBUTE_VALUE : ExceptionCode.RENDER_DOCUMENT_UNEXPECTED_ATTRIBUTE_END); } } private void initDefaultWriters() { registerWriter(Bbox.class, new BboxWriter()); registerWriter(Point.class, new PointWriter()); registerWriter(LineString.class, new LineStringWriter()); registerWriter(LinearRing.class, new LineStringWriter()); registerWriter(Polygon.class, new PolygonWriter()); registerWriter(MultiPoint.class, new MultiPointWriter()); registerWriter(MultiLineString.class, new MultiLineStringWriter()); registerWriter(MultiPolygon.class, new MultiPolygonWriter()); registerWriter(GeometryCollection.class, new GeometryCollectionWriter()); } /** * ??? */ private class ElementState { private String name; private String id; private boolean needsCloseTag; private boolean opened; public ElementState(String name) { this.name = name; } public String getName() { return name; } public boolean needsCloseTag() { return needsCloseTag; } public void setNeedsCloseTag(boolean needsCloseTag) { this.needsCloseTag = needsCloseTag; } public boolean isOpened() { return opened; } public void setOpened(boolean opened) { this.opened = opened; } public void setId(String id) { this.id = id; } public String getId() { return this.id; } } public void writeId(String id) throws RenderException { if (currentId == null) { if (rootId != null) { currentId = rootId + "." + id; } else { currentId = id; } } else { currentId = currentId + "." + id; } writeAttribute("id", currentId); elements.peek().setId(currentId); } private void unwindId() { if (elements.size() > 0) { ElementState head = elements.peek(); if (head.getId() != null) { currentId = head.getId(); } } else { currentId = null; } } public String getCurrentId() { return currentId; } public DecimalFormat getFormatter() { return FORMATTER; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy