/*
* This is part of Geomajas, a GIS framework, http://www.geomajas.org/.
*
* Copyright 2008-2015 Geosparc nv, http://www.geosparc.com/, Belgium.
*
* The program is available in open source according to the GNU Affero
* General Public License. All contributions in this program are covered
* by the Geomajas Contributors License Agreement. For full licensing
* details, see LICENSE.txt in the project root.
*/
package org.geomajas.gwt.client.gfx.context;
import org.geomajas.geometry.Coordinate;
import org.geomajas.gwt.client.spatial.geometry.Geometry;
import org.geomajas.gwt.client.spatial.geometry.LineString;
import org.geomajas.gwt.client.spatial.geometry.LinearRing;
import org.geomajas.gwt.client.spatial.geometry.MultiLineString;
import org.geomajas.gwt.client.spatial.geometry.MultiPolygon;
import org.geomajas.gwt.client.spatial.geometry.Polygon;
/**
* <p>
* Decoder for geometry objects, that transforms them into strings that can be used as the "d" attribute of SVG path
* elements.
* </p>
*
* @author Pieter De Graef
*/
public final class SvgPathDecoder {
private SvgPathDecoder() {
}
/**
* This function decodes a Geometry (line or polygon) to a path's d-attribute.
*
* @param geometry
* The geometry to be decoded into a single path D attribute.
* @return The D attribute value as a string.
*/
public static String decode(Geometry geometry) {
return decode(geometry, 1.0f);
}
/**
* This function decodes a Geometry (line or polygon) to a path's d-attribute.
*
* @param geometry
* The geometry to be decoded into a single path D attribute.
* @param scale
* A scale value to apply on all the coordinates of the geometry before decoding.
* @return The D attribute value as a string.
*/
public static String decode(Geometry geometry, float scale) {
if (geometry == null) {
return "";
}
if (geometry instanceof LinearRing) {
return decodeLinearRing((LinearRing) geometry);
} else if (geometry instanceof LineString) {
return decodeLineString((LineString) geometry);
} else if (geometry instanceof Polygon) {
return decodePolygon((Polygon) geometry);
} else if (geometry instanceof MultiPolygon) {
return decodeMultiPolygon((MultiPolygon) geometry);
} else if (geometry instanceof MultiLineString) {
return decodeMultiLineString((MultiLineString) geometry);
}
return "";
}
// -------------------------------------------------------------------------
// Private functions:
// -------------------------------------------------------------------------
/**
* Decode LineString.
*
* @param lineString
* @return
*/
private static String decodeLineString(LineString lineString) {
if (lineString == null || lineString.isEmpty()) {
return "";
}
StringBuilder buffer = new StringBuilder();
Coordinate[] coordinates = lineString.getCoordinates();
for (int i = 0; i < coordinates.length; i++) {
buffer.append(getX(coordinates[i]));
buffer.append(" ");
buffer.append(getY(coordinates[i]));
if (i < (coordinates.length - 1)) {
buffer.append(", ");
}
}
return "M" + buffer.toString();
}
private static String decodeLinearRing(LinearRing linearRing) {
if (linearRing == null || linearRing.isEmpty()) {
return "";
}
StringBuilder buffer = new StringBuilder();
Coordinate[] coordinates = linearRing.getCoordinates();
for (int i = 0; i < coordinates.length - 1; i++) {
buffer.append(getX(coordinates[i]));
buffer.append(" ");
buffer.append(getY(coordinates[i]));
if (i < (coordinates.length - 2)) {
buffer.append(", ");
}
}
return "M" + buffer.toString() + " Z";
}
private static String decodeMultiLineString(MultiLineString multiLine) {
int n = multiLine.getNumGeometries();
StringBuilder pstr = new StringBuilder();
for (int i = 0; i < n; i++) {
pstr.append(decodeLineString((LineString) multiLine.getGeometryN(i)));
}
return pstr.toString();
}
private static String decodePolygon(Polygon polygon) {
if (polygon == null || polygon.isEmpty()) {
return "";
}
StringBuilder pstr = new StringBuilder();
pstr.append(decodeLinearRing(polygon.getExteriorRing()));
for (int i = 0; i < polygon.getNumInteriorRing(); i++) {
pstr.append(decodeLinearRing(polygon.getInteriorRingN(i)));
}
return pstr.toString();
}
private static String decodeMultiPolygon(MultiPolygon multipoly) {
StringBuilder pstr = new StringBuilder();
for (int i = 0; i < multipoly.getNumGeometries(); i++) {
pstr.append(decodePolygon((Polygon) multipoly.getGeometryN(i)));
}
return pstr.toString();
}
/** Values in SVG may not go over 1000000. */
private static double getX(Coordinate c) {
double value = c.getX();
if (value > 1000000) {
value = 1000000;
} else if (value < -1000000) {
value = -1000000;
}
return value;
}
/** Values in SVG may not go over 1000000. */
private static double getY(Coordinate c) {
double value = c.getY();
if (value > 1000000) {
value = 1000000;
} else if (value < -1000000) {
value = -1000000;
}
return value;
}
}