/* (c) 2014 Open Source Geospatial Foundation - all rights reserved
* (c) 2001 - 2013 OpenPlans
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.wfs.response.dxf;
import java.io.IOException;
import java.io.Writer;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.FeatureIterator;
import org.geotools.feature.type.FeatureTypeImpl;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.util.logging.Logging;
import org.opengis.feature.Property;
import org.opengis.feature.type.FeatureType;
import org.opengis.feature.type.GeometryType;
import org.opengis.feature.type.Name;
import org.opengis.feature.type.PropertyDescriptor;
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.LineString;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.geom.Polygon;
/**
* DXFWriter for the release 14 of DXF.
* see http://www.autodesk.com/techpubs/autocad/acadr14/dxf/index.htm
*
* @author Mauro Bartolomeoli, mbarto@infosia.it
*
*/
public class Rel14DXFWriter extends AbstractDXFWriter {
private static final Logger LOGGER = Logging.getLogger(Rel14DXFWriter.class);
// cache for block names
Map<String, String> blockNames = null;
// cache for block handles
Map<String, String> blockHandles = null;
// cache for block handles
Map<String, Object> textConfig = null;
// block name counter (blocks will be names "0", "1", ...
int blockCounter = 0;
// DXF version
protected String version = "AC1014";
public Rel14DXFWriter() {
super();
textConfig = new HashMap<String, Object>();
textConfig.put("height", 0.72);
}
public Rel14DXFWriter(Writer writer) {
super(writer);
}
/**
* Supports version if it's a number and equals to 14.
*/
public boolean supportsVersion(String version) {
if (super.supportsVersion(version))
return true;
try {
int v = Integer.parseInt(version);
return v == 14;
} catch (Exception e) {
return false;
}
}
/**
* Creates a new writer, using the given underlying writer.
*/
public DXFWriter newInstance(Writer writer) {
return new Rel14DXFWriter(writer);
}
/**
* Writes the DXF for the given feature list.
*/
@Override
public void write(List featureList, String version) throws IOException {
// DXF General Structure
writeHeader(featureList);
writeClasses(featureList);
writeTables(featureList);
writeBlocks(featureList);
writeEntities(featureList);
writeObjects(featureList);
writeEof();
blockNames.clear();
blockHandles.clear();
}
/**
* Writes the Header section.
*
* @param featureList
* @throws IOException
*/
private void writeHeader(List featureList) throws IOException {
writeSectionStart("HEADER");
// writes a list of variables
writeVariables(featureList);
writeSectionEnd();
}
/**
* Writes the classes section.
*
* @param featureList
* @throws IOException
*/
private void writeClasses(List featureList) throws IOException {
writeSectionStart("CLASSES");
writeClass("ACDBDICTIONARYWDFLT", "AcDbDictionaryWithDefault", "ObjectDBX Classes", 0,
false, false);
writeClass("TABLESTYLE", "AcDbTableStyle", "ObjectDBX Classes", 2047, false, false);
writeClass("DICTIONARYVAR", "AcDbDictionaryVar", "ObjectDBX Classes", 0, false, false);
writeClass("XRECORD", "AcDbXrecord", "AutoCAD 2000", 0, false, false);
writeClass("LWPOLYLINE", "AcDbPolyline", "AutoCAD 2000", 0, false, true);
writeClass("HATCH", "AcDbHatch", "AutoCAD 2000", 0, false, true);
writeClass("ACDBPLACEHOLDER", "AcDbPlaceHolder", "ObjectDBX Classes", 0, false, false);
writeClass("LAYOUT", "AcDbLayout", "ObjectDBX Classes", 0, false, false);
writeSectionEnd();
}
/**
* Writes a class definition.
*
* @param name
* @param devname
* @param description
* @param flags
* @param proxy
* @param entities
* @throws IOException
*/
private void writeClass(String name, String devname, String description, int flags,
boolean proxy, boolean entities) throws IOException {
writeGroup(0, "CLASS");
writeGroup(1, name);
writeGroup(2, devname);
writeGroup(3, description);
writeFlags(90, flags);
writeIntegerGroup(280, proxy ? 1 : 0);
writeIntegerGroup(281, entities ? 1 : 0);
}
/**
* Writes the tables section
*
* @param featureList
* @throws IOException
*/
private void writeTables(List featureList) throws IOException {
LOGGER.warning("Rel14DXFWriter.writeTables");
writeSectionStart("TABLES");
// Tables structure
writeViewPort(featureList);
writeLineTypes();
writeLayers(featureList);
writeStyles();
writeView();
writeUCS();
writeApplications();
writeDimensionStyles();
writeBlockRecords(featureList);
writeSectionEnd();
}
/**
* Writes the blocks section
*
* @param featureList
* @throws IOException
*/
private void writeBlocks(List featureList) throws IOException {
writeSectionStart("BLOCKS");
// static blocks (model space and paper space)
writeModelSpaceBlock();
writePaperSpaceBlock();
// blocks computed from the feature list
// (complex geometries)
writeEntityBlocks(featureList);
writeAttributeDefinitionBlocks(featureList);
writeSectionEnd();
}
/**
* Writes the entities section
*
* @param featureList
* @throws IOException
*/
private void writeEntities(List featureList) throws IOException {
writeSectionStart("ENTITIES");
// entities computed from the feature list
// (simple geometries or insert of blocks)
for (Object coll : featureList)
writeEntity((FeatureCollection) coll);
writeSectionEnd();
}
/**
* Writes the objects section
*
* @param featureList
* @throws IOException
*/
private void writeObjects(List featureList) throws IOException {
loadFromResource("objects");
}
/**
* Writes entities representing the given collection.
*
* @param coll
* @throws IOException
*/
private void writeEntity(FeatureCollection coll) throws IOException {
String layer = getLayerName(coll);
if (geometryAsBlock) {
for (String name : blockNames.values())
writeInsert(layer, name);
} else {
// iterates through all the items
FeatureIterator<SimpleFeature> iter = coll.features();
try {
while (iter.hasNext()) {
SimpleFeature f = iter.next();
String fid = f.getID();
// if it's a block insert it, else write the geometry
// directly
if (blockNames.containsKey(fid)) {
String name = blockNames.get(fid);
writeInsert(layer, name);
} else {
writeGeometry(layer, "1F", (Geometry) f.getDefaultGeometry());
String name = blockNames.get(coll.hashCode()+"");
if (writeAttributes) {
String ownerHandle = blockHandles.get(coll.hashCode()
+ "");
String attributesLayer = layer + "_attributes";
// writeInsert(layer, name);
writeInsertWithAttributes(attributesLayer, ownerHandle,
name, f);
}
}
}
} finally {
iter.close();
}
}
}
private void writeAttributes(String layer, String ownerHandle, SimpleFeature f) throws IOException {
// TODO Auto-generated method stub
for ( Property p : f.getProperties()) {
Name name = p.getName();
LOGGER.warning(" attr: " + name.getLocalPart() + " = " + p.getValue());
if (!(p.getValue() instanceof Geometry)) {
writeAttribute(layer, ownerHandle, name.getLocalPart(), p.getValue());
}
}
}
private void writeAttribute(String layer, String ownerHandle, String attribName, Object value) throws IOException {
writeGroup(0, "ATTRIB");
writeHandle("Geometry");
// String handle = getNewHandle("Attrib");
// writeGroup(5, handle);
writeOwnerHandle(ownerHandle);
writeSubClass("AcDbEntity");
writeLayer(layer);
writeSubClass("AcDbText");
writeDoubleGroup(10, 0.0);
writeDoubleGroup(20, 0.0);
writeDoubleGroup(30, 0.0);
writeDoubleGroup(40, 0.72 /*(Double) textConfig.get("height")*/);
String valueString = "";
if (value != null) {
valueString = value.toString();
}
writeGroup(1, valueString);
writeSubClass("AcDbAttribute");
writeGroup(2, attribName);
writeGroup(70, " 0");
}
/**
* Writes a block insert entity.
*
* @param layer
* @param name
* @throws IOException
*/
private void writeInsert(String layer, String name) throws IOException {
writeGroup(0, "INSERT");
writeHandle("Geometry");
writeSubClass("AcDbEntity");
writeLayer(layer);
writeSubClass("AcDbBlockReference");
writeName(name);
writePoint(0.0, 0.0, 0.0);
}
private void writeInsertWithAttributes(String layer, String ownerHandle, String name, SimpleFeature f) throws IOException {
writeGroup(0, "INSERT");
writeOwnerHandle(ownerHandle);
writeHandle("Geometry");
writeSubClass("AcDbEntity");
writeLayer(layer);
writeSubClass("AcDbBlockReference");
writeGroup(66, " 1");
writeName(name);
Geometry geometry = (Geometry)f.getDefaultGeometry();
Point intPoint = geometry.getInteriorPoint();
writePoint(intPoint.getX(), intPoint.getY(), 0.0);
writeAttributes(layer, ownerHandle, f);
writeGroup(0, "SEQEND");
writeHandle("Geometry");
// String handle = getNewHandle("AttDef");
// writeGroup(5, handle);
writeOwnerHandle(ownerHandle);
writeSubClass("AcDbEntity");
writeLayer(layer);
}
/**
* Writes all the given feature list associated blocks.
*
* @param featureList
* @throws IOException
*/
private void writeEntityBlocks(List featureList) throws IOException {
for (Object coll : featureList)
writeFeatureBlocks((FeatureCollection) coll);
}
/**
* Writes all the given feature collection associated blocks.
*
* @param featureList
* @throws IOException
*/
private void writeFeatureBlocks(FeatureCollection coll) throws IOException {
LOGGER.warning("Rel14DXFWriter.writeFeatureBlocks");
String layer = getLayerName(coll);
FeatureIterator<SimpleFeature> iter = coll.features();
try {
while (iter.hasNext()) {
SimpleFeature f = iter.next();
String fid = f.getID();
// consider only items cached to be treated as
// blocks (by the previous block_record analysis)
if (blockNames.containsKey(fid)) {
String ownerHandle = blockHandles.get(fid);
String name = blockNames.get(fid);
String startHandle = getNewHandle("Block");
String endHandle = getNewHandle("Block");
writeStartBlock(startHandle, ownerHandle, false, "0", name);
writeGeometry(layer, ownerHandle, (Geometry) f.getDefaultGeometry());
writeEndBlock(endHandle, ownerHandle, false, "0", name);
}
}
} finally {
iter.close();
}
}
/**
* Writes all the given attribute definition blocks to be used for later INSERT
* entities
*
* @param featureList
* @throws IOException
*/
private void writeAttributeDefinitionBlocks(List<FeatureCollection> featureList) throws IOException {
LOGGER.warning("Rel14DXFWriter.writeAttributeDefinitionBlocks");
for (FeatureCollection coll : featureList) {
String fid = coll.hashCode()+"";
// consider only items cached to be treated as
// blocks (by the previous block_record analysis)
if (blockNames.containsKey(coll.hashCode()+"")) {
String ownerHandle = blockHandles.get(coll.hashCode()+"");
String name = blockNames.get(coll.hashCode()+"");
String startHandle = getNewHandle("Block");
String endHandle = getNewHandle("Block");
writeStartBlock(startHandle, ownerHandle, false, "0", name);
String attributesLayer = getLayerName(coll) + "_attributes";
// writeGeometryStart("POINT", layer, ownerHandle);
writeGeometryStart("CIRCLE", attributesLayer, ownerHandle);
// writeSubClass("AcDbPoint");
writeSubClass("AcDbCircle");
writePoint(0.0, 0.0, 0.0);
writeDoubleGroup(40, 1.0);
writeAttributeDefinitions(attributesLayer, ownerHandle, coll);
writeEndBlock(endHandle, ownerHandle, false, "0", name);
}
}
}
private void writeAttributeDefinitions(String layer, String ownerHandle,
FeatureCollection fc) throws IOException {
FeatureTypeImpl schema = (FeatureTypeImpl) fc.getSchema();
for ( PropertyDescriptor p : schema.getDescriptors()) {
Name name = p.getName();
LOGGER.warning(" attr: " + name.getLocalPart());
if (!(p.getType() instanceof GeometryType)) {
writeAttrDef(layer, ownerHandle, name.getLocalPart());
}
}
}
private void writeAttrDef(String layer, String ownerHandle, String attribName) throws IOException {
// http://www.autodesk.com/techpubs/autocad/acad2000/dxf/attdef_dxf_06.htm
writeGroup(0, "ATTDEF");
writeHandle("Geometry");
// String handle = getNewHandle("AttDef");
// writeGroup(5, handle);
writeOwnerHandle(ownerHandle);
writeSubClass("AcDbEntity");
writeLayer(layer);
writeSubClass("AcDbText");
writeDoubleGroup(10, 0.0);
writeDoubleGroup(20, 0.0);
writeDoubleGroup(30, 0.0);
writeDoubleGroup(40, 2.0);
writeGroup(1, "");
writeSubClass("AcDbAttributeDefinition");
writeGroup(3, attribName);
writeGroup(2, attribName);
writeGroup(70, " 0");
}
/**
* Writes a given geometry.
*
* @param layer
* @param ownerHandle
* @param geom
* @throws IOException
*/
private void writeGeometry(String layer, String ownerHandle, Geometry geom) throws IOException {
if (geom instanceof GeometryCollection) {
GeometryCollection coll = (GeometryCollection) geom;
for (int count = 0; count < coll.getNumGeometries(); count++)
writeGeometry(layer, ownerHandle, coll.getGeometryN(count));
} else if (geom instanceof Polygon) {
Polygon p = (Polygon) geom;
writeGeometry(layer, ownerHandle, p.getExteriorRing());
for (int count = 0; count < p.getNumInteriorRing(); count++)
writeGeometry(layer, ownerHandle, p.getInteriorRingN(count));
} else if (geom instanceof LineString) {
LineString l = (LineString) geom;
Coordinate[] coords = l.getCoordinates();
writePolylineGeometry(layer, ownerHandle, coords, false);
} else if (geom instanceof Point) {
Point p = (Point) geom;
writePointGeometry(layer, ownerHandle, p);
}
}
/**
* Writes a point geometry.
*
* @param layer
* @param ownerHandle
* @param p
* @throws IOException
*/
private void writePointGeometry(String layer, String ownerHandle, Point p) throws IOException {
writeGeometryStart("POINT", layer, ownerHandle);
writeSubClass("AcDbPoint");
writePoint(p.getX(), p.getY(), 0.0);
}
/**
* Writes a polyline geometry.
*
* @param layer
* @param ownerHandle
* @param coords
* @param closed
* @throws IOException
*/
private void writePolylineGeometry(String layer, String ownerHandle, Coordinate[] coords,
boolean closed) throws IOException {
writeGeometryStart("LWPOLYLINE", layer, ownerHandle);
writeSubClass("AcDbPolyline");
writeIntegerGroup(90, coords.length);
writeDoubleGroup(43, 0.0);
if (closed)
writeIntegerGroup(70, 1);
for (Coordinate coord : coords)
writePoint(coord.x, coord.y, Double.NaN);
}
/**
* Writes the static model space block.
*
* @throws IOException
*/
private void writeModelSpaceBlock() throws IOException {
writeStartBlock("20", "1F", false, "0", "*MODEL_SPACE");
writeEndBlock("21", "1F", false, "0", "*MODEL_SPACE");
}
/**
* Writes the static paper space block.
*
* @throws IOException
*/
private void writePaperSpaceBlock() throws IOException {
writeStartBlock("1C", "1B", true, "0", "*PAPER_SPACE");
writeEndBlock("1D", "1B", true, "0", "*MODEL_SPACE");
}
/**
* Writes a start block section.
*
* @param handle
* @param ownerHandle
* @param paperSpace
* @param layer
* @param name
* @throws IOException
*/
private void writeStartBlock(String handle, String ownerHandle, boolean paperSpace,
String layer, String name) throws IOException {
writeGroup(0, "BLOCK");
writeGroup(5, handle);
writeOwnerHandle(ownerHandle);
writeSubClass("AcDbEntity");
writeLayer(layer);
if (paperSpace)
writeIntegerGroup(67, 1);
writeSubClass("AcDbBlockBegin");
writeName(name);
writeIntegerGroup(70, 0);
writeIntegerGroup(71, 0);
writePoint(0.0, 0.0, 0.0);
writeGroup(3, name);
writePath("");
}
/**
* Writes an end block section.
*
* @param handle
* @param ownerHandle
* @param paperSpace
* @param layer
* @param name
* @throws IOException
*/
private void writeEndBlock(String handle, String ownerHandle, boolean paperSpace, String layer,
String name) throws IOException {
writeGroup(0, "ENDBLK");
writeGroup(5, handle);
writeOwnerHandle(ownerHandle);
writeSubClass("AcDbEntity");
if (paperSpace)
writeIntegerGroup(67, 1);
writeLayer(layer);
writeSubClass("AcDbBlockEnd");
}
/**
* Writes block references table.
*
* @param featureList
* @throws IOException
*/
private void writeBlockRecords(List featureList) throws IOException {
writeTableStart("BLOCK_RECORD");
writeGroup(5, "1");
writeOwnerHandle("0");
writeSubClass("AcDbSymbolTable");
// 2 fixed blocks (paper space and model space)
// N dynamic blocks for complex geometries
writeSize(2 + countBlocks(featureList));
// writes the 2 fixed block references
writeModelSpaceBlockRecord();
writePaperSpaceBlockRecord();
// write each dynamic block reference, saving handles
// for further reference (they will be assigned as owner
// handles for the real blocks)
if (blockNames != null) {
for (String fid : blockNames.keySet())
blockHandles.put(fid, writeBlockRecord(blockNames.get(fid)));
}
writeTableEnd();
}
/**
* Writes a block reference, given the desired name. The handle is dinamically created.
*
* @param blockName
*
* @throws IOException
*/
private String writeBlockRecord(String blockName) throws IOException {
String handle = getNewHandle("BlockRecord");
writeBlockRecord(handle, "1", blockName);
return handle;
}
/**
* Writes the model space fixed block reference.
*
* @throws IOException
*/
private void writeModelSpaceBlockRecord() throws IOException {
writeBlockRecord("1F", "1", "*MODEL_SPACE");
}
/**
* Writes the paper space fixed block reference.
*
* @throws IOException
*/
private void writePaperSpaceBlockRecord() throws IOException {
writeBlockRecord("1B", "1", "*PAPER_SPACE");
}
/**
* Writes a block reference, using given handles.
*
* @param handle
* @param ownerHandle
* @param name
* @throws IOException
*/
private void writeBlockRecord(String handle, String ownerHandle, String name)
throws IOException {
writeGroup(0, "BLOCK_RECORD");
writeGroup(5, handle);
writeOwnerHandle(ownerHandle);
writeSubClass("AcDbSymbolTableRecord");
writeSubClass("AcDbBlockTableRecord");
writeName(name);
}
/**
* Builds a block list for the given feature list.
*
* @param featureList
*
*/
private int countBlocks(List featureList) {
if (blockNames == null) {
// initializes block cache
// for names and handles
blockNames = new HashMap<String, String>();
blockHandles = new HashMap<String, String>();
// cycle through feature to accumulate
// blocks
for (Object coll : featureList)
addBlocks((FeatureCollection) coll);
}
return blockNames.size();
}
/**
* Add blocks for the given collection.
*
* @param coll
*/
private void addBlocks(FeatureCollection coll) {
FeatureIterator<SimpleFeature> iter = coll.features();
try {
while (iter.hasNext()) {
SimpleFeature f = iter.next();
Geometry geom = (Geometry) f.getDefaultGeometry();
// if the geometry is complex, it will be
// exported as a block; we use fid to cache
// this for further using (blocks and entities
// sections)
if (geometryAsBlock || isBlockGeometry(geom)) {
LOGGER.warning(" added");
blockNames.put(f.getID(), (blockCounter++) + "");
}
}
} finally {
iter.close();
}
if (writeAttributes) {
// add attribute definition blocks
blockNames.put(coll.hashCode()+"", (blockCounter++) + "");
}
}
/**
* Checks if a geometry is complex and should be exported as a block.
*
* @param geom
*
*/
private boolean isBlockGeometry(Geometry geom) {
if (geom != null) {
// collections are exported as blocks
// quick fix: generates a false reference to a block "0"
/* if (GeometryCollection.class.isAssignableFrom(geom.getClass()))
return true; */
// polygons with holes are exported as blocks
if (Polygon.class.isAssignableFrom(geom.getClass())) {
return ((Polygon) geom).getNumInteriorRing() > 0;
}
}
return false;
}
/**
* Writes the dimstyle table.
*
* @throws IOException
*/
private void writeDimensionStyles() throws IOException {
writeTableStart("DIMSTYLE");
writeGroup(5, "A");
writeOwnerHandle("0");
writeSubClass("AcDbSymbolTable");
writeSize(1);
writeDimensionStyle("27", "A", "11", "STANDARD", 0);
writeTableEnd();
}
/**
* Writes a dimstyle item.
*
* @param handle
* @param ownerHandle
* @param styleHandle
* @param name
* @param flags
* @throws IOException
*/
private void writeDimensionStyle(String handle, String ownerHandle, String styleHandle,
String name, int flags) throws IOException {
writeGroup(0, "DIMSTYLE");
writeGroup(105, handle);
writeOwnerHandle(ownerHandle);
writeSubClass("AcDbSymbolTableRecord");
writeSubClass("AcDbDimStyleTableRecord");
writeName(name);
writeIntegerGroup(70, flags);
writeGroup(3, "");
writeGroup(4, "");
writeGroup(5, "");
writeGroup(6, "");
writeGroup(7, "");
writeDoubleGroup(40, 1.0);
writeDoubleGroup(41, 0.18);
writeLength(42, 0.0625);
writeDoubleGroup(43, 0.38);
writeDoubleGroup(44, 0.18);
writeDoubleGroup(45, 0.0);
writeDoubleGroup(46, 0.0);
writeDoubleGroup(47, 0.0);
writeDoubleGroup(48, 0.0);
writeDoubleGroup(140, 0.18);
writeDoubleGroup(141, 0.09);
writeDoubleGroup(142, 0.0);
writeDoubleGroup(143, 25.4);
writeDoubleGroup(144, 1.0);
writeDoubleGroup(145, 0.0);
writeDoubleGroup(146, 1.0);
writeDoubleGroup(147, 0.09);
writeIntegerGroup(71, 0);
writeIntegerGroup(72, 0);
writeIntegerGroup(73, 1);
writeIntegerGroup(74, 1);
writeIntegerGroup(75, 0);
writeIntegerGroup(76, 0);
writeIntegerGroup(77, 0);
writeIntegerGroup(78, 0);
writeIntegerGroup(170, 0);
writeIntegerGroup(171, 2);
writeIntegerGroup(172, 0);
writeIntegerGroup(173, 0);
writeIntegerGroup(174, 0);
writeIntegerGroup(175, 0);
writeIntegerGroup(176, 0);
writeIntegerGroup(177, 0);
writeIntegerGroup(178, 0);
writeIntegerGroup(270, 2);
writeIntegerGroup(271, 4);
writeIntegerGroup(272, 4);
writeIntegerGroup(273, 2);
writeIntegerGroup(274, 2);
writeGroup(340, styleHandle);
writeIntegerGroup(275, 0);
writeIntegerGroup(280, 0);
writeIntegerGroup(281, 0);
writeIntegerGroup(282, 0);
writeIntegerGroup(283, 1);
writeIntegerGroup(284, 0);
writeIntegerGroup(285, 0);
writeIntegerGroup(286, 0);
writeIntegerGroup(287, 3);
writeIntegerGroup(288, 0);
}
/**
* Writes the view table.
*
* @throws IOException
*/
private void writeView() throws IOException {
writeTableStart("VIEW");
writeGroup(5, "6");
writeOwnerHandle("0");
writeSubClass("AcDbSymbolTable");
writeSize(0);
writeTableEnd();
}
/**
* Writes the layer table.
*
* @param featureList
* @throws IOException
*/
private void writeLayers(List featureList) throws IOException {
writeTableStart("LAYER");
writeGroup(5, "2");
writeOwnerHandle("0");
writeSubClass("AcDbSymbolTable");
writeSize(featureList.size() + 1);
writeBgLayer();
// write a layer for each feature collection
for (Object coll : featureList) {
writeLayer((FeatureCollection) coll);
}
if (writeAttributes){
for (Object coll : featureList) {
writeAttributeLayer((FeatureCollection) coll);
}
}
writeTableEnd();
}
/**
* Writes a layer with the given properties
*
* @throws IOException
*/
private void writeLayerItem(String handle, String ownerHandle, String name, boolean frozen,
int color, int ltype) throws IOException {
writeGroup(0, "LAYER");
writeGroup(5, handle);
writeOwnerHandle(ownerHandle);
writeSubClass("AcDbSymbolTableRecord");
writeSubClass("AcDbLayerTableRecord");
// layer name
writeName(name);
// flags
writeIntegerGroup(70, frozen ? 2 : 0);
// color
if (color != -1)
writeColor(color);
// line type
if (ltype != -1)
writeLineType(ltype);
}
/**
* Writes the background ("0") layer.
*
* @throws IOException
*/
private void writeBgLayer() throws IOException {
writeLayerItem("10", "2", "0", false, 7, 0);
}
/**
* Writes a layer for the given featurecollection.
*
* @param coll
* @throws IOException
*/
private void writeLayer(FeatureCollection coll) throws IOException {
writeLayerItem(getNewHandle("Layer"), "2", getLayerName(coll), false, getColor(coll),
getLineType(coll));
}
/**
* Writes a layer for the given featurecollection.
*
* @param coll
* @throws IOException
*/
private void writeAttributeLayer(FeatureCollection coll) throws IOException {
String attributesLayer = getLayerName(coll) + "_attributes";
writeLayerItem(getNewHandle("Layer"), "2", attributesLayer, false, getColor(coll),
getLineType(coll));
}
/**
* Writes the line types table.
*
* @throws IOException
*/
private void writeLineTypes() throws IOException {
writeTableStart("LTYPE");
writeGroup(5, "5");
writeOwnerHandle("0");
writeSubClass("AcDbSymbolTable");
writeSize(lineTypes.length);
writeLineType("14", "5", "BYBLOCK", "", 0.0, new LineTypeItem[] {});
writeLineType("15", "5", "BYLAYER", "", 0.0, new LineTypeItem[] {});
for (LineType ltype : lineTypes)
writeLineType(getNewHandle("LType"), "5", ltype.getName(), ltype.getDescription(),
ltype.getLength(), ltype.getItems());
writeTableEnd();
}
/**
* Writes a LineType definition.
* @param handle
* @param ownerHandle
* @param name
* @param description
* @param length
* @param items
* @throws IOException
*/
private void writeLineType(String handle, String ownerHandle, String name, String description,
double length, LineTypeItem[] items) throws IOException {
writeGroup(0, "LTYPE");
writeGroup(5, handle);
writeOwnerHandle(ownerHandle);
writeSubClass("AcDbSymbolTableRecord");
writeSubClass("AcDbLinetypeTableRecord");
writeName(name);
writeIntegerGroup(70, 0);
writeGroup(3, description);
writeIntegerGroup(72, 65);
writeIntegerGroup(73, items.length);
writeLength(40, length);
for (LineTypeItem item : items) {
writeLength(49, item.getLength());
writeIntegerGroup(74, 0);
}
}
/**
* Writes the appid tables.
*
* @throws IOException
*/
private void writeApplications() throws IOException {
writeTableStart("APPID");
writeGroup(5, "9");
writeOwnerHandle("0");
writeSubClass("AcDbSymbolTable");
writeSize(1);
writeApplication("12", "9", "ACAD");
writeTableEnd();
}
/**
* Writes the default ACAD appid.
*
* @param handle
* @param ownerHandle
* @param name
* @throws IOException
*/
private void writeApplication(String handle, String ownerHandle, String name)
throws IOException {
writeGroup(0, "APPID");
writeGroup(5, handle);
writeOwnerHandle(ownerHandle);
writeSubClass("AcDbSymbolTableRecord");
writeSubClass("AcDbRegAppTableRecord");
// app name
writeName(name);
// flags
writeIntegerGroup(70, 0);
}
/**
* Writes the UCS table.
*
* @throws IOException
*/
private void writeUCS() throws IOException {
writeTableStart("UCS");
writeGroup(5, "7");
writeOwnerHandle("0");
writeSubClass("AcDbSymbolTable");
writeSize(0);
writeTableEnd();
}
/**
* Writes the styles table.
*
* @throws IOException
*/
private void writeStyles() throws IOException {
writeTableStart("STYLE");
writeGroup(5, "3");
writeOwnerHandle("0");
writeSubClass("AcDbSymbolTable");
writeSize(1);
writeStyleItem("11", "3", "STANDARD", 0);
writeTableEnd();
}
/**
* Writes a style item.
* @param handle
* @param ownerHandle
* @param name
* @param flags
* @throws IOException
*/
private void writeStyleItem(String handle, String ownerHandle, String name, int flags)
throws IOException {
writeGroup(0, "STYLE");
writeGroup(5, handle);
writeOwnerHandle(ownerHandle);
writeSubClass("AcDbSymbolTableRecord");
writeSubClass("AcDbTextStyleTableRecord");
writeName(name);
writeIntegerGroup(70, flags);
writeDoubleGroup(40, 0.0);
writeDoubleGroup(41, 1.0);
writeDoubleGroup(50, 0.0);
writeIntegerGroup(71, 0);
writeDoubleGroup(42, 0.2);
writeGroup(3, "txt");
writeGroup(4, "");
}
/**
* Writes the viewport table.
*
* @param featureList
* @throws IOException
*/
private void writeViewPort(List featureList) throws IOException {
writeTableStart("VPORT");
writeGroup(5, "8");
writeOwnerHandle("0");
writeSubClass("AcDbSymbolTable");
writeSize(1);
writeViewPortItem("*ACTIVE", featureList);
writeTableEnd();
}
/**
* Writes a viewport framing the given feature list.
*
* @param name
* @param featureList
* @throws IOException
*/
private void writeViewPortItem(String name, List featureList) throws IOException {
writeGroup(0, "VPORT");
writeHandle("VPort");
writeSubClass("AcDbSymbolTableRecord");
writeSubClass("AcDbViewportTableRecord");
writeName(name);
// flags
writeIntegerGroup(70, 0);
// lower-left point
writePoint(10, 0.0, 0.0, Double.NaN);
// upper right point
writePoint(11, 1.0, 1.0, Double.NaN);
ReferencedEnvelope env = getEnvelope(featureList);
// center point
writePoint(12, env.getMedian(0), env.getMedian(1), Double.NaN);
// snap point
writePoint(13, 0.0, 0.0, Double.NaN);
// snap spacing
writePoint(14, 0.5, 0.5, Double.NaN);
// grid spacing
writePoint(15, 0.5, 0.5, Double.NaN);
// view direction
writePoint(16, 0.0, 0.0, 1.0);
// view target point
writePoint(17, 0.0, 0.0, 0.0);
// view height
writeDoubleGroup(40, env.getHeight());
// view aspect ratio
writeDoubleGroup(41, env.getWidth() / env.getHeight());
// lens length
writeDoubleGroup(42, 50.0);
// front clipping plane
writeDoubleGroup(43, 0.0);
// back clipping plane
writeDoubleGroup(44, 0.0);
// snap rotation angle
writeDoubleGroup(50, 0.0);
// view twist angle
writeDoubleGroup(51, 0.0);
// view mode
writeIntegerGroup(71, 0);
// circle zoom percent
writeIntegerGroup(72, 100);
// fast zoom setting
writeIntegerGroup(73, 1);
// ucs icon
writeIntegerGroup(74, 3);
// snap on/off
writeIntegerGroup(75, 0);
// grid on/off
writeIntegerGroup(76, 0);
// snap style
writeIntegerGroup(77, 0);
// snap isopair
writeIntegerGroup(78, 0);
}
/**
* Writes variables for the header section.
*
* @param featureList
* @throws IOException
*/
protected void writeVariables(List featureList) throws IOException {
// version
writeVariable("ACADVER");
writeGroup(1, version);
// internal version
writeVariable("ACADMAINTVER");
writeIntegerGroup(70, 9);
// codepage
writeVariable("DWGCODEPAGE");
// encoding
writeGroup(3, encoding);
// insertion point
writeVariable("INSBASE");
writePoint(0.0, 0.0, 0.0);
// extracts global envelope
ReferencedEnvelope e = getEnvelope(featureList);
// drawing extension
if (e != null) {
writeVariable("EXTMIN");
writePoint(e.getMinX(), e.getMinY(), 0.0);
writeVariable("EXTMAX");
writePoint(e.getMaxX(), e.getMaxY(), 0.0);
}
// creation/update dates
writeVariable("TDCREATE");
writeJulianDate((new GregorianCalendar()).getTime());
writeVariable("TDUPDATE");
writeJulianDate((new GregorianCalendar()).getTime());
// fixed variables, read from resource
loadFromResource("header");
}
/**
* Description for the writer.
*/
public String getDescription() {
return "DXF Release 14";
}
}