diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..9ed4869 --- /dev/null +++ b/pom.xml @@ -0,0 +1,60 @@ + + + 4.0.0 + org.openjump + dxf-driver + 1.0.0 + dxf-driver + Driver for dxf file format + + + 1.8 + 1.8 + UTF-8 + 0.0.0 + 1.18.1 + + + + + org.locationtech.jts + jts-core + ${jts.version} + + + org.openjump + OpenJUMP + 2.0 + system + ${project.basedir}/lib/OpenJUMP-0.0.0-r6c6037006e98f46a22f3d937b67694a133e6167f.jar + + + junit + junit + 4.13.2 + test + + + + + + + \ No newline at end of file diff --git a/src/main/java/fr/michaelm/jump/drivers/dxf/DXFDriverConfiguration.java b/src/main/java/fr/michaelm/jump/drivers/dxf/DXFDriverConfiguration.java new file mode 100644 index 0000000..cceb39f --- /dev/null +++ b/src/main/java/fr/michaelm/jump/drivers/dxf/DXFDriverConfiguration.java @@ -0,0 +1,88 @@ +/* + * Library name : dxf + * (C) 2021 Michaël Michaud + * + * This program 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 2 + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * For more information, contact: + * + * m.michael.michaud@orange.fr + * + */ + +package fr.michaelm.jump.drivers.dxf; + +import com.vividsolutions.jump.workbench.plugin.Extension; +import com.vividsolutions.jump.workbench.plugin.PlugInContext; + +/** + * This is the entry class to declare the dxf driver to JUMP. + * You can put the <extension>drivers.dxf.DXFDriverConfiguration</extension> + * element in the workbench-properties.xml file or put the .jar file containing + * the driver in the ext directory of your installation. + * @author Michaël Michaud + * @version 1.0.0 + */ +// History +// 1.0.0 (2021-04-11) : * refactoring for OpenJUMP 2, JTS 1.18 +// 0.9.0 (2018-06-02) : * fix a regression preventing export of MultiPolygons +// * use java 5 features (foreach, autoboxing, generics...) +// 0.8.1 (2016-09-29) : * makes it compatible with 1.9.1 release +// (remove multi-layer export capability - use java 1.7) +// 0.8.0 (2013-10-09) : * make it compatible with next 1.7.0 OpenJUMP release +// 0.7.8 (2012-09-22) : * Fix a bug preventing TEXT entities to be read +// * Bug fixed x==Double.NaN --> Double.isNaN(x) in DXFPoint +// 0.7.7 (2012-02-23) : * Fixed bug 3492384 preventing export of z in "lines" +// 0.7.6 (2012-01-16) : * Compile again for java 1.5 compatibility +// 0.7.5 (2011-12-02) : * Throws NumberFormatException +// 0.7.4 (2011-11-20) : * fixed a compatibility problem between 0.7.3 and OJ1.4.3 +// 0.7.3 (2011-04-10) : * fixed a bug in DxfBLOCKS +// * clean up the code +// 0.7.2 (2011-04-07) : * add TEXT_ROTATION attribute from Giuseppe Aruta code +// 0.7 (2010-11-01) : * read polygons with less than 3 points as lines +// and lines with less than two different points as points +// 0.6 () : * added DxfLWPOLYLINE +// 0.5 (2006-11-12) : * remove the header writing option after L. Becker and +// R. Littlefield have fix the bug in the header writing +// * bug fixed x==Double.NaN --> Double.isNaN(x) +// 0.4.x (2006-10-19) : * add optional '_' suffix +// * add optional header writer +// * DXF layer name is taken from layer attribute if it exists or +// from layer name else if +// * add multi-geometry export +// * add attribute tests an ability to export ANY jump layer +// * add ability to export holes in a separate layer or not +// * replace standard SaveFileDataSourceQueryChooser by a +// SaveDxfFileDataSourceQueryChooser with options for header +// for entity handles and for layer name. +// * add two options (one for header writing and the other +// to suffix layers containing holes) and a function to +// create valid DXF layer names from JUMP layer names +// 0.4 (2006-10-15) : * makes it possible to export any JUMP layer (in 0.3, +// layers which were not issued from a dxf file could not +// be exported because it misses some attributes). +// 0.3 (2003-12-10) +// 0.2 +public class DXFDriverConfiguration extends Extension { + + public void configure(PlugInContext context) { + new InstallDXFDataSourceQueryChooserPlugIn().initialize(context); + } + + public String getName() {return "DXF driver";} + + public String getVersion() {return "1.0.0 (2021-04-11)";} + +} diff --git a/src/main/java/fr/michaelm/jump/drivers/dxf/DXFFileReaderWriter.java b/src/main/java/fr/michaelm/jump/drivers/dxf/DXFFileReaderWriter.java new file mode 100644 index 0000000..cad2feb --- /dev/null +++ b/src/main/java/fr/michaelm/jump/drivers/dxf/DXFFileReaderWriter.java @@ -0,0 +1,40 @@ +/* + * Library name : dxf + * (C) 2021 Michaël Michaud + * + * This program 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 2 + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * For more information, contact: + * + * m.michael.michaud@orange.fr + * + */ + +package fr.michaelm.jump.drivers.dxf; + +import com.vividsolutions.jump.io.datasource.StandardReaderWriterFileDataSource; + + +/** + * DXF driver containg a DXFReader and a DXFWriter. + * @author Michaël Michaud + */ +public class DXFFileReaderWriter extends StandardReaderWriterFileDataSource { + + public DXFFileReaderWriter() { + super(new DxfReader(), new DxfWriter(), new String[] { "dxf" }); + } + +} diff --git a/src/main/java/fr/michaelm/jump/drivers/dxf/DxfBLOCKS.java b/src/main/java/fr/michaelm/jump/drivers/dxf/DxfBLOCKS.java new file mode 100644 index 0000000..edde43f --- /dev/null +++ b/src/main/java/fr/michaelm/jump/drivers/dxf/DxfBLOCKS.java @@ -0,0 +1,86 @@ +/* + * Library name : dxf + * (C) 2021 Michaël Michaud + * + * This program 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 2 + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * For more information, contact: + * + * m.michael.michaud@orange.fr + * + */ + +package fr.michaelm.jump.drivers.dxf; + +import java.io.RandomAccessFile; +import java.io.IOException; +import com.vividsolutions.jump.feature.FeatureCollection; +import com.vividsolutions.jump.feature.FeatureDataset; + + +/** + * A DXF block contains a block of geometries. The dxf driver can read entities + * inside a block, but it will not remember that the entities are in a same + * block. + * @author Michaël Michaud + */ +// History +public class DxfBLOCKS { + + FeatureCollection entities; + + public DxfBLOCKS() { + entities = new FeatureDataset(DxfFile.DXF_SCHEMA); + } + + public static DxfBLOCKS readBlocks(RandomAccessFile raf) + throws NumberFormatException, IOException { + return readEntities(raf); + } + + public static DxfBLOCKS readEntities(RandomAccessFile raf) + throws NumberFormatException, IOException { + DxfBLOCKS dxfEntities = new DxfBLOCKS(); + DxfGroup group = new DxfGroup(2, "BLOCKS"); + while (group != null && !group.equals(DxfFile.ENDSEC)) { + if (group.getCode() == 0) { + if (DxfFile.DEBUG) group.print(8); + if (group.getValue().equals("POINT")) { + group = DxfPOINT.readEntity(raf, dxfEntities.entities); + } + else if (group.getValue().equals("TEXT")) { + group = DxfTEXT.readEntity(raf, dxfEntities.entities); + } + else if (group.getValue().equals("LINE")) { + group = DxfLINE.readEntity(raf, dxfEntities.entities); + } + else if (group.getValue().equals("POLYLINE")) { + group = DxfPOLYLINE.readEntity(raf, dxfEntities.entities); + } + else if (group.getValue().equals("LWPOLYLINE")) { + group = DxfLWPOLYLINE.readEntity(raf, dxfEntities.entities); + } + else { + group = DxfGroup.readGroup(raf); + } + } + else { + group = DxfGroup.readGroup(raf); + } + } + return dxfEntities; + } + +} diff --git a/src/main/java/fr/michaelm/jump/drivers/dxf/DxfCLASSES.java b/src/main/java/fr/michaelm/jump/drivers/dxf/DxfCLASSES.java new file mode 100644 index 0000000..18eb867 --- /dev/null +++ b/src/main/java/fr/michaelm/jump/drivers/dxf/DxfCLASSES.java @@ -0,0 +1,54 @@ +/* + * Library name : dxf + * (C) 2021 Michaël Michaud + * + * This program 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 2 + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * For more information, contact: + * + * m.michael.michaud@orange.fr + * + */ + +package fr.michaelm.jump.drivers.dxf; + +import java.io.RandomAccessFile; +import java.io.IOException; + + +/** + * Dxf section between the HEADER and the TABLES sections. + * Not mandatory for DXF 12, don't use it. + * @author Michaël Michaud + */ +public class DxfCLASSES { + + public DxfCLASSES() {} + + public static DxfCLASSES readClasses(RandomAccessFile raf) + throws NumberFormatException, IOException { + DxfCLASSES classes = new DxfCLASSES(); + DxfGroup group; + // readGroup returns a DxfGroup or throws an Exception. It does not return null. + while (null != (group = DxfGroup.readGroup(raf)) && !group.equals(DxfFile.ENDSEC)) { + // Read until end of CLASSES section without doing anything + } + return classes; + } + + public String toString() { + return DxfFile.SECTION.toString() + DxfFile.CLASSES + DxfFile.ENDSEC; + } +} diff --git a/src/main/java/fr/michaelm/jump/drivers/dxf/DxfENTITIES.java b/src/main/java/fr/michaelm/jump/drivers/dxf/DxfENTITIES.java new file mode 100644 index 0000000..f021c17 --- /dev/null +++ b/src/main/java/fr/michaelm/jump/drivers/dxf/DxfENTITIES.java @@ -0,0 +1,115 @@ +/* + * Library name : dxf + * (C) 2021 Michaël Michaud + * + * This program 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 2 + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * For more information, contact: + * + * m.michael.michaud@orange.fr + * + */ + +package fr.michaelm.jump.drivers.dxf; + +import java.io.RandomAccessFile; +import java.io.BufferedWriter; +import java.io.IOException; +import java.util.Iterator; +import com.vividsolutions.jump.feature.Feature; +import com.vividsolutions.jump.feature.FeatureCollection; +import com.vividsolutions.jump.feature.FeatureDataset; + +/** + * The ENTITIES section of a DXF file containing all the data. + * @author Michaël Michaud + */ +public class DxfENTITIES { + + FeatureCollection entities; + + public DxfENTITIES() { + entities = new FeatureDataset(DxfFile.DXF_SCHEMA); + } + + public FeatureCollection getEntities() { + return entities; + } + + public void setEntities(FeatureCollection featureCollection) { + this.entities = featureCollection; + } + + public static DxfENTITIES readEntities(RandomAccessFile raf) throws IOException { + DxfENTITIES dxfEntities = new DxfENTITIES(); + DxfGroup group = new DxfGroup(2, "ENTITIES"); + while (group != null && !group.equals(DxfFile.ENDSEC)) { + if (group.getCode() == 0) { + if (DxfFile.DEBUG) group.print(8); + if (group.getValue().equals("POINT")) { + group = DxfPOINT.readEntity(raf, dxfEntities.entities); + } + else if (group.getValue().equals("TEXT")) { + group = DxfTEXT.readEntity(raf, dxfEntities.entities); + } + else if (group.getValue().equals("LINE")) { + group = DxfLINE.readEntity(raf, dxfEntities.entities); + } + else if (group.getValue().equals("POLYLINE")) { + group = DxfPOLYLINE.readEntity(raf, dxfEntities.entities); + } + else if (group.getValue().equals("LWPOLYLINE")) { + group = DxfLWPOLYLINE.readEntity(raf, dxfEntities.entities); + } + else { + group = DxfGroup.readGroup(raf); + } + } + else { + group = DxfGroup.readGroup(raf); + } + } + return dxfEntities; + } + + public String toString() { + Iterator it = entities.iterator(); + Feature feature; + StringBuilder sb = new StringBuilder(DxfFile.SECTION.toString()); + sb.append(DxfFile.ENTITIES); + while (it.hasNext()) { + feature = it.next(); + sb.append(DxfENTITY.feature2Dxf(feature, "LAYER0", true)); + } + sb.append(DxfFile.ENDSEC); + return sb.toString(); + } + + public void write(BufferedWriter bw, String defaultLayer) throws IOException { + Iterator it = entities.iterator(); + Feature feature; + bw.write(DxfFile.SECTION.toString()); + bw.write(DxfFile.ENTITIES.toString()); + while (it.hasNext()) { + feature = it.next(); + String entity = DxfENTITY.feature2Dxf(feature, defaultLayer, true); + if (entity != null) { + bw.write(entity); + } + } + bw.write(DxfFile.ENDSEC.toString()); + } + +} diff --git a/src/main/java/fr/michaelm/jump/drivers/dxf/DxfENTITY.java b/src/main/java/fr/michaelm/jump/drivers/dxf/DxfENTITY.java new file mode 100644 index 0000000..232dc7e --- /dev/null +++ b/src/main/java/fr/michaelm/jump/drivers/dxf/DxfENTITY.java @@ -0,0 +1,310 @@ +/* + * Library name : dxf + * (C) 2021 Michaël Michaud + * + * This program 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 2 + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * For more information, contact: + * + * m.michael.michaud@orange.fr + * + */ + +package fr.michaelm.jump.drivers.dxf; + + +import com.vividsolutions.jump.feature.Feature; +import org.locationtech.jts.geom.*; + + +/** + * A DXF ENTITY is equivalent to a JUMP feature. This class is the parent class + * for POLYLINE, POINT, LINE and every kind of geometric entity present in a + * DXF file. + * @author Michaël Michaud + */ +// History +// 2012-02-23 : fixed a bug in line export (it did always export z=0) +// 2006-10-19 : add multi-geometry export +// add attribute tests an ability to export ANY jump layer +// add ability to export holes in a separate layer or not +public class DxfENTITY { + + public final static DxfGroup LINE = new DxfGroup(0, "LINE"); + public final static DxfGroup POINT = new DxfGroup(0, "POINT"); + public final static DxfGroup CIRCLE = new DxfGroup(0, "CIRCLE"); + public final static DxfGroup ARC = new DxfGroup(0, "ARC"); + public final static DxfGroup TRACE = new DxfGroup(0, "TRACE"); + public final static DxfGroup SOLID = new DxfGroup(0, "SOLID"); + public final static DxfGroup TEXT = new DxfGroup(0, "TEXT"); + public final static DxfGroup SHAPE = new DxfGroup(0, "SHAPE"); + public final static DxfGroup BLOCK = new DxfGroup(0, "BLOCK"); + public final static DxfGroup ENDBLK = new DxfGroup(0, "ENDBLK"); + public final static DxfGroup INSERT = new DxfGroup(0, "INSERT"); + public final static DxfGroup ATTDEF = new DxfGroup(0, "ATTDEF"); + public final static DxfGroup ATTRIB = new DxfGroup(0, "ATTRIB"); + public final static DxfGroup POLYLINE = new DxfGroup(0, "POLYLINE"); + public final static DxfGroup LWPOLYLINE = new DxfGroup(0, "LWPOLYLINE"); + public final static DxfGroup VERTEX = new DxfGroup(0, "VERTEX"); + public final static DxfGroup SEQEND = new DxfGroup(0, "SEQEND"); + public final static DxfGroup _3DFACE = new DxfGroup(0, "3DFACE"); + public final static DxfGroup VIEWPORT = new DxfGroup(0, "VIEWPORT"); + public final static DxfGroup DIMENSION = new DxfGroup(0, "DIMENSION"); + public final static PrecisionModel DPM = new PrecisionModel(); + public static int precision = 4; + + private String layerName = "DEFAULT"; + //private String lineType = null; + //private float elevation = 0f; + //private float thickness = 0f; + //private int colorNumber = 256; + //private int space = 0; + //private double[] extrusionDirection = null; + //private int flags = 0; + + public String getLayerName() {return layerName;} + + public void setLayerName(String layerName) { + this.layerName = layerName; + } + + public DxfENTITY(String layerName) { + this.layerName = layerName; + } + + public static String feature2Dxf(Feature feature, String layerName, boolean suffix) { + Geometry g = feature.getGeometry(); + if (g.getGeometryType().equals("Point")) { + return point2Dxf(feature, layerName); + } + else if (g.getGeometryType().equals("LineString")) { + return lineString2Dxf(feature, layerName); + } + else if (g.getGeometryType().equals("Polygon")) { + return polygon2Dxf(feature, layerName, suffix); + } + else if (g instanceof GeometryCollection) { + StringBuilder sb = new StringBuilder(); + for (int i = 0 ; i < g.getNumGeometries() ; i++) { + Feature ff = feature.clone(true); + ff.setGeometry(g.getGeometryN(i)); + sb.append(feature2Dxf(ff, layerName, suffix)); + } + return sb.toString(); + } + else { + return null; + } + } + + public static String point2Dxf(Feature feature, String layerName) { + StringBuilder sb; + boolean hasText = (feature.getSchema().hasAttribute("TEXT") && + feature.getAttribute("TEXT") != null); + if (hasText) {sb = new StringBuilder(DxfGroup.toString(0, "TEXT"));} + else {sb = new StringBuilder(DxfGroup.toString(0, "POINT"));} + if (feature.getSchema().hasAttribute("LAYER") && + !feature.getString("LAYER").trim().equals("")) { + sb.append(DxfGroup.toString(8, feature.getAttribute("LAYER"))); + } + else {sb.append(DxfGroup.toString(8, layerName));} + if (feature.getSchema().hasAttribute("LTYPE") && + !feature.getAttribute("LTYPE").equals("BYLAYER")) { + sb.append(DxfGroup.toString(6, feature.getAttribute("LTYPE"))); + } + //if (feature.getSchema().hasAttribute("ELEVATION") && + // feature.getAttribute("ELEVATION") != null && + // !feature.getAttribute("ELEVATION").equals(new Float(0f))) { + // sb.append(DxfGroup.toString(38, feature.getAttribute("ELEVATION"))); + //} + if (feature.getSchema().hasAttribute("THICKNESS") && + feature.getAttribute("THICKNESS") != null && + !feature.getAttribute("THICKNESS").equals(0f)) { + sb.append(DxfGroup.toString(39, feature.getAttribute("THICKNESS"))); + } + if (feature.getSchema().hasAttribute("COLOR") && + feature.getAttribute("COLOR") != null && + (Integer)feature.getAttribute("COLOR") != 256) { + sb.append(DxfGroup.toString(62, feature.getAttribute("COLOR").toString())); + } + Coordinate coord = feature.getGeometry().getCoordinate(); + 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)); + if (hasText) { + sb.append(DxfGroup.toString(1, feature.getAttribute("TEXT"))); + } + if (hasText && feature.getSchema().hasAttribute("TEXT_HEIGHT") && + feature.getAttribute("TEXT_HEIGHT") != null) { + sb.append(DxfGroup.toString(40, feature.getAttribute("TEXT_HEIGHT"))); + } + if (hasText && feature.getSchema().hasAttribute("TEXT_ROTATION") && + feature.getAttribute("TEXT_ROTATION") != null) { + sb.append(DxfGroup.toString(50, feature.getAttribute("TEXT_ROTATION"))); + } + if (hasText && feature.getSchema().hasAttribute("TEXT_STYLE") && + feature.getAttribute("TEXT_STYLE") != null) { + sb.append(DxfGroup.toString(7, feature.getAttribute("TEXT_STYLE"))); + } + return sb.toString(); + } + + public static String lineString2Dxf(Feature feature, String layerName) { + LineString geom = (LineString)feature.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 isLine = (coords.length == 2); + StringBuilder sb; + if (!isLine) { + sb = new StringBuilder(DxfGroup.toString(0, "POLYLINE")); + } + else { + sb = new StringBuilder(DxfGroup.toString(0, "LINE")); + } + if (feature.getSchema().hasAttribute("LAYER") && + !feature.getString("LAYER").trim().equals("")) { + sb.append(DxfGroup.toString(8, feature.getAttribute("LAYER"))); + } + else {sb.append(DxfGroup.toString(8, layerName));} + if (feature.getSchema().hasAttribute("LTYPE") && + !feature.getAttribute("LTYPE").equals("BYLAYER")) { + sb.append(DxfGroup.toString(6, feature.getAttribute("LTYPE"))); + } + if (feature.getSchema().hasAttribute("ELEVATION") && + feature.getAttribute("ELEVATION") != null) { + sb.append(DxfGroup.toString(38, feature.getAttribute("ELEVATION"))); + } + if (feature.getSchema().hasAttribute("THICKNESS") && + feature.getAttribute("THICKNESS") != null) { + sb.append(DxfGroup.toString(39, feature.getAttribute("THICKNESS"))); + } + if (feature.getSchema().hasAttribute("COLOR") && + feature.getAttribute("THICKNESS") != null) { + sb.append(DxfGroup.toString(62, feature.getAttribute("COLOR").toString())); + } + // modified by L. Becker and R. Littlefield (add the Line case) + if (isLine){ + sb.append(DxfGroup.toString(10, coords[0].x, precision)); + sb.append(DxfGroup.toString(20, coords[0].y, precision)); + if (!Double.isNaN(coords[0].z)) { + sb.append(DxfGroup.toString(30, coords[0].z, precision)); + } + sb.append(DxfGroup.toString(11, coords[1].x, precision)); + sb.append(DxfGroup.toString(21, coords[1].y, precision)); + if (!Double.isNaN(coords[1].z)) { + sb.append(DxfGroup.toString(31, coords[1].z, precision)); + } + } + else { + sb.append(DxfGroup.toString(66, 1)); + sb.append(DxfGroup.toString(10, "0.0")); + sb.append(DxfGroup.toString(20, "0.0")); + if (!Double.isNaN(coords[0].z)) sb.append(DxfGroup.toString(30, "0.0")); + sb.append(DxfGroup.toString(70, 8)); + + for (Coordinate coord : coords) { + sb.append(DxfGroup.toString(0, "VERTEX")); + if (feature.getSchema().hasAttribute("LAYER") && + !feature.getString("LAYER").trim().equals("")) { + sb.append(DxfGroup.toString(8, feature.getAttribute("LAYER"))); + } + else {sb.append(DxfGroup.toString(8, layerName));} + 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)); + sb.append(DxfGroup.toString(70, 32)); + } + sb.append(DxfGroup.toString(0, "SEQEND")); + } + return sb.toString(); + } + + public static String polygon2Dxf(Feature feature, String layerName, boolean suffix) { + Polygon geom = (Polygon)feature.getGeometry(); + Coordinate[] coords = geom.getExteriorRing().getCoordinates(); + StringBuilder sb = new StringBuilder(DxfGroup.toString(0, "POLYLINE")); + sb.append(DxfGroup.toString(8, layerName)); + if (feature.getSchema().hasAttribute("LTYPE") && + feature.getAttribute("LTYPE") != null && + !feature.getAttribute("LTYPE").equals("BYLAYER")) { + sb.append(DxfGroup.toString(6, feature.getAttribute("LTYPE"))); + } + if (feature.getSchema().hasAttribute("ELEVATION") && + feature.getAttribute("ELEVATION") != null) { + sb.append(DxfGroup.toString(38, feature.getAttribute("ELEVATION"))); + } + if (feature.getSchema().hasAttribute("THICKNESS") && + feature.getAttribute("THICKNESS") != null) { + sb.append(DxfGroup.toString(39, feature.getAttribute("THICKNESS"))); + } + if (feature.getSchema().hasAttribute("COLOR") && + feature.getAttribute("COLOR") != null) { + sb.append(DxfGroup.toString(62, feature.getAttribute("COLOR").toString())); + } + sb.append(DxfGroup.toString(66, 1)); + sb.append(DxfGroup.toString(10, "0.0")); + sb.append(DxfGroup.toString(20, "0.0")); + if (!Double.isNaN(coords[0].z)) sb.append(DxfGroup.toString(30, "0.0")); + sb.append(DxfGroup.toString(70, 9)); + for (Coordinate coord : coords) { + sb.append(DxfGroup.toString(0, "VERTEX")); + sb.append(DxfGroup.toString(8, layerName)); + 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)); + sb.append(DxfGroup.toString(70, 32)); + } + sb.append(DxfGroup.toString(0, "SEQEND")); + for (int h = 0 ; h < geom.getNumInteriorRing() ; h++) { + //System.out.println("polygon2Dxf (hole)" + suffix); + sb.append(DxfGroup.toString(0, "POLYLINE")); + if (suffix) sb.append(DxfGroup.toString(8, layerName+"_")); + else sb.append(DxfGroup.toString(8, layerName)); + if (feature.getSchema().hasAttribute("LTYPE") && + !feature.getAttribute("LTYPE").equals("BYLAYER")) { + sb.append(DxfGroup.toString(6, feature.getAttribute("LTYPE"))); + } + if (feature.getSchema().hasAttribute("THICKNESS") && + feature.getAttribute("THICKNESS") != null) { + sb.append(DxfGroup.toString(39, feature.getAttribute("THICKNESS"))); + } + if (feature.getSchema().hasAttribute("COLOR") && + feature.getAttribute("COLOR") != null) { + sb.append(DxfGroup.toString(62, feature.getAttribute("COLOR"))); + } + sb.append(DxfGroup.toString(66, 1)); + sb.append(DxfGroup.toString(10, "0.0")); + sb.append(DxfGroup.toString(20, "0.0")); + if (!Double.isNaN(coords[0].z)) sb.append(DxfGroup.toString(30, "0.0")); + sb.append(DxfGroup.toString(70, 9)); + coords = geom.getInteriorRingN(h).getCoordinates(); + for (Coordinate coord : coords) { + sb.append(DxfGroup.toString(0, "VERTEX")); + if (suffix) sb.append(DxfGroup.toString(8, layerName+"_")); + else sb.append(DxfGroup.toString(8, layerName)); + 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)); + sb.append(DxfGroup.toString(70, 32)); + } + sb.append(DxfGroup.toString(0, "SEQEND")); + } + + return sb.toString(); + } + +} diff --git a/src/main/java/fr/michaelm/jump/drivers/dxf/DxfFile.java b/src/main/java/fr/michaelm/jump/drivers/dxf/DxfFile.java new file mode 100644 index 0000000..e0c6e9c --- /dev/null +++ b/src/main/java/fr/michaelm/jump/drivers/dxf/DxfFile.java @@ -0,0 +1,330 @@ +/* + * Library name : dxf + * (C) 2021 Michaël Michaud + * + * This program 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 2 + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * For more information, contact: + * + * m.michael.michaud@orange.fr + * + */ + +package fr.michaelm.jump.drivers.dxf; + +import java.io.RandomAccessFile; +import java.io.IOException; +import java.io.File; +import java.io.FileWriter; +import java.util.Date; +import javax.swing.JFileChooser; +import javax.swing.JFrame; +import com.vividsolutions.jump.feature.Feature; +import com.vividsolutions.jump.feature.FeatureSchema; +import com.vividsolutions.jump.feature.FeatureDataset; +import com.vividsolutions.jump.feature.AttributeType; +import com.vividsolutions.jump.feature.FeatureCollection; +import org.locationtech.jts.geom.Envelope; +import org.locationtech.jts.geom.GeometryFactory; + +/** + * A whole dataset contained in a DXF file, and main methods to read from and + * to write to the file. + * + * @author Michaël Michaud + */ +public class DxfFile { + + public static boolean DEBUG = false; + + public final static DxfGroup SECTION = new DxfGroup(0, "SECTION"); + public final static DxfGroup ENDSEC = new DxfGroup(0, "ENDSEC"); + public final static DxfGroup EOF = new DxfGroup(0, "EOF"); + public final static DxfGroup HEADER = new DxfGroup(2, "HEADER"); + + // CLASSES section is used from version 13 + public final static DxfGroup CLASSES = new DxfGroup(2, "CLASSES"); + public final static DxfGroup TABLES = new DxfGroup(2, "TABLES"); + public final static DxfGroup BLOCKS = new DxfGroup(2, "BLOCKS"); + public final static DxfGroup ENTITIES = new DxfGroup(2, "ENTITIES"); + + // OBJECTS section is used from version 13 + public final static DxfGroup OBJECTS = new DxfGroup(2, "OBJECTS"); + + // Common FeatureSchema for ENTITIES + public final static FeatureSchema DXF_SCHEMA = new FeatureSchema(); + public static boolean DXF_SCHEMA_INITIALIZED = false; + //static int iterator = 0; + private DxfHEADER header = null; + private DxfCLASSES classes = null; + private DxfTABLES tables = null; + private DxfBLOCKS blocks = null; + private DxfENTITIES entities = null; + private int coordinatePrecision = 2; + + FeatureCollection features; + + public DxfFile() { + initializeDXF_SCHEMA(); + } + + /** + * Initialize a JUMP FeatureSchema to load dxf data keeping some graphic + * attributes. + */ + public static void initializeDXF_SCHEMA() { + if (DXF_SCHEMA.getAttributeCount() != 0) return; + // codes 10,20,30... used by POINT, TEXT, LINE, POLYLINE, LWPOLYLINE + DXF_SCHEMA.addAttribute("GEOMETRY", AttributeType.GEOMETRY); + // code 8, common to all entities + DXF_SCHEMA.addAttribute("LAYER", AttributeType.STRING); + // code 6, common to all entities + DXF_SCHEMA.addAttribute("LTYPE", AttributeType.STRING); + // code 38 used by LWPOLYLINE + DXF_SCHEMA.addAttribute("ELEVATION", AttributeType.DOUBLE); + // code 39 used by POINT, TEXT, LINE, POLYLINE, LWPOLYLINE + DXF_SCHEMA.addAttribute("THICKNESS", AttributeType.DOUBLE); + // code 62, common to all entities + DXF_SCHEMA.addAttribute("COLOR", AttributeType.INTEGER); + // code 1 used by TEXT + DXF_SCHEMA.addAttribute("TEXT", AttributeType.STRING); + // code 40 used by TEXT + DXF_SCHEMA.addAttribute("TEXT_HEIGHT", AttributeType.DOUBLE); + // code 50 used by TEXT + DXF_SCHEMA.addAttribute("TEXT_ROTATION", AttributeType.DOUBLE); + // code 7 used by TEXT + DXF_SCHEMA.addAttribute("TEXT_STYLE", AttributeType.STRING); + } + + public int getCoordinatePrecision(){ + return coordinatePrecision; + } + + public void setCoordinatePrecision(int coordinatePrecision) { + this.coordinatePrecision = coordinatePrecision; + } + + public static DxfFile createFromFile(File file) throws IOException { + RandomAccessFile raf = new RandomAccessFile(file, "r"); + return createFromFile(raf); + } + + public static DxfFile createFromFile(RandomAccessFile raf) + throws NumberFormatException, IOException { + DxfFile dxfFile = new DxfFile(); + initializeDXF_SCHEMA(); + dxfFile.features = new FeatureDataset(DXF_SCHEMA); + DxfGroup group; + try { + while (null != (group = DxfGroup.readGroup(raf))) { + if (group.equals(SECTION)) { + group = DxfGroup.readGroup(raf); + //if (group == null) break; // never happens, readGroup throws Exception + if (DxfFile.DEBUG) group.print(0); + if (group.equals(HEADER)) { + dxfFile.header = DxfHEADER.readHeader(raf); + } + else if (group.equals(CLASSES)) { + dxfFile.classes = DxfCLASSES.readClasses(raf); + } + else if (group.equals(TABLES)) { + dxfFile.tables = DxfTABLES.readTables(raf); + } + else if (group.equals(BLOCKS)) { + dxfFile.blocks = DxfBLOCKS.readEntities(raf); + dxfFile.features.addAll(dxfFile.blocks.entities.getFeatures()); + } + else if (group.equals(ENTITIES)) { + dxfFile.entities = DxfENTITIES.readEntities(raf); + dxfFile.features.addAll(dxfFile.entities.entities.getFeatures()); + } + else if (group.equals(OBJECTS)) { + //objects = DxfOBJECTS.readObjects(br); + } + else if (group.getCode() == 999) { + System.out.println("Comment : " + group.getValue()); + } + else { + //System.out.println("Group " + group.getCode() + " " + group.getValue() + " UNKNOWN"); + } + } + else if (group.getCode() == 999) { + //System.out.println("Comment : " + group.getValue()); + } + else if (group.equals(EOF)) { + break; + } + else { + //System.out.println("Group " + group.getCode() + " " + group.getValue() + " UNKNOWN"); + } + } + } finally { + raf.close(); + } + return dxfFile; + } + + public FeatureCollection read(GeometryFactory gf) { + return features; + } + + public FeatureCollection getFeatureCollection() { + return null; + } + + public static void write(FeatureCollection features, String[] layerNames, + FileWriter fw, int precision, boolean suffix) { + + Envelope envelope = features.getEnvelope(); + + Date date = new Date(System.currentTimeMillis()); + try { + // COMMENTAIRES DU TRADUCTEUR + fw.write(DxfGroup.toString(999, features.size() + " features")); + fw.write(DxfGroup.toString(999, "TRANSLATED BY DXF Driver 0.9.0")); + fw.write(DxfGroup.toString(999, "DATE : " + date)); + + // ECRITURE DU HEADER + fw.write(DxfGroup.toString(0, "SECTION")); + fw.write(DxfGroup.toString(2, "HEADER")); + fw.write(DxfGroup.toString(9, "$ACADVER")); + fw.write(DxfGroup.toString(1, "AC1009")); + fw.write(DxfGroup.toString(9, "$CECOLOR")); + fw.write(DxfGroup.toString(62, 256)); + fw.write(DxfGroup.toString(9, "$CELTYPE")); + fw.write(DxfGroup.toString(6, "DUPLAN")); + fw.write(DxfGroup.toString(9, "$CLAYER")); + fw.write(DxfGroup.toString(8, "0")); // corrected by L. Becker on 2006-11-08 + fw.write(DxfGroup.toString(9, "$ELEVATION")); + fw.write(DxfGroup.toString(40, 0.0, 3)); + fw.write(DxfGroup.toString(9, "$EXTMAX")); + fw.write(DxfGroup.toString(10, envelope.getMaxX(), 6)); + fw.write(DxfGroup.toString(20, envelope.getMaxY(), 6)); + //fw.write(DxfGroup.toString(30, envelope.getMaxX(), 6)); + fw.write(DxfGroup.toString(9, "$EXTMIN")); + fw.write(DxfGroup.toString(10, envelope.getMinX(), 6)); + fw.write(DxfGroup.toString(20, envelope.getMinY(), 6)); + //fw.write(DxfGroup.toString(30, envelope.getMaxX(), 6)); + fw.write(DxfGroup.toString(9, "$INSBASE")); + fw.write(DxfGroup.toString(10, 0.0, 1)); + fw.write(DxfGroup.toString(20, 0.0, 1)); + fw.write(DxfGroup.toString(30, 0.0, 1)); + fw.write(DxfGroup.toString(9, "$LIMCHECK")); + fw.write(DxfGroup.toString(70, 1)); + fw.write(DxfGroup.toString(9, "$LIMMAX")); + fw.write(DxfGroup.toString(10, envelope.getMaxX(), 6)); + fw.write(DxfGroup.toString(20, envelope.getMaxY(), 6)); + fw.write(DxfGroup.toString(9, "$LIMMIN")); + fw.write(DxfGroup.toString(10, envelope.getMinX(), 6)); + fw.write(DxfGroup.toString(20, envelope.getMinY(), 6)); + fw.write(DxfGroup.toString(9, "$LUNITS")); + fw.write(DxfGroup.toString(70, 2)); + fw.write(DxfGroup.toString(9, "$LUPREC")); + fw.write(DxfGroup.toString(70, 2)); + fw.write(DxfGroup.toString(0, "ENDSEC")); + + // ECRITURE DES TABLES + fw.write(DxfGroup.toString(0, "SECTION")); + fw.write(DxfGroup.toString(2, "TABLES")); + fw.write(DxfGroup.toString(0, "TABLE")); + fw.write(DxfGroup.toString(2, "STYLE")); + fw.write(DxfGroup.toString(70, 1)); + fw.write(DxfGroup.toString(0, "STYLE")); // added by L. Becker on 2006-11-08 + DxfTABLE_STYLE_ITEM style = + new DxfTABLE_STYLE_ITEM("STANDARD", 0, 0f, 1f, 0f, 0, 1.0f, "xxx.txt", "yyy.txt"); + fw.write(style.toString()); + fw.write(DxfGroup.toString(0, "ENDTAB")); + fw.write(DxfGroup.toString(0, "TABLE")); + fw.write(DxfGroup.toString(2, "LTYPE")); + fw.write(DxfGroup.toString(70, 1)); + fw.write(DxfGroup.toString(0, "LTYPE")); // added by L. Becker on 2006-11-08 + DxfTABLE_LTYPE_ITEM ltype = + new DxfTABLE_LTYPE_ITEM("CONTINUE", 0, "", 65, 0f, new float[0]); + fw.write(ltype.toString()); + fw.write(DxfGroup.toString(0, "ENDTAB")); + fw.write(DxfGroup.toString(0, "TABLE")); + fw.write(DxfGroup.toString(2, "LAYER")); + fw.write(DxfGroup.toString(70, 2)); + for (String layerName : layerNames) { + DxfTABLE_LAYER_ITEM dxfLayer = + new DxfTABLE_LAYER_ITEM(layerName, 0, 131, "CONTINUE"); + fw.write(DxfGroup.toString(0, "LAYER")); // added by L. Becker on 2006-11-08 + fw.write(dxfLayer.toString()); + if (suffix) { + dxfLayer = new DxfTABLE_LAYER_ITEM(layerName + "_", + 0, 131, "CONTINUE"); + fw.write(DxfGroup.toString(0, "LAYER")); // added by L. Becker on 2006-11-08 + fw.write(dxfLayer.toString()); + } + } + fw.write(DxfGroup.toString(0, "ENDTAB")); + fw.write(DxfGroup.toString(0, "ENDSEC")); + + // ECRITURE DES FEATURES + fw.write(DxfGroup.toString(0, "SECTION")); + fw.write(DxfGroup.toString(2, "ENTITIES")); + for (Feature feature : features.getFeatures()) { + // use the layer attribute for layer name + String entity; + if (feature.getSchema().hasAttribute("LAYER")) { + entity = DxfENTITY.feature2Dxf(feature, feature.getString("LAYER"), suffix); + } + // use the JUMP layer name for DXF layer name + else if (layerNames.length > 0) { + entity = DxfENTITY.feature2Dxf(feature, layerNames[0], suffix); + } + else { + entity = DxfENTITY.feature2Dxf(feature, "0", suffix); + } + if (entity != null) { + fw.write(entity); + } + } + fw.write(DxfGroup.toString(0, "ENDSEC")); + + // FIN DE FICHIER + fw.write(DxfGroup.toString(0, "EOF")); + fw.flush(); + } catch(IOException ioe) { + ioe.printStackTrace(); + } finally { + if (null != fw) { + try { + fw.close(); + } catch(IOException ignored){} + } + } + } + + public static void main(String[] args) { + JFileChooser jfc = new JFileChooser("C:/Michael/Test/dxf"); + File f = null; + int r = jfc.showOpenDialog(new JFrame()); + if(r == JFileChooser.APPROVE_OPTION) { + f = jfc.getSelectedFile(); + } + try { + DxfFile dxfFile = DxfFile.createFromFile(f); + f = new File("C:/Michael/Test/dxf/essai.dxf"); + java.io.BufferedWriter bw = new java.io.BufferedWriter(new java.io.FileWriter(f)); + bw.write(dxfFile.header.toString()); + bw.write(dxfFile.tables.toString()); + bw.write(dxfFile.entities.toString()); + bw.write(DxfGroup.toString(0, "EOF")); + bw.close(); + } catch(IOException ignored) {} + } + +} diff --git a/src/main/java/fr/michaelm/jump/drivers/dxf/DxfGroup.java b/src/main/java/fr/michaelm/jump/drivers/dxf/DxfGroup.java new file mode 100644 index 0000000..3c42e8a --- /dev/null +++ b/src/main/java/fr/michaelm/jump/drivers/dxf/DxfGroup.java @@ -0,0 +1,161 @@ +/* + * Library name : dxf + * (C) 2021 Michaël Michaud + * + * This program 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 2 + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * For more information, contact: + * + * m.michael.michaud@orange.fr + * + */ + +package fr.michaelm.jump.drivers.dxf; + +import java.io.RandomAccessFile; +import java.io.IOException; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.util.Locale; + +/** + * DxfGroup is a group containing a dxf code and a dxf value. + * The class contains several utils to read and write groups an to format data. + * @author Michaël Michaud + */ +public class DxfGroup { + + // Write international decimal symbol (.), not the french one (,) + private static final DecimalFormatSymbols dfs = new DecimalFormatSymbols(Locale.US); + + private static final DecimalFormat[] decimalFormats = new DecimalFormat[]{ + new DecimalFormat("#0", dfs), + new DecimalFormat("#0.0", dfs), + new DecimalFormat("#0.00", dfs), + new DecimalFormat("#0.000", dfs), + new DecimalFormat("#0.0000", dfs), + new DecimalFormat("#0.00000", dfs), + new DecimalFormat("#0.000000", dfs), + new DecimalFormat("#0.0000000", dfs), + new DecimalFormat("#0.00000000", dfs), + new DecimalFormat("#0.000000000", dfs), + new DecimalFormat("#0.0000000000", dfs), + new DecimalFormat("#0.00000000000", dfs), + new DecimalFormat("#0.000000000000", dfs)}; + + private int code = -1; + private String value; + private long address; + + public DxfGroup(int code, String value) { + this.code = code; + this.value = value; + } + + public DxfGroup(String code, String value) { + try { + this.value = value; + this.code = Integer.parseInt(code.trim()); + } + catch(NumberFormatException nfe) { + System.out.println("Error reading group: \"" + code + "=" + + value + "\" is not a valid code/value pair"); + } + } + + public int getCode() {return code;} + public void setCode(int code) {this.code = code;} + public String getValue() {return value;} + public int getIntValue() {return Integer.parseInt(value.trim());} + public float getFloatValue() {return Float.parseFloat(value.trim());} + public double getDoubleValue() {return Double.parseDouble(value.trim());} + public void setValue(String value) {this.value = value;} + public long getAddress() {return address;} + private void setAddress(long address) {this.address = address;} + + public boolean equals(Object other){ + if (other instanceof DxfGroup && + code==((DxfGroup)other).getCode() && + value.equals(((DxfGroup)other).getValue())) { + return true; + } + else return false; + } + + public String toString() { + String codeString = " " + code; + int stringLength = codeString.length(); + codeString = codeString.substring(stringLength-(code<1000?3:4), stringLength); + return codeString + "\r\n" + value + "\r\n"; + } + + public void print(int indent) { + for (int i = 0 ; i < indent ; i++) System.out.print(" "); + System.out.println("" + code + " = " + value); + } + + public boolean isValid() { + return code >= 0; + } + + public static String int34car(int code) { + if (code<10) return " " + code; + else if (code<100) return " " + code; + else return Integer.toString(code); + } + + public static String int6car(int value) { + String s = " " + value; + return s.substring(s.length()-6); + } + + public static String toString(int code, String value) { + return int34car(code) + "\r\n" + value + "\r\n"; + } + + public static String toString(int code, int value) { + return int34car(code) + "\r\n" + int6car(value) + "\r\n"; + } + + public static String toString(int code, float value, int decimalPartLength) { + return int34car(code) + "\r\n" + + decimalFormats[decimalPartLength].format(value) + "\r\n"; + } + + public static String toString(int code, double value, int decimalPartLength) { + return int34car(code) + "\r\n" + + decimalFormats[decimalPartLength].format(value) + "\r\n"; + } + + public static String toString(int code, Object value) { + if (value instanceof String) {return toString(code, (String)value);} + else if (value instanceof Integer) {return toString(code, ((Integer)value).intValue());} + else if (value instanceof Float) {return toString(code, (Float)value, 3);} + else if (value instanceof Double) {return toString(code, (Double)value, 6);} + else return toString(code, value.toString()); + } + + /** + * Read a group from the current position in a RandomAccessFime. + * @return a DxfGroup + */ + public static DxfGroup readGroup(RandomAccessFile raf) throws IOException { + long pos = raf.getFilePointer(); + DxfGroup dxfGroup = new DxfGroup(raf.readLine(), raf.readLine()); + dxfGroup.setAddress(pos); + return dxfGroup; + } + +} diff --git a/src/main/java/fr/michaelm/jump/drivers/dxf/DxfHEADER.java b/src/main/java/fr/michaelm/jump/drivers/dxf/DxfHEADER.java new file mode 100644 index 0000000..2eb8892 --- /dev/null +++ b/src/main/java/fr/michaelm/jump/drivers/dxf/DxfHEADER.java @@ -0,0 +1,243 @@ +/* + * Library name : dxf + * (C) 2021 Michaël Michaud + * + * This program 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 2 + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * For more information, contact: + * + * m.michael.michaud@orange.fr + * + */ + +package fr.michaelm.jump.drivers.dxf; + +import java.io.RandomAccessFile; +import java.io.IOException; +import java.util.Map; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.ArrayList; +import java.util.Iterator; + +/** + * A DXF HEADER section. + * This class has a static method to read the header section of a DXF file + * and a toString method to format the header section into DXF format + * @author Michaël Michaud + */ +public class DxfHEADER { + public static final String ACADVER = "ACADVER"; + public static final String ANGBASE = "ANGBASE"; + public static final String ANGDIR = "ANGDIR"; + public static final String ATTDIA = "ATTDIA"; + public static final String ATTMODE = "ATTMODE"; + public static final String ATTREQ = "ATTREQ"; + public static final String AUNITS = "AUNITS"; + public static final String AUPREC = "AUPREC"; + public static final String AXISMODE = "AXISMODE"; + public static final String AXISUNIT = "AXISUNIT"; + public static final String BLIPMODE = "BLIPMODE"; + public static final String CECOLOR = "CECOLOR"; + public static final String CELTYPE = "CELTYPE"; + public static final String CHAMFERA = "CHAMFERA"; + public static final String CHAMFERB = "CHAMFERB"; + public static final String CLAYER = "CLAYER"; + public static final String COORDS = "COORDS"; + public static final String DIMALT = "DIMALT"; + public static final String DIMALTD = "DIMALTD"; + public static final String DIMALTF = "DIMALTF"; + public static final String DIMAPOST = "DIMAPOST"; + public static final String DIMASO = "DIMASO"; + public static final String DIMASZ = "DIMASZ"; + public static final String DIMBLK = "DIMBLK"; + public static final String DIMBLK1 = "DIMBLK1"; + public static final String DIMBLK2 = "DIMBLK2"; + public static final String DIMCEN = "DIMCEN"; + public static final String DIMCLRD = "DIMCLRD"; + public static final String DIMCLRE = "DIMCLRE"; + public static final String DIMCLRT = "DIMCLRT"; + public static final String DIMDLE = "DIMDLE"; + public static final String DIMDLI = "DIMDLI"; + public static final String DIMEXE = "DIMEXE"; + public static final String DIMEXO = "DIMEXO"; + public static final String DIMGAP = "DIMGAP"; + public static final String DIMLFAC = "DIMLFAC"; + public static final String DIMLIM = "DIMLIM"; + public static final String DIMPOST = "DIMPOST"; + public static final String DIMRND = "DIMRND"; + public static final String DIMSAH = "DIMSAH"; + public static final String DIMSCALE = "DIMSCALE"; + public static final String DIMSE1 = "DIMSE1"; + public static final String DIMSE2 = "DIMSE2"; + public static final String DIMSHO = "DIMSHO"; + public static final String DIMSOXD = "DIMSOXD"; + public static final String DIMSTYLE = "DIMSTYLE"; + public static final String DIMTAD = "DIMTAD"; + public static final String DIMTFAC = "DIMTFAC"; + public static final String DIMTIH = "DIMTIH"; + public static final String DIMTIX = "DIMTIX"; + public static final String DIMTM = "DIMTM"; + public static final String DIMTOFL = "DIMTOFL"; + public static final String DIMTOH = "DIMTOH"; + public static final String DIMTOL = "DIMTOL"; + public static final String DIMTP = "DIMTP"; + public static final String DIMTSZ = "DIMTSZ"; + public static final String DIMTVP = "DIMTVP"; + public static final String DIMTXT = "DIMTXT"; + public static final String DIMZIN = "DIMZIN"; + public static final String DRAGMODE = "DRAGMODE"; + public static final String DWGCODEPAGE = "DWGCODEPAGE"; + public static final String ELEVATION = "ELEVATION"; + public static final String EXTMAX = "EXTMAX"; + public static final String EXTMIN = "EXTMIN"; + public static final String FASTZOOM = "FASTZOOM"; + public static final String FILLETRAD = "FILLETRAD"; + public static final String FILLMODE = "FILLMODE"; + public static final String GRIDMODE = "GRIDMODE"; + public static final String GRIDUNIT = "GRIDUNIT"; + public static final String HANDLING = "HANDLING"; + public static final String HANDSEED = "HANDSEED"; + public static final String INSBASE = "INSBASE"; + public static final String LIMCHECK = "LIMCHECK"; + public static final String LIMMAX = "LIMMAX"; + public static final String LIMMIN = "LIMMIN"; + public static final String LTSCALE = "LTSCALE"; + public static final String LUNITS = "LUNITS"; + public static final String LUPREC = "LUPREC"; + public static final String MAXACTVP = "MAXACTVP"; + public static final String MENU = "MENU"; + public static final String MIRRTEXT = "MIRRTEXT"; + public static final String ORTHOMODE = "ORTHOMODE"; + public static final String OSMODE = "OSMODE"; + public static final String PDMODE = "PDMODE"; + public static final String PDSIZE = "PDSIZE"; + public static final String PELEVATION = "PELEVATION"; + public static final String PEXTMAX = "PEXTMAX"; + public static final String PEXTMIN = "PEXTMIN"; + public static final String PLIMCHECK = "PLIMCHECK"; + public static final String PLIMMAX = "PLIMMAX"; + public static final String PLIMMIN = "PLIMMIN"; + public static final String PLINEGEN = "PLINEGEN"; + public static final String PLINEWID = "PLINEWID"; + public static final String PSLTSCALE = "PSLTSCALE"; + public static final String PUCSNAME = "PUCSNAME"; + public static final String PUCSORG = "PUCSORG"; + public static final String PUCSXDIR = "PUCSXDIR"; + public static final String PUCSYDIR = "PUCSYDIR"; + public static final String QTEXTMODE = "QTEXTMODE"; + public static final String REGENMODE = "REGENMODE"; + public static final String SHADEDGE = "SHADEDGE"; + public static final String SHADEDIF = "SHADEDIF"; + public static final String SKETCHINC = "SKETCHINC"; + public static final String SKPOLY = "SKPOLY"; + public static final String SNAPANG = "SNAPANG"; + public static final String SNAPBASE = "SNAPBASE"; + public static final String SNAPISOPAIR = "SNAPISOPAIR"; + public static final String SNAPMODE = "SNAPMODE"; + public static final String SNAPSTYLE = "SNAPSTYLE"; + public static final String SNAPUNIT = "SNAPUNIT"; + public static final String SPLFRAME = "SPLFRAME"; + public static final String SPLINESEGS = "SPLINESEGS"; + public static final String SPLINETYPE = "SPLINETYPE"; + public static final String SURFTAB1 = "SURFTAB1"; + public static final String SURFTAB2 = "SURFTAB2"; + public static final String SURFTYPE = "SURFTYPE"; + public static final String SURFU = "SURFU"; + public static final String SURFV = "SURFV"; + public static final String TDCREATE = "TDCREATE"; + public static final String TDINDWG = "TDINDWG"; + public static final String TDUPDATE = "TDUPDATE"; + public static final String TDUSRTIMER = "TDUSRTIMER"; + public static final String TEXTSIZE = "TEXTSIZE"; + public static final String TEXTSTYLE = "TEXTSTYLE"; + public static final String THICKNESS = "THICKNESS"; + public static final String TILEMODE = "TILEMODE"; + public static final String TRACEWID = "TRACEWID"; + public static final String UCSNAME = "UCSNAME"; + public static final String UCSORG = "UCSORG"; + public static final String UCSXDIR = "UCSXDIR"; + public static final String UCSYDIR = "UCSYDIR"; + public static final String UNITMODE = "UNITMODE"; + public static final String USERI1 = "USERI1"; + public static final String USERI2 = "USERI2"; + public static final String USERI3 = "USERI3"; + public static final String USERI4 = "USERI4"; + public static final String USERI5 = "USERI5"; + public static final String USERR1 = "USERR1"; + public static final String USERR2 = "USERR2"; + public static final String USERR3 = "USERR3"; + public static final String USERR4 = "USERR4"; + public static final String USERR5 = "USERR5"; + public static final String USRTIMER = "USRTIMER"; + public static final String VIEWCTR = "VIEWCTR"; + public static final String VIEWDIR = "VIEWDIR"; + public static final String VIEWSIZE = "VIEWSIZE"; + public static final String VISRETAIN = "VISRETAIN"; + public static final String WORLDVIEW = "WORLDVIEW"; + + Map> headerTable; + + public DxfHEADER() { + headerTable = new LinkedHashMap<>(); + } + + public List getVariable(String nomVariable) { + return headerTable.get(nomVariable); + } + + public void setVariable(String nomVariable, List groups) { + headerTable.put(nomVariable, groups); + } + + public static DxfHEADER readHeader(RandomAccessFile raf) throws NumberFormatException, IOException { + DxfHEADER header = new DxfHEADER(); + DxfGroup group; + String nomVariable = null; + while (null != (group = DxfGroup.readGroup(raf))) { + if (group.equals(DxfFile.ENDSEC)) break; + else if (group.getCode()==9) { + if (DxfFile.DEBUG) group.print(4); + nomVariable = group.getValue(); + nomVariable = nomVariable.substring(1); + header.headerTable.put(nomVariable, new ArrayList<>(1)); + } + //else if (group.getCode() == 999) {} + else if (nomVariable != null) { + if (DxfFile.DEBUG) group.print(8); + List groups = header.headerTable.get(nomVariable); + groups.add(group); + } + //else { } + } + return header; + } + + public String toString() { + Iterator it = headerTable.keySet().iterator(); + StringBuilder sb = new StringBuilder(DxfFile.SECTION.toString()); + sb.append(DxfFile.HEADER); + while (it.hasNext()) { + String var = it.next(); + sb.append(DxfGroup.toString(9, "$"+var)); + List liste = headerTable.get(var); + for (DxfGroup dxfGroup : liste) { + sb.append(dxfGroup.toString()); + } + } + sb.append(DxfFile.ENDSEC); + return sb.toString(); + } +} diff --git a/src/main/java/fr/michaelm/jump/drivers/dxf/DxfLINE.java b/src/main/java/fr/michaelm/jump/drivers/dxf/DxfLINE.java new file mode 100644 index 0000000..9ebf529 --- /dev/null +++ b/src/main/java/fr/michaelm/jump/drivers/dxf/DxfLINE.java @@ -0,0 +1,82 @@ +/* + * Library name : dxf + * (C) 2021 Michaël Michaud + * + * This program 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 2 + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * For more information, contact: + * + * m.michael.michaud@orange.fr + * + */ + +package fr.michaelm.jump.drivers.dxf; + +import java.io.RandomAccessFile; +import java.io.IOException; + +import com.vividsolutions.jump.feature.Feature; +import com.vividsolutions.jump.feature.BasicFeature; +import com.vividsolutions.jump.feature.FeatureCollection; +import org.locationtech.jts.geom.Coordinate; +import org.locationtech.jts.geom.GeometryFactory; + +/** + * LINE DXF entity. + * This class has a static method reading a DXF LINE and adding the new + * feature to a FeatureCollection + * @author Michaël Michaud + */ +public class DxfLINE extends DxfENTITY { + + public DxfLINE() {super("DEFAULT");} + + public static DxfGroup readEntity(RandomAccessFile raf, FeatureCollection entities) + throws IOException { + Feature feature = new BasicFeature(DxfFile.DXF_SCHEMA); + feature.setAttribute("LTYPE", "BYLAYER"); + feature.setAttribute("THICKNESS", 0.0); + feature.setAttribute("COLOR", 256); // equivalent to BYLAYER + double x1=Double.NaN, y1=Double.NaN, z1=Double.NaN; + double x2=Double.NaN, y2=Double.NaN, z2=Double.NaN; + DxfGroup group; + while (null != (group = DxfGroup.readGroup(raf))) { + int code = group.getCode(); + if (code==0) break; + if (DxfFile.DEBUG) group.print(12); + if (code==8) feature.setAttribute("LAYER", group.getValue()); + else if (code==6) feature.setAttribute("LTYPE", group.getValue()); + else if (code==39) feature.setAttribute("THICKNESS", group.getDoubleValue()); + else if (code==62) feature.setAttribute("COLOR", group.getIntValue()); + else if (code==10) x1 = group.getDoubleValue(); + else if (code==20) y1 = group.getDoubleValue(); + else if (code==30) z1 = group.getDoubleValue(); + else if (code==11) x2 = group.getDoubleValue(); + else if (code==21) y2 = group.getDoubleValue(); + else if (code==31) z2 = group.getDoubleValue(); + //else {} + } + if (!Double.isNaN(x1) && !Double.isNaN(y1) && !Double.isNaN(x2) && !Double.isNaN(y2)) { + GeometryFactory gf = new GeometryFactory(DPM,0); + feature.setGeometry(gf.createLineString( + new Coordinate[]{new Coordinate(x1,y1,z1),new Coordinate(x2,y2,z2)}) + ); + if (DxfFile.DEBUG) System.out.println(" " + feature.getString("LAYER") + " : " + feature.getGeometry()); + entities.add(feature); + } + return group; + } + +} diff --git a/src/main/java/fr/michaelm/jump/drivers/dxf/DxfLWPOLYLINE.java b/src/main/java/fr/michaelm/jump/drivers/dxf/DxfLWPOLYLINE.java new file mode 100644 index 0000000..d965f90 --- /dev/null +++ b/src/main/java/fr/michaelm/jump/drivers/dxf/DxfLWPOLYLINE.java @@ -0,0 +1,132 @@ +/* + * Library name : dxf + * (C) 2021 Michaël Michaud + * + * This program 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 2 + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * For more information, contact: + * + * m.michael.michaud@orange.fr + * + */ + +package fr.michaelm.jump.drivers.dxf; + +import java.io.RandomAccessFile; +import java.io.IOException; +import com.vividsolutions.jump.feature.Feature; +import com.vividsolutions.jump.feature.BasicFeature; +import com.vividsolutions.jump.feature.FeatureCollection; +import org.locationtech.jts.geom.*; + +/** + * LWPOLYLINE DXF entity. + * This class has a static method reading a DXF LWPOLYLINE and adding the new + * feature to a FeatureCollection + * @author Michaël Michaud + */ +public class DxfLWPOLYLINE extends DxfENTITY { + + public DxfLWPOLYLINE() {super("DEFAULT");} + + public static DxfGroup readEntity(RandomAccessFile raf, FeatureCollection entities) + throws IOException { + Feature feature = new BasicFeature(entities.getFeatureSchema()); + GeometryFactory gf = new GeometryFactory(DPM,0); + String geomType = "LineString"; + CoordinateList coordList = new CoordinateList(); + feature.setAttribute("LTYPE", "BYLAYER"); + feature.setAttribute("ELEVATION", 0.0); + feature.setAttribute("THICKNESS", 0.0); + feature.setAttribute("COLOR", 256); // equivalent to BYLAYER + double x=Double.NaN; + double y=Double.NaN; + double z=Double.NaN; + Coordinate coord = null; + DxfGroup group = DxfFile.ENTITIES; + int code; + while (0 != (code = group.getCode())) { + if (DxfFile.DEBUG) group.print(12); + if (code==8) { + feature.setAttribute("LAYER", group.getValue()); + } + else if (code==6) { + feature.setAttribute("LTYPE", group.getValue()); + } + else if (code==38) { + feature.setAttribute("ELEVATION", group.getDoubleValue()); + z = group.getDoubleValue(); + } + else if (code==39) { + feature.setAttribute("THICKNESS", group.getDoubleValue()); + } + else if (code==62) { + feature.setAttribute("COLOR", group.getIntValue()); + } + else if (code==70) { + if ((group.getIntValue()&1)==1) geomType = "Polygon"; + } + else if (code==10) { + coord = new Coordinate(); + coord.x = group.getDoubleValue(); + } + else if (code==20) { + if (coord != null) { + coord.y = group.getDoubleValue(); + coordList.add(new Coordinate(x, y, z)); + } + } + //else {} + group = DxfGroup.readGroup(raf); + } + if (geomType.equals("LineString")) { + // Handle cases where coordList does not describe a valid Line + if (coordList.size() == 1) { + feature.setGeometry(gf.createPoint(coordList.getCoordinate(0))); + } + else if (coordList.size() == 2 && + coordList.getCoordinate(0).equals(coordList.getCoordinate(1))) { + feature.setGeometry(gf.createPoint(coordList.getCoordinate(0))); + } + else { + feature.setGeometry(gf.createLineString(coordList.toCoordinateArray())); + } + if (DxfFile.DEBUG) System.out.println(" " + feature.getString("LAYER") + " : " + feature.getGeometry()); + entities.add(feature); + } + else if (geomType.equals("Polygon")) { + coordList.closeRing(); + // Handle cases where coordList does not describe a valid Polygon + if (coordList.size() == 1) { + feature.setGeometry(gf.createPoint(coordList.getCoordinate(0))); + } + else if (coordList.size() == 2 && + coordList.getCoordinate(0).equals(coordList.getCoordinate(1))) { + feature.setGeometry(gf.createPoint(coordList.getCoordinate(0))); + } + else if (coordList.size() == 2 || coordList.size() == 3) { + feature.setGeometry(gf.createLineString(coordList.toCoordinateArray())); + } + else { + feature.setGeometry(gf.createPolygon(gf.createLinearRing(coordList.toCoordinateArray()))); + } + if (DxfFile.DEBUG) System.out.println(" " + feature.getString("LAYER") + " : " + feature.getGeometry()); + entities.add(feature); + } + //else {} + return group; + } + +} diff --git a/src/main/java/fr/michaelm/jump/drivers/dxf/DxfPOINT.java b/src/main/java/fr/michaelm/jump/drivers/dxf/DxfPOINT.java new file mode 100644 index 0000000..5aef597 --- /dev/null +++ b/src/main/java/fr/michaelm/jump/drivers/dxf/DxfPOINT.java @@ -0,0 +1,79 @@ +/* + * Library name : dxf + * (C) 2021 Michaël Michaud + * + * This program 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 2 + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * For more information, contact: + * + * m.michael.michaud@orange.fr + * + */ + +package fr.michaelm.jump.drivers.dxf; + +import java.io.RandomAccessFile; +import java.io.IOException; + +import com.vividsolutions.jump.feature.Feature; +import com.vividsolutions.jump.feature.BasicFeature; +import com.vividsolutions.jump.feature.FeatureCollection; +import org.locationtech.jts.geom.Coordinate; +import org.locationtech.jts.geom.GeometryFactory; + + +/** + * POINT DXF entity. + * This class has a static method reading a DXF POINT and adding the new + * feature to a FeatureCollection + * @author Michaël Michaud + */ +public class DxfPOINT extends DxfENTITY { + + public DxfPOINT() {super("DEFAULT");} + + public static DxfGroup readEntity(RandomAccessFile raf, + FeatureCollection entities) + throws IOException { + Feature feature = new BasicFeature(DxfFile.DXF_SCHEMA); + feature.setAttribute("LTYPE", "BYLAYER"); + feature.setAttribute("THICKNESS", 0.0); + feature.setAttribute("COLOR", 256); // equivalent to BYLAYER + double x=Double.NaN, y=Double.NaN, z=Double.NaN; + DxfGroup group; + while (null != (group = DxfGroup.readGroup(raf))) { + int code = group.getCode(); + if (code == 0) break; + if (DxfFile.DEBUG) group.print(12); + if (code==8) feature.setAttribute("LAYER", group.getValue()); + else if (code==6) feature.setAttribute("LTYPE", group.getValue()); + //else if (code==38) feature.setAttribute("ELEVATION", new Double(group.getDoubleValue())); + else if (code==39) feature.setAttribute("THICKNESS", group.getDoubleValue()); + else if (code==62) feature.setAttribute("COLOR", group.getIntValue()); + else if (code==10) x = group.getDoubleValue(); + else if (code==20) y = group.getDoubleValue(); + else if (code==30) z = group.getDoubleValue(); + //else {} + } + if (!Double.isNaN(x) && !Double.isNaN(y)) { + GeometryFactory gf = new GeometryFactory(DPM,0); + feature.setGeometry(gf.createPoint(new Coordinate(x,y,z))); + if (DxfFile.DEBUG) System.out.println(" " + feature.getString("LAYER") + " : " + feature.getGeometry()); + entities.add(feature); + } + return group; + } + +} diff --git a/src/main/java/fr/michaelm/jump/drivers/dxf/DxfPOLYLINE.java b/src/main/java/fr/michaelm/jump/drivers/dxf/DxfPOLYLINE.java new file mode 100644 index 0000000..12306e9 --- /dev/null +++ b/src/main/java/fr/michaelm/jump/drivers/dxf/DxfPOLYLINE.java @@ -0,0 +1,126 @@ +/* + * Library name : dxf + * (C) 2021 Michaël Michaud + * + * This program 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 2 + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * For more information, contact: + * + * m.michael.michaud@orange.fr + * + */ + +package fr.michaelm.jump.drivers.dxf; + +import java.io.RandomAccessFile; +import java.io.IOException; + +import com.vividsolutions.jump.feature.Feature; +import com.vividsolutions.jump.feature.BasicFeature; +import com.vividsolutions.jump.feature.FeatureCollection; +import org.locationtech.jts.geom.CoordinateList; +import org.locationtech.jts.geom.GeometryFactory; + + +/** + * POLYLINE DXF entity. + * This class has a static method reading a DXF POLYLINE and adding the new + * feature to a FeatureCollection + * @author Michaël Michaud + */ +// History +public class DxfPOLYLINE extends DxfENTITY { + + public DxfPOLYLINE() {super("DEFAULT");} + + public static DxfGroup readEntity(RandomAccessFile raf, + FeatureCollection entities) + throws IOException { + Feature feature = new BasicFeature(entities.getFeatureSchema()); + String geomType = "LineString"; + CoordinateList coordList = new CoordinateList(); + feature.setAttribute("LTYPE", "BYLAYER"); + feature.setAttribute("THICKNESS", 0.0); + feature.setAttribute("COLOR", 256); // equivalent to BYLAYER + //double x=Double.NaN, y=Double.NaN, z=Double.NaN; + DxfGroup group = DxfFile.ENTITIES; + GeometryFactory gf = new GeometryFactory(DPM,0); + while (!group.equals(SEQEND)) { + if (DxfFile.DEBUG) group.print(12); + int code = group.getCode(); + if (code==8) { + feature.setAttribute("LAYER", group.getValue()); + } + else if (code==6) { + feature.setAttribute("LTYPE", group.getValue()); + } + else if (code==39) { + feature.setAttribute("THICKNESS", group.getDoubleValue()); + } + else if (code==62) { + feature.setAttribute("COLOR", group.getIntValue()); + } + else if (code==70) { + if ((group.getIntValue()&1)==1) geomType = "Polygon"; + } + else if (group.equals(VERTEX)) { + group = DxfVERTEX.readEntity(raf, coordList); + continue; + } + else if (group.equals(SEQEND)) { + continue; + } + //else {} + group = DxfGroup.readGroup(raf); + } + if (geomType.equals("LineString")) { + // Handle cases where coordList does not describe a valid Line + if (coordList.size() == 1) { + feature.setGeometry(gf.createPoint(coordList.getCoordinate(0))); + } + else if (coordList.size() == 2 && + coordList.getCoordinate(0).equals(coordList.getCoordinate(1))) { + feature.setGeometry(gf.createPoint(coordList.getCoordinate(0))); + } + else { + feature.setGeometry(gf.createLineString(coordList.toCoordinateArray())); + } + if (DxfFile.DEBUG) System.out.println(" " + feature.getString("LAYER") + " : " + feature.getGeometry()); + entities.add(feature); + } + else if (geomType.equals("Polygon")) { + coordList.closeRing(); + // Handle cases where coordList does not describe a valid Polygon + if (coordList.size() == 1) { + feature.setGeometry(gf.createPoint(coordList.getCoordinate(0))); + } + else if (coordList.size() == 2 && + coordList.getCoordinate(0).equals(coordList.getCoordinate(1))) { + feature.setGeometry(gf.createPoint(coordList.getCoordinate(0))); + } + else if (coordList.size() == 2 || coordList.size() == 3) { + feature.setGeometry(gf.createLineString(coordList.toCoordinateArray())); + } + else { + feature.setGeometry(gf.createPolygon(gf.createLinearRing(coordList.toCoordinateArray()))); + } + if (DxfFile.DEBUG) System.out.println(" " + feature.getString("LAYER") + " : " + feature.getGeometry()); + entities.add(feature); + } + //else {} + return group; + } + +} diff --git a/src/main/java/fr/michaelm/jump/drivers/dxf/DxfReader.java b/src/main/java/fr/michaelm/jump/drivers/dxf/DxfReader.java new file mode 100644 index 0000000..2376501 --- /dev/null +++ b/src/main/java/fr/michaelm/jump/drivers/dxf/DxfReader.java @@ -0,0 +1,95 @@ +/* + * Library name : dxf + * (C) 2021 Michaël Michaud + * + * This program 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 2 + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * For more information, contact: + * + * m.michael.michaud@orange.fr + * + */ + +package fr.michaelm.jump.drivers.dxf; + + +import com.vividsolutions.jump.feature.*; +import com.vividsolutions.jump.io.JUMPReader; +import com.vividsolutions.jump.io.DriverProperties; +import com.vividsolutions.jump.io.IllegalParametersException; +import org.locationtech.jts.geom.GeometryFactory; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collection; + + +/** + * DXF reader. + * Use the file name to read in the DriverProperties parameter, read the file + * and return a FeatureCollection. + * @author Michaël Michaud + */ +public class DxfReader implements JUMPReader { + + //private DxfFile dxfFile = null; + + /** Creates new DxfReader */ + public DxfReader() { + } + + /** + * Main method to read a DXF file. + * @param dp 'InputFile' or 'DefaultValue' to specify input .dxf file. + * + */ + public FeatureCollection read(DriverProperties dp) throws Exception { + FeatureCollection result; + String dxfFileName; + String fname; + int loc; + dxfFileName = dp.getProperty("File"); + + if (dxfFileName == null) { + dxfFileName = dp.getProperty("DefaultValue"); + } + + if (dxfFileName == null) { + throw new IllegalParametersException("no File property specified"); + } + + loc = dxfFileName.lastIndexOf(File.separatorChar); + fname = dxfFileName.substring(loc + 1); + loc = fname.lastIndexOf("."); + if (loc == -1) { + throw new IllegalParametersException("Filename must end in '.dxf'"); + } + + //dxfFile = getDXFFile(dxfFileName, dp.getProperty("CompressedFile")); + DxfFile dxfFile; + GeometryFactory factory = new GeometryFactory(); + dxfFile = DxfFile.createFromFile(new File(dxfFileName)); + result = dxfFile.read(factory); + System.gc(); + return result; + } + + private Collection exceptions; + public Collection getExceptions() { + if (exceptions == null) exceptions = new ArrayList<>(); + return exceptions; + } + +} diff --git a/src/main/java/fr/michaelm/jump/drivers/dxf/DxfTABLES.java b/src/main/java/fr/michaelm/jump/drivers/dxf/DxfTABLES.java new file mode 100644 index 0000000..819863c --- /dev/null +++ b/src/main/java/fr/michaelm/jump/drivers/dxf/DxfTABLES.java @@ -0,0 +1,216 @@ +/* + * Library name : dxf + * (C) 2021 Michaël Michaud + * + * This program 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 2 + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * For more information, contact: + * + * m.michael.michaud@orange.fr + * + */ + +package fr.michaelm.jump.drivers.dxf; + +import java.io.RandomAccessFile; +import java.io.IOException; +import java.util.Map; +import java.util.HashMap; + + +/** + * The TABLES section of a DXF file. It contains LAYERs, LTYPEs... + * There is a static reader to read the TABLES section in a DXF file + * and a toString method able to write the section in a DXF form + * @author Michaël Michaud + */ +// History +// 2006-11-12 : Bug fixed x==Double.NaN --> Double.isNaN(x) +public class DxfTABLES { + + public final static DxfGroup TABLE = new DxfGroup(0, "TABLE"); + public final static DxfGroup ENDTAB = new DxfGroup(0, "ENDTAB"); + public final static DxfGroup NBMAX = new DxfGroup(70, "NBMAX"); + public final static DxfGroup APPID = new DxfGroup(2, "APPID"); + public final static DxfGroup DIMSTYLE = new DxfGroup(2, "DIMSTYLE"); + public final static DxfGroup LTYPE = new DxfGroup(2, "LTYPE"); + public final static DxfGroup LAYER = new DxfGroup(2, "LAYER"); + public final static DxfGroup STYLE = new DxfGroup(2, "STYLE"); + public final static DxfGroup UCS = new DxfGroup(2, "UCS"); + public final static DxfGroup VIEW = new DxfGroup(2, "VIEW"); + public final static DxfGroup VPORT = new DxfGroup(2, "VPORT"); + + private Map appId; + private Map dimStyle; + private Map lType; + private Map layer; + private Map style; + private Map ucs; + private Map view; + private Map vPort; + + public DxfTABLES() { + appId = new HashMap<>(); + dimStyle = new HashMap<>(); + lType = new HashMap<>(); + layer = new HashMap<>(); + style = new HashMap<>(); + ucs = new HashMap<>(); + view = new HashMap<>(); + vPort = new HashMap<>(); + } + + public static DxfTABLES readTables(RandomAccessFile raf) throws NumberFormatException, IOException { + DxfTABLES tables = new DxfTABLES(); + DxfGroup group; + //String nomVariable = null; + // Iteration over each table + while (null != (group = DxfGroup.readGroup(raf))) { + if (group.equals(DxfFile.ENDSEC)) break; + //Map map = null; + else if (group.equals(TABLE)) { + // Lecture du groupe portant le nom de la table + group = DxfGroup.readGroup(raf); + //if (group == null) break; // never happens + if (DxfFile.DEBUG) group.print(4); + if (group.equals(APPID)) { + tables.appId = DxfTABLE_APPID_ITEM.readTable(raf); + } + else if (group.equals(DIMSTYLE)) { + tables.dimStyle = DxfTABLE_DIMSTYLE_ITEM.readTable(raf); + } + else if (group.equals(LTYPE)) { + tables.lType = DxfTABLE_LTYPE_ITEM.readTable(raf); + } + else if (group.equals(LAYER)) { + tables.layer = DxfTABLE_LAYER_ITEM.readTable(raf); + } + else if (group.equals(STYLE)) { + tables.style = DxfTABLE_STYLE_ITEM.readTable(raf); + } + else if (group.equals(UCS)) { + tables.ucs = DxfTABLE_UCS_ITEM.readTable(raf); + } + else if (group.equals(VIEW)) { + tables.view = DxfTABLE_VIEW_ITEM.readTable(raf); + } + else if (group.equals(VPORT)) { + tables.vPort = DxfTABLE_VPORT_ITEM.readTable(raf); + } + //else if (group.getCode() == 999) {} + //else {} + } + //else if (group.getCode() == 999) {} + //else {} + } + return tables; + } + + public String toString() { + StringBuilder sb = new StringBuilder(DxfFile.SECTION.toString()); + sb.append(DxfFile.TABLES); + if (vPort.size() > 0) { + sb.append(DxfTABLES.TABLE.toString()); + sb.append(DxfTABLES.VPORT.toString()); + sb.append(DxfGroup.toString(70, Integer.toString(vPort.size()))); + //Iterator it = vPort.keySet().iterator(); + for (DxfTABLE_ITEM item : vPort.values()) { + sb.append(DxfGroup.toString(0, "VPORT")); + sb.append(item.toString()); + } + sb.append(DxfTABLES.ENDTAB.toString()); + } + if (appId.size() > 0) { + sb.append(DxfTABLES.TABLE.toString()); + sb.append(DxfTABLES.APPID.toString()); + sb.append(DxfGroup.toString(70, Integer.toString(appId.size()))); + //Iterator it = appId.keySet().iterator(); + for (DxfTABLE_ITEM item : appId.values()) { + sb.append(DxfGroup.toString(0, "APPID")); + sb.append(item.toString()); + } + sb.append(DxfTABLES.ENDTAB.toString()); + } + if (dimStyle.size() > 0) { + sb.append(DxfTABLES.TABLE.toString()); + sb.append(DxfTABLES.DIMSTYLE.toString()); + sb.append(DxfGroup.toString(70, Integer.toString(dimStyle.size()))); + //Iterator it = dimStyle.keySet().iterator(); + for (DxfTABLE_ITEM item : dimStyle.values()) { + sb.append(DxfGroup.toString(0, "DIMSTYLE")); + sb.append(item.toString()); + } + sb.append(DxfTABLES.ENDTAB.toString()); + } + if (lType.size() > 0) { + sb.append(DxfTABLES.TABLE.toString()); + sb.append(DxfTABLES.LTYPE.toString()); + sb.append(DxfGroup.toString(70, Integer.toString(lType.size()))); + //Iterator it = lType.keySet().iterator(); + for (DxfTABLE_ITEM item : lType.values()) { + sb.append(DxfGroup.toString(0, "LTYPE")); + sb.append(item.toString()); + } + sb.append(DxfTABLES.ENDTAB.toString()); + } + if (layer.size() > 0) { + sb.append(DxfTABLES.TABLE.toString()); + sb.append(DxfTABLES.LAYER.toString()); + sb.append(DxfGroup.toString(70, Integer.toString(layer.size()))); + //Iterator it = layer.keySet().iterator(); + for (DxfTABLE_ITEM item : layer.values()) { + sb.append(DxfGroup.toString(0, "LAYER")); + sb.append(item.toString()); + } + sb.append(DxfTABLES.ENDTAB.toString()); + } + if (style.size() > 0) { + sb.append(DxfTABLES.TABLE.toString()); + sb.append(DxfTABLES.STYLE.toString()); + sb.append(DxfGroup.toString(70, Integer.toString(style.size()))); + //Iterator it = style.keySet().iterator(); + for (DxfTABLE_ITEM item : style.values()) { + sb.append(DxfGroup.toString(0, "STYLE")); + sb.append(item.toString()); + } + sb.append(DxfTABLES.ENDTAB.toString()); + } + if (ucs.size() >0) { + sb.append(DxfTABLES.TABLE.toString()); + sb.append(DxfTABLES.UCS.toString()); + sb.append(DxfGroup.toString(70, Integer.toString(ucs.size()))); + //Iterator it = ucs.keySet().iterator(); + for (DxfTABLE_ITEM item : ucs.values()) { + sb.append(DxfGroup.toString(0, "UCS")); + sb.append(item.toString()); + } + sb.append(DxfTABLES.ENDTAB.toString()); + } + if (view.size() >0) { + sb.append(DxfTABLES.TABLE.toString()); + sb.append(DxfTABLES.VIEW.toString()); + sb.append(DxfGroup.toString(70, Integer.toString(view.size()))); + //Iterator it = view.keySet().iterator(); + for (DxfTABLE_ITEM item : view.values()) { + sb.append(DxfGroup.toString(0, "VIEW")); + sb.append(item.toString()); + } + sb.append(DxfTABLES.ENDTAB.toString()); + } + sb.append(DxfFile.ENDSEC); + return sb.toString(); + } + +} diff --git a/src/main/java/fr/michaelm/jump/drivers/dxf/DxfTABLE_APPID_ITEM.java b/src/main/java/fr/michaelm/jump/drivers/dxf/DxfTABLE_APPID_ITEM.java new file mode 100644 index 0000000..d19600b --- /dev/null +++ b/src/main/java/fr/michaelm/jump/drivers/dxf/DxfTABLE_APPID_ITEM.java @@ -0,0 +1,66 @@ +/* + * Library name : dxf + * (C) 2021 Michaël Michaud + * + * This program 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 2 + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * For more information, contact: + * + * m.michael.michaud@orange.fr + * + */ + +package fr.michaelm.jump.drivers.dxf; + +import java.io.RandomAccessFile; +import java.io.IOException; +import java.util.Map; +import java.util.LinkedHashMap; + +/** + * The APPID item in the TABLES section + * There is a static reader to read the item in a DXF file + * and a toString method able to write it in a DXF form + * @author Michaël Michaud + */ +public class DxfTABLE_APPID_ITEM extends DxfTABLE_ITEM { + + public DxfTABLE_APPID_ITEM(String name, int flags) { + super(name, flags); + } + + public static Map readTable(RandomAccessFile raf) throws IOException { + DxfTABLE_APPID_ITEM item = new DxfTABLE_APPID_ITEM("DEFAULT", 0); + Map table = new LinkedHashMap<>(); + DxfGroup group; + while (null != (group = DxfGroup.readGroup(raf)) && !group.equals(ENDTAB)) { + //group = DxfGroup.readGroup(raf); + if (DxfFile.DEBUG) group.print(8); + if (group.equals(APPID)) { + item = new DxfTABLE_APPID_ITEM("DEFAULT", 0); + } + else if (group.getCode()==2) { + item.setName(group.getValue()); + table.put(item.getName(), item); + } + //else if (group.getCode()==5) {} // tag appeared in version 13 of DXF + //else if (group.getCode()==100) {} // tag appeared in version 13 of DXF + else if (group.getCode()==70) {item.setFlags(group.getIntValue());} + //else {} + } + return table; + } + +} diff --git a/src/main/java/fr/michaelm/jump/drivers/dxf/DxfTABLE_DIMSTYLE_ITEM.java b/src/main/java/fr/michaelm/jump/drivers/dxf/DxfTABLE_DIMSTYLE_ITEM.java new file mode 100644 index 0000000..704d395 --- /dev/null +++ b/src/main/java/fr/michaelm/jump/drivers/dxf/DxfTABLE_DIMSTYLE_ITEM.java @@ -0,0 +1,68 @@ +/* + * Library name : dxf + * (C) 2021 Michaël Michaud + * + * This program 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 2 + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * For more information, contact: + * + * m.michael.michaud@orange.fr + * + */ + +package fr.michaelm.jump.drivers.dxf; + +import java.io.RandomAccessFile; +import java.io.IOException; +import java.util.Map; +import java.util.LinkedHashMap; + +/** + * The DIMSTYLE item in the TABLES section + * There is a static reader to read the item in a DXF file + * and a toString method able to write it in a DXF form + * @author Michaël Michaud + */ +public class DxfTABLE_DIMSTYLE_ITEM extends DxfTABLE_ITEM { + + public DxfTABLE_DIMSTYLE_ITEM(String name, int flags) { + super(name, flags); + } + + public static Map readTable(RandomAccessFile raf) throws IOException { + DxfTABLE_DIMSTYLE_ITEM item = new DxfTABLE_DIMSTYLE_ITEM("DEFAULT", 0); + Map table = new LinkedHashMap<>(); + DxfGroup group; + while (null != (group = DxfGroup.readGroup(raf)) && !group.equals(ENDTAB)) { + //group = DxfGroup.readGroup(raf); + if (DxfFile.DEBUG) group.print(8); + if (group.equals(DIMSTYLE)) { + item = new DxfTABLE_DIMSTYLE_ITEM("DEFAULT", 0); + } + else if (group.getCode()==2) { + item.setName(group.getValue()); + table.put(item.getName(), item); + } + //else if (group.getCode()==5) {} // tag appeared in version 13 of DXF + //else if (group.getCode()==100) {} // tag appeared in version 13 of DXF + else if (group.getCode()==70) { + item.setFlags(group.getIntValue()); + } + //else {} + } + return table; + } + +} diff --git a/src/main/java/fr/michaelm/jump/drivers/dxf/DxfTABLE_ITEM.java b/src/main/java/fr/michaelm/jump/drivers/dxf/DxfTABLE_ITEM.java new file mode 100644 index 0000000..a8080e6 --- /dev/null +++ b/src/main/java/fr/michaelm/jump/drivers/dxf/DxfTABLE_ITEM.java @@ -0,0 +1,71 @@ +/* + * Library name : dxf + * (C) 2021 Michaël Michaud + * + * This program 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 2 + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * For more information, contact: + * + * m.michael.michaud@orange.fr + * + */ + +package fr.michaelm.jump.drivers.dxf; + + +/** + * This class represent one of the TABLE of the TABLES section. + * It has as many subclasses as the number of table types + * @author Michaël Michaud + */ +public class DxfTABLE_ITEM { + + public final static DxfGroup ENDTAB = new DxfGroup(0, "ENDTAB"); + public final static DxfGroup APPID = new DxfGroup(0, "APPID"); + public final static DxfGroup DIMSTYLE = new DxfGroup(0, "DIMSTYLE"); + public final static DxfGroup LAYER = new DxfGroup(0, "LAYER"); + public final static DxfGroup LTYPE = new DxfGroup(0, "LTYPE"); + public final static DxfGroup STYLE = new DxfGroup(0, "STYLE"); + public final static DxfGroup UCS = new DxfGroup(0, "UCS"); + public final static DxfGroup VIEW = new DxfGroup(0, "VIEW"); + public final static DxfGroup VPORT = new DxfGroup(0, "VPORT"); + + private String name; + private int flags; + + public DxfTABLE_ITEM(String name, int flags) { + this.name = name; + this.flags = flags; + } + + public String getName(){return name;} + public void setName(String name) {this.name = name;} + public int getFlags(){return flags;} + public void setFlags(int flags) {this.flags = flags;} + + public boolean getFlag1(){return ((flags&1)==1);} + public boolean getFlag2(){return ((flags&2)==2);} + public boolean getFlag4(){return ((flags&4)==4);} + public boolean getFlag8(){return ((flags&8)==8);} + public boolean getFlag16(){return ((flags&16)==16);} + public boolean getFlag32(){return ((flags&32)==32);} + public boolean getFlag64(){return ((flags&64)==64);} + public boolean getFlag128(){return ((flags&128)==128);} + + public String toString() { + return DxfGroup.toString(2, name) + DxfGroup.toString(70, flags); + } + +} diff --git a/src/main/java/fr/michaelm/jump/drivers/dxf/DxfTABLE_LAYER_ITEM.java b/src/main/java/fr/michaelm/jump/drivers/dxf/DxfTABLE_LAYER_ITEM.java new file mode 100644 index 0000000..9ef9a6a --- /dev/null +++ b/src/main/java/fr/michaelm/jump/drivers/dxf/DxfTABLE_LAYER_ITEM.java @@ -0,0 +1,93 @@ +/* + * Library name : dxf + * (C) 2021 Michaël Michaud + * + * This program 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 2 + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * For more information, contact: + * + * m.michael.michaud@orange.fr + * + */ + +package fr.michaelm.jump.drivers.dxf; + +import java.io.RandomAccessFile; +import java.io.IOException; +import java.util.Map; +import java.util.LinkedHashMap; + +/** + * The LAYER item in the TABLES section + * There is a static reader to read the item in a DXF file + * and a toString method able to write it in a DXF form + * @author Michaël Michaud + */ +public class DxfTABLE_LAYER_ITEM extends DxfTABLE_ITEM { + + private int colorNumber; + private String lineType; + + public DxfTABLE_LAYER_ITEM(String name, int flags) { + super(name, flags); + this.colorNumber = 0; + this.lineType = "DEFAULT"; + } + + public DxfTABLE_LAYER_ITEM(String name, int flags, int colorNumber, String lineType) { + super(name, flags); + this.colorNumber = colorNumber; + this.lineType = lineType; + } + + public String getLineType() {return lineType;} + + public void setLineType(String lineType) {this.lineType = lineType;} + + public int getcolorNumber() {return colorNumber;} + + public void setColorNumber(int colorNumber) {this.colorNumber = colorNumber;} + + public static Map readTable(RandomAccessFile raf) throws IOException { + DxfTABLE_LAYER_ITEM item = new DxfTABLE_LAYER_ITEM("DEFAULT", 0); + Map table = new LinkedHashMap<>(); + DxfGroup group; + while (null != (group = DxfGroup.readGroup(raf)) && !group.equals(ENDTAB)) { + //group = DxfGroup.readGroup(raf); + if (DxfFile.DEBUG) group.print(8); + if (group.equals(LAYER)) { + item = new DxfTABLE_LAYER_ITEM("DEFAULT", 0); + } + else if (group.getCode()==2) { + //System.out.println("\t\t" + group.getValue()); + item.setName(group.getValue()); + table.put(item.getName(), item); + } + //else if (group.getCode()==5) {} // tag appeared in version 13 of DXF + //else if (group.getCode()==100) {} // tag appeared in version 13 of DXF + else if (group.getCode()==70) {item.setFlags(group.getIntValue());} + else if (group.getCode()==62) {item.setColorNumber(group.getIntValue());} + else if (group.getCode()==6) {item.setLineType(group.getValue());} + //else {} + } + return table; + } + + public String toString() { + return super.toString() + DxfGroup.toString(62, colorNumber) + + DxfGroup.toString(6, lineType); + } + +} diff --git a/src/main/java/fr/michaelm/jump/drivers/dxf/DxfTABLE_LTYPE_ITEM.java b/src/main/java/fr/michaelm/jump/drivers/dxf/DxfTABLE_LTYPE_ITEM.java new file mode 100644 index 0000000..d066ab0 --- /dev/null +++ b/src/main/java/fr/michaelm/jump/drivers/dxf/DxfTABLE_LTYPE_ITEM.java @@ -0,0 +1,112 @@ +/* + * Library name : dxf + * (C) 2021 Michaël Michaud + * + * This program 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 2 + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * For more information, contact: + * + * m.michael.michaud@orange.fr + * + */ + +package fr.michaelm.jump.drivers.dxf; + +import java.io.RandomAccessFile; +import java.io.IOException; +import java.util.Map; +import java.util.LinkedHashMap; + +/** + * The LTYPE item in the TABLES section + * There is a static reader to read the item in a DXF file + * and a toString method able to write it in a DXF form + * @author Michaël Michaud + */ +public class DxfTABLE_LTYPE_ITEM extends DxfTABLE_ITEM { + private String description; + private int alignment; + private float patternLength; + private float[] pattern; + + public DxfTABLE_LTYPE_ITEM(String name, int flags) { + super(name, flags); + this.description = ""; + this.alignment = 0; + this.patternLength = 1f; + this.pattern = new float[]{1f}; + } + + public DxfTABLE_LTYPE_ITEM(String name, int flags, String description, + int alignment, float patternLength, float[] pattern) { + super(name, flags); + this.description = description; + this.alignment = alignment; + this.patternLength = patternLength; + this.pattern = pattern; + } + + public String getDescription() {return description;} + public void setDescription(String description) {this.description = description;} + public int getAlignment() {return alignment;} + public void setAlignment(int alignment) {this.alignment = alignment;} + public float getPatternLength() {return patternLength;} + public void setPatternLength(float patternLength) {this.patternLength = patternLength;} + public float[] getPattern() {return pattern;} + public void setPattern(float[] pattern) {this.pattern = pattern;} + + public static Map readTable(RandomAccessFile raf) throws IOException { + DxfTABLE_LTYPE_ITEM item = new DxfTABLE_LTYPE_ITEM("DEFAULT", 0); + Map table = new LinkedHashMap<>(); + DxfGroup group; + int patternDashCount = 0; + while (null != (group = DxfGroup.readGroup(raf)) && !group.equals(ENDTAB)) { + //group = DxfGroup.readGroup(raf); + if (DxfFile.DEBUG) group.print(8); + if (group.equals(LTYPE)) { + item = new DxfTABLE_LTYPE_ITEM("DEFAULT", 0); + } + else if (group.getCode()==2) { + item.setName(group.getValue()); + table.put(item.getName(), item); + } + //else if (group.getCode()==5) {} // tag appeared in version 13 of DXF + //else if (group.getCode()==100) {} // tag appeared in version 13 of DXF + else if (group.getCode()==70) {item.setFlags(group.getIntValue());} + else if (group.getCode()==3) {item.setDescription(group.getValue());} + else if (group.getCode()==72) {item.setAlignment(group.getIntValue());} + else if (group.getCode()==73) {item.setPattern(new float[group.getIntValue()]);} + else if (group.getCode()==40) {item.setPatternLength(group.getFloatValue());} + else if (group.getCode()==49 && patternDashCount < item.getPattern().length) { + item.getPattern()[patternDashCount++] = group.getFloatValue(); + } + //else {} + } + return table; + } + + public String toString() { + StringBuilder sb = new StringBuilder(super.toString()); + sb.append(DxfGroup.toString(3, description)); + sb.append(DxfGroup.toString(72, alignment)); + sb.append(DxfGroup.toString(73, pattern.length)); + sb.append(DxfGroup.toString(40, patternLength, 3)); + for (float p : pattern) { + sb.append(DxfGroup.toString(49, p, 3)); + } + return sb.toString(); + } + +} diff --git a/src/main/java/fr/michaelm/jump/drivers/dxf/DxfTABLE_STYLE_ITEM.java b/src/main/java/fr/michaelm/jump/drivers/dxf/DxfTABLE_STYLE_ITEM.java new file mode 100644 index 0000000..4d26a12 --- /dev/null +++ b/src/main/java/fr/michaelm/jump/drivers/dxf/DxfTABLE_STYLE_ITEM.java @@ -0,0 +1,147 @@ +/* + * Library name : dxf + * (C) 2021 Michaël Michaud + * + * This program 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 2 + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * For more information, contact: + * + * m.michael.michaud@orange.fr + * + */ + +package fr.michaelm.jump.drivers.dxf; + +import java.io.RandomAccessFile; +import java.io.IOException; +import java.util.Map; +import java.util.LinkedHashMap; + +/** + * The STYLE item in the TABLES section + * There is a static reader to read the item from a DXF file + * and a toString method to write it in the DXF format + * @author Michaël Michaud + */ +public class DxfTABLE_STYLE_ITEM extends DxfTABLE_ITEM { + + private float textHeight; + private float widthFactor; + private float obliqueAngle; + private int textGenerationFlags; + private float lastHeightUsed; + private String primaryFontFileName; + private String bigFontFileName; + + public DxfTABLE_STYLE_ITEM(String name, int flags) { + super(name, flags); + this.textHeight = 0f; + this.widthFactor = 0f; + this.obliqueAngle = 0f; + this.textGenerationFlags = 0; + this.lastHeightUsed = 0f; + this.primaryFontFileName = ""; + this.bigFontFileName = ""; + } + + public DxfTABLE_STYLE_ITEM(String name, int flags, + float textHeight, + float widthFactor, + float obliqueAngle, + int textGenerationFlags, + float lastHeightUsed, + String primaryFontFileName, + String bigFontFileName) { + super(name, flags); + this.textHeight = textHeight; + this.widthFactor = widthFactor; + this.obliqueAngle = obliqueAngle; + this.textGenerationFlags = textGenerationFlags; + this.lastHeightUsed = lastHeightUsed; + this.primaryFontFileName = primaryFontFileName; + this.bigFontFileName = bigFontFileName; + } + + public float getTextHeight() {return textHeight;} + public float getWidthFactor() {return widthFactor;} + public float getObliqueAngle() {return obliqueAngle;} + public int getTextGenerationFlags() {return textGenerationFlags;} + public float getLastHeightUsed() {return lastHeightUsed;} + public String getPrimaryFontFileName() {return primaryFontFileName;} + public String getBigFontFileName() {return bigFontFileName;} + + public void setTextHeight(float textHeight) { + this.textHeight = textHeight; + } + public void setWidthFactor(float widthFactor) { + this.widthFactor = widthFactor; + } + public void setObliqueAngle(float obliqueAngle) { + this.obliqueAngle = obliqueAngle; + } + public void setTextGenerationFlags(int textGenerationFlags) { + this.textGenerationFlags = textGenerationFlags; + } + public void setLastHeightUsed(float lastHeightUsed) { + this.lastHeightUsed = lastHeightUsed; + } + public void setPrimaryFontFileName(String primaryFontFileName) { + this.primaryFontFileName = primaryFontFileName; + } + public void setBigFontFileName(String bigFontFileName) { + this.bigFontFileName = bigFontFileName; + } + + public static Map readTable(RandomAccessFile raf) throws IOException { + DxfTABLE_STYLE_ITEM item = new DxfTABLE_STYLE_ITEM("DEFAULT", 0); + Map table = new LinkedHashMap<>(); + DxfGroup group; + while (null != (group = DxfGroup.readGroup(raf)) && !group.equals(ENDTAB)) { + //group = DxfGroup.readGroup(raf); + if (DxfFile.DEBUG) group.print(8); + if (group.equals(STYLE)) { + item = new DxfTABLE_STYLE_ITEM("DEFAULT", 0); + } + else if (group.getCode()==2) { + item.setName(group.getValue()); + table.put(item.getName(), item); + } + //else if (group.getCode()==5) {} // tag appeared in version 13 of DXF + //else if (group.getCode()==100) {} // tag appeared in version 13 of DXF + else if (group.getCode()==70) {item.setFlags(group.getIntValue());} + else if (group.getCode()==40) {item.setTextHeight(group.getFloatValue());} + else if (group.getCode()==41) {item.setWidthFactor(group.getFloatValue());} + else if (group.getCode()==50) {item.setObliqueAngle(group.getFloatValue());} + else if (group.getCode()==71) {item.setTextGenerationFlags(group.getIntValue());} + else if (group.getCode()==42) {item.setLastHeightUsed(group.getFloatValue());} + else if (group.getCode()==3) {item.setPrimaryFontFileName(group.getValue());} + else if (group.getCode()==4) {item.setBigFontFileName(group.getValue());} + //else {} + } + return table; + } + + public String toString() { + return super.toString() + + DxfGroup.toString(40, textHeight, 3) + + DxfGroup.toString(41, widthFactor, 3) + + DxfGroup.toString(50, obliqueAngle, 3) + + DxfGroup.toString(71, textGenerationFlags) + + DxfGroup.toString(42, lastHeightUsed, 3) + + DxfGroup.toString(3, primaryFontFileName) + + DxfGroup.toString(4, bigFontFileName); + } + +} diff --git a/src/main/java/fr/michaelm/jump/drivers/dxf/DxfTABLE_UCS_ITEM.java b/src/main/java/fr/michaelm/jump/drivers/dxf/DxfTABLE_UCS_ITEM.java new file mode 100644 index 0000000..83137ac --- /dev/null +++ b/src/main/java/fr/michaelm/jump/drivers/dxf/DxfTABLE_UCS_ITEM.java @@ -0,0 +1,136 @@ +/* + * Library name : dxf + * (C) 2021 Michaël Michaud + * + * This program 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 2 + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * For more information, contact: + * + * m.michael.michaud@orange.fr + * + */ + +package fr.michaelm.jump.drivers.dxf; + +import java.io.RandomAccessFile; +import java.io.IOException; +import java.util.Map; +import java.util.LinkedHashMap; + +/** + * The UCS item in the TABLES section + * There is a static reader to read the item in a DXF file + * and a toString method able to write it in a DXF form + * @author Michaël Michaud + */ +public class DxfTABLE_UCS_ITEM extends DxfTABLE_ITEM { + + private double[] origin; + private double[] xAxisDirection; + private double[] yAxisDirection; + + public DxfTABLE_UCS_ITEM(String name, int flags) { + super(name, flags); + this.origin = new double[3]; + this.xAxisDirection = new double[3]; + this.yAxisDirection = new double[3]; + } + + public DxfTABLE_UCS_ITEM(String name, int flags, + double[] origin, + double[] xAxisDirection, + double[] yAxisDirection ) { + super(name, flags); + this.origin = origin; + this.xAxisDirection = xAxisDirection; + this.yAxisDirection = yAxisDirection; + } + + public double[] getOrigin() {return origin;} + public double getOriginX() {return origin[0];} + public double getOriginY() {return origin[1];} + public double getOriginZ() {return origin[2];} + + public double[] getXAxisDirection() {return xAxisDirection;} + public double getXAxisDirectionX() {return xAxisDirection[0];} + public double getXAxisDirectionY() {return xAxisDirection[1];} + public double getXAxisDirectionZ() {return xAxisDirection[2];} + + public double[] getYAxisDirection() {return yAxisDirection;} + public double getYAxisDirectionX() {return yAxisDirection[0];} + public double getYAxisDirectionY() {return yAxisDirection[1];} + public double getYAxisDirectionZ() {return yAxisDirection[2];} + + public void setOrigin(double[] origin) {this.origin = origin;} + public void setOriginX(double originX) {this.origin[0] = originX;} + public void setOriginY(double originY) {this.origin[1] = originY;} + public void setOriginZ(double originZ) {this.origin[2] = originZ;} + + public void setXAxisDirection(double[] xAxisDirection) {this.xAxisDirection = xAxisDirection;} + public void setXAxisDirectionX(double xAxisDirectionX) {this.xAxisDirection[0] = xAxisDirectionX;} + public void setXAxisDirectionY(double xAxisDirectionY) {this.xAxisDirection[1] = xAxisDirectionY;} + public void setXAxisDirectionZ(double xAxisDirectionZ) {this.xAxisDirection[2] = xAxisDirectionZ;} + + + public void setYAxisDirection(double[] yAxisDirection) {this.yAxisDirection = yAxisDirection;} + public void setYAxisDirectionX(double yAxisDirectionX) {this.yAxisDirection[0] = yAxisDirectionX;} + public void setYAxisDirectionY(double yAxisDirectionY) {this.yAxisDirection[1] = yAxisDirectionY;} + public void setYAxisDirectionZ(double yAxisDirectionZ) {this.yAxisDirection[2] = yAxisDirectionZ;} + + public static Map readTable(RandomAccessFile raf) throws IOException { + DxfTABLE_UCS_ITEM item = new DxfTABLE_UCS_ITEM("DEFAULT", 0); + Map table = new LinkedHashMap<>(); + DxfGroup group; + while (null != (group = DxfGroup.readGroup(raf)) && !group.equals(ENDTAB)) { + //group = DxfGroup.readGroup(raf); + if (DxfFile.DEBUG) group.print(8); + if (group.equals(UCS)) { + item = new DxfTABLE_UCS_ITEM("DEFAULT", 0); + } + else if (group.getCode()==2) { + item.setName(group.getValue()); + table.put(item.getName(), item); + } + //else if (group.getCode()==5) {} // tag appeared in version 13 of DXF + //else if (group.getCode()==100) {} // tag appeared in version 13 of DXF + else if (group.getCode()==70) {item.setFlags(group.getIntValue());} + else if (group.getCode()==10) {item.setOriginX(group.getDoubleValue());} + else if (group.getCode()==20) {item.setOriginY(group.getDoubleValue());} + else if (group.getCode()==30) {item.setOriginZ(group.getDoubleValue());} + else if (group.getCode()==11) {item.setXAxisDirectionX(group.getDoubleValue());} + else if (group.getCode()==21) {item.setXAxisDirectionY(group.getDoubleValue());} + else if (group.getCode()==31) {item.setXAxisDirectionZ(group.getDoubleValue());} + else if (group.getCode()==12) {item.setYAxisDirectionX(group.getDoubleValue());} + else if (group.getCode()==22) {item.setYAxisDirectionY(group.getDoubleValue());} + else if (group.getCode()==32) {item.setYAxisDirectionZ(group.getDoubleValue());} + //else {} + } + return table; + } + + public String toString() { + return super.toString() + + DxfGroup.toString(10, origin[0], 6) + + DxfGroup.toString(20, origin[1], 6) + + DxfGroup.toString(30, origin[2], 6) + + DxfGroup.toString(11, xAxisDirection[0], 6) + + DxfGroup.toString(21, xAxisDirection[1], 6) + + DxfGroup.toString(31, xAxisDirection[2], 6) + + DxfGroup.toString(12, yAxisDirection[0], 6) + + DxfGroup.toString(22, yAxisDirection[1], 6) + + DxfGroup.toString(32, yAxisDirection[2], 6); + } + +} diff --git a/src/main/java/fr/michaelm/jump/drivers/dxf/DxfTABLE_VIEW_ITEM.java b/src/main/java/fr/michaelm/jump/drivers/dxf/DxfTABLE_VIEW_ITEM.java new file mode 100644 index 0000000..0dbf943 --- /dev/null +++ b/src/main/java/fr/michaelm/jump/drivers/dxf/DxfTABLE_VIEW_ITEM.java @@ -0,0 +1,205 @@ +/* + * Library name : dxf + * (C) 2021 Michaël Michaud + * + * This program 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 2 + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * For more information, contact: + * + * m.michael.michaud@orange.fr + * + */ + +package fr.michaelm.jump.drivers.dxf; + +import java.io.RandomAccessFile; +import java.io.IOException; +import java.util.Map; +import java.util.LinkedHashMap; + +/** + * The VIEW item in the TABLES section + * There is a static reader to read the item in a DXF file + * and a toString method able to write it in a DXF form + * @author Michaël Michaud + */ +public class DxfTABLE_VIEW_ITEM extends DxfTABLE_ITEM { + private float viewHeight; + private float viewWidth; + private double viewCenterPointX; + private double viewCenterPointY; + private double[] viewDirectionFromTarget; + private double[] targetPoint; + private float lensLength; + private double frontClippingPlaneOffset; + private double backClippingPlaneOffset; + private float twistAngle; + private int viewMode; + + public DxfTABLE_VIEW_ITEM(String name, int flags) { + super(name, flags); + this.viewHeight = 0f; + this.viewWidth = 0f; + this.viewCenterPointX = 0.0; + this.viewCenterPointY = 0; + this.viewDirectionFromTarget = new double[3]; + this.targetPoint = new double[3]; + this.lensLength = 0f; + this.frontClippingPlaneOffset = 0.0; + this.backClippingPlaneOffset = 0.0; + this.twistAngle = 0f; + this.viewMode = 0; + } + + public DxfTABLE_VIEW_ITEM(String name, int flags, + float viewHeight, + float viewWidth, + double viewCenterPointX, + double viewCenterPointY, + double[] viewDirectionFromTarget, + double[] targetPoint, + float lensLength, + double frontClippingPlaneOffset, + double backClippingPlaneOffset, + float twistAngle, + int viewMode) { + super(name, flags); + this.viewHeight = viewHeight; + this.viewWidth = viewWidth; + this.viewCenterPointX = viewCenterPointX; + this.viewCenterPointY = viewCenterPointY; + this.viewDirectionFromTarget = viewDirectionFromTarget; + this.targetPoint = targetPoint; + this.lensLength = lensLength; + this.frontClippingPlaneOffset = frontClippingPlaneOffset; + this.backClippingPlaneOffset = backClippingPlaneOffset; + this.twistAngle = twistAngle; + this.viewMode = viewMode; + } + + public float getViewHeight() {return viewHeight;} + public float getViewWidth() {return viewWidth;} + public double getViewCenterPointX() {return viewCenterPointX;} + public double getViewCenterPointY() {return viewCenterPointY;} + public double[] getViewDirectionFromTarget() {return viewDirectionFromTarget;} + public double[] getTargetPoint() {return targetPoint;} + public float getLensLength() {return lensLength;} + public double getFrontClippingPlaneOffset() {return frontClippingPlaneOffset;} + public double getBackClippingPlaneOffset() {return backClippingPlaneOffset;} + public float getTwistAngle() {return twistAngle;} + public int getViewMode() {return viewMode;} + + public void setViewHeight(float viewHeight) {this.viewHeight = viewHeight;} + public void setViewWidth(float viewWidth) {this.viewWidth = viewWidth;} + public void setViewCenterPointX(double viewCenterPointX) {this.viewCenterPointX = viewCenterPointX;} + public void setViewCenterPointY(double viewCenterPointY) {this.viewCenterPointY = viewCenterPointY;} + public void setViewDirectionFromTarget(double[] viewDirectionFromTarget) {this.viewDirectionFromTarget = viewDirectionFromTarget;} + public void setTargetPoint(double[] targetPoint) {this.targetPoint = targetPoint;} + public void setLensLength(float lensLength) {this.lensLength = lensLength;} + public void setFrontClippingPlaneOffset(double frontClippingPlaneOffset) {this.frontClippingPlaneOffset = frontClippingPlaneOffset;} + public void setBackClippingPlaneOffset(double backClippingPlaneOffset) {this.backClippingPlaneOffset = backClippingPlaneOffset;} + public void setTwistAngle(float twistAngle) {this.twistAngle = twistAngle;} + public void setViewMode(int viewMode) {this.viewMode = viewMode;} + + public static Map readTable(RandomAccessFile raf) throws IOException { + DxfTABLE_VIEW_ITEM item = new DxfTABLE_VIEW_ITEM("DEFAULT", 0); + Map table = new LinkedHashMap<>(); + DxfGroup group; + while (null != (group = DxfGroup.readGroup(raf)) && !group.equals(ENDTAB)) { + //group = DxfGroup.readGroup(raf); + if (DxfFile.DEBUG) group.print(8); + int code = group.getCode(); + if (group.equals(VIEW)) { + item = new DxfTABLE_VIEW_ITEM("DEFAULT", 0); + } + else if (code==2) { + item.setName(group.getValue()); + table.put(item.getName(), item); + } + //else if (code==5) {} // tag appeared in version 13 of DXF + //else if (code==100) {} // tag appeared in version 13 of DXF + else if (code==70) { + item.setFlags(group.getIntValue()); + } + else if (code==40) { + item.setViewHeight(group.getFloatValue()); + } + else if (code==41) { + item.setViewWidth(group.getFloatValue()); + } + else if (code==10) { + item.setViewCenterPointX(group.getDoubleValue()); + } + else if (code==20) { + item.setViewCenterPointY(group.getDoubleValue()); + } + else if (code==11) { + item.getViewDirectionFromTarget()[0] = group.getDoubleValue(); + } + else if (code==21) { + item.getViewDirectionFromTarget()[1] = group.getDoubleValue(); + } + else if (code==31) { + item.getViewDirectionFromTarget()[2] = group.getDoubleValue(); + } + else if (code==12) { + item.getTargetPoint()[0] = group.getDoubleValue(); + } + else if (code==22) { + item.getTargetPoint()[1] = group.getDoubleValue(); + } + else if (code==32) { + item.getTargetPoint()[2] = group.getDoubleValue(); + } + else if (code==42) { + item.setLensLength(group.getFloatValue()); + } + else if (code==43) { + item.setFrontClippingPlaneOffset(group.getDoubleValue()); + } + else if (code==44) { + item.setBackClippingPlaneOffset(group.getDoubleValue()); + } + else if (code==50) { + item.setTwistAngle(group.getFloatValue()); + } + else if (code==71) { + item.setViewMode(group.getIntValue()); + } + //else {} + } + return table; + } + + public String toString() { + return super.toString() + + DxfGroup.toString(40, viewHeight, 6) + + DxfGroup.toString(41, viewWidth, 6) + + DxfGroup.toString(10, viewCenterPointX, 6) + + DxfGroup.toString(20, viewCenterPointY, 6) + + DxfGroup.toString(11, viewDirectionFromTarget[0], 6) + + DxfGroup.toString(21, viewDirectionFromTarget[1], 6) + + DxfGroup.toString(31, viewDirectionFromTarget[2], 6) + + DxfGroup.toString(12, targetPoint[0], 6) + + DxfGroup.toString(22, targetPoint[1], 6) + + DxfGroup.toString(32, targetPoint[2], 6) + + DxfGroup.toString(42, lensLength, 6) + + DxfGroup.toString(43, frontClippingPlaneOffset, 6) + + DxfGroup.toString(44, backClippingPlaneOffset, 6) + + DxfGroup.toString(50, twistAngle, 6) + + DxfGroup.toString(71, viewMode); + } + +} diff --git a/src/main/java/fr/michaelm/jump/drivers/dxf/DxfTABLE_VPORT_ITEM.java b/src/main/java/fr/michaelm/jump/drivers/dxf/DxfTABLE_VPORT_ITEM.java new file mode 100644 index 0000000..722805c --- /dev/null +++ b/src/main/java/fr/michaelm/jump/drivers/dxf/DxfTABLE_VPORT_ITEM.java @@ -0,0 +1,395 @@ +/* + * Library name : dxf + * (C) 2021 Michaël Michaud + * + * This program 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 2 + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * For more information, contact: + * + * m.michael.michaud@orange.fr + * + */ + +package fr.michaelm.jump.drivers.dxf; + +import java.io.RandomAccessFile; +import java.io.IOException; +import java.util.Map; +import java.util.LinkedHashMap; + +/** + * The VPORT item in the TABLES section + * There is a static reader to read the item in a DXF file + * and a toString method able to write it in a DXF form + * @author Michaël Michaud + */ +public class DxfTABLE_VPORT_ITEM extends DxfTABLE_ITEM { + private double[] lowerLeftCorner; // XY 0.0 to 1.0 + private double[] upperRightCorner; // XY 0.0 to 1.0 + private double[] centerPoint; // XY + private double[] snapBasePoint; // XY + private double[] snapSpacing; // X and Y + private double[] gridSpacing; // X and Y + private double[] viewDirection; // XYZ + private double[] viewTargetPoint; // XYZ + private double viewHeight; + private float aspectRatio; + private float lensLength; + private double frontClippingPlaneOffset; + private double backClippingPlaneOffset; + private float snapRotationAngle; + private float twistAngle; + private int viewMode; + private int circleZoomPercent; + private int fastZoomSetting; + private int ucsIconSetting; + private int snapOnOff; + private int gridOnOff; + private int snapStyle; + private int snapIsoPair; + + + public DxfTABLE_VPORT_ITEM(String name, int flags) { + super(name, flags); + this.lowerLeftCorner = new double[2]; + this.upperRightCorner = new double[2]; + this.centerPoint = new double[2]; + this.snapBasePoint = new double[2]; + this.snapSpacing = new double[2]; + this.gridSpacing = new double[2]; + this.viewDirection = new double[3]; + this.viewTargetPoint = new double[3]; + this.viewHeight = 0; + this.aspectRatio = 0; + this.lensLength = 0; + this.frontClippingPlaneOffset = 0; + this.backClippingPlaneOffset = 0; + this.snapRotationAngle = 0; + this.twistAngle = 0; + this.viewMode = 0; + this.circleZoomPercent = 0; + this.fastZoomSetting = 0; + this.ucsIconSetting = 0; + this.snapOnOff = 0; + this.gridOnOff = 0; + this.snapStyle = 0; + this.snapIsoPair = 0; + } + + public DxfTABLE_VPORT_ITEM(String name, int flags, + double[] lowerLeftCorner, + double[] upperRightCorner, + double[] centerPoint, + double[] snapBasePoint, + double[] snapSpacing, + double[] gridSpacing, + double[] viewDirection, + double[] viewTargetPoint, + double viewHeight, + float aspectRatio, + float lensLength, + double frontClippingPlaneOffset, + double backClippingPlaneOffset, + float snapRotationAngle, + float twistAngle, + int viewMode, + int circleZoomPercent, + int fastZoomSetting, + int ucsIconSetting, + int snapOnOff, + int gridOnOff, + int snapStyle, + int snapIsoPair ) { + super(name, flags); + this.lowerLeftCorner = lowerLeftCorner; + this.upperRightCorner = upperRightCorner; + this.centerPoint = centerPoint; + this.snapBasePoint = snapBasePoint; + this.snapSpacing = snapSpacing; + this.gridSpacing = gridSpacing; + this.viewDirection = viewDirection; + this.viewTargetPoint = viewTargetPoint; + this.viewHeight = viewHeight; + this.aspectRatio = aspectRatio; + this.lensLength = lensLength; + this.frontClippingPlaneOffset = frontClippingPlaneOffset; + this.backClippingPlaneOffset = backClippingPlaneOffset; + this.snapRotationAngle = snapRotationAngle; + this.twistAngle = twistAngle; + this.viewMode = viewMode; + this.circleZoomPercent = circleZoomPercent; + this.fastZoomSetting = fastZoomSetting; + this.ucsIconSetting = ucsIconSetting; + this.snapOnOff = snapOnOff; + this.gridOnOff = gridOnOff; + this.snapStyle = snapStyle; + this.snapIsoPair = snapIsoPair; + } + + public double[] getLowerLeftCorner() {return lowerLeftCorner;} + public double[] getUpperRightCorner() {return upperRightCorner;} + public double[] getCenterPoint() {return centerPoint;} + public double[] getSnapBasePoint() {return snapBasePoint;} + public double[] getSnapSpacing() {return snapSpacing;} + public double[] getGridSpacing() {return gridSpacing;} + public double[] getViewDirection() {return viewDirection;} + public double[] getViewTargetPoint() {return viewTargetPoint;} + public double getViewHeight() {return viewHeight;} + public float getAspectRatio() {return aspectRatio;} + public float getLensLength() {return lensLength;} + public double getFrontClippingPlaneOffset() {return frontClippingPlaneOffset;} + public double getBackClippingPlaneOffset() {return backClippingPlaneOffset;} + public float getSnapRotationAngle() {return snapRotationAngle;} + public float getTwistAngle() {return twistAngle;} + public int getViewMode() {return viewMode;} + public int getCircleZoomPercent() {return circleZoomPercent;} + public int getFastZoomSetting() {return fastZoomSetting;} + public int getUcsIconSetting() {return ucsIconSetting;} + public int getSnapOnOff() {return snapOnOff;} + public int getGridOnOff() {return gridOnOff;} + public int getSnapStyle() {return snapStyle;} + public int getSnapIsoPair() {return snapIsoPair;} + + public void setLowerLeftCorner(double[] lowerLeftCorner) { + this.lowerLeftCorner = lowerLeftCorner; + } + public void setUpperRightCorner(double[] upperRightCorner) { + this.upperRightCorner = upperRightCorner; + } + public void setCenterPoint(double[] centerPoint) { + this.centerPoint = centerPoint; + } + public void setSnapBasePoint(double[] snapBasePoint) { + this.snapBasePoint = snapBasePoint; + } + public void setSnapSpacing(double[] snapSpacing) { + this.snapSpacing = snapSpacing; + } + public void setGridSpacing(double[] gridSpacing) { + this.gridSpacing = gridSpacing; + } + public void setViewDirection(double[] viewDirection) { + this.viewDirection = viewDirection; + } + public void setViewTargetPoint(double[] viewTargetPoint) { + this.viewTargetPoint = viewTargetPoint; + } + public void setViewHeight(double viewHeight) { + this.viewHeight = viewHeight; + } + public void setAspectRatio(float aspectRatio) { + this.aspectRatio = aspectRatio; + } + public void setLensLength(float lensLength) { + this.lensLength = lensLength; + } + public void setFrontClippingPlaneOffset(double frontClippingPlaneOffset) { + this.frontClippingPlaneOffset = frontClippingPlaneOffset; + } + public void setBackClippingPlaneOffset(double backClippingPlaneOffset) { + this.backClippingPlaneOffset = backClippingPlaneOffset; + } + public void setSnapRotationAngle(float snapRotationAngle) { + this.snapRotationAngle = snapRotationAngle; + } + public void setTwistAngle(float twistAngle) { + this.twistAngle = twistAngle; + } + public void setViewMode(int viewMode) { + this.viewMode = viewMode; + } + public void setCircleZoomPercent(int circleZoomPercent) { + this.circleZoomPercent = circleZoomPercent; + } + public void setFastZoomSetting(int fastZoomSetting) { + this.fastZoomSetting = fastZoomSetting; + } + public void setUcsIconSetting(int ucsIconSetting) { + this.ucsIconSetting = ucsIconSetting; + } + public void setSnapOnOff(int snapOnOff) { + this.snapOnOff = snapOnOff; + } + public void setGridOnOff(int gridOnOff) { + this.gridOnOff = gridOnOff; + } + public void setSnapStyle(int snapStyle) { + this.snapStyle = snapStyle; + } + public void setSnapIsoPair(int snapIsoPair) { + this.snapIsoPair = snapIsoPair; + } + + public static Map readTable(RandomAccessFile raf) throws IOException { + DxfTABLE_VPORT_ITEM item = new DxfTABLE_VPORT_ITEM("DEFAULT", 0); + Map table = new LinkedHashMap<>(); + DxfGroup group; + while (null != (group = DxfGroup.readGroup(raf)) && !group.equals(ENDTAB)) { + //group = DxfGroup.readGroup(raf); + if (DxfFile.DEBUG) group.print(8); + if (group.equals(VPORT)) { + item = new DxfTABLE_VPORT_ITEM("DEFAULT", 0); + } + else if (group.getCode()==2) { + item.setName(group.getValue()); + table.put(item.getName(), item); + } + //else if (group.getCode()==5) {} // tag appeared in version 13 of DXF + //else if (group.getCode()==100) {} // tag appeared in version 13 of DXF + else if (group.getCode()==70) { + item.setFlags(group.getIntValue()); + } + else if (group.getCode()==10) { + item.getLowerLeftCorner()[0] = group.getDoubleValue(); + } + else if (group.getCode()==20) { + item.getLowerLeftCorner()[1] = group.getDoubleValue(); + } + else if (group.getCode()==11) { + item.getUpperRightCorner()[0] = group.getDoubleValue(); + } + else if (group.getCode()==21) { + item.getUpperRightCorner()[1] = group.getDoubleValue(); + } + else if (group.getCode()==12) { + item.getCenterPoint()[0] = group.getDoubleValue(); + } + else if (group.getCode()==22) { + item.getCenterPoint()[1] = group.getDoubleValue(); + } + else if (group.getCode()==13) { + item.getSnapBasePoint()[0] = group.getDoubleValue(); + } + else if (group.getCode()==23) { + item.getSnapBasePoint()[1] = group.getDoubleValue(); + } + else if (group.getCode()==14) { + item.getSnapSpacing()[0] = group.getDoubleValue(); + } + else if (group.getCode()==24) { + item.getSnapSpacing()[1] = group.getDoubleValue(); + } + else if (group.getCode()==15) { + item.getGridSpacing()[0] = group.getDoubleValue(); + } + else if (group.getCode()==25) { + item.getGridSpacing()[1] = group.getDoubleValue(); + } + else if (group.getCode()==16) { + item.getViewDirection()[1] = group.getDoubleValue(); + } + else if (group.getCode()==26) { + item.getViewDirection()[1] = group.getDoubleValue(); + } + else if (group.getCode()==36) { + item.getViewDirection()[2] = group.getDoubleValue(); + } + else if (group.getCode()==17) { + item.getViewTargetPoint()[1] = group.getDoubleValue(); + } + else if (group.getCode()==27) { + item.getViewTargetPoint()[1] = group.getDoubleValue(); + } + else if (group.getCode()==37) { + item.getViewTargetPoint()[2] = group.getDoubleValue(); + } + else if (group.getCode()==40) { + item.setViewHeight(group.getDoubleValue()); + } + else if (group.getCode()==41) { + item.setAspectRatio(group.getFloatValue()); + } + else if (group.getCode()==42) { + item.setLensLength(group.getFloatValue()); + } + else if (group.getCode()==43) { + item.setFrontClippingPlaneOffset(group.getDoubleValue()); + } + else if (group.getCode()==44) { + item.setBackClippingPlaneOffset(group.getDoubleValue()); + } + else if (group.getCode()==50) { + item.setSnapRotationAngle(group.getFloatValue()); + } + else if (group.getCode()==51) { + item.setTwistAngle(group.getFloatValue()); + } + else if (group.getCode()==71) { + item.setViewMode(group.getIntValue()); + } + else if (group.getCode()==72) { + item.setCircleZoomPercent(group.getIntValue()); + } + else if (group.getCode()==73) { + item.setFastZoomSetting(group.getIntValue()); + } + else if (group.getCode()==74) { + item.setUcsIconSetting(group.getIntValue()); + } + else if (group.getCode()==75) { + item.setSnapOnOff(group.getIntValue()); + } + else if (group.getCode()==76) { + item.setGridOnOff(group.getIntValue()); + } + else if (group.getCode()==77) { + item.setSnapStyle(group.getIntValue()); + } + else if (group.getCode()==78) { + item.setSnapIsoPair(group.getIntValue()); + } + //else {} + } + return table; + } + + public String toString() { + return super.toString() + + DxfGroup.toString(10, lowerLeftCorner[0], 6) + + DxfGroup.toString(20, lowerLeftCorner[1], 6) + + DxfGroup.toString(11, upperRightCorner[0], 6) + + DxfGroup.toString(21, upperRightCorner[1], 6) + + DxfGroup.toString(12, centerPoint[0], 6) + + DxfGroup.toString(22, centerPoint[1], 6) + + DxfGroup.toString(13, snapBasePoint[0], 6) + + DxfGroup.toString(23, snapBasePoint[1], 6) + + DxfGroup.toString(14, snapSpacing[0], 6) + + DxfGroup.toString(24, snapSpacing[1], 6) + + DxfGroup.toString(15, gridSpacing[0], 6) + + DxfGroup.toString(25, gridSpacing[1], 6) + + DxfGroup.toString(16, viewDirection[0], 6) + + DxfGroup.toString(26, viewDirection[1], 6) + + DxfGroup.toString(36, viewDirection[2], 6) + + DxfGroup.toString(17, viewTargetPoint[0], 6) + + DxfGroup.toString(27, viewTargetPoint[1], 6) + + DxfGroup.toString(37, viewTargetPoint[2], 6) + + DxfGroup.toString(40, viewHeight, 6) + + DxfGroup.toString(41, aspectRatio, 6) + + DxfGroup.toString(42, lensLength, 6) + + DxfGroup.toString(43, frontClippingPlaneOffset, 6) + + DxfGroup.toString(44, backClippingPlaneOffset, 6) + + DxfGroup.toString(50, snapRotationAngle, 6) + + DxfGroup.toString(51, twistAngle, 6) + + DxfGroup.toString(71, viewMode) + + DxfGroup.toString(72, circleZoomPercent) + + DxfGroup.toString(73, fastZoomSetting) + + DxfGroup.toString(74, ucsIconSetting) + + DxfGroup.toString(75, snapOnOff) + + DxfGroup.toString(76, gridOnOff) + + DxfGroup.toString(77, snapStyle) + + DxfGroup.toString(78, snapIsoPair); + } + +} diff --git a/src/main/java/fr/michaelm/jump/drivers/dxf/DxfTEXT.java b/src/main/java/fr/michaelm/jump/drivers/dxf/DxfTEXT.java new file mode 100644 index 0000000..bac7921 --- /dev/null +++ b/src/main/java/fr/michaelm/jump/drivers/dxf/DxfTEXT.java @@ -0,0 +1,88 @@ +/* + * Library name : dxf + * (C) 2021 Michaël Michaud + * + * This program 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 2 + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * For more information, contact: + * + * m.michael.michaud@orange.fr + * + */ + +package fr.michaelm.jump.drivers.dxf; + +import java.io.RandomAccessFile; +import java.io.IOException; + +import com.vividsolutions.jump.feature.Feature; +import com.vividsolutions.jump.feature.BasicFeature; +import com.vividsolutions.jump.feature.FeatureCollection; +import org.locationtech.jts.geom.Coordinate; +import org.locationtech.jts.geom.GeometryFactory; + + +/** + * A TEXT and its static readEntity method to read a TEXT in a DXF file. + * @author Michaël Michaud + */ +// History +// 2012-09-22 : Fix a bug preventing TEXT entities to be read +// 2011-04-10 : Add TEXT_ROTATION +// 2006-11-12 : Bug fixed x==Double.NaN --> Double.isNaN(x) +public class DxfTEXT extends DxfENTITY { + + public DxfTEXT() {super("DEFAULT");} + + public static DxfGroup readEntity(RandomAccessFile raf, + FeatureCollection entities) + throws IOException { + Feature feature = new BasicFeature(DxfFile.DXF_SCHEMA); + feature.setAttribute("LTYPE", "BYLAYER"); + feature.setAttribute("THICKNESS", 0.0); + feature.setAttribute("COLOR", 256); // equivalent to BYLAYER + feature.setAttribute("TEXT", ""); + feature.setAttribute("TEXT_HEIGHT", 0.0); + feature.setAttribute("TEXT_ROTATION", 0.0); + feature.setAttribute("TEXT_STYLE", "STANDARD"); + double x=Double.NaN, y=Double.NaN, z=Double.NaN; + DxfGroup group; + GeometryFactory gf = new GeometryFactory(DPM,0); + while (null != (group = DxfGroup.readGroup(raf))) { + int code = group.getCode(); + if (code == 0) break; + if (DxfFile.DEBUG) group.print(12); + if (code==8) feature.setAttribute("LAYER", group.getValue()); + else if (code==6) feature.setAttribute("LTYPE", group.getValue()); + else if (code==39) feature.setAttribute("THICKNESS", group.getDoubleValue()); + else if (code==62) feature.setAttribute("COLOR", group.getIntValue()); + else if (code==10) x = group.getDoubleValue(); + else if (code==20) y = group.getDoubleValue(); + else if (code==30) z = group.getDoubleValue(); + else if (code==1) feature.setAttribute("TEXT", group.getValue()); + else if (code==40) feature.setAttribute("TEXT_HEIGHT", group.getDoubleValue()); + else if (code==50) feature.setAttribute("TEXT_ROTATION", group.getDoubleValue()); + else if (code==7) feature.setAttribute("TEXT_STYLE", group.getValue()); + //else {} + } + if (!Double.isNaN(x) && !Double.isNaN(y)) { + feature.setGeometry(gf.createPoint(new Coordinate(x,y,z))); + if (DxfFile.DEBUG) System.out.println(" " + feature.getString("LAYER") + " : " + feature.getGeometry()); + entities.add(feature); + } + return group; + } + +} diff --git a/src/main/java/fr/michaelm/jump/drivers/dxf/DxfVERTEX.java b/src/main/java/fr/michaelm/jump/drivers/dxf/DxfVERTEX.java new file mode 100644 index 0000000..83b9208 --- /dev/null +++ b/src/main/java/fr/michaelm/jump/drivers/dxf/DxfVERTEX.java @@ -0,0 +1,64 @@ +/* + * Library name : dxf + * (C) 2021 Michaël Michaud + * + * This program 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 2 + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * For more information, contact: + * + * m.michael.michaud@orange.fr + * + */ + +package fr.michaelm.jump.drivers.dxf; + +import org.locationtech.jts.geom.Coordinate; +import org.locationtech.jts.geom.CoordinateList; +import java.io.RandomAccessFile; +import java.io.IOException; + + +/** + * A VERTEX and a static readEntity method to read a VERTEX in a DXF file. + * @author Michaël Michaud + */ +// History +// 2006-11-12 : Bug fixed x==Double.NaN --> Double.isNaN(x) +public class DxfVERTEX extends DxfENTITY { + + public DxfVERTEX() {super("DEFAULT");} + + public static DxfGroup readEntity(RandomAccessFile raf, + CoordinateList coordList) + throws NumberFormatException, IOException { + //Coordinate coord; + double x=Double.NaN, y=Double.NaN, z=Double.NaN; + DxfGroup group; + int code; + while (null != (group = DxfGroup.readGroup(raf)) && + 0 != (code = group.getCode())) { + if (code==10) x = group.getDoubleValue(); + else if (code==20) y = group.getDoubleValue(); + else if (code==30) z = group.getDoubleValue(); + //else {} + } + if (!Double.isNaN(x) && !Double.isNaN(y)) { + if (DxfFile.DEBUG) System.out.println(" " + new Coordinate(x,y,z)); + coordList.add(new Coordinate(x,y,z)); + } + return group; + } + +} diff --git a/src/main/java/fr/michaelm/jump/drivers/dxf/DxfWriter.java b/src/main/java/fr/michaelm/jump/drivers/dxf/DxfWriter.java new file mode 100644 index 0000000..329e3df --- /dev/null +++ b/src/main/java/fr/michaelm/jump/drivers/dxf/DxfWriter.java @@ -0,0 +1,98 @@ +/* + * Library name : dxf + * (C) 2021 Michaël Michaud + * + * This program 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 2 + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * For more information, contact: + * + * m.michael.michaud@orange.fr + * + */ + +package fr.michaelm.jump.drivers.dxf; + +import com.vividsolutions.jump.feature.*; +import com.vividsolutions.jump.io.JUMPWriter; +import com.vividsolutions.jump.io.DriverProperties; +import com.vividsolutions.jump.io.IllegalParametersException; + +import java.io.*; + + +/** + * DXF writer + * @author Michaël Michaud + */ +// History +// 2006-11-12 : Much clean-up made on 2006-11-12 for version 0.5 +public class DxfWriter implements JUMPWriter { + + //DxfFile dxfFile = null; + + /** Creates new DxfWriter */ + public DxfWriter() {} + + /** + * Main method - write the featurecollection to a DXF file. + * + * @param featureCollection collection to write + * @param dp 'OutputFile' or 'DefaultValue' to specify where to write. + */ + public void write(FeatureCollection featureCollection, DriverProperties dp) + throws Exception { + String dxfFileName; + String fname; + int loc; + dxfFileName = dp.getProperty("File"); + + if (dxfFileName == null) { + dxfFileName = dp.getProperty("DefaultValue"); + } + if (dxfFileName == null) { + throw new IllegalParametersException("no File property specified"); + } + + // Fix on 2016-09-29 to make it compatible with OpenJUMP 1.9.1 + //String[] layerNameProp = (String[])dp.get("LAYER_NAME"); + //String[] layerNames = layerNameProp == null ? new String[]{}:layerNameProp; + String layerNameProperty = dp.getProperty("LAYER_NAME"); + String[] layerNames; + if (layerNameProperty == null) layerNames = new String[]{""}; + else layerNames = layerNameProperty.split("\n"); + + // Check if the writer has to create layers with "_" suffix for layers with holes + // Warning : using getProperty instead of get return null + // because SUFFIX is not a String + boolean suffix = true; + Object suffixObject = dp.get("SUFFIX"); + if (suffixObject != null) { + if (suffixObject instanceof Boolean) suffix = (Boolean)suffixObject; + else if (suffixObject instanceof String) suffix = Boolean.parseBoolean(suffixObject.toString()); + } + + loc = dxfFileName.lastIndexOf(File.separatorChar); + fname = dxfFileName.substring(loc + 1); // ie. "/data1/hills.dxf" -> "hills.dxf" + loc = fname.lastIndexOf("."); + if (loc == -1) { + throw new IllegalParametersException("Filename must end in '.dxf'"); + } + + FileWriter fw = new FileWriter(dxfFileName); + DxfFile.write(featureCollection, layerNames, fw, 2, suffix); + fw.close(); + } + +} diff --git a/src/main/java/fr/michaelm/jump/drivers/dxf/InstallDXFDataSourceQueryChooserPlugIn.java b/src/main/java/fr/michaelm/jump/drivers/dxf/InstallDXFDataSourceQueryChooserPlugIn.java new file mode 100644 index 0000000..50359ef --- /dev/null +++ b/src/main/java/fr/michaelm/jump/drivers/dxf/InstallDXFDataSourceQueryChooserPlugIn.java @@ -0,0 +1,87 @@ +/* + * Library name : dxf + * (C) 2021 Michaël Michaud + * + * This program 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 2 + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * For more information, contact: + * + * m.michael.michaud@orange.fr + * + */ + +package fr.michaelm.jump.drivers.dxf; + +import javax.swing.JFileChooser; + +import com.vividsolutions.jump.workbench.datasource.InstallStandardDataSourceQueryChoosersPlugIn; +import com.vividsolutions.jump.workbench.plugin.PlugInContext; +import com.vividsolutions.jump.io.JUMPWriter; +import com.vividsolutions.jump.io.JUMPReader; +import com.vividsolutions.jump.workbench.datasource.LoadFileDataSourceQueryChooser; +import com.vividsolutions.jump.workbench.datasource.DataSourceQueryChooserManager; +import com.vividsolutions.jump.workbench.WorkbenchContext; + + +/** + * Install the DXF driver. + * Extends the InstallStandardDataSourceQueryChoosersPlugIn class, overloading + * initialize() to initialize DxfReader, DxfWriter. + * @author Michaël Michaud + */ +// History +// 2006-10-18 : replace standard SaveFileDataSourceQueryChooser by a +// SaveDxfFileDataSourceQueryChooser with options for header for entity +// handles and for layer name. +public class InstallDXFDataSourceQueryChooserPlugIn extends InstallStandardDataSourceQueryChoosersPlugIn { + + private void addFileDataSourceQueryChoosers( + JUMPReader reader, + JUMPWriter writer, + final String description, + WorkbenchContext workbenchContext, + Class readerWriterDataSourceClass + ) { + DataSourceQueryChooserManager.get( + workbenchContext.getBlackboard()) + .addLoadDataSourceQueryChooser(new LoadFileDataSourceQueryChooser( + readerWriterDataSourceClass, + description, + extensions(readerWriterDataSourceClass), + workbenchContext) { + protected void addFileFilters(JFileChooser chooser) { + super.addFileFilters(chooser); + InstallStandardDataSourceQueryChoosersPlugIn.addCompressedFileFilter( + description, + chooser); + } + }).addSaveDataSourceQueryChooser( + new SaveDxfFileDataSourceQueryChooser( + readerWriterDataSourceClass, + description, + extensions(readerWriterDataSourceClass), + workbenchContext)); + } + + public void initialize(final PlugInContext context) { + addFileDataSourceQueryChoosers( + new DxfReader(), + new DxfWriter(), + "dxf", + context.getWorkbenchContext(), + DXFFileReaderWriter.class); + } + +} diff --git a/src/main/java/fr/michaelm/jump/drivers/dxf/SaveDxfFileDataSourceQueryChooser.java b/src/main/java/fr/michaelm/jump/drivers/dxf/SaveDxfFileDataSourceQueryChooser.java new file mode 100644 index 0000000..2cf1a78 --- /dev/null +++ b/src/main/java/fr/michaelm/jump/drivers/dxf/SaveDxfFileDataSourceQueryChooser.java @@ -0,0 +1,154 @@ +/* + * Library name : dxf + * (C) 2021 Michaël Michaud + * + * This program 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 2 + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * For more information, contact: + * + * m.michael.michaud@orange.fr + * + */ + +package fr.michaelm.jump.drivers.dxf; + +import java.awt.Component; +import java.io.File; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.JCheckBox; +import javax.swing.JPanel; + +import com.vividsolutions.jump.feature.Feature; +import com.vividsolutions.jump.feature.FeatureSchema; +import com.vividsolutions.jump.workbench.datasource.SaveFileDataSourceQueryChooser; +import com.vividsolutions.jump.workbench.model.*; +import com.vividsolutions.jump.workbench.WorkbenchContext; + + +/** + * User interface to save a JUMP layer into a DXF file + * Add an option to the standard panel + * - option to create "_" suffixed layers for holes in polygon + * @author Michaël Michaud + */ +// History +// 2006-11-12 : remove the header option after L. Becker and R. Littlefield +// have fix the bug in the header writing +// 2006-10-18 : add two options (one for header writing and the other to suffix +// layers containing holes) and a function to create valid DXF +// layer names from JUMP layer names +public class SaveDxfFileDataSourceQueryChooser extends SaveFileDataSourceQueryChooser { + + // Array making it possible to replace any of the 383 first unicode + // characters by a valid character for DXF layer name or file name + // (removes accents, escape characters and most of special symbols) + private static final String[] asciiChar = new String[] { + "","","","","","","","","","","","","","","","", //00-0F + "","","","","","","","","","","","","","","","", //10-1F + "_","_","_","_","_","_","_","_","_","_","_","_","_","-",".","_", //20-2F + "0","1","2","3","4","5","6","7","8","9","_","_","_","_","_","_", //30-3F + "_","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O", //40-4F + "P","Q","R","S","T","U","V","W","X","Y","Z","_","_","_","_","_", //50-5F + "_","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o", //60-6F + "p","q","r","s","t","u","v","w","x","y","z","_","_","_","_","", //70-7F + "","","","","","","","","","","","","","","","", //80-8F + "","","","","","","","","","","","","","","","", //90-9F + "_","_","c","L","_","Y","_","_","","c","a","","_","-","r","", //A0-AF + "o","_","2","3","","u","_",".","","1","o","","_","_","_","_", //B0-BF + "A","A","A","A","A","A","AE","C","E","E","E","E","I","I","I","I",//C0-CF + "E","N","O","O","O","O","O","x","O","U","U","U","U","Y","T","SS",//D0-DF + "a","a","a","a","a","a","ae","c","e","e","e","e","i","i","i","i",//E0-EF + "e","n","o","o","o","o","o","_","0","u","u","u","u","y","t","y", //F0-FF + "A","a","A","a","A","a","C","c","C","c","C","c","C","c","D","d", //100-10F + "D","d","E","e","E","e","E","e","E","e","E","e","G","g","G","g", //110-11F + "G","g","G","g","H","h","H","h","I","i","I","i","I","i","I","i", //120-12F + "I","i","IJ","ij","J","j","K","k","k","L","l","L","l","L","l","L", //130-13F + "l","L","l","N","n","N","n","N","n","n","N","n","O","o","O","o", //140-14F + "O","o","OE","oe","R","r","R","r","R","r","S","s","S","s","S","s", //150-15F + "S","s","T","t","T","t","T","t","U","u","U","u","U","u","U","u", //160-16F + "U","u","U","u","W","w","Y","y","Y","Z","z","Z","z","Z","z","_" //170-17F + }; + + WorkbenchContext context; + JPanel optionPanel = new JPanel(); + JCheckBox suffixCB = new JCheckBox("Put polygon holes in layers with a '_' suffix", true); + + SaveDxfFileDataSourceQueryChooser(Class readerWriterDataSourceClass, String description, + String[] extensions, WorkbenchContext workbenchContext) { + super(readerWriterDataSourceClass, description, extensions, workbenchContext); + this.context = workbenchContext; + Box box = new Box(BoxLayout.Y_AXIS); + optionPanel.add(box); + //box.add(headerCB); + box.add(suffixCB); + } + + protected Map toProperties(File file) { + Map properties = new HashMap<>(super.toProperties(file)); + Layer selectedLayer = context.getLayerableNamePanel().getSelectedLayers()[0]; + String layerName = toAscii(selectedLayer.getName()).substring(0, Math.min(selectedLayer.getName().length(), 31)); + properties.put("LAYER_NAME", layerName); + // If the layer schema has an attribute "LAYER" the value of this + // attribute is used for the DXF layer name + if (selectedLayer instanceof Layer) { + FeatureSchema fs = selectedLayer.getFeatureCollectionWrapper().getFeatureSchema(); + if (fs.hasAttribute("LAYER")) { + Set layerSet = new HashSet<>(); + List features = selectedLayer.getFeatureCollectionWrapper().getFeatures(); + for (Feature feature : features) { + if (feature.getString("LAYER") != null && + feature.getString("LAYER").trim().length()>0 && + !feature.getString("LAYER").endsWith("_")) { + layerSet.add(feature.getString("LAYER")); + } + } + String[] set = layerSet.toArray(new String[0]); + StringBuilder sb = new StringBuilder(); + for (int i = 0 ; i < set.length ; i++) { + if (i > 0) sb.append("\n"); + sb.append(set[i]); + } + properties.put("LAYER_NAME", sb.toString()); + } + } + properties.put("SUFFIX", suffixCB.isSelected()); + return properties; + } + + protected Component getSouthComponent1() { + return optionPanel; + } + + /** + * Remove accents using the asciiChar array. + */ + public static String toAscii(String in) { + String input = in.trim(); + StringBuilder output = new StringBuilder(); + for(int i = 0 ; i < input.length() ; i++) { + int carVal = input.charAt(i); + if (carVal < 384) {output.append(asciiChar[carVal]);} + else {output.append("_");} + } + return output.toString(); + } + +}