/*
* This file is part of JGrasstools (http://www.jgrasstools.org)
* (C) Michael Michaud
* (C) HydroloGIS - www.hydrologis.com
*
* JGrasstools is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.jgrasstools.gears.io.dxfdwg.libs;
import org.geotools.feature.simple.SimpleFeatureBuilder;
import org.jgrasstools.gears.io.dxfdwg.libs.dxf.DxfGroup;
import org.jgrasstools.gears.utils.features.FeatureMate;
import org.jgrasstools.gears.utils.features.FeatureUtilities;
import org.jgrasstools.gears.utils.geometry.EGeometryType;
import org.opengis.feature.simple.SimpleFeature;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryCollection;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.geom.Polygon;
/**
* Utils for DXF format.
*
* <p>Based on work of: Michael Michaud</p>
*
* @author Andrea Antonello (www.hydrologis.com)
*/
public class DxfUtils {
public static final String SUFFIX = "_";
public static final String ZERO = "0.0";
public static final String SEQEND = "SEQEND";
public static final String VERTEX = "VERTEX";
public static final String LINE = "LINE";
public static final String POLYLINE = "POLYLINE";
public static final String POINT = "POINT";
public static final String LAYER = "LAYER";
public static final String TEXT_STYLE = "TEXT_STYLE";
public static final String BYLAYER = "BYLAYER";
public static final String LTYPE = "LTYPE";
public static final String ELEVATION = "ELEVATION";
public static final String THICKNESS = "THICKNESS";
public static final String COLOR = "COLOR";
public static final String TEXT_HEIGHT = "TEXT_HEIGHT";
public static final String TEXT = "TEXT";
public static final int precision = 3;
private DxfUtils() {}
/**
* Write a {@link SimpleFeature} to dxf string.
*
* @param featureMate the feature to convert.
* @param layerName the layer name in case none is in the attributes.
* @param elevationAttrName the attribute defining elevation or <code>null</code>.
* @param suffix <code>true</code> if suffix is needed.
* @param force2CoordsToLine if <code>true</code>, lines that are composed of just 2 coordinates
* will be handled as LINE instead of the default which is POLYLINE.
* @return the string representation.
*/
public static String feature2Dxf( FeatureMate featureMate, String layerName, String elevationAttrName, boolean suffix,
boolean force2CoordsToLine ) {
Geometry g = featureMate.getGeometry();
if (EGeometryType.isPoint(g)) {
return point2Dxf(featureMate, layerName, elevationAttrName);
} else if (EGeometryType.isLine(g)) {
return lineString2Dxf(featureMate, layerName, elevationAttrName, force2CoordsToLine);
} else if (EGeometryType.isPolygon(g)) {
return polygon2Dxf(featureMate, layerName, elevationAttrName, suffix);
} else if (g instanceof GeometryCollection) {
StringBuilder sb = new StringBuilder();
for( int i = 0; i < g.getNumGeometries(); i++ ) {
SimpleFeature ff = SimpleFeatureBuilder.copy(featureMate.getFeature());
ff.setDefaultGeometry(g.getGeometryN(i));
FeatureMate fm = new FeatureMate(ff);
sb.append(feature2Dxf(fm, layerName, elevationAttrName, suffix, force2CoordsToLine));
}
return sb.toString();
} else {
return null;
}
}
private static String point2Dxf( FeatureMate featureMate, String layerName, String elevationAttrName ) {
StringBuilder sb;
// TEXT
SimpleFeature feature = featureMate.getFeature();
Object attribute = FeatureUtilities.getAttributeCaseChecked(feature, TEXT);
boolean hasText = attribute != null && !attribute.equals("");
if (hasText) {
sb = new StringBuilder(DxfGroup.toString(0, TEXT));
} else {
sb = new StringBuilder(DxfGroup.toString(0, POINT));
}
// LAYER
handleLAYER(feature, layerName, sb);
// LTYPE
handleLTYPE(feature, sb);
// ELEVATION
handleELEVATION(feature, sb);
// THICKNESS
handleTHICKNESS(feature, sb);
// COLOR
handleColor(feature, sb);
Coordinate coord = ((Point) featureMate.getGeometry()).getCoordinate();
if (elevationAttrName != null) {
Double elev = featureMate.getAttribute(elevationAttrName, Double.class);
if (elev != null) {
coord.z = elev;
}
}
sb.append(DxfGroup.toString(10, coord.x, precision));
sb.append(DxfGroup.toString(20, coord.y, precision));
if (!Double.isNaN(coord.z))
sb.append(DxfGroup.toString(30, coord.z, precision));
handleTEXTHEIGHT(feature, sb, hasText);
return sb.toString();
}
private static String lineString2Dxf( FeatureMate featureMate, String layerName, String elevationAttrName,
boolean force2CoordsToLine ) {
Geometry geom = featureMate.getGeometry();
Coordinate[] coords = geom.getCoordinates();
// Correction added by L. Becker and R Littlefield on 2006-11-08
// It writes 2 points-only polylines in a line instead of a polyline
// to make it possible to incorporate big dataset in View32
boolean is2CoordsLine = coords.length == 2;
boolean doLine = is2CoordsLine && force2CoordsToLine;
StringBuilder sb;
if (doLine) {
sb = new StringBuilder(DxfGroup.toString(0, LINE));
} else {
sb = new StringBuilder(DxfGroup.toString(0, POLYLINE));
}
double elev = Double.NaN;
if (elevationAttrName != null) {
Double tmp = featureMate.getAttribute(elevationAttrName, Double.class);
if (tmp != null) {
elev = tmp;
}
}
SimpleFeature feature = featureMate.getFeature();
handleLAYER(feature, layerName, sb);
handleLTYPE(feature, sb);
handleELEVATION(feature, sb);
handleTHICKNESS(feature, sb);
handleColor(feature, sb);
// modified by L. Becker and R. Littlefield (add the Line case)
if (doLine) {
sb.append(DxfGroup.toString(10, coords[0].x, precision));
sb.append(DxfGroup.toString(20, coords[0].y, precision));
coords[0].z = elev;
if (!Double.isNaN(coords[0].z))
sb.append(DxfGroup.toString(30, ZERO));
sb.append(DxfGroup.toString(11, coords[1].x, precision));
sb.append(DxfGroup.toString(21, coords[1].y, precision));
coords[1].z = elev;
if (!Double.isNaN(coords[1].z))
sb.append(DxfGroup.toString(31, ZERO));
} else {
sb.append(DxfGroup.toString(66, 1));
sb.append(DxfGroup.toString(10, ZERO));
sb.append(DxfGroup.toString(20, ZERO));
coords[0].z = elev;
if (!Double.isNaN(coords[0].z))
sb.append(DxfGroup.toString(30, ZERO));
sb.append(DxfGroup.toString(70, 8));
for( int i = 0; i < coords.length; i++ ) {
sb.append(DxfGroup.toString(0, VERTEX));
handleLAYER(feature, layerName, sb);
sb.append(DxfGroup.toString(10, coords[i].x, precision));
sb.append(DxfGroup.toString(20, coords[i].y, precision));
coords[i].z = elev;
if (!Double.isNaN(coords[i].z))
sb.append(DxfGroup.toString(30, coords[i].z, precision));
sb.append(DxfGroup.toString(70, 32));
}
sb.append(DxfGroup.toString(0, SEQEND));
}
return sb.toString();
}
private static String polygon2Dxf( FeatureMate featureMate, String layerName, String elevationAttrName, boolean suffix ) {
Geometry geometry = featureMate.getGeometry();
int numGeometries = geometry.getNumGeometries();
StringBuilder sb = new StringBuilder();
for( int g = 0; g < numGeometries; g++ ) {
Polygon geom = (Polygon) geometry.getGeometryN(g);
Coordinate[] coords = geom.getExteriorRing().getCoordinates();
sb.append(DxfGroup.toString(0, POLYLINE));
sb.append(DxfGroup.toString(8, layerName));
SimpleFeature feature = featureMate.getFeature();
handleLTYPE(feature, sb);
handleELEVATION(feature, sb);
handleTHICKNESS(feature, sb);
handleColor(feature, sb);
double elev = Double.NaN;
if (elevationAttrName != null) {
Double tmp = featureMate.getAttribute(elevationAttrName, Double.class);
if (tmp != null) {
elev = tmp;
}
}
sb.append(DxfGroup.toString(66, 1));
sb.append(DxfGroup.toString(10, ZERO));
sb.append(DxfGroup.toString(20, ZERO));
coords[0].z = elev;
if (!Double.isNaN(coords[0].z))
sb.append(DxfGroup.toString(30, ZERO));
sb.append(DxfGroup.toString(70, 9));
for( int i = 0; i < coords.length; i++ ) {
sb.append(DxfGroup.toString(0, VERTEX));
sb.append(DxfGroup.toString(8, layerName));
sb.append(DxfGroup.toString(10, coords[i].x, precision));
sb.append(DxfGroup.toString(20, coords[i].y, precision));
coords[i].z = elev;
if (!Double.isNaN(coords[i].z))
sb.append(DxfGroup.toString(30, coords[i].z, precision));
sb.append(DxfGroup.toString(70, 32));
}
sb.append(DxfGroup.toString(0, SEQEND));
for( int h = 0; h < geom.getNumInteriorRing(); h++ ) {
sb.append(DxfGroup.toString(0, POLYLINE));
if (suffix)
sb.append(DxfGroup.toString(8, layerName + SUFFIX));
else
sb.append(DxfGroup.toString(8, layerName));
handleLTYPE(feature, sb);
handleTHICKNESS(feature, sb);
handleColor(feature, sb);
sb.append(DxfGroup.toString(66, 1));
sb.append(DxfGroup.toString(10, ZERO));
sb.append(DxfGroup.toString(20, ZERO));
coords[0].z = elev;
if (!Double.isNaN(coords[0].z))
sb.append(DxfGroup.toString(30, ZERO));
sb.append(DxfGroup.toString(70, 9));
coords = geom.getInteriorRingN(h).getCoordinates();
for( int i = 0; i < coords.length; i++ ) {
sb.append(DxfGroup.toString(0, VERTEX));
if (suffix)
sb.append(DxfGroup.toString(8, layerName + SUFFIX));
else
sb.append(DxfGroup.toString(8, layerName));
sb.append(DxfGroup.toString(10, coords[i].x, precision));
sb.append(DxfGroup.toString(20, coords[i].y, precision));
coords[i].z = elev;
if (!Double.isNaN(coords[i].z))
sb.append(DxfGroup.toString(30, coords[i].z, precision));
sb.append(DxfGroup.toString(70, 32));
}
sb.append(DxfGroup.toString(0, SEQEND));
}
}
return sb.toString();
}
private static void handleLAYER( SimpleFeature feature, String layerName, StringBuilder sb ) {
Object attribute;
attribute = FeatureUtilities.getAttributeCaseChecked(feature, LAYER);
if (attribute != null && !attribute.equals("")) {
sb.append(DxfGroup.toString(8, feature.getAttribute(LAYER)));
} else {
sb.append(DxfGroup.toString(8, layerName));
}
}
private static void handleTEXTHEIGHT( SimpleFeature feature, StringBuilder sb, boolean hasText ) {
Object attribute;
attribute = FeatureUtilities.getAttributeCaseChecked(feature, TEXT_HEIGHT);
boolean hasTextHeight = attribute != null && !attribute.equals(new Float(0f));
if (hasTextHeight) {
sb.append(DxfGroup.toString(40, feature.getAttribute(TEXT_HEIGHT)));
}
if (hasText && hasTextHeight) {
sb.append(DxfGroup.toString(1, feature.getAttribute(TEXT)));
sb.append(DxfGroup.toString(7, feature.getAttribute(TEXT_STYLE)));
}
}
private static void handleColor( SimpleFeature feature, StringBuilder sb ) {
Object attribute = FeatureUtilities.getAttributeCaseChecked(feature, COLOR);
if (attribute != null && ((Integer) attribute).intValue() != 256) {
sb.append(DxfGroup.toString(62, feature.getAttribute(COLOR).toString()));
}
}
private static void handleTHICKNESS( SimpleFeature feature, StringBuilder sb ) {
Object attribute = FeatureUtilities.getAttributeCaseChecked(feature, THICKNESS);
if (attribute != null && !attribute.equals(new Float(0f))) {
sb.append(DxfGroup.toString(39, feature.getAttribute(THICKNESS)));
}else{
sb.append(DxfGroup.toString(39, 100));
}
}
private static void handleELEVATION( SimpleFeature feature, StringBuilder sb ) {
Object attribute = FeatureUtilities.getAttributeCaseChecked(feature, ELEVATION);
if (attribute != null && !attribute.equals(new Float(0f))) {
sb.append(DxfGroup.toString(38, feature.getAttribute(ELEVATION)));
}
}
private static void handleLTYPE( SimpleFeature feature, StringBuilder sb ) {
Object attribute = FeatureUtilities.getAttributeCaseChecked(feature, LTYPE);
if (attribute != null && !attribute.equals(BYLAYER)) {
sb.append(DxfGroup.toString(6, feature.getAttribute(LTYPE)));
}
}
}