Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add translation support #11

Merged
merged 10 commits into from
Nov 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# By default text files use native line endings for the platform
* text=auto

*.ili text eol=crlf
*.dxf text eol=lf
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ repositories {

dependencies {
implementation 'ch.interlis:iox-ili:1.23.1'
implementation 'ch.interlis:ili2c-tool:5.5.4'
implementation 'ch.interlis:ili2c-core:5.5.4'

implementation 'commons-cli:commons-cli:1.9.0'
Expand All @@ -40,4 +41,5 @@ jar {

test {
useJUnitPlatform()
testLogging.showStandardStreams = true
}
4 changes: 3 additions & 1 deletion config/checkstyle/checkstyle.xml
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,9 @@
<!-- Checks for Size Violations. -->
<!-- See https://checkstyle.org/checks/sizes/index.html -->
<module name="MethodLength"/>
<module name="ParameterNumber"/>
<module name="ParameterNumber">
<property name="max" value="8"/>
</module>

<!-- Checks for whitespace -->
<!-- See https://checkstyle.org/checks/whitespace/index.html -->
Expand Down
8 changes: 4 additions & 4 deletions src/main/java/ch/geowerkstatt/lk2dxf/DxfWriter.java
Original file line number Diff line number Diff line change
Expand Up @@ -273,13 +273,13 @@ public void writeBlockInsert(String layerName, String blockName, double rotation
* @param position The position of the text.
* @see <a href="https://help.autodesk.com/view/OARX/2024/ENU/?guid=GUID-62E5383D-8A14-47B4-BFC4-35824CAE8363">TEXT (DXF Reference)</a>
*/
public void writeText(String layerName, String textStyle, String text, String hAlignment, String vAlignment, double orientation, IomObject position) throws IOException {
var hAlignmentValue = switch (hAlignment.toLowerCase(Locale.ROOT)) {
public void writeText(String layerName, String textStyle, String text, String hAlignment, String vAlignment, double orientation, double size, IomObject position) throws IOException {
var hAlignmentValue = switch (Objects.requireNonNullElse(hAlignment, "").toLowerCase(Locale.ROOT)) {
case "right" -> 2;
case "center" -> 1;
default -> 0; // Left
};
var vAlignmentValue = switch (vAlignment.toLowerCase(Locale.ROOT)) {
var vAlignmentValue = switch (Objects.requireNonNullElse(vAlignment, "").toLowerCase(Locale.ROOT)) {
case "top", "cap" -> 3;
case "half" -> 2;
case "bottom" -> 1;
Expand All @@ -297,7 +297,7 @@ public void writeText(String layerName, String textStyle, String text, String hA
writeElement(7, textStyle);
writeElement(10, isDefaultAlignment ? Double.parseDouble(position.getattrvalue("C1")) : 0.0);
writeElement(20, isDefaultAlignment ? Double.parseDouble(position.getattrvalue("C2")) : 0.0);
writeElement(40, 1.25); // text height
writeElement(40, size); // text height
writeElement(1, text);
if (hAlignmentValue != 0) {
writeElement(72, hAlignmentValue);
Expand Down
37 changes: 2 additions & 35 deletions src/main/java/ch/geowerkstatt/lk2dxf/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
import java.io.File;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Stream;

public final class Main {
Expand Down Expand Up @@ -55,50 +54,18 @@ public static void main(String[] args) {

private static void processFiles(LK2DxfOptions options) {
Optional<Geometry> perimeter = options.parsePerimeter();
AtomicInteger counter = new AtomicInteger();

try (var dxfWriter = new DxfWriter(options.dxfFile(), 3, ObjectMapper.getLayerMappings(), "lk2dxf " + Main.VERSION)) {
for (String xtfFile : options.xtfFiles()) {
try (LKMapXtfReader reader = new LKMapXtfReader(new File(xtfFile))) {
try (XtfStreamReader reader = new XtfStreamReader(new File(xtfFile))) {
ObjectMapper mapper = new ObjectMapper();
Stream<MappedObject> objects = mapper.mapObjects(reader.readObjects());

if (perimeter.isPresent()) {
objects = objects.filter(o -> perimeter.get().intersects(o.geometry()));
}

objects.forEach(o -> {
try {
switch (o.layerMapping().objectClass()) {
case "LKFlaeche" ->
dxfWriter.writeHatch(o.layerMapping().layer(), o.iomObject().getattrobj(o.layerMapping().geometry(), 0));
case "LKLinie" ->
dxfWriter.writeLwPolyline(o.layerMapping().layer(), o.iomObject().getattrobj(o.layerMapping().geometry(), 0));
case "LKPunkt" -> dxfWriter.writeBlockInsert(
o.layerMapping().layer(),
o.layerMapping().symbol(),
Optional.ofNullable(o.iomObject().getattrvalue(o.layerMapping().orientation())).map(Double::parseDouble).orElse(90.0),
o.iomObject().getattrobj(o.layerMapping().geometry(), 0));
case "LKObjekt_Text" -> dxfWriter.writeText(
o.layerMapping().layer(),
o.layerMapping().font(),
o.iomObject().getattrvalue(o.layerMapping().text()),
o.iomObject().getattrvalue(o.layerMapping().hAlign()),
o.iomObject().getattrvalue(o.layerMapping().vAlign()),
Double.parseDouble(o.iomObject().getattrvalue(o.layerMapping().orientation())),
o.iomObject().getattrobj(o.layerMapping().geometry(), 0));

default -> System.out.println("Unsupported geometry type: " + o.layerMapping().geometryType());
//throw new IllegalArgumentException("Unsupported geometry type: " + o.layerMapping().geometryType());
}

System.out.println(counter.incrementAndGet() + ": " + o.iomObject().getobjectoid() + " -> " + o.layerMapping().layer());
} catch (Exception e) {
System.err.println("Failed to process object: " + o.iomObject().getobjectoid());
e.printStackTrace();
return;
}
});
objects.forEach(o -> o.writeToDxf(dxfWriter));
} catch (Exception e) {
System.err.println("Failed to process file: " + xtfFile);
e.printStackTrace();
Expand Down
67 changes: 42 additions & 25 deletions src/main/java/ch/geowerkstatt/lk2dxf/MappedObject.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,42 +8,59 @@
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;

public record MappedObject(Geometry geometry, IomObject iomObject, LayerMapping layerMapping) {
public record MappedObject(
String oid,
Geometry geometry,
IomObject iomGeometry,
double orientation,
String vAlign,
String hAlign,
String text,
LayerMapping layerMapping) {
private static final GeometryFactory GEOMETRY_FACTORY = new JtsextGeometryFactory();

/**
* Creates a new geometry object from the given {@link IomObject}.
* @param iomObject The {@link IomObject} to create the geometry object from.
* @return A geometry object containing the {@link IomObject} and its extracted {@link Geometry}.
* @throws IllegalArgumentException If the object tag is not supported.
* Creates a new {@link MappedObject} that contains all information to process the object further.
*
* @throws RuntimeException If an error occurs while extracting the geometry.
*/
public static MappedObject create(IomObject iomObject, LayerMapping layerMapping) {
public MappedObject(String oid, IomObject iomGeometry, Double orientation, String vAlign, String hAlign, String text, LayerMapping layerMapping) {
this(oid, constructGeometry(iomGeometry, layerMapping.output(), oid), iomGeometry, orientation == null ? 90 : orientation, vAlign, hAlign, text, layerMapping);
}

private static Geometry constructGeometry(IomObject iomGeometry, LayerMapping.OutputType outputType, String oid) {
try {
Geometry geometry = switch (layerMapping.geometryType()) {
case "Point" -> readPoint(iomObject, layerMapping.geometry());
case "Line" -> readLine(iomObject, layerMapping.geometry());
case "Surface" -> readSurface(iomObject, layerMapping.geometry());
default -> throw new IllegalArgumentException("Unsupported object tag: " + iomObject.getobjecttag());
return switch (outputType) {
case TEXT, POINT -> GEOMETRY_FACTORY.createPoint(Iox2jtsext.coord2JTS(iomGeometry));
case LINE -> Iox2jtsext.polyline2JTS(iomGeometry, false, 0.0);
case SURFACE -> Iox2jtsext.surface2JTS(iomGeometry, 0.0);
};
return new MappedObject(geometry, iomObject, layerMapping);
} catch (IoxException e) {
throw new RuntimeException("Error creating geometry for object with id \"" + iomObject.getobjectoid() + "\".", e);
throw new RuntimeException("Error creating geometry for object with id \"" + oid + "\".", e);
}
}

private static Geometry readPoint(IomObject iomObject, String attributeName) throws IoxException {
IomObject position = iomObject.getattrobj(attributeName, 0);
return GEOMETRY_FACTORY.createPoint(Iox2jtsext.coord2JTS(position));
}

private static Geometry readLine(IomObject iomObject, String attributeName) throws IoxException {
IomObject line = iomObject.getattrobj(attributeName, 0);
return Iox2jtsext.polyline2JTS(line, false, 0.0);
}
/**
* Writes the object to a DXF file using the provided {@link DxfWriter}.
*/
public void writeToDxf(DxfWriter dxfWriter) {
try {
if (iomGeometry == null) {
throw new IllegalStateException("Cannot write object to dxf without geometry.");
}

private static Geometry readSurface(IomObject iomObject, String attributeName) throws IoxException {
IomObject surface = iomObject.getattrobj(attributeName, 0);
return Iox2jtsext.surface2JTS(surface, 0.0);
switch (layerMapping().output()) {
case SURFACE -> dxfWriter.writeHatch(layerMapping().layer(), iomGeometry);
case LINE -> dxfWriter.writeLwPolyline(layerMapping().layer(), iomGeometry);
case POINT ->
dxfWriter.writeBlockInsert(layerMapping().layer(), layerMapping().symbol(), orientation, iomGeometry);
case TEXT ->
dxfWriter.writeText(layerMapping().layer(), layerMapping().font(), text, hAlign, vAlign, orientation, layerMapping().textsize(), iomGeometry);
default -> throw new AssertionError("Unknown output type: " + layerMapping().output());
}
} catch (Exception e) {
System.err.println("Failed to write object: " + oid() + " to dxf.");
e.printStackTrace();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,9 @@
import java.util.stream.StreamSupport;

/**
* A reader for LKMap INTERLIS transfer files.
* A reader for INTERLIS transfer files.
*/
public final class LKMapXtfReader implements AutoCloseable {
private static final String BASKET_NAME = "SIA405_LKMap_2015_LV95.SIA405_LKMap";
public final class XtfStreamReader implements AutoCloseable {
private static final ReaderFactory READER_FACTORY = new ReaderFactory();

private final IoxReader reader;
Expand All @@ -34,7 +33,7 @@ public final class LKMapXtfReader implements AutoCloseable {
* @param xtfFile The file to read from.
* @throws IoxException If an error occurs while creating the transfer file reader.
*/
public LKMapXtfReader(File xtfFile) throws IoxException {
public XtfStreamReader(File xtfFile) throws IoxException {
LogEventFactory logEventFactory = new LogEventFactory();
Settings settings = new Settings();
this.reader = READER_FACTORY.createReader(xtfFile, logEventFactory, settings);
Expand Down Expand Up @@ -68,7 +67,7 @@ private enum LKMapXtfReaderState {
}

/**
* A sequential spliterator for reading objects from the surrounding {@link LKMapXtfReader}.
* A sequential spliterator for reading objects from the surrounding {@link XtfStreamReader}.
* Advancing the spliterator will read from the xtf reader and may throw an exception when reading invalid data.
*/
private class XtfReaderSpliterator implements Spliterator<IomObject> {
Expand All @@ -89,9 +88,6 @@ public boolean tryAdvance(Consumer<? super IomObject> action) {
if (state != LKMapXtfReaderState.TRANSFER) {
throw new IllegalStateException("Unexpected start basket event in state: " + state);
}
if (!BASKET_NAME.equals(startBasketEvent.getType())) {
throw new IllegalStateException("Invalid basket type: " + startBasketEvent.getType());
}
state = LKMapXtfReaderState.BASKET;
System.out.println("Start basket \"" + startBasketEvent.getBid() + "\"");
}
Expand Down
28 changes: 26 additions & 2 deletions src/main/java/ch/geowerkstatt/lk2dxf/mapping/LayerMapping.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;

import java.util.Collection;
import java.util.List;
import java.util.Map;

public record LayerMapping(
String layer,
String objectClass,
String geometryType,
@JsonDeserialize(converter = ObjectClassConverter.class)
Collection<String> objectClass,
OutputType output,
String geometry,
int color,
String orientation,
Expand All @@ -22,4 +24,26 @@ public record LayerMapping(
String font,
@JsonDeserialize(converter = MappingConverter.class)
Map<String, List<String>> mapping) {

public enum OutputType {
/**
* The object has a surface and is exported as a filled polygon.
*/
SURFACE,

/**
* The object has a line geometry.
*/
LINE,

/**
* The object represents text with font, alignment and orientation.
*/
TEXT,

/**
* The object has a point geometry that gets marked with a symbol.
*/
POINT,
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,15 @@
import java.io.InputStream;
import java.util.List;

/**
* Read and interpret the layer mapping configuration.
*/
public final class MappingReader {
private static final String MAPPING_RESOURCE = "/mappings.csv";
private static final CsvMapper MAPPER = CsvMapper
.builder()
.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES)
.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS)
.build();

private MappingReader() { }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package ch.geowerkstatt.lk2dxf.mapping;

import com.fasterxml.jackson.databind.util.StdConverter;

import java.util.*;
import java.util.regex.Pattern;

public final class ObjectClassConverter extends StdConverter<String, Collection<String>> {
private static final Pattern VALUE_SEPARATOR = Pattern.compile("\\|");

@Override
public Collection<String> convert(String s) {
return new HashSet<>(Arrays.asList(VALUE_SEPARATOR.split(s)));
}
}
Loading