Skip to content

Commit

Permalink
added tiling module and API
Browse files Browse the repository at this point in the history
  • Loading branch information
clausnagel committed Oct 30, 2024
1 parent 3fbeb54 commit 07874a9
Show file tree
Hide file tree
Showing 18 changed files with 1,146 additions and 1 deletion.
5 changes: 5 additions & 0 deletions citydb-tiling/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
dependencies {
api project(':citydb-database')
api project(':citydb-model')
implementation project(':citydb-config')
}
9 changes: 9 additions & 0 deletions citydb-tiling/src/main/java/module-info.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module org.citydb.tiling {
requires org.citydb.config;
requires transitive org.citydb.database;
requires transitive org.citydb.model;

exports org.citydb.tiling;
exports org.citydb.tiling.options;
exports org.citydb.tiling.encoding;
}
91 changes: 91 additions & 0 deletions citydb-tiling/src/main/java/org/citydb/tiling/Tile.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* 3D City Database - The Open Source CityGML Database
* https://www.3dcitydb.org/
*
* Copyright 2013 - 2024
* Chair of Geoinformatics
* Technical University of Munich, Germany
* https://www.lrg.tum.de/gis/
*
* The 3D City Database is jointly developed with the following
* cooperation partners:
*
* Virtual City Systems, Berlin <https://vc.systems/>
* M.O.S.S. Computer Grafik Systeme GmbH, Taufkirchen <http://www.moss.de/>
*
* 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.citydb.tiling;

import org.citydb.database.adapter.DatabaseAdapter;
import org.citydb.database.geometry.GeometryException;
import org.citydb.database.srs.SpatialReference;
import org.citydb.database.srs.SrsException;
import org.citydb.model.geometry.Envelope;
import org.citydb.model.geometry.Point;

import java.sql.SQLException;

public class Tile {
private final Envelope extent;
private final int column;
private final int row;
private final DatabaseAdapter adapter;

Tile(Envelope extent, int column, int row, DatabaseAdapter adapter) {
this.extent = extent;
this.column = column;
this.row = row;
this.adapter = adapter;
}

public Envelope getExtent() {
return extent;
}

public int getColumn() {
return column;
}

public int getRow() {
return row;
}

public boolean isOnTile(Envelope extent) throws TilingException {
return extent != null && isOnTile(Point.of(extent.getCenter())
.setSRID(extent.getSRID().orElse(null))
.setSrsIdentifier(extent.getSrsIdentifier().orElse(null)));
}

public boolean isOnTile(Point point) throws TilingException {
if (point != null) {
try {
SpatialReference reference = adapter.getGeometryAdapter().getSpatialReference(extent)
.orElse(adapter.getDatabaseMetadata().getSpatialReference());
if (reference.getSRID() != adapter.getDatabaseMetadata().getSpatialReference().getSRID()) {
point = adapter.getGeometryAdapter().transform(point);
}
} catch (GeometryException | SrsException | SQLException e) {
throw new TilingException("Failed to transform the point geometry to the database SRS.", e);
}

return point.getCoordinate().getX() > extent.getLowerCorner().getX()
&& point.getCoordinate().getX() <= extent.getUpperCorner().getX()
&& point.getCoordinate().getY() > extent.getLowerCorner().getY()
&& point.getCoordinate().getY() <= extent.getUpperCorner().getY();
} else {
return false;
}
}
}
74 changes: 74 additions & 0 deletions citydb-tiling/src/main/java/org/citydb/tiling/TileIterator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* 3D City Database - The Open Source CityGML Database
* https://www.3dcitydb.org/
*
* Copyright 2013 - 2024
* Chair of Geoinformatics
* Technical University of Munich, Germany
* https://www.lrg.tum.de/gis/
*
* The 3D City Database is jointly developed with the following
* cooperation partners:
*
* Virtual City Systems, Berlin <https://vc.systems/>
* M.O.S.S. Computer Grafik Systeme GmbH, Taufkirchen <http://www.moss.de/>
*
* 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.citydb.tiling;

import org.citydb.tiling.options.TileMatrixOrigin;

import java.util.Iterator;
import java.util.NoSuchElementException;

public class TileIterator implements Iterator<Tile> {
private final TileMatrix matrix;
private final TileMatrixOrigin origin;
private int column = -1;
private int row;
private boolean hasNext;

TileIterator(TileMatrix matrix, TileMatrixOrigin origin) {
this.matrix = matrix;
this.origin = origin;
}

@Override
public boolean hasNext() {
if (!hasNext) {
if (++column == matrix.getColumns()) {
column = 0;
row++;
}

hasNext = row < matrix.getRows();
}

return hasNext;
}

@Override
public Tile next() {
try {
if (hasNext()) {
return matrix.getTileAt(column, row, origin);
} else {
throw new NoSuchElementException();
}
} finally {
hasNext = false;
}
}
}
155 changes: 155 additions & 0 deletions citydb-tiling/src/main/java/org/citydb/tiling/TileMatrix.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
/*
* 3D City Database - The Open Source CityGML Database
* https://www.3dcitydb.org/
*
* Copyright 2013 - 2024
* Chair of Geoinformatics
* Technical University of Munich, Germany
* https://www.lrg.tum.de/gis/
*
* The 3D City Database is jointly developed with the following
* cooperation partners:
*
* Virtual City Systems, Berlin <https://vc.systems/>
* M.O.S.S. Computer Grafik Systeme GmbH, Taufkirchen <http://www.moss.de/>
*
* 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.citydb.tiling;

import org.citydb.core.concurrent.LazyInitializer;
import org.citydb.database.adapter.DatabaseAdapter;
import org.citydb.model.geometry.Coordinate;
import org.citydb.model.geometry.Envelope;
import org.citydb.tiling.options.TileMatrixOrigin;
import org.geotools.referencing.CRS;

public class TileMatrix {
private final Envelope extent;
private final DatabaseAdapter adapter;
private final int columns;
private final int rows;
private final double tileWidth;
private final double tileHeight;
private final double[] columnOffsets;
private final double[] rowOffsets;
private final LazyInitializer<Boolean> swapAxes;
private TileMatrixOrigin tileMatrixOrigin = TileMatrixOrigin.TOP_LEFT;

TileMatrix(Coordinate lowerCorner, Coordinate upperCorner, int columns, int rows, double tileWidth,
double tileHeight, DatabaseAdapter adapter) {
this.columns = columns > 0 ? columns : 1;
this.rows = rows > 0 ? rows : 1;
this.tileWidth = tileWidth;
this.tileHeight = tileHeight;
this.adapter = adapter;

columnOffsets = computeOffsets(columns, tileWidth);
rowOffsets = computeOffsets(rows, tileHeight);
extent = Envelope.of(lowerCorner, upperCorner)
.setSRID(adapter.getDatabaseMetadata().getSpatialReference().getSRID());
swapAxes = LazyInitializer.of(() -> adapter.getDatabaseMetadata().getSpatialReference().getDefinition()
.map(crs -> CRS.AxisOrder.NORTH_EAST.equals(CRS.getAxisOrder(crs)))
.orElse(false));
}

public Envelope getExtent() {
return extent;
}

public int size() {
return columns * rows;
}

public int getColumns() {
return columns;
}

public int getRows() {
return rows;
}

public double getTileWidth() {
return tileWidth;
}

public double getTileHeight() {
return tileHeight;
}

public TileMatrixOrigin getOrigin() {
return tileMatrixOrigin;
}

TileMatrix setTileMatrixOrigin(TileMatrixOrigin tileMatrixOrigin) {
if (tileMatrixOrigin != null) {
this.tileMatrixOrigin = tileMatrixOrigin;
}

return this;
}

public TileIterator getTileIterator() {
return new TileIterator(this, getOrigin());
}

public TileIterator getTileIterator(TileMatrixOrigin origin) {
return new TileIterator(this, origin);
}

public Tile getTileAt(int column, int row) {
return getTileAt(column, row, getOrigin());
}

public Tile getTileAt(int column, int row, TileMatrixOrigin origin) {
if (column < 0 || column >= columns || row < 0 || row >= rows) {
throw new IndexOutOfBoundsException("Tile index (" + column + "," + row + ") is out of bounds.");
}

double minX, minY, maxX, maxY;
if (swapAxes.get()) {
minX = extent.getUpperCorner().getY();
minY = extent.getUpperCorner().getX();
maxX = extent.getLowerCorner().getY();
maxY = extent.getLowerCorner().getX();
} else {
minX = extent.getLowerCorner().getX();
minY = extent.getLowerCorner().getY();
maxX = extent.getUpperCorner().getX();
maxY = extent.getUpperCorner().getY();
}

int rowIndex = origin == TileMatrixOrigin.BOTTOM_LEFT ? rows - row - 1 : row;
Coordinate lowerCorner = Coordinate.of(
minX + columnOffsets[column],
rowIndex == rows - 1 ? minY : maxY - rowOffsets[rowIndex + 1]);
Coordinate upperCorner = Coordinate.of(
column == columns - 1 ? maxX : minX + columnOffsets[column + 1],
maxY - rowOffsets[rowIndex]);

return new Tile(Envelope.of(lowerCorner, upperCorner)
.setSRID(adapter.getDatabaseMetadata().getSpatialReference().getSRID()),
column, row, adapter);
}

private double[] computeOffsets(int size, double offset) {
double[] offsets = new double[size];
offsets[0] = 0;
for (int i = 1; i < offsets.length; i++) {
offsets[i] = offsets[i - 1] + offset;
}

return offsets;
}
}
Loading

0 comments on commit 07874a9

Please sign in to comment.