This is an automated email from the ASF dual-hosted git repository.

bchapuis pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-baremaps.git


The following commit(s) were added to refs/heads/main by this push:
     new 6e0da543 Refactor the openstreetmap handlers (#564)
6e0da543 is described below

commit 6e0da543fd03fcd45f6532e15e3849003776f46d
Author: Bertil Chapuis <[email protected]>
AuthorDate: Fri Dec 23 11:12:11 2022 +0100

    Refactor the openstreetmap handlers (#564)
    
    * Split the coordinate and reference map builders
    
    * Improve way geometry creation
    
    * Add a consumer that collects geometries in a map
    
    * Simplify the coordinate and reference map builders
    
    * Improve projection transformer
---
 .../baremaps/collection/type/GeometryDataType.java | 42 ++++++++++++++++
 .../apache/baremaps/database/ImportService.java    | 22 ++++++---
 .../openstreetmap/function/CacheBuilder.java       | 57 ----------------------
 .../function/CoordinateMapBuilder.java             | 44 +++++++++++++++++
 .../function/EntityProjectionTransformer.java      | 18 +++++--
 .../openstreetmap/function/GeometryMapBuilder.java | 51 +++++++++++++++++++
 .../function/ReferenceMapBuilder.java              | 44 +++++++++++++++++
 .../openstreetmap/function/WayGeometryBuilder.java |  5 +-
 .../baremaps/openstreetmap/pbf/PbfBlockReader.java | 16 ++++--
 .../baremaps/collection/type/DataTypeProvider.java |  6 +++
 codestyle.xml                                      |  2 +-
 11 files changed, 230 insertions(+), 77 deletions(-)

diff --git 
a/baremaps-core/src/main/java/org/apache/baremaps/collection/type/GeometryDataType.java
 
b/baremaps-core/src/main/java/org/apache/baremaps/collection/type/GeometryDataType.java
new file mode 100644
index 00000000..4227eb37
--- /dev/null
+++ 
b/baremaps-core/src/main/java/org/apache/baremaps/collection/type/GeometryDataType.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not 
use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software 
distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 
KIND, either express
+ * or implied. See the License for the specific language governing permissions 
and limitations under
+ * the License.
+ */
+
+package org.apache.baremaps.collection.type;
+
+
+
+import java.nio.ByteBuffer;
+import org.apache.baremaps.openstreetmap.utils.GeometryUtils;
+import org.locationtech.jts.geom.Geometry;
+
+public class GeometryDataType implements DataType<Geometry> {
+
+  @Override
+  public int size(Geometry value) {
+    return 4 + GeometryUtils.serialize(value).length;
+  }
+
+  @Override
+  public void write(ByteBuffer buffer, int position, Geometry value) {
+    byte[] bytes = GeometryUtils.serialize(value);
+    buffer.putInt(position, bytes.length);
+    buffer.put(position + 4, bytes);
+  }
+
+  @Override
+  public Geometry read(ByteBuffer buffer, int position) {
+    int length = buffer.getInt(position);
+    byte[] bytes = new byte[length];
+    buffer.get(position + 4, bytes);
+    return GeometryUtils.deserialize(bytes);
+  }
+}
diff --git 
a/baremaps-core/src/main/java/org/apache/baremaps/database/ImportService.java 
b/baremaps-core/src/main/java/org/apache/baremaps/database/ImportService.java
index ab1b58ad..e3af0a56 100644
--- 
a/baremaps-core/src/main/java/org/apache/baremaps/database/ImportService.java
+++ 
b/baremaps-core/src/main/java/org/apache/baremaps/database/ImportService.java
@@ -23,10 +23,7 @@ import java.util.concurrent.Callable;
 import org.apache.baremaps.collection.LongDataMap;
 import org.apache.baremaps.database.repository.HeaderRepository;
 import org.apache.baremaps.database.repository.Repository;
-import org.apache.baremaps.openstreetmap.function.BlockEntitiesHandler;
-import org.apache.baremaps.openstreetmap.function.CacheBuilder;
-import org.apache.baremaps.openstreetmap.function.EntityGeometryBuilder;
-import org.apache.baremaps.openstreetmap.function.EntityProjectionTransformer;
+import org.apache.baremaps.openstreetmap.function.*;
 import org.apache.baremaps.openstreetmap.model.Node;
 import org.apache.baremaps.openstreetmap.model.Relation;
 import org.apache.baremaps.openstreetmap.model.Way;
@@ -60,17 +57,26 @@ public class ImportService implements Callable<Void> {
 
   @Override
   public Void call() throws Exception {
-    var cacheBuilder = new CacheBuilder(coordinateMap, referenceMap);
+    // Initialize and chain the entity handlers
+    var coordinateMapBuilder = new CoordinateMapBuilder(coordinateMap);
+    var referenceMapBuilder = new ReferenceMapBuilder(referenceMap);
     var entityGeometryBuilder = new EntityGeometryBuilder(coordinateMap, 
referenceMap);
     var entityProjectionTransformer = new EntityProjectionTransformer(4326, 
databaseSrid);
-    var blockEntitiesHandler =
-        new 
BlockEntitiesHandler(entityGeometryBuilder.andThen(entityProjectionTransformer));
-    var blockMapper = 
consumeThenReturn(cacheBuilder.andThen(blockEntitiesHandler));
+    var entityHandler = coordinateMapBuilder
+        .andThen(referenceMapBuilder)
+        .andThen(entityGeometryBuilder)
+        .andThen(entityProjectionTransformer);
+
+    // Initialize the block mapper
+    var blockMapper = consumeThenReturn(new 
BlockEntitiesHandler(entityHandler));
     var blockImporter =
         new BlockImporter(headerRepository, nodeRepository, wayRepository, 
relationRepository);
+
+    // Process the blocks
     try (InputStream inputStream = Files.newInputStream(path)) {
       batch(new 
PbfBlockReader().stream(inputStream).map(blockMapper)).forEach(blockImporter);
     }
+
     return null;
   }
 
diff --git 
a/baremaps-core/src/main/java/org/apache/baremaps/openstreetmap/function/CacheBuilder.java
 
b/baremaps-core/src/main/java/org/apache/baremaps/openstreetmap/function/CacheBuilder.java
deleted file mode 100644
index 435867eb..00000000
--- 
a/baremaps-core/src/main/java/org/apache/baremaps/openstreetmap/function/CacheBuilder.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not 
use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software 
distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 
KIND, either express
- * or implied. See the License for the specific language governing permissions 
and limitations under
- * the License.
- */
-
-package org.apache.baremaps.openstreetmap.function;
-
-
-
-import java.util.List;
-import java.util.function.Consumer;
-import org.apache.baremaps.collection.LongDataMap;
-import org.apache.baremaps.openstreetmap.model.Block;
-import org.apache.baremaps.openstreetmap.model.DataBlock;
-import org.apache.baremaps.stream.StreamException;
-import org.locationtech.jts.geom.Coordinate;
-
-/** A consumer that caches openstreetmap coordinates and references. */
-public class CacheBuilder implements Consumer<Block> {
-
-  private final LongDataMap<Coordinate> coordinateMap;
-  private final LongDataMap<List<Long>> referenceMap;
-
-  /**
-   * Constructs a {@code CacheBlockConsumer} with the provided caches.
-   *
-   * @param coordinateMap the map of coordinates
-   * @param referenceMap the map of references
-   */
-  public CacheBuilder(LongDataMap<Coordinate> coordinateMap, 
LongDataMap<List<Long>> referenceMap) {
-    this.coordinateMap = coordinateMap;
-    this.referenceMap = referenceMap;
-  }
-
-  /** {@inheritDoc} */
-  @Override
-  public void accept(Block block) {
-    try {
-      if (block instanceof DataBlock dataBlock) {
-        dataBlock.getDenseNodes().stream().forEach(
-            node -> coordinateMap.put(node.getId(), new 
Coordinate(node.getLon(), node.getLat())));
-        dataBlock.getNodes().stream().forEach(
-            node -> coordinateMap.put(node.getId(), new 
Coordinate(node.getLon(), node.getLat())));
-        dataBlock.getWays().stream().forEach(way -> 
referenceMap.put(way.getId(), way.getNodes()));
-      }
-    } catch (Exception e) {
-      throw new StreamException(e);
-    }
-  }
-}
diff --git 
a/baremaps-core/src/main/java/org/apache/baremaps/openstreetmap/function/CoordinateMapBuilder.java
 
b/baremaps-core/src/main/java/org/apache/baremaps/openstreetmap/function/CoordinateMapBuilder.java
new file mode 100644
index 00000000..b0e1492b
--- /dev/null
+++ 
b/baremaps-core/src/main/java/org/apache/baremaps/openstreetmap/function/CoordinateMapBuilder.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not 
use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software 
distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 
KIND, either express
+ * or implied. See the License for the specific language governing permissions 
and limitations under
+ * the License.
+ */
+
+package org.apache.baremaps.openstreetmap.function;
+
+
+
+import java.util.function.Consumer;
+import org.apache.baremaps.collection.LongDataMap;
+import org.apache.baremaps.openstreetmap.model.Entity;
+import org.apache.baremaps.openstreetmap.model.Node;
+import org.locationtech.jts.geom.Coordinate;
+
+/** A consumer that stores openstreetmap coordinates in a map. */
+public class CoordinateMapBuilder implements Consumer<Entity> {
+
+  private final LongDataMap<Coordinate> coordinateMap;
+
+  /**
+   * Constructs a {@code CacheBlockConsumer} with the provided map.
+   *
+   * @param coordinateMap the map of coordinates
+   */
+  public CoordinateMapBuilder(LongDataMap<Coordinate> coordinateMap) {
+    this.coordinateMap = coordinateMap;
+  }
+
+  /** {@inheritDoc} */
+  @Override
+  public void accept(Entity entity) {
+    if (entity instanceof Node node) {
+      coordinateMap.put(node.getId(), new Coordinate(node.getLon(), 
node.getLat()));
+    }
+  }
+}
diff --git 
a/baremaps-core/src/main/java/org/apache/baremaps/openstreetmap/function/EntityProjectionTransformer.java
 
b/baremaps-core/src/main/java/org/apache/baremaps/openstreetmap/function/EntityProjectionTransformer.java
index beb1a010..41a0096c 100644
--- 
a/baremaps-core/src/main/java/org/apache/baremaps/openstreetmap/function/EntityProjectionTransformer.java
+++ 
b/baremaps-core/src/main/java/org/apache/baremaps/openstreetmap/function/EntityProjectionTransformer.java
@@ -22,22 +22,30 @@ import org.locationtech.jts.geom.Geometry;
 /** Changes the projection of the geometry of an entity via side-effects. */
 public class EntityProjectionTransformer implements Consumer<Entity> {
 
+  private final int sourceSrid;
+
+  private final int targetSrid;
+
   private final ProjectionTransformer projectionTransformer;
 
   /**
    * Creates a consumer that reproject geometries with the provided SRIDs.
    *
-   * @param inputSRID the input SRID
-   * @param outputSRID the output SRID
+   * @param sourceSrid the source SRID
+   * @param targetSrid the target SRID
    */
-  public EntityProjectionTransformer(int inputSRID, int outputSRID) {
-    this.projectionTransformer = new ProjectionTransformer(inputSRID, 
outputSRID);
+  public EntityProjectionTransformer(int sourceSrid, int targetSrid) {
+    this.sourceSrid = sourceSrid;
+    this.targetSrid = targetSrid;
+    this.projectionTransformer = new ProjectionTransformer(sourceSrid, 
targetSrid);
   }
 
   /** {@inheritDoc} */
   @Override
   public void accept(Entity entity) {
-    if (entity instanceof Element element && element.getGeometry() != null) {
+    if (sourceSrid != targetSrid
+        && entity instanceof Element element
+        && element.getGeometry() != null) {
       Geometry geometry = 
projectionTransformer.transform(element.getGeometry());
       element.setGeometry(geometry);
     }
diff --git 
a/baremaps-core/src/main/java/org/apache/baremaps/openstreetmap/function/GeometryMapBuilder.java
 
b/baremaps-core/src/main/java/org/apache/baremaps/openstreetmap/function/GeometryMapBuilder.java
new file mode 100644
index 00000000..2828b496
--- /dev/null
+++ 
b/baremaps-core/src/main/java/org/apache/baremaps/openstreetmap/function/GeometryMapBuilder.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not 
use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software 
distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 
KIND, either express
+ * or implied. See the License for the specific language governing permissions 
and limitations under
+ * the License.
+ */
+
+package org.apache.baremaps.openstreetmap.function;
+
+
+
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+import org.apache.baremaps.collection.LongDataMap;
+import org.apache.baremaps.openstreetmap.model.Element;
+import org.apache.baremaps.openstreetmap.model.Entity;
+import org.locationtech.jts.geom.Geometry;
+
+/**
+ * A consumer that stores the geometry of an element in a map.
+ */
+public class GeometryMapBuilder implements Consumer<Entity> {
+
+  private final LongDataMap<Geometry> geometryMap;
+
+  private final Predicate<Entity> filter;
+
+  /**
+   * Constructs a {@code GeometryMapBuilder} with the provided map.
+   *
+   * @param geometryMap the geometry map
+   * @param filter the entity filter
+   */
+  public GeometryMapBuilder(LongDataMap<Geometry> geometryMap, 
Predicate<Entity> filter) {
+    this.geometryMap = geometryMap;
+    this.filter = filter;
+  }
+
+  /** {@inheritDoc} */
+  @Override
+  public void accept(Entity entity) {
+    if (filter.test(entity) && entity instanceof Element element) {
+      geometryMap.put(element.getId(), element.getGeometry());
+    }
+  }
+}
diff --git 
a/baremaps-core/src/main/java/org/apache/baremaps/openstreetmap/function/ReferenceMapBuilder.java
 
b/baremaps-core/src/main/java/org/apache/baremaps/openstreetmap/function/ReferenceMapBuilder.java
new file mode 100644
index 00000000..6f720b1d
--- /dev/null
+++ 
b/baremaps-core/src/main/java/org/apache/baremaps/openstreetmap/function/ReferenceMapBuilder.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not 
use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software 
distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 
KIND, either express
+ * or implied. See the License for the specific language governing permissions 
and limitations under
+ * the License.
+ */
+
+package org.apache.baremaps.openstreetmap.function;
+
+
+
+import java.util.List;
+import java.util.function.Consumer;
+import org.apache.baremaps.collection.LongDataMap;
+import org.apache.baremaps.openstreetmap.model.Entity;
+import org.apache.baremaps.openstreetmap.model.Way;
+
+/** A consumer that stores openstreetmap references in a map. */
+public class ReferenceMapBuilder implements Consumer<Entity> {
+
+  private final LongDataMap<List<Long>> referenceMap;
+
+  /**
+   * Constructs a {@code CacheBlockConsumer} with the provided map.
+   *
+   * @param referenceMap the map of references
+   */
+  public ReferenceMapBuilder(LongDataMap<List<Long>> referenceMap) {
+    this.referenceMap = referenceMap;
+  }
+
+  /** {@inheritDoc} */
+  @Override
+  public void accept(Entity entity) {
+    if (entity instanceof Way way) {
+      referenceMap.put(way.getId(), way.getNodes());
+    }
+  }
+}
diff --git 
a/baremaps-core/src/main/java/org/apache/baremaps/openstreetmap/function/WayGeometryBuilder.java
 
b/baremaps-core/src/main/java/org/apache/baremaps/openstreetmap/function/WayGeometryBuilder.java
index 392cb909..3d6f21bc 100644
--- 
a/baremaps-core/src/main/java/org/apache/baremaps/openstreetmap/function/WayGeometryBuilder.java
+++ 
b/baremaps-core/src/main/java/org/apache/baremaps/openstreetmap/function/WayGeometryBuilder.java
@@ -50,7 +50,10 @@ public class WayGeometryBuilder implements Consumer<Way> {
       Coordinate[] array = list.toArray(new Coordinate[list.size()]);
       LineString line = GEOMETRY_FACTORY_WGS84.createLineString(array);
       if (!line.isEmpty()) {
-        if (!line.isClosed()) {
+        // Ways can be open or closed depending on the geometry or the tags:
+        // https://wiki.openstreetmap.org/wiki/Way
+        if (!line.isClosed() || way.getTags().containsKey("highway")
+            || way.getTags().containsKey("barrier")) {
           way.setGeometry(line);
         } else {
           Polygon polygon = 
GEOMETRY_FACTORY_WGS84.createPolygon(line.getCoordinates());
diff --git 
a/baremaps-core/src/main/java/org/apache/baremaps/openstreetmap/pbf/PbfBlockReader.java
 
b/baremaps-core/src/main/java/org/apache/baremaps/openstreetmap/pbf/PbfBlockReader.java
index 7e74c969..42c442ca 100644
--- 
a/baremaps-core/src/main/java/org/apache/baremaps/openstreetmap/pbf/PbfBlockReader.java
+++ 
b/baremaps-core/src/main/java/org/apache/baremaps/openstreetmap/pbf/PbfBlockReader.java
@@ -147,13 +147,19 @@ public class PbfBlockReader implements OsmReader<Block> {
     var blocks = StreamUtils.bufferInSourceOrder(StreamUtils.stream(new 
BlobIterator(inputStream)),
         new BlobToBlockMapper(), Runtime.getRuntime().availableProcessors());
     if (geometry) {
-      var cacheBuilder = new CacheBuilder(coordinateMap, referenceMap);
+      // Initialize and chain the entity handlers
+      var coordinateMapBuilder = new CoordinateMapBuilder(coordinateMap);
+      var referenceMapBuilder = new ReferenceMapBuilder(referenceMap);
       var entityGeometryBuilder = new EntityGeometryBuilder(coordinateMap, 
referenceMap);
       var entityProjectionTransformer = new EntityProjectionTransformer(4326, 
srid);
-      var entityHandler = srid == 4326 ? entityGeometryBuilder
-          : entityGeometryBuilder.andThen(entityProjectionTransformer);
-      var blockEntitiesHandler = new BlockEntitiesHandler(entityHandler);
-      var blockMapper = 
consumeThenReturn(cacheBuilder.andThen(blockEntitiesHandler));
+      var entityHandler = coordinateMapBuilder
+          .andThen(referenceMapBuilder)
+          .andThen(entityGeometryBuilder)
+          .andThen(entityProjectionTransformer);
+
+      // Initialize the block mapper
+      var blockMapper = consumeThenReturn(new 
BlockEntitiesHandler(entityHandler));
+
       blocks = blocks.map(blockMapper);
     }
     return blocks;
diff --git 
a/baremaps-core/src/test/java/org/apache/baremaps/collection/type/DataTypeProvider.java
 
b/baremaps-core/src/test/java/org/apache/baremaps/collection/type/DataTypeProvider.java
index 1d3b8eae..f6d53d92 100644
--- 
a/baremaps-core/src/test/java/org/apache/baremaps/collection/type/DataTypeProvider.java
+++ 
b/baremaps-core/src/test/java/org/apache/baremaps/collection/type/DataTypeProvider.java
@@ -18,6 +18,7 @@ import java.util.List;
 import java.util.stream.Stream;
 import org.junit.jupiter.params.provider.Arguments;
 import org.locationtech.jts.geom.Coordinate;
+import org.locationtech.jts.geom.GeometryFactory;
 
 public class DataTypeProvider {
 
@@ -29,6 +30,11 @@ public class DataTypeProvider {
         Arguments.of(new DoubleListDataType(), List.of((double) 1, (double) 2, 
(double) 3)),
         Arguments.of(new FloatDataType(), (float) 1),
         Arguments.of(new FloatListDataType(), List.of((float) 1, (float) 2, 
(float) 3)),
+        Arguments.of(new GeometryDataType(),
+            new GeometryFactory().createPoint(new Coordinate(1, 1))),
+        Arguments.of(new GeometryDataType(),
+            new GeometryFactory()
+                .createLineString(new Coordinate[] {new Coordinate(1, 1), new 
Coordinate(2, 2)})),
         Arguments.of(new IntegerDataType(), 1),
         Arguments.of(new IntegerListDataType(), List.of(1, 2, 3)),
         Arguments.of(new LongDataType(), (long) 1),
diff --git a/codestyle.xml b/codestyle.xml
index 75a4c877..e7c3770e 100644
--- a/codestyle.xml
+++ b/codestyle.xml
@@ -65,7 +65,7 @@
     <setting id="org.eclipse.jdt.core.formatter.comment.format_line_comments" 
value="true"/>
     <setting 
id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments"
 value="do not insert"/>
     <setting 
id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations"
 value="insert"/>
-    <setting id="org.eclipse.jdt.core.formatter.join_wrapped_lines" 
value="true"/>
+    <setting id="org.eclipse.jdt.core.formatter.join_wrapped_lines" 
value="false"/>
     <setting 
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block" 
value="insert"/>
     <setting 
id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call"
 value="16"/>
     <setting 
id="org.eclipse.jdt.core.formatter.wrap_non_simple_local_variable_annotation" 
value="true"/>

Reply via email to