├── .github └── workflows │ └── maven.yml ├── .gitignore ├── LICENSE.txt ├── README.md ├── build-adds ├── osm2world-windows.bat └── osm2world.sh ├── core ├── pom.xml └── src │ ├── main │ └── java │ │ └── org │ │ └── osm2world │ │ ├── GlobalValues.java │ │ ├── O2WConverter.java │ │ ├── O2WConverterImpl.java │ │ ├── conversion │ │ ├── ConfigUtil.java │ │ ├── ConversionLog.java │ │ ├── O2WConfig.java │ │ ├── ProgressListener.java │ │ └── package-info.java │ │ ├── map_data │ │ ├── creation │ │ │ ├── EmptyTerrainBuilder.java │ │ │ ├── MapDataBuilder.java │ │ │ ├── MapDataCreationUtil.java │ │ │ ├── MultipolygonAreaBuilder.java │ │ │ ├── OSMToMapDataConverter.java │ │ │ └── package-info.java │ │ ├── data │ │ │ ├── MapArea.java │ │ │ ├── MapAreaSegment.java │ │ │ ├── MapData.java │ │ │ ├── MapElement.java │ │ │ ├── MapMetadata.java │ │ │ ├── MapMultipolygonRelation.java │ │ │ ├── MapNode.java │ │ │ ├── MapRelation.java │ │ │ ├── MapRelationElement.java │ │ │ ├── MapSegment.java │ │ │ ├── MapWay.java │ │ │ ├── MapWaySegment.java │ │ │ ├── Tag.java │ │ │ ├── TagSet.java │ │ │ ├── overlaps │ │ │ │ ├── MapIntersectionWW.java │ │ │ │ ├── MapOverlap.java │ │ │ │ ├── MapOverlapAA.java │ │ │ │ ├── MapOverlapNA.java │ │ │ │ ├── MapOverlapType.java │ │ │ │ └── MapOverlapWA.java │ │ │ └── package-info.java │ │ └── package-info.java │ │ ├── map_elevation │ │ ├── creation │ │ │ ├── BridgeTunnelEleCalculator.java │ │ │ ├── ConstraintEleCalculator.java │ │ │ ├── DelaunayTriangulation.java │ │ │ ├── EleCalculator.java │ │ │ ├── EleConstraintEnforcer.java │ │ │ ├── EleConstraintValidator.java │ │ │ ├── EleTagEleCalculator.java │ │ │ ├── InverseDistanceWeightingInterpolator.java │ │ │ ├── LeastSquaresInterpolator.java │ │ │ ├── LinearInterpolator.java │ │ │ ├── NaturalNeighborInterpolator.java │ │ │ ├── NoOpEleCalculator.java │ │ │ ├── NoneEleConstraintEnforcer.java │ │ │ ├── SRTMData.java │ │ │ ├── SRTMTile.java │ │ │ ├── SimpleEleConstraintEnforcer.java │ │ │ ├── TagEleCalculator.java │ │ │ ├── TerrainElevationData.java │ │ │ ├── TerrainInterpolator.java │ │ │ └── ZeroInterpolator.java │ │ ├── data │ │ │ ├── EleConnector.java │ │ │ ├── EleConnectorGroup.java │ │ │ └── GroundState.java │ │ └── package-info.java │ │ ├── math │ │ ├── Angle.java │ │ ├── BoundedObject.java │ │ ├── Vector3D.java │ │ ├── Vector4D.java │ │ ├── VectorXYZ.java │ │ ├── VectorXYZW.java │ │ ├── VectorXZ.java │ │ ├── algorithms │ │ │ ├── CAGUtil.java │ │ │ ├── Earcut4JTriangulationUtil.java │ │ │ ├── FaceDecompositionUtil.java │ │ │ ├── GeometryUtil.java │ │ │ ├── JTSBufferUtil.java │ │ │ ├── JTSConversionUtil.java │ │ │ ├── JTSTriangulationUtil.java │ │ │ ├── LineSegmentIntersectionFinder.java │ │ │ ├── NormalCalculationUtil.java │ │ │ ├── Poly2TriTriangulationUtil.java │ │ │ ├── SimpleLineSegmentIntersectionFinder.java │ │ │ ├── TriangulationUtil.java │ │ │ └── package-info.java │ │ ├── datastructures │ │ │ ├── IndexGrid.java │ │ │ ├── Map2dTree.java │ │ │ ├── MapQuadtree.java │ │ │ ├── SpatialIndex.java │ │ │ ├── VectorGridXZ.java │ │ │ └── package-info.java │ │ ├── geo │ │ │ ├── CardinalDirection.java │ │ │ ├── GeoBounds.java │ │ │ ├── LatLon.java │ │ │ ├── LatLonBounds.java │ │ │ ├── LatLonEle.java │ │ │ ├── MapProjection.java │ │ │ ├── MercatorProjection.java │ │ │ ├── MetricMapProjection.java │ │ │ ├── OrthographicAzimuthalMapProjection.java │ │ │ ├── TileBounds.java │ │ │ ├── TileNumber.java │ │ │ └── package-info.java │ │ ├── package-info.java │ │ └── shapes │ │ │ ├── AxisAlignedBoundingBoxXYZ.java │ │ │ ├── AxisAlignedRectangleXZ.java │ │ │ ├── CircleXZ.java │ │ │ ├── CircularSectorXZ.java │ │ │ ├── ClosedShapeXZ.java │ │ │ ├── FaceXYZ.java │ │ │ ├── FlatSimplePolygonShapeXYZ.java │ │ │ ├── LineSegmentXYZ.java │ │ │ ├── LineSegmentXZ.java │ │ │ ├── LineXZ.java │ │ │ ├── PolygonShapeXZ.java │ │ │ ├── PolygonWithHolesXYZ.java │ │ │ ├── PolygonWithHolesXZ.java │ │ │ ├── PolygonXYZ.java │ │ │ ├── PolylineShapeXZ.java │ │ │ ├── PolylineXYZ.java │ │ │ ├── PolylineXZ.java │ │ │ ├── RoundShapeXZ.java │ │ │ ├── ShapeXZ.java │ │ │ ├── SimpleClosedShapeXZ.java │ │ │ ├── SimplePolygonShapeXZ.java │ │ │ ├── SimplePolygonXZ.java │ │ │ ├── TriangleXYZ.java │ │ │ ├── TriangleXZ.java │ │ │ └── package-info.java │ │ ├── osm │ │ ├── creation │ │ │ ├── GeodeskReader.java │ │ │ ├── MbtilesReader.java │ │ │ ├── OSMDataReader.java │ │ │ ├── OSMDataReaderView.java │ │ │ ├── OSMFileReader.java │ │ │ ├── OSMStreamReader.java │ │ │ ├── OverpassReader.java │ │ │ └── package-info.java │ │ ├── data │ │ │ ├── OSMData.java │ │ │ └── package-info.java │ │ ├── package-info.java │ │ └── ruleset │ │ │ ├── HardcodedRuleset.java │ │ │ ├── Ruleset.java │ │ │ └── package-info.java │ │ ├── output │ │ ├── CommonTarget.java │ │ ├── Output.java │ │ ├── common │ │ │ ├── AbstractOutput.java │ │ │ ├── DrawBasedOutput.java │ │ │ ├── ExtrudeOption.java │ │ │ ├── FaceOutput.java │ │ │ ├── MeshOutput.java │ │ │ ├── Primitive.java │ │ │ ├── PrimitiveOutput.java │ │ │ ├── ResourceOutputSettings.java │ │ │ ├── compression │ │ │ │ ├── Compression.java │ │ │ │ └── CompressionUtil.java │ │ │ ├── lighting │ │ │ │ └── GlobalLightingParameters.java │ │ │ └── rendering │ │ │ │ ├── Camera.java │ │ │ │ ├── ImmutableCamera.java │ │ │ │ ├── MutableCamera.java │ │ │ │ ├── OrthographicProjection.java │ │ │ │ ├── OrthographicUtil.java │ │ │ │ ├── PerspectiveProjection.java │ │ │ │ └── Projection.java │ │ ├── frontend_pbf │ │ │ ├── FrontendPbf.java │ │ │ ├── FrontendPbfOutput.java │ │ │ ├── frontend.proto │ │ │ └── package-info.java │ │ ├── gltf │ │ │ ├── GltfModel.java │ │ │ ├── GltfOutput.java │ │ │ ├── data │ │ │ │ ├── Gltf.java │ │ │ │ ├── GltfAccessor.java │ │ │ │ ├── GltfAnimation.java │ │ │ │ ├── GltfAsset.java │ │ │ │ ├── GltfBuffer.java │ │ │ │ ├── GltfBufferView.java │ │ │ │ ├── GltfCamera.java │ │ │ │ ├── GltfImage.java │ │ │ │ ├── GltfMaterial.java │ │ │ │ ├── GltfMesh.java │ │ │ │ ├── GltfNode.java │ │ │ │ ├── GltfSampler.java │ │ │ │ ├── GltfScene.java │ │ │ │ ├── GltfSkin.java │ │ │ │ ├── GltfTexture.java │ │ │ │ └── TransformationMatrix.java │ │ │ └── package-info.java │ │ ├── obj │ │ │ ├── ObjMultiFileOutput.java │ │ │ ├── ObjOutput.java │ │ │ └── package-info.java │ │ ├── package-info.java │ │ ├── povray │ │ │ ├── POVRayOutput.java │ │ │ └── package-info.java │ │ └── statistics │ │ │ ├── StatisticsOutput.java │ │ │ └── package-info.java │ │ ├── package-info.java │ │ ├── scene │ │ ├── Scene.java │ │ ├── color │ │ │ ├── ColorNameDefinition.java │ │ │ ├── ColorNameDefinitions.java │ │ │ └── LColor.java │ │ ├── material │ │ │ ├── BlankTexture.java │ │ │ ├── CompositeTexture.java │ │ │ ├── ConfMaterial.java │ │ │ ├── DataUriTexture.java │ │ │ ├── ImageFileTexture.java │ │ │ ├── ImmutableMaterial.java │ │ │ ├── Material.java │ │ │ ├── Materials.java │ │ │ ├── RasterImageFileTexture.java │ │ │ ├── RasterImageFormat.java │ │ │ ├── RuntimeTexture.java │ │ │ ├── SvgImageFileTexture.java │ │ │ ├── TextTexture.java │ │ │ ├── TextureAtlas.java │ │ │ ├── TextureCam.java │ │ │ ├── TextureData.java │ │ │ ├── TextureDataDimensions.java │ │ │ ├── TextureLayer.java │ │ │ └── UriTexture.java │ │ ├── mesh │ │ │ ├── ExtrusionGeometry.java │ │ │ ├── Geometry.java │ │ │ ├── LODRange.java │ │ │ ├── LevelOfDetail.java │ │ │ ├── Mesh.java │ │ │ ├── MeshStore.java │ │ │ ├── MeshUtil.java │ │ │ ├── ShapeGeometry.java │ │ │ └── TriangleGeometry.java │ │ ├── model │ │ │ ├── ExternalResourceModel.java │ │ │ ├── InstanceParameters.java │ │ │ ├── Model.java │ │ │ ├── ModelInstance.java │ │ │ ├── Models.java │ │ │ └── ProceduralModel.java │ │ ├── package-info.java │ │ └── texcoord │ │ │ ├── FaceFitTexCoordFunction.java │ │ │ ├── GlobalXYTexCoordFunction.java │ │ │ ├── GlobalXZTexCoordFunction.java │ │ │ ├── GlobalZYTexCoordFunction.java │ │ │ ├── MapBasedTexCoordFunction.java │ │ │ ├── NamedTexCoordFunction.java │ │ │ ├── PrecomputedTexCoordFunction.java │ │ │ ├── SlopedTrianglesTexCoordFunction.java │ │ │ ├── StripWallTexCoordFunction.java │ │ │ ├── TexCoordFunction.java │ │ │ └── TexCoordUtil.java │ │ ├── util │ │ ├── FaultTolerantIterationUtil.java │ │ ├── Resolution.java │ │ ├── ValueParseUtil.java │ │ ├── enums │ │ │ ├── ForwardBackward.java │ │ │ ├── ForwardBackwardBoth.java │ │ │ ├── LeftRight.java │ │ │ └── LeftRightBoth.java │ │ ├── exception │ │ │ ├── InvalidGeometryException.java │ │ │ └── TriangulationException.java │ │ ├── functions │ │ │ ├── CheckedConsumer.java │ │ │ ├── DefaultFactory.java │ │ │ └── Factory.java │ │ ├── package-info.java │ │ └── test │ │ │ ├── TestFileUtil.java │ │ │ └── package-info.java │ │ └── world │ │ ├── attachment │ │ ├── AttachmentConnector.java │ │ └── AttachmentSurface.java │ │ ├── creation │ │ ├── WorldCreator.java │ │ └── WorldModule.java │ │ ├── data │ │ ├── AbstractAreaWorldObject.java │ │ ├── AreaWorldObject.java │ │ ├── CachingProceduralWorldObject.java │ │ ├── NoOutlineNodeWorldObject.java │ │ ├── NoOutlineWaySegmentWorldObject.java │ │ ├── NodeModelInstance.java │ │ ├── NodeWorldObject.java │ │ ├── OutlineNodeWorldObject.java │ │ ├── ProceduralWorldObject.java │ │ ├── WaySegmentWorldObject.java │ │ └── WorldObject.java │ │ ├── modules │ │ ├── AerowayModule.java │ │ ├── BarrierModule.java │ │ ├── BicycleParkingModule.java │ │ ├── BridgeModule.java │ │ ├── CliffModule.java │ │ ├── ExternalModelModule.java │ │ ├── GolfModule.java │ │ ├── InvisibleModule.java │ │ ├── MastModule.java │ │ ├── ParkingModule.java │ │ ├── PoolModule.java │ │ ├── PowerModule.java │ │ ├── RailwayModule.java │ │ ├── RoadModule.java │ │ ├── SportsModule.java │ │ ├── StreetFurnitureModule.java │ │ ├── SurfaceAreaModule.java │ │ ├── TreeModule.java │ │ ├── TunnelModule.java │ │ ├── WaterModule.java │ │ ├── building │ │ │ ├── Building.java │ │ │ ├── BuildingBottom.java │ │ │ ├── BuildingDefaults.java │ │ │ ├── BuildingModule.java │ │ │ ├── BuildingPart.java │ │ │ ├── Door.java │ │ │ ├── DoorParameters.java │ │ │ ├── ExteriorBuildingWall.java │ │ │ ├── GeometryWindow.java │ │ │ ├── LevelAndHeightData.java │ │ │ ├── TexturedWindow.java │ │ │ ├── WallElement.java │ │ │ ├── WallSurface.java │ │ │ ├── Window.java │ │ │ ├── WindowImplementation.java │ │ │ ├── WindowParameters.java │ │ │ ├── indoor │ │ │ │ ├── BuildingPartInterior.java │ │ │ │ ├── Ceiling.java │ │ │ │ ├── IndoorArea.java │ │ │ │ ├── IndoorFloor.java │ │ │ │ ├── IndoorModule.java │ │ │ │ ├── IndoorObjectData.java │ │ │ │ ├── IndoorRoom.java │ │ │ │ └── IndoorWall.java │ │ │ └── roof │ │ │ │ ├── ChimneyRoof.java │ │ │ │ ├── ComplexRoof.java │ │ │ │ ├── DomeRoof.java │ │ │ │ ├── FlatRoof.java │ │ │ │ ├── GabledRoof.java │ │ │ │ ├── GambrelRoof.java │ │ │ │ ├── HalfHippedRoof.java │ │ │ │ ├── HeightfieldRoof.java │ │ │ │ ├── HippedRoof.java │ │ │ │ ├── MansardRoof.java │ │ │ │ ├── OnionRoof.java │ │ │ │ ├── PyramidalRoof.java │ │ │ │ ├── Roof.java │ │ │ │ ├── RoofWithRidge.java │ │ │ │ ├── RoundRoof.java │ │ │ │ ├── SkillionRoof.java │ │ │ │ └── SpindleRoof.java │ │ ├── common │ │ │ ├── AbstractModule.java │ │ │ ├── BridgeOrTunnel.java │ │ │ ├── ConfigurableWorldModule.java │ │ │ ├── WorldModuleBillboardUtil.java │ │ │ ├── WorldModuleGeometryUtil.java │ │ │ └── WorldModuleParseUtil.java │ │ └── traffic_sign │ │ │ ├── TrafficSignGroup.java │ │ │ ├── TrafficSignIdentifier.java │ │ │ ├── TrafficSignModel.java │ │ │ ├── TrafficSignModule.java │ │ │ └── TrafficSignType.java │ │ ├── network │ │ ├── AbstractNetworkWaySegmentWorldObject.java │ │ ├── JunctionNodeWorldObject.java │ │ ├── NetworkAreaWorldObject.java │ │ ├── NetworkCalculator.java │ │ ├── NetworkNodeWorldObject.java │ │ ├── NetworkUtil.java │ │ ├── NetworkWaySegmentWorldObject.java │ │ ├── VisibleConnectorNodeWorldObject.java │ │ └── package-info.java │ │ └── package-info.java │ └── test │ ├── java │ └── org │ │ └── osm2world │ │ ├── DelaunayTriangulationTest.java │ │ ├── O2WConverterImplTest.java │ │ ├── O2WConverterTest.java │ │ ├── conversion │ │ └── O2WConfigTest.java │ │ ├── map_data │ │ ├── creation │ │ │ ├── MapDataBuilderTest.java │ │ │ └── OSMToMapDataConverterTest.java │ │ └── data │ │ │ ├── MapMetadataTest.java │ │ │ └── TagSetTest.java │ │ ├── map_elevation │ │ └── creation │ │ │ └── SRTMDataTest.java │ │ ├── math │ │ ├── AngleTest.java │ │ ├── VectorXYZTest.java │ │ ├── VectorXZTest.java │ │ ├── algorithms │ │ │ ├── CAGUtilTest.java │ │ │ ├── Earcut4JTriangulationTest.java │ │ │ ├── FaceDecompositionUtilTest.java │ │ │ ├── GeometryUtilTest.java │ │ │ ├── JTSBufferUtilTest.java │ │ │ ├── LineSegmentIntersectionFinderTest.java │ │ │ ├── NormalCalculationUtilTest.java │ │ │ ├── Poly2TriTriangulationUtilTest.java │ │ │ └── SimpleLineSegmentIntersectionFinderTest.java │ │ ├── datastructures │ │ │ └── IndexGridTest.java │ │ ├── geo │ │ │ ├── AbstractMapProjectionTest.java │ │ │ ├── MetricMapProjectionTest.java │ │ │ ├── OrthographicAzimuthalMapProjectionTest.java │ │ │ ├── TileBoundsTest.java │ │ │ └── TileNumberTest.java │ │ └── shapes │ │ │ ├── AxisAlignedRectangleTest.java │ │ │ ├── CircleXZTest.java │ │ │ ├── FaceXYZTest.java │ │ │ ├── LineSegmentXZTest.java │ │ │ ├── LineXZTest.java │ │ │ ├── PolylineXZTest.java │ │ │ ├── SimplePolygonXZTest.java │ │ │ ├── TriangleXYZTest.java │ │ │ └── TriangleXZTest.java │ │ ├── osm │ │ └── creation │ │ │ ├── GeodeskReaderTest.java │ │ │ ├── OSMFileReaderTest.java │ │ │ └── OverpassReaderTest.java │ │ ├── output │ │ ├── common │ │ │ └── FaceOutputTest.java │ │ ├── frontend_pbf │ │ │ └── FrontendPbfOutputTest.java │ │ ├── gltf │ │ │ ├── GltfModelTest.java │ │ │ ├── GltfOutputTest.java │ │ │ └── data │ │ │ │ └── TransformationMatrixTest.java │ │ └── obj │ │ │ └── ObjOutputTest.java │ │ ├── scene │ │ ├── material │ │ │ ├── DataUriTextureTest.java │ │ │ ├── MaterialTest.java │ │ │ ├── TextureAtlasTest.java │ │ │ ├── TextureCamTest.java │ │ │ ├── TextureDataTest.java │ │ │ └── TextureTestUtil.java │ │ ├── mesh │ │ │ ├── ExtrusionGeometryTest.java │ │ │ ├── LODRangeTest.java │ │ │ ├── MeshStoreTest.java │ │ │ ├── MeshTestUtil.java │ │ │ ├── MeshUtilTest.java │ │ │ ├── ShapeGeometryTest.java │ │ │ └── TriangleGeometryTest.java │ │ └── texcoord │ │ │ └── TexCoordUtilTest.java │ │ ├── test │ │ ├── TestUtil.java │ │ └── TestWorldModule.java │ │ ├── util │ │ ├── ResolutionTest.java │ │ ├── ValueParseUtilTest.java │ │ └── color │ │ │ └── LColorTest.java │ │ └── world │ │ └── modules │ │ ├── PowerModuleTest.java │ │ ├── RoadModuleTest.java │ │ ├── SportsModuleTest.java │ │ ├── building │ │ ├── BuildingModuleTest.java │ │ ├── BuildingPartTest.java │ │ ├── Indoor │ │ │ └── IndoorWallTest.java │ │ ├── LevelAndHeightDataTest.java │ │ ├── WallSurfaceTest.java │ │ ├── WindowParametersTest.java │ │ └── roof │ │ │ └── SkillionRoofTest.java │ │ ├── common │ │ ├── WorldModuleGeometryUtilTest.java │ │ └── WorldModuleParseUtilTest.java │ │ └── traffic_sign │ │ ├── TrafficSignIdentifierTest.java │ │ └── TrafficSignModuleTest.java │ └── resources │ ├── coastline_big_island.osm │ ├── coastline_islands.osm │ ├── coastline_islands_and_coast.osm │ ├── coastline_multiple_coasts.osm │ ├── config │ ├── parentConfig.properties │ ├── testConfig_01.properties │ ├── testConfig_02.properties │ └── textures │ │ └── test.png │ ├── gltf │ ├── BoxVertexColors │ │ ├── BoxVertexColors.glb │ │ ├── BoxVertexColors.gltf │ │ ├── BoxVertexColors_embedded.gltf │ │ └── buffer.bin │ ├── SimpleMeshes │ │ ├── SimpleMeshes.gltf │ │ └── triangle.bin │ ├── Triangle │ │ ├── Triangle.gltf │ │ ├── Triangle_embedded.gltf │ │ └── simpleTriangle.bin │ └── TriangleWithoutIndices │ │ ├── TriangleWithoutIndices.gltf │ │ ├── TriangleWithoutIndices_embedded.gltf │ │ └── triangleWithoutIndices.bin │ ├── issue-203.osm │ ├── josmTest01.osm │ ├── josm_emoji.osm │ ├── meta.mbtiles │ ├── metadata_only_locale.json │ ├── mp_broken.osm │ ├── mp_two_holes.osm │ ├── mp_two_holes_advanced.osm │ ├── mp_two_holes_advanced2.osm │ ├── mp_two_holes_outer_tagged.osm │ ├── mp_two_holes_touching_inners.osm │ ├── sameCoordNodes.osm │ ├── self_intersection.osm │ ├── simpleTest01.gol │ ├── simpleTest01.osm │ ├── simpleTest01.osm.pbf │ ├── srtm │ ├── N04E033.hgt │ └── N04E034.SRTMGL3.hgt.zip │ └── validFile.osm ├── desktop ├── pom.xml └── src │ ├── main │ ├── java │ │ └── org │ │ │ └── osm2world │ │ │ ├── console │ │ │ ├── OSM2World.java │ │ │ ├── commands │ │ │ │ ├── ConvertCommand.java │ │ │ │ ├── GuiCommand.java │ │ │ │ ├── ParamsCommand.java │ │ │ │ ├── RootCommand.java │ │ │ │ ├── converters │ │ │ │ │ └── LodConverter.java │ │ │ │ └── mixins │ │ │ │ │ ├── CameraOptions.java │ │ │ │ │ ├── ConfigOptions.java │ │ │ │ │ ├── InputOptions.java │ │ │ │ │ ├── LoggingOptions.java │ │ │ │ │ └── MetadataOptions.java │ │ │ ├── legacy │ │ │ │ ├── CLIArguments.java │ │ │ │ ├── CLIArgumentsGroup.java │ │ │ │ ├── CLIArgumentsUtil.java │ │ │ │ ├── LegacyCLI.java │ │ │ │ ├── LegacyCLIOutput.java │ │ │ │ └── ParamFileDirMode.java │ │ │ └── package-info.java │ │ │ └── viewer │ │ │ ├── Viewer.java │ │ │ ├── control │ │ │ ├── actions │ │ │ │ ├── AboutAction.java │ │ │ │ ├── AbstractExportAction.java │ │ │ │ ├── AbstractLoadOSMAction.java │ │ │ │ ├── DownloadOverpassAction.java │ │ │ │ ├── ExitAction.java │ │ │ │ ├── ExportGltfAction.java │ │ │ │ ├── ExportObjAction.java │ │ │ │ ├── ExportObjDirAction.java │ │ │ │ ├── ExportPOVRayAction.java │ │ │ │ ├── ExportPngAction.java │ │ │ │ ├── ExportScreenshotAction.java │ │ │ │ ├── HelpControlsAction.java │ │ │ │ ├── OpenOSMAction.java │ │ │ │ ├── OrthoBoundsAction.java │ │ │ │ ├── OrthoTileAction.java │ │ │ │ ├── ReloadOSMAction.java │ │ │ │ ├── ResetCameraAction.java │ │ │ │ ├── SetCameraToCoordinateAction.java │ │ │ │ ├── SetEleCalculatorAction.java │ │ │ │ ├── SetLodAction.java │ │ │ │ ├── SetTerrainInterpolatorAction.java │ │ │ │ ├── ShowCameraConfigurationAction.java │ │ │ │ ├── StatisticsAction.java │ │ │ │ ├── ToggleBackfaceCullingAction.java │ │ │ │ ├── ToggleDebugViewAction.java │ │ │ │ ├── ToggleOrthographicProjectionAction.java │ │ │ │ ├── ToggleWireframeAction.java │ │ │ │ └── ToggleWorldObjectsAction.java │ │ │ └── navigation │ │ │ │ └── DefaultNavigation.java │ │ │ ├── model │ │ │ ├── Data.java │ │ │ ├── Defaults.java │ │ │ ├── MessageManager.java │ │ │ └── RenderOptions.java │ │ │ ├── package-info.java │ │ │ └── view │ │ │ ├── FileDrop.java │ │ │ ├── ProgressDialog.java │ │ │ ├── RecentFilesUpdater.java │ │ │ ├── StatisticsDialog.java │ │ │ ├── TextRenderer.java │ │ │ ├── TextRendererFixedFunction.java │ │ │ ├── TextRendererShader.java │ │ │ ├── ViewerFrame.java │ │ │ ├── ViewerGLCanvas.java │ │ │ └── debug │ │ │ ├── AttachmentConnectorDebugView.java │ │ │ ├── AttachmentSurfaceDebugView.java │ │ │ ├── DebugView.java │ │ │ ├── EleConnectorDebugView.java │ │ │ ├── EleConstraintDebugView.java │ │ │ ├── FaceDebugView.java │ │ │ ├── GroundFootprintDebugView.java │ │ │ ├── HelpView.java │ │ │ ├── InternalCoordsDebugView.java │ │ │ ├── InverseDistanceWeightingInterpolatorDebugView.java │ │ │ ├── LatLonDebugView.java │ │ │ ├── LeastSquaresInterpolatorDebugView.java │ │ │ ├── LinearInterpolatorDebugView.java │ │ │ ├── Map2dTreeDebugView.java │ │ │ ├── MapDataBoundsDebugView.java │ │ │ ├── MapDataDebugView.java │ │ │ ├── NaturalNeighborInterpolatorDebugView.java │ │ │ ├── OrthoBoundsDebugView.java │ │ │ ├── QuadtreeDebugView.java │ │ │ ├── RoofDataDebugView.java │ │ │ ├── ShadowView.java │ │ │ ├── SkyboxView.java │ │ │ ├── TerrainInterpolatorDebugView.java │ │ │ ├── WorldObjectNormalsDebugView.java │ │ │ └── WorldObjectView.java │ └── resources │ │ ├── attribution.xml │ │ └── logo.png │ └── test │ ├── java │ └── org │ │ └── osm2world │ │ └── console │ │ ├── OSM2WorldTest.java │ │ └── legacy │ │ └── CLIArgumentsGroupTest.java │ └── resources │ └── testWall.osm ├── doc └── changes.txt ├── opengl ├── pom.xml └── src │ └── main │ ├── java │ └── org │ │ └── osm2world │ │ └── output │ │ ├── image │ │ ├── ImageExporter.java │ │ ├── ImageOutput.java │ │ ├── ImageOutputFormat.java │ │ └── package-info.java │ │ └── jogl │ │ ├── AbstractJOGLOutput.java │ │ ├── AbstractPrimitiveShader.java │ │ ├── AbstractShader.java │ │ ├── BackgroundShader.java │ │ ├── DefaultShader.java │ │ ├── DepthBufferShader.java │ │ ├── JOGLOutput.java │ │ ├── JOGLOutputFixedFunction.java │ │ ├── JOGLOutputShader.java │ │ ├── JOGLRendererVBO.java │ │ ├── JOGLRendererVBOFixedFunction.java │ │ ├── JOGLRendererVBONonAreaShader.java │ │ ├── JOGLRendererVBOShader.java │ │ ├── JOGLRendererVBOShadowVolume.java │ │ ├── JOGLRenderingParameters.java │ │ ├── JOGLTextureManager.java │ │ ├── NonAreaPrimitive.java │ │ ├── NonAreaShader.java │ │ ├── PrimitiveBuffer.java │ │ ├── SSAOShader.java │ │ ├── ShaderManager.java │ │ ├── ShadowMapShader.java │ │ ├── ShadowVolumeShader.java │ │ ├── VBOData.java │ │ ├── VBODataFixedFunction.java │ │ ├── VBODataNonAreaShader.java │ │ ├── VBODataShader.java │ │ ├── VBODataShadowVolume.java │ │ └── package-info.java │ └── resources │ └── shaders │ ├── background.fragment │ ├── background.vertex │ ├── default.fragment │ ├── default.vertex │ ├── nonarea.fragment │ ├── nonarea.vertex │ ├── shadowmap.fragment │ ├── shadowmap.vertex │ ├── shadowvolume.fragment │ └── shadowvolume.vertex ├── pom.xml └── resources └── osm2world_definitions.inc /.github/workflows/maven.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a Java project with Maven 2 | 3 | name: Java CI with Maven 4 | 5 | on: [push] 6 | 7 | jobs: 8 | build: 9 | 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - uses: actions/checkout@v3 14 | - name: Set up JDK 17 15 | uses: actions/setup-java@v3 16 | with: 17 | java-version: '17' 18 | distribution: 'temurin' 19 | - name: Build with Maven 20 | run: mvn --batch-mode --update-snapshots package 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OSM2World 2 | /textures 3 | /locales 4 | /models 5 | /srtm 6 | /*.properties 7 | 8 | # Build 9 | /target 10 | /core/target 11 | /desktop/target 12 | /opengl/target 13 | /dist 14 | /bin 15 | /build 16 | 17 | # IntelliJ 18 | *.iml 19 | *.iws 20 | *.ipr 21 | .idea/ 22 | 23 | # Eclipse 24 | .settings/ 25 | .metadata/ 26 | .classpath 27 | .project 28 | 29 | # NetBeans 30 | nbproject/ 31 | nbbuild/ 32 | nbdist/ 33 | nbactions.xml 34 | nbbuild.xml 35 | nb-configuration.xml 36 | 37 | # VSCode 38 | .vscode 39 | 40 | # Miscellaneous 41 | *~ 42 | *.swp 43 | .DS_Store 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | OSM2World is an Open Source converter that creates three-dimensional models of the world in various formats from OpenStreetMap data. Visit the project website at https://osm2world.org/ for documentation, downloads, screenshots and contact information! 2 | 3 | # Compiling 4 | 5 | Run `mvn package` in the project root. 6 | -------------------------------------------------------------------------------- /build-adds/osm2world-windows.bat: -------------------------------------------------------------------------------- 1 | java --add-exports java.base/java.lang=ALL-UNNAMED --add-exports java.desktop/sun.awt=ALL-UNNAMED --add-exports java.desktop/sun.java2d=ALL-UNNAMED -Xmx2G -jar OSM2World.jar %* 2 | -------------------------------------------------------------------------------- /build-adds/osm2world.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd `dirname $0` 4 | 5 | # retrieve VM parameters 6 | 7 | vmparams="-Xmx2G --add-exports java.base/java.lang=ALL-UNNAMED --add-exports java.desktop/sun.awt=ALL-UNNAMED --add-exports java.desktop/sun.java2d=ALL-UNNAMED" 8 | 9 | if [[ $1 == --vm-params=* ]] 10 | then 11 | vmparams=${1:12} 12 | shift 13 | fi 14 | 15 | # run OSM2World 16 | 17 | java $vmparams -jar OSM2World.jar $@ 18 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/GlobalValues.java: -------------------------------------------------------------------------------- 1 | package org.osm2world; 2 | 3 | /** 4 | * globally accessible constants 5 | */ 6 | public final class GlobalValues { 7 | 8 | private GlobalValues() {} 9 | 10 | /** version string */ 11 | public static final String VERSION_STRING = "0.5.0-SNAPSHOT"; 12 | 13 | /** link to the OSM wiki documentation */ 14 | public static final String WIKI_URI = "https://wiki.osm.org/OSM2World"; 15 | 16 | /** link to OSM2World home page */ 17 | public static final String OSM2WORLD_URI = "https://osm2world.org"; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/conversion/ConfigUtil.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.conversion; 2 | 3 | import java.awt.*; 4 | import java.io.File; 5 | import java.io.IOException; 6 | 7 | /** 8 | * utility class for parsing configuration values 9 | */ 10 | final public class ConfigUtil { 11 | 12 | private ConfigUtil() { } 13 | 14 | /** 15 | * Registers the fonts that exist in the directory specified 16 | * by the "fontDirectory" key in the configuration file. 17 | * The respective fonts can then be used in Font object constructors. 18 | */ 19 | public static void parseFonts(O2WConfig config) { 20 | 21 | if(!config.containsKey("fontDirectory")) return; 22 | 23 | String directoryName = config.getString("fontDirectory"); 24 | File fontDir = new File(directoryName); 25 | 26 | if(!fontDir.isDirectory()) return; 27 | 28 | GraphicsEnvironment gEnv = GraphicsEnvironment.getLocalGraphicsEnvironment(); 29 | 30 | File[] listOfFiles = fontDir.listFiles(); 31 | 32 | for (File file : listOfFiles) { 33 | if (file.isFile()) { 34 | 35 | try { 36 | gEnv.registerFont(Font.createFont(Font.TRUETYPE_FONT, file)); 37 | } catch (FontFormatException | IOException e) { 38 | System.err.println("Could not register font "+file.getName()); 39 | e.printStackTrace(); 40 | } 41 | } 42 | } 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/conversion/ProgressListener.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.conversion; 2 | 3 | /** 4 | * implemented by classes that want to be informed about a conversion run's progress 5 | */ 6 | public interface ProgressListener { 7 | 8 | enum Phase { 9 | MAP_DATA, 10 | REPRESENTATION, 11 | ELEVATION, 12 | TERRAIN, 13 | OUTPUT, 14 | FINISHED 15 | } 16 | 17 | /** 18 | * announces the current progress. 19 | * Will be called at least at the start of each new {@link Phase}. 20 | * 21 | * @param progress rough estimate of the conversion's progress as a value between 0.0 and 1.0 22 | */ 23 | void updateProgress(Phase currentPhase, double progress); 24 | 25 | } 26 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/conversion/package-info.java: -------------------------------------------------------------------------------- 1 | /** Thread-global context for a given conversion */ 2 | package org.osm2world.conversion; -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/map_data/creation/MapDataCreationUtil.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.map_data.creation; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.osm2world.map_data.data.MapNode; 7 | 8 | public class MapDataCreationUtil { 9 | 10 | public static List withoutConsecutiveDuplicates(List nodes) { 11 | List result = new ArrayList<>(); 12 | for (MapNode node : nodes) { 13 | if (result.isEmpty() || node.getPos().distanceTo(result.get(result.size() - 1).getPos()) > 0) { 14 | result.add(node); 15 | } 16 | } 17 | return result; 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/map_data/creation/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Functionality to create map data for use with OSM2World. 3 | *

4 | * Map data can be converted from raw OSM data, 5 | * or it can be created directly with the {@link org.osm2world.map_data.creation.MapDataBuilder}. 6 | */ 7 | package org.osm2world.map_data.creation; -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/map_data/data/MapAreaSegment.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.map_data.data; 2 | 3 | /** 4 | * segment of a {@link MapArea}'s outline. This isn't a {@link MapElement}s 5 | * itself (for example, it has no individual representation). 6 | * Instead, it's simply a different way to access an area's data. 7 | * 8 | * @see MapData 9 | */ 10 | public class MapAreaSegment extends MapSegment { 11 | 12 | private final MapArea area; 13 | private final boolean areaRight; 14 | 15 | MapAreaSegment(MapArea area, boolean areaRight, 16 | MapNode startNode, MapNode endNode) { 17 | super(startNode, endNode); 18 | this.area = area; 19 | this.areaRight = areaRight; 20 | } 21 | 22 | public MapArea getArea() { 23 | return area; 24 | } 25 | 26 | /** 27 | * returns true if the area is to the right of this segment 28 | */ 29 | public boolean isAreaRight() { 30 | return areaRight; 31 | } 32 | 33 | @Override 34 | public String toString() { 35 | return area + "[" + startNode + "->" + endNode + "]"; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/map_data/data/MapElement.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.map_data.data; 2 | 3 | import java.util.Collection; 4 | import java.util.List; 5 | 6 | import org.osm2world.map_data.data.overlaps.MapOverlap; 7 | import org.osm2world.math.BoundedObject; 8 | import org.osm2world.world.data.WorldObject; 9 | 10 | /** 11 | * An element from an OSM dataset. 12 | * 13 | * @see MapData 14 | */ 15 | public interface MapElement extends BoundedObject { 16 | 17 | /** 18 | * returns the visual representations of this element. 19 | * 20 | * The order should match the order in which they were added, 21 | * so that dependencies are preserved (elements that depend on 22 | * another element should be placed after that element). 23 | * The first element is considered the "primary" representation, 24 | * and for some purposes - such as elevation calculation -, only this 25 | * representation will be used. 26 | */ 27 | public List getRepresentations(); 28 | 29 | /** 30 | * returns the primary representation, or null if the object doesn't have any. 31 | * @see #getRepresentations() 32 | */ 33 | public WorldObject getPrimaryRepresentation(); 34 | 35 | /** 36 | * returns all overlaps between this {@link MapElement} 37 | * and other {@link MapElement}s. 38 | */ 39 | public Collection> getOverlaps(); 40 | 41 | /** returns this element's tags */ 42 | TagSet getTags(); 43 | 44 | /** returns the corresponding {@link MapRelationElement} */ 45 | public MapRelationElement getElementWithId(); 46 | 47 | } 48 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/map_data/data/MapMultipolygonRelation.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.map_data.data; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collection; 5 | import java.util.List; 6 | 7 | /** 8 | * a multipolygon relation containing multiple outer rings. 9 | * Unlike simpler multipolygons, this cannot be represented as a single {@link MapArea}. 10 | * Contains several {@link MapArea} elements as members. 11 | */ 12 | public class MapMultipolygonRelation extends MapRelation { 13 | 14 | private final List areas = new ArrayList<>(); 15 | 16 | public MapMultipolygonRelation(long id, TagSet tags, Collection areas) { 17 | 18 | super(id, tags); 19 | 20 | if (!tags.contains("type", "multipolygon")) { 21 | throw new IllegalArgumentException("not a multipolygon relation"); 22 | } 23 | 24 | areas.forEach(it -> this.addMember("outer", it)); 25 | 26 | } 27 | 28 | @Override 29 | public void addMember(String role, MapRelationElement element) { 30 | if (role.equals("outer") && element instanceof MapArea a) { 31 | super.addMember(role, element); 32 | areas.add(a); 33 | } else { 34 | throw new IllegalArgumentException("invalid role or member type"); 35 | } 36 | } 37 | 38 | public List getAreas() { 39 | return areas; 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/map_data/data/MapRelationElement.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.map_data.data; 2 | 3 | import static java.util.Collections.emptyList; 4 | 5 | import java.util.ArrayList; 6 | import java.util.Collection; 7 | import java.util.List; 8 | 9 | /** 10 | * Something that can be a member of a {@link MapRelation}. 11 | * TODO: eventually merge with {@link MapElement} 12 | */ 13 | public abstract class MapRelationElement { 14 | 15 | private List memberships = emptyList(); 16 | 17 | /** 18 | * returns all relation memberships containing this element 19 | */ 20 | public Collection getMemberships() { 21 | return memberships; 22 | } 23 | 24 | /** 25 | * adds a relation membership; must only be called from {@link MapRelation#addMember(String, MapRelationElement)}. 26 | */ 27 | void addMembership(MapRelation.Membership membership) { 28 | 29 | assert membership.getElement() == this; 30 | 31 | if (memberships.isEmpty()) { 32 | memberships = new ArrayList<>(); 33 | } 34 | 35 | memberships.add(membership); 36 | 37 | } 38 | 39 | /** 40 | * returns the element's id 41 | */ 42 | public abstract long getId(); 43 | 44 | /** 45 | * see {@link MapElement#getTags()} 46 | */ 47 | public abstract TagSet getTags(); 48 | 49 | /** 50 | * returns the element's id, prefixed with a letter (n for node, w for way, r for relation) 51 | */ 52 | @Override 53 | public abstract String toString(); 54 | 55 | } 56 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/map_data/data/Tag.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.map_data.data; 2 | 3 | /** 4 | * immutable representation of an OSM tag (key-value-pair) 5 | */ 6 | public class Tag { 7 | 8 | /** key of the tag; != null */ 9 | public final String key; 10 | 11 | /** value of the tag; != null */ 12 | public final String value; 13 | 14 | public Tag(String key, String value) { 15 | assert key != null && value != null; 16 | this.key = key; 17 | this.value = value; 18 | } 19 | 20 | @Override 21 | public boolean equals(Object obj) { 22 | return obj instanceof Tag otherTag && key.equals(otherTag.key) && value.equals(otherTag.value); 23 | } 24 | 25 | @Override 26 | public int hashCode() { 27 | return 31 * key.hashCode() + value.hashCode(); 28 | } 29 | 30 | @Override 31 | public String toString() { 32 | return key + "=" + value; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/map_data/data/overlaps/MapIntersectionWW.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.map_data.data.overlaps; 2 | 3 | import org.osm2world.map_data.data.MapElement; 4 | import org.osm2world.map_data.data.MapWaySegment; 5 | import org.osm2world.math.VectorXZ; 6 | 7 | /** intersection between two {@link MapWaySegment}s ("Way-Way") */ 8 | public class MapIntersectionWW extends MapOverlap { 9 | 10 | public final VectorXZ pos; 11 | 12 | public MapIntersectionWW(MapWaySegment line1, MapWaySegment line2, VectorXZ pos) { 13 | super(line1, line2, MapOverlapType.INTERSECT); 14 | this.pos = pos; 15 | } 16 | 17 | /** 18 | * takes one of the intersecting {@link MapWaySegment}s 19 | * and returns the other one 20 | */ 21 | public MapWaySegment getOther(MapElement line) { 22 | return (MapWaySegment) super.getOther(line); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/map_data/data/overlaps/MapOverlap.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.map_data.data.overlaps; 2 | 3 | import org.osm2world.map_data.data.MapElement; 4 | import org.osm2world.map_data.data.MapWaySegment; 5 | 6 | /** 7 | * supertype for intersections and inclusions 8 | * between two {@link MapElement}s 9 | */ 10 | public abstract class MapOverlap { 11 | 12 | public final T1 e1; 13 | public final T2 e2; 14 | 15 | public final MapOverlapType type; 16 | 17 | public MapOverlap(T1 e1, T2 e2, MapOverlapType type) { 18 | this.e1 = e1; 19 | this.e2 = e2; 20 | this.type = type; 21 | } 22 | 23 | /** 24 | * takes one of the {@link MapWaySegment}s that participate 25 | * in this overlap and returns the other one 26 | */ 27 | public MapElement getOther(MapElement element) { 28 | if (element == e1) { 29 | return e2; 30 | } else if (element == e2) { 31 | return e1; 32 | } else { 33 | throw new IllegalArgumentException("element isn't part of this intersection"); 34 | } 35 | } 36 | 37 | @Override 38 | public String toString() { 39 | return "( " + e1.toString() + " - " + e2.toString() + " )"; 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/map_data/data/overlaps/MapOverlapAA.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.map_data.data.overlaps; 2 | 3 | import java.util.Collection; 4 | 5 | import org.osm2world.map_data.data.MapArea; 6 | import org.osm2world.map_data.data.MapElement; 7 | import org.osm2world.math.VectorXZ; 8 | 9 | /** 10 | * overlap between two areas ("Area-Area"). 11 | * The two areas' outlines either intersect 12 | * or one of them is completely within the other one. 13 | */ 14 | public class MapOverlapAA extends MapOverlap { 15 | 16 | public MapOverlapAA(MapArea area1, MapArea area2, MapOverlapType type) { 17 | super(area1, area2, type); 18 | } 19 | 20 | @Override 21 | public MapArea getOther(MapElement element) { 22 | return (MapArea) super.getOther(element); 23 | } 24 | 25 | public Collection getIntersectionPositions() { 26 | return e1.getPolygon().intersectionPositions(e2.getPolygon()); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/map_data/data/overlaps/MapOverlapNA.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.map_data.data.overlaps; 2 | 3 | import org.osm2world.map_data.data.MapArea; 4 | import org.osm2world.map_data.data.MapNode; 5 | import org.osm2world.map_data.data.MapWaySegment; 6 | 7 | /** 8 | * overlap between a {@link MapWaySegment} and a {@link MapArea} ("Way-Area"). 9 | * The way either intersects with the area 10 | * or is completely contained within the area. 11 | */ 12 | public class MapOverlapNA extends MapOverlap { 13 | 14 | public MapOverlapNA(MapNode node, MapArea area, MapOverlapType type) { 15 | super(node, area, type); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/map_data/data/overlaps/MapOverlapType.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.map_data.data.overlaps; 2 | 3 | import org.osm2world.map_data.data.MapElement; 4 | import org.osm2world.map_data.data.MapSegment; 5 | 6 | //TODO: multiple ones at same time (areas that share segments AND intersect)! 7 | 8 | public enum MapOverlapType { 9 | 10 | /** two {@link MapElement}s intersect */ 11 | INTERSECT, 12 | 13 | /** the second {@link MapElement} contains the first {@link MapElement} */ 14 | CONTAIN, 15 | 16 | /** 17 | * {@link MapSegment#sharesBothNodes(MapSegment)} 18 | * is true for a pair of {@link MapSegment}s, one from each {@link MapElement} 19 | */ 20 | SHARE_SEGMENT 21 | 22 | } 23 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/map_data/data/package-info.java: -------------------------------------------------------------------------------- 1 | /** The classes used to represent map data inside OSM2World. */ 2 | package org.osm2world.map_data.data; -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/map_data/package-info.java: -------------------------------------------------------------------------------- 1 | /** OSM2World's abstraction of OSM map data. */ 2 | package org.osm2world.map_data; -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/map_elevation/creation/BridgeTunnelEleCalculator.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.map_elevation.creation; 2 | 3 | import org.osm2world.map_data.data.TagSet; 4 | import org.osm2world.world.modules.BridgeModule; 5 | import org.osm2world.world.modules.TunnelModule; 6 | 7 | /** 8 | * sets elevations to zero (or terrain elevation if available), except for bridges and tunnels 9 | */ 10 | public class BridgeTunnelEleCalculator extends TagEleCalculator { 11 | 12 | final double eleOffsetBridge; 13 | final double eleOffsetTunnel; 14 | 15 | private BridgeTunnelEleCalculator(double eleOffsetBridge, double eleOffsetTunnel) { 16 | this.eleOffsetBridge = eleOffsetBridge; 17 | this.eleOffsetTunnel = eleOffsetTunnel; 18 | } 19 | 20 | public BridgeTunnelEleCalculator() { 21 | this(0.1, 0.0); 22 | } 23 | 24 | @Override 25 | protected Double getEleForTags(TagSet tags, double terrainEle) { 26 | 27 | if (BridgeModule.isBridge(tags)) { 28 | return terrainEle + eleOffsetBridge; 29 | } else if (TunnelModule.isTunnel(tags)) { 30 | return terrainEle + eleOffsetTunnel; 31 | } else { 32 | return terrainEle; 33 | } 34 | 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/map_elevation/creation/EleCalculator.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.map_elevation.creation; 2 | 3 | import javax.annotation.Nonnull; 4 | 5 | import org.osm2world.map_data.data.MapData; 6 | import org.osm2world.map_elevation.data.EleConnector; 7 | 8 | /** 9 | * calculates elevations using terrain elevation and information from {@link MapData} 10 | */ 11 | public interface EleCalculator { 12 | 13 | /** 14 | * provides elevation information for all elements in the {@link MapData}. 15 | * The result will be provided to the {@link EleConnector}s 16 | * in the map data. It is assumed that connectors' elevations are initially set to the elevation of the terrain. 17 | */ 18 | void calculateElevations(@Nonnull MapData mapData); 19 | 20 | } 21 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/map_elevation/creation/EleTagEleCalculator.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.map_elevation.creation; 2 | 3 | import static org.osm2world.util.ValueParseUtil.parseOsmDecimal; 4 | 5 | import org.osm2world.map_data.data.TagSet; 6 | 7 | /** 8 | * sets elevations based on ele tags 9 | */ 10 | public class EleTagEleCalculator extends TagEleCalculator { 11 | 12 | @Override 13 | protected Double getEleForTags(TagSet tags, double terrainEle) { 14 | if (tags.containsKey("ele")) { 15 | return parseOsmDecimal(tags.getValue("ele"), null); 16 | } else { 17 | return null; 18 | } 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/map_elevation/creation/LinearInterpolator.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.map_elevation.creation; 2 | 3 | import static org.osm2world.math.shapes.AxisAlignedRectangleXZ.bbox; 4 | 5 | import java.util.Collection; 6 | 7 | import org.osm2world.map_elevation.creation.DelaunayTriangulation.DelaunayTriangle; 8 | import org.osm2world.math.VectorXYZ; 9 | import org.osm2world.math.VectorXZ; 10 | import org.osm2world.math.shapes.AxisAlignedRectangleXZ; 11 | 12 | /** 13 | * triangulates the point set of elevation sites, 14 | * then interpolates linearly within each triangle 15 | * (i.e. treats the triangles as flat) 16 | */ 17 | public class LinearInterpolator implements TerrainInterpolator { 18 | 19 | private DelaunayTriangulation triangulation; 20 | 21 | @Override 22 | public void setKnownSites(Collection sites) { 23 | 24 | if (sites.isEmpty()) { 25 | throw new IllegalArgumentException("No sites with elevation available"); 26 | } 27 | 28 | AxisAlignedRectangleXZ boundingBox = bbox(sites); 29 | boundingBox = boundingBox.pad(100); 30 | 31 | triangulation = new DelaunayTriangulation(boundingBox); 32 | 33 | for (VectorXYZ site : sites) { 34 | triangulation.insert(site); 35 | } 36 | 37 | } 38 | 39 | @Override 40 | public VectorXYZ interpolateEle(VectorXZ pos) { 41 | 42 | DelaunayTriangle triangle = triangulation.getEnclosingTriangle(pos); 43 | 44 | double ele = triangle.asTriangleXYZ().getYAt(pos); 45 | 46 | return pos.xyz(ele); 47 | 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/map_elevation/creation/NoOpEleCalculator.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.map_elevation.creation; 2 | 3 | import javax.annotation.Nonnull; 4 | 5 | import org.osm2world.map_data.data.MapData; 6 | 7 | /** 8 | * leaves existing elevations unmodified. 9 | * Usually, those existing elevations will be either all 0 or based on a terrain model. 10 | */ 11 | public class NoOpEleCalculator implements EleCalculator { 12 | 13 | @Override 14 | public void calculateElevations(@Nonnull MapData mapData) {} 15 | 16 | } 17 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/map_elevation/creation/NoneEleConstraintEnforcer.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.map_elevation.creation; 2 | 3 | import java.util.List; 4 | 5 | import org.osm2world.map_elevation.data.EleConnector; 6 | 7 | /** 8 | * enforcer implementation that simply passes the interpolated terrain 9 | * elevations through, and does not actually enforce constraints. 10 | */ 11 | public class NoneEleConstraintEnforcer implements EleConstraintEnforcer { 12 | 13 | @Override 14 | public void addConnectors(Iterable connectors) {} 15 | 16 | @Override 17 | public void requireSameEle(EleConnector c1, EleConnector c2) {} 18 | 19 | @Override 20 | public void requireSameEle(Iterable cs) {} 21 | 22 | @Override 23 | public void requireVerticalDistance(ConstraintType type, double distance, 24 | EleConnector upper, EleConnector lower) {} 25 | 26 | @Override 27 | public void requireVerticalDistance(ConstraintType type, double distance, 28 | EleConnector upper, EleConnector base1, EleConnector base2) {} 29 | 30 | @Override 31 | public void requireIncline(ConstraintType type, double incline, 32 | List cs) {} 33 | 34 | @Override 35 | public void requireSmoothness( 36 | EleConnector from, EleConnector via, EleConnector to) {} 37 | 38 | @Override 39 | public void enforceConstraints() {} 40 | 41 | } 42 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/map_elevation/creation/TagEleCalculator.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.map_elevation.creation; 2 | 3 | import javax.annotation.Nonnull; 4 | 5 | import org.osm2world.map_data.data.MapData; 6 | import org.osm2world.map_data.data.TagSet; 7 | import org.osm2world.map_elevation.data.EleConnector; 8 | import org.osm2world.util.FaultTolerantIterationUtil; 9 | import org.osm2world.world.data.WorldObject; 10 | 11 | /** 12 | * relies on tags that explicitly set elevation. 13 | * Subclasses determine the tag(s) to be used for this purpose. 14 | */ 15 | public abstract class TagEleCalculator implements EleCalculator { 16 | 17 | @Override 18 | public void calculateElevations(@Nonnull MapData mapData) { 19 | 20 | FaultTolerantIterationUtil.forEach(mapData.getWorldObjects(), (WorldObject worldObject) -> { 21 | 22 | for (EleConnector conn : worldObject.getEleConnectors()) { 23 | Double ele = getEleForTags(worldObject.getPrimaryMapElement().getTags(), conn.getPosXYZ().y); 24 | if (ele != null) { 25 | conn.setPosXYZ(conn.pos.xyz(ele)); 26 | } 27 | } 28 | 29 | }); 30 | 31 | } 32 | 33 | /** 34 | * returns the elevation as set explicitly by the tags 35 | * 36 | * @param terrainEle initial elevation value derived from terrain data, or 0 if no terrain data is available 37 | * @return elevation; null if the tags don't define the elevation 38 | */ 39 | protected abstract Double getEleForTags(TagSet tags, double terrainEle); 40 | 41 | } 42 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/map_elevation/creation/TerrainElevationData.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.map_elevation.creation; 2 | 3 | import java.io.IOException; 4 | import java.util.Collection; 5 | 6 | import org.osm2world.math.VectorXYZ; 7 | import org.osm2world.math.shapes.AxisAlignedRectangleXZ; 8 | 9 | /** 10 | * a source of terrain elevation data. Implementations may range from raster 11 | * data such as SRTM to sparsely distributed points with known elevation. 12 | */ 13 | public interface TerrainElevationData { 14 | 15 | /** 16 | * returns all points with known elevation within the bounds 17 | */ 18 | Collection getSites(AxisAlignedRectangleXZ bounds) throws IOException; 19 | 20 | } 21 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/map_elevation/creation/TerrainInterpolator.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.map_elevation.creation; 2 | 3 | import java.util.Collection; 4 | 5 | import org.osm2world.math.VectorXYZ; 6 | import org.osm2world.math.VectorXZ; 7 | 8 | /** 9 | * strategy for elevation interpolation from a set of known points 10 | */ 11 | public interface TerrainInterpolator { 12 | 13 | /** 14 | * @param sites non-empty collection of points with known elevation 15 | */ 16 | void setKnownSites(Collection sites); 17 | 18 | VectorXYZ interpolateEle(VectorXZ pos); 19 | 20 | } 21 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/map_elevation/creation/ZeroInterpolator.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.map_elevation.creation; 2 | 3 | import java.util.Collection; 4 | 5 | import org.osm2world.math.VectorXYZ; 6 | import org.osm2world.math.VectorXZ; 7 | 8 | /** 9 | * sets every point's elevation to 0 10 | */ 11 | public class ZeroInterpolator implements TerrainInterpolator { 12 | 13 | @Override 14 | public void setKnownSites(Collection sites) { 15 | // do nothing 16 | } 17 | 18 | @Override 19 | public VectorXYZ interpolateEle(VectorXZ pos) { 20 | return pos.xyz(0); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/map_elevation/data/GroundState.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.map_elevation.data; 2 | 3 | public enum GroundState { 4 | 5 | ON, ABOVE, BELOW, ATTACHED; 6 | 7 | } -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/map_elevation/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Elevation data. 3 | *

4 | * OSM2World can use elevation data alongside map data for better results. 5 | */ 6 | package org.osm2world.map_elevation; -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/math/BoundedObject.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.math; 2 | 3 | import org.osm2world.math.shapes.AxisAlignedRectangleXZ; 4 | 5 | /** 6 | * object which has an extent in the XZ plane that can be enclosed with a rectangle 7 | */ 8 | public interface BoundedObject { 9 | 10 | /** returns the minimum axis-aligned bounding rectangle of this object */ 11 | public AxisAlignedRectangleXZ boundingBox(); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/math/Vector3D.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.math; 2 | 3 | public interface Vector3D extends BoundedObject { 4 | 5 | public double getX(); 6 | public double getY(); 7 | public double getZ(); 8 | 9 | public VectorXZ xz(); 10 | 11 | private VectorXYZ xyz() { 12 | if (this instanceof VectorXYZ) { 13 | return (VectorXYZ) this; 14 | } else { 15 | return new VectorXYZ(getX(), getY(), getZ()); 16 | } 17 | } 18 | 19 | public static double distance(Vector3D v1, Vector3D v2) { 20 | return v1.xyz().distanceTo(v2.xyz()); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/math/Vector4D.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.math; 2 | 3 | public interface Vector4D { 4 | public double getX(); 5 | public double getY(); 6 | public double getZ(); 7 | public double getW(); 8 | } 9 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/math/algorithms/JTSBufferUtil.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.math.algorithms; 2 | 3 | import static org.osm2world.math.algorithms.JTSConversionUtil.polygonsFromJTS; 4 | import static org.osm2world.math.algorithms.JTSConversionUtil.toJTS; 5 | 6 | import java.util.List; 7 | 8 | import org.locationtech.jts.geom.Geometry; 9 | import org.locationtech.jts.operation.buffer.BufferOp; 10 | import org.locationtech.jts.operation.buffer.BufferParameters; 11 | import org.osm2world.math.shapes.PolygonShapeXZ; 12 | import org.osm2world.math.shapes.PolygonWithHolesXZ; 13 | 14 | public final class JTSBufferUtil { 15 | 16 | private JTSBufferUtil() {} 17 | 18 | /** grows or shrinks a polygon */ 19 | public static final List bufferPolygon(PolygonShapeXZ polygon, double distance) { 20 | 21 | BufferParameters bufferParams = new BufferParameters(); 22 | bufferParams.setJoinStyle(BufferParameters.JOIN_MITRE); 23 | bufferParams.setMitreLimit(BufferParameters.DEFAULT_MITRE_LIMIT); 24 | BufferOp op = new BufferOp(toJTS(polygon), bufferParams); 25 | 26 | Geometry result = op.getResultGeometry(distance); 27 | 28 | /* interpret the result as polygons */ 29 | 30 | return polygonsFromJTS(result); 31 | 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/math/algorithms/SimpleLineSegmentIntersectionFinder.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.math.algorithms; 2 | 3 | import static org.osm2world.math.algorithms.GeometryUtil.getTrueLineSegmentIntersection; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | import org.osm2world.math.VectorXZ; 9 | import org.osm2world.math.algorithms.LineSegmentIntersectionFinder.Intersection; 10 | import org.osm2world.math.shapes.LineSegmentXZ; 11 | 12 | /** a simple but slow alternative to {@link LineSegmentIntersectionFinder} */ 13 | public class SimpleLineSegmentIntersectionFinder { 14 | 15 | /** 16 | * finds all intersections in a set of line segments. 17 | * Only reports true intersections, not shared start or end points. 18 | */ 19 | public static final List> findAllIntersections(List segments) { 20 | 21 | List> result = new ArrayList<>(); 22 | 23 | for (int i = 0; i < segments.size(); i++) { 24 | for (int j = i + 1; j < segments.size(); j++) { 25 | LineSegmentXZ segI = segments.get(i); 26 | LineSegmentXZ segJ = segments.get(j); 27 | VectorXZ intersectionPos = getTrueLineSegmentIntersection(segI.p1, segI.p2, segJ.p1, segJ.p2); 28 | if (intersectionPos != null) { 29 | result.add(new Intersection(intersectionPos, segI, segJ)); 30 | } 31 | } 32 | } 33 | 34 | return result; 35 | 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/math/algorithms/package-info.java: -------------------------------------------------------------------------------- 1 | /** Algorithms for geometric calculations such as triangulation, finding intersections and subtracting polygons. */ 2 | package org.osm2world.math.algorithms; -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/math/datastructures/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Data structures to store and query geometric objects. 3 | * Implementations of {@link org.osm2world.math.datastructures.SpatialIndex} are used to speed up calculations. 4 | */ 5 | package org.osm2world.math.datastructures; -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/math/geo/CardinalDirection.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.math.geo; 2 | 3 | import static java.lang.Math.PI; 4 | 5 | import org.osm2world.math.VectorXZ; 6 | 7 | /** 8 | * one of the four cardinal directions 9 | */ 10 | public enum CardinalDirection { 11 | 12 | N, E, S, W; 13 | 14 | /** 15 | * returns the closest cardinal direction for an angle 16 | * 17 | * @param angle angle to north direction in radians; 18 | * consistent with {@link VectorXZ#angle()} 19 | */ 20 | public static CardinalDirection closestCardinal(double angle) { 21 | angle = angle % (2 * PI); 22 | if (angle < PI / 4) { 23 | return N; 24 | } else if (angle < 3 * PI / 4) { 25 | return E; 26 | } else if (angle < 5 * PI / 4) { 27 | return S; 28 | } else if (angle < 7 * PI / 4) { 29 | return W; 30 | } else { 31 | return N; 32 | } 33 | } 34 | 35 | public boolean isOppositeOf(CardinalDirection other) { 36 | return this == N && other == S 37 | || this == E && other == W 38 | || this == S && other == N 39 | || this == W && other == E; 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/math/geo/GeoBounds.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.math.geo; 2 | 3 | /** 4 | * a region on the globe between minimum and maximum latitude and longitude values 5 | */ 6 | public interface GeoBounds { 7 | 8 | LatLonBounds latLonBounds(); 9 | 10 | } 11 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/math/geo/MapProjection.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.math.geo; 2 | 3 | import org.osm2world.math.VectorXZ; 4 | 5 | /** 6 | * projection which converts {@link LatLon} coordinates to OSM2World's internal {@link VectorXZ} coordinate system, 7 | * and allows the inverse calculation as well. 8 | *

9 | * In OSM2World coordinates, 1 unit of distance along the X, Y or Z axis corresponds to approximately 1 meter. 10 | * The X axis points east, the Z axis points north. 11 | *

12 | * OSM2World's map projections are intended to use the "dense" space of floating point values by making all coordinates 13 | * relative to a suitable origin. Because OSM2World only processes relatively small parts of the globe at a time, 14 | * projections which only work well locally around the origin are well suited. 15 | */ 16 | public interface MapProjection { 17 | 18 | /** performs projection into the internal coordinate system */ 19 | default public VectorXZ toXZ(LatLon latlon) { 20 | return toXZ(latlon.lat, latlon.lon); 21 | } 22 | 23 | /** performs projection into the internal coordinate system */ 24 | public VectorXZ toXZ(double lat, double lon); 25 | 26 | /** inverse for {@link #toXZ(LatLon)} */ 27 | default public LatLon toLatLon(VectorXZ pos) { 28 | return new LatLon(toLat(pos), toLon(pos)); 29 | } 30 | 31 | /** returns only the latitude of {@link #toLatLon(VectorXZ)} */ 32 | public double toLat(VectorXZ pos); 33 | 34 | /** returns only the longitude of {@link #toLatLon(VectorXZ)} */ 35 | public double toLon(VectorXZ pos); 36 | 37 | /** returns the origin, i.e. the {@link LatLon} that maps to (0,0) */ 38 | public LatLon getOrigin(); 39 | 40 | } 41 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/math/geo/package-info.java: -------------------------------------------------------------------------------- 1 | /** Map projections, latitude + longitude, and tile coordinates. */ 2 | package org.osm2world.math.geo; -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/math/package-info.java: -------------------------------------------------------------------------------- 1 | /** Classes for geometric objects that are used throughout OSM2World. */ 2 | package org.osm2world.math; -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/math/shapes/FaceXYZ.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.math.shapes; 2 | 3 | import static java.lang.Math.abs; 4 | import static org.osm2world.math.shapes.FlatSimplePolygonShapeXYZ.triangleOnFace; 5 | 6 | import java.util.List; 7 | 8 | import org.osm2world.math.VectorXYZ; 9 | import org.osm2world.util.exception.InvalidGeometryException; 10 | 11 | /** 12 | * a simple polygon where all vertices are in the same plane 13 | */ 14 | public class FaceXYZ extends PolygonXYZ implements FlatSimplePolygonShapeXYZ { 15 | 16 | private final VectorXYZ normal; 17 | 18 | public FaceXYZ(List vertexLoop) { 19 | 20 | super(vertexLoop); 21 | 22 | /* calculate the normal vector of the triangle defined by 3 non-collinear outline vertices */ 23 | 24 | normal = triangleOnFace(vertexLoop).getNormal(); 25 | 26 | /* check that the vertices lie in a plane, throw exception otherwise */ 27 | 28 | for (VectorXYZ v : vertexLoop) { 29 | if (abs(rotateToOrFromFacePlane(v, true).y - getCenter().y) > 0.01) { 30 | throw new InvalidGeometryException("face vertices do not lie in a plane"); 31 | } 32 | } 33 | 34 | } 35 | 36 | @Override 37 | public VectorXYZ getNormal() { 38 | return normal; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/math/shapes/LineSegmentXYZ.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.math.shapes; 2 | 3 | import org.osm2world.math.VectorXYZ; 4 | 5 | public class LineSegmentXYZ { 6 | 7 | public final VectorXYZ p1, p2; 8 | 9 | public LineSegmentXYZ(VectorXYZ p1, VectorXYZ p2) { 10 | this.p1 = p1; 11 | this.p2 = p2; 12 | } 13 | 14 | public LineSegmentXZ getSegmentXZ() { 15 | return new LineSegmentXZ(p1.xz(), p2.xz()); 16 | } 17 | 18 | @Override 19 | public String toString() { 20 | return "[" + p1 + ", " + p2 + "]"; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/math/shapes/LineXZ.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.math.shapes; 2 | 3 | import javax.annotation.Nonnull; 4 | import javax.annotation.Nullable; 5 | 6 | import org.osm2world.math.Vector3D; 7 | import org.osm2world.math.VectorXZ; 8 | import org.osm2world.math.algorithms.GeometryUtil; 9 | 10 | /** an infinite line in the XZ plane */ 11 | public record LineXZ(@Nonnull VectorXZ p1, @Nonnull VectorXZ p2) { 12 | 13 | public LineXZ { 14 | if (p1.equals(p2)) { 15 | throw new IllegalArgumentException("Points defining a line must be distinct"); 16 | } 17 | } 18 | 19 | /** returns a normalized vector indicating the line's direction */ 20 | public VectorXZ getDirection() { 21 | return p2.subtract(p1).normalize(); 22 | } 23 | 24 | public @Nullable VectorXZ getIntersection(LineXZ l) { 25 | return GeometryUtil.getLineIntersection(p1, getDirection(), l.p1, l.getDirection()); 26 | } 27 | 28 | public @Nullable VectorXZ getIntersection(LineSegmentXZ l) { 29 | @Nullable VectorXZ intersection = GeometryUtil.getLineIntersection(p1, getDirection(), l.p1, l.getDirection()); 30 | if (intersection != null && GeometryUtil.isBetween(intersection, l.p1, l.p2)) { 31 | return intersection; 32 | } 33 | return null; 34 | } 35 | 36 | /** returns the closest distance between p and this line */ 37 | public double distanceTo(VectorXZ v) { 38 | return GeometryUtil.distanceFromLine(v, p1, p2); 39 | } 40 | 41 | public double distanceToXZ(Vector3D v) { 42 | return GeometryUtil.distanceFromLine(v.xz(), p1, p2); 43 | } 44 | 45 | @Override 46 | public String toString() { 47 | return "[" + p1 + ", " + p2 + "]"; 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/math/shapes/PolygonWithHolesXYZ.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.math.shapes; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.osm2world.math.BoundedObject; 7 | 8 | /** 9 | * a three-dimensional polygon that may have inner rings 10 | */ 11 | public record PolygonWithHolesXYZ(PolygonXYZ outer, List holes) implements BoundedObject { 12 | 13 | public List rings() { 14 | List result = new ArrayList<>(holes().size() + 1); 15 | result.add(outer()); 16 | result.addAll(holes()); 17 | return result; 18 | } 19 | 20 | @Override 21 | public AxisAlignedRectangleXZ boundingBox() { 22 | return AxisAlignedRectangleXZ.bboxUnion(rings()); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/math/shapes/PolylineXYZ.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.math.shapes; 2 | 3 | import java.util.List; 4 | import java.util.Objects; 5 | 6 | import org.osm2world.math.VectorXYZ; 7 | 8 | public class PolylineXYZ { 9 | 10 | protected final List vertices; 11 | 12 | public PolylineXYZ(List vertices) { 13 | this.vertices = vertices; 14 | } 15 | 16 | public List getVertices() { 17 | return vertices; 18 | } 19 | 20 | public int size() { 21 | return vertices.size(); 22 | } 23 | 24 | public double length() { 25 | double result = 0; 26 | for (int i = 0; i + 1 < vertices.size(); i++) { 27 | result += vertices.get(i).distanceTo(vertices.get(i+1)); 28 | } 29 | return result; 30 | } 31 | 32 | @Override 33 | public int hashCode() { 34 | return vertices.hashCode(); 35 | } 36 | 37 | @Override 38 | public boolean equals(Object obj) { 39 | return obj instanceof PolylineXYZ && Objects.equals(vertices, ((PolylineXYZ)obj).vertices); 40 | } 41 | 42 | @Override 43 | public String toString() { 44 | return vertices.toString(); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/math/shapes/RoundShapeXZ.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.math.shapes; 2 | 3 | import java.util.List; 4 | 5 | import org.osm2world.math.VectorXZ; 6 | 7 | /** 8 | * a shape that is at least partly round, 9 | * i.e. cannot be described with perfect accuracy by a finite number of vertices. 10 | * As such, methods like {@link #vertices()} produce an approximation. 11 | */ 12 | public interface RoundShapeXZ extends ShapeXZ { 13 | 14 | @Override 15 | public default List vertices() { 16 | // use a default number of points to approximate the shape with a polygon 17 | return vertices(36); 18 | } 19 | 20 | public List vertices(int numPoints); 21 | 22 | } 23 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/math/shapes/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Immutable classes and interfaces representing shapes. 3 | *

4 | * Most them are 2D shapes inheriting from {@link org.osm2world.math.shapes.ShapeXZ}, 5 | * but some shapes have 3D equivalents. 6 | */ 7 | package org.osm2world.math.shapes; -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/osm/creation/OSMDataReader.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.osm.creation; 2 | 3 | import java.io.IOException; 4 | 5 | import org.osm2world.math.geo.LatLonBounds; 6 | import org.osm2world.math.geo.TileNumber; 7 | import org.osm2world.osm.data.OSMData; 8 | 9 | /** 10 | * a data source which provides access to map data using the OpenStreetMap data model 11 | */ 12 | public interface OSMDataReader { 13 | 14 | /** 15 | * returns all available data from this data source. 16 | * Will fail for data sources which provide access to entire databases or collections of tiles. 17 | */ 18 | public default OSMData getAllData() throws IOException { 19 | throw new UnsupportedOperationException("Getting all data is not supported for this data source" + 20 | " (" + this.getClass().getSimpleName() +")"); 21 | } 22 | 23 | public default OSMData getData(TileNumber tile) throws IOException { 24 | return getData(tile.latLonBounds()); 25 | } 26 | 27 | public default OSMData getData(LatLonBounds bounds) throws IOException { 28 | return getAllData(); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/osm/creation/package-info.java: -------------------------------------------------------------------------------- 1 | /** Code for reading OSM data from some data source */ 2 | package org.osm2world.osm.creation; -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/osm/data/package-info.java: -------------------------------------------------------------------------------- 1 | /** Representation of OSM data in memory */ 2 | package org.osm2world.osm.data; -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/osm/package-info.java: -------------------------------------------------------------------------------- 1 | /** Unprocessed OSM map data. */ 2 | package org.osm2world.osm; -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/osm/ruleset/Ruleset.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.osm.ruleset; 2 | 3 | import de.topobyte.osm4j.core.model.iface.OsmTag; 4 | import org.osm2world.map_data.data.Tag; 5 | import org.osm2world.map_data.data.TagSet; 6 | 7 | public interface Ruleset { 8 | 9 | /** identifies tags that indicate that a closed way represents an area */ 10 | public boolean isAreaTag(Tag tag); 11 | 12 | /** 13 | * identifies tags which (almost) exclusively appear outside the sea. 14 | * This lets us make a guess whether a tile is a land tile. 15 | */ 16 | public boolean isLandTag(OsmTag tag); 17 | 18 | /** 19 | * identifies tags which (almost) exclusively appear on the sea. 20 | * This lets us make a guess whether a tile is a land tile. 21 | */ 22 | public boolean isSeaTag(OsmTag tag); 23 | 24 | /** checks if this relation type is considered relevant for OSM2World */ 25 | public boolean isRelevantRelation(TagSet tags); 26 | 27 | } 28 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/osm/ruleset/package-info.java: -------------------------------------------------------------------------------- 1 | /** Assumptions about OSM data, e.g. which tags indicate areas vs. linear ways */ 2 | package org.osm2world.osm.ruleset; -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/output/Output.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.output; 2 | 3 | import org.osm2world.conversion.O2WConfig; 4 | import org.osm2world.scene.Scene; 5 | import org.osm2world.world.data.WorldObject; 6 | 7 | /** 8 | * A sink for rendering/writing {@link WorldObject}s to. 9 | */ 10 | public interface Output { 11 | 12 | void setConfiguration(O2WConfig config); 13 | O2WConfig getConfiguration(); 14 | 15 | /** 16 | * writes an entire {@link Scene} to this output. 17 | * Will close the output at the end so no further content can be written. 18 | */ 19 | void outputScene(Scene scene); 20 | 21 | } 22 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/output/common/AbstractOutput.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.output.common; 2 | 3 | import javax.annotation.Nonnull; 4 | 5 | import org.osm2world.conversion.O2WConfig; 6 | import org.osm2world.output.Output; 7 | 8 | /** 9 | * superclass for {@link Output} implementations that defines some 10 | * of the required methods using others. Extending it reduces the number of 11 | * methods that have to be provided by the implementation 12 | */ 13 | public abstract class AbstractOutput implements Output { 14 | 15 | protected @Nonnull O2WConfig config = new O2WConfig(); 16 | 17 | @Override 18 | public O2WConfig getConfiguration() { 19 | return config; 20 | } 21 | 22 | @Override 23 | public void setConfiguration(O2WConfig config) { 24 | if (config != null) { 25 | this.config = config; 26 | } else { 27 | this.config = new O2WConfig(); 28 | } 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/output/common/ExtrudeOption.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.output.common; 2 | 3 | import java.util.List; 4 | import java.util.Set; 5 | 6 | import org.osm2world.math.shapes.ShapeXZ; 7 | import org.osm2world.scene.material.Material; 8 | 9 | /** 10 | * Flags describing available options for 11 | * {@link DrawBasedOutput#drawExtrudedShape(Material, ShapeXZ, List, List, List, List, Set)}. 12 | */ 13 | public enum ExtrudeOption { 14 | 15 | /** 16 | * determines whether the beginning of the "pipe" created by the extrusion should be capped 17 | * or left open. Only works for simple, closed shapes (e.g. polygons or circles). 18 | */ 19 | START_CAP, 20 | 21 | /** 22 | * determines whether the end of the "pipe" created by the extrusion should be capped 23 | * or left open. Only works for simple, closed shapes (e.g. polygons or circles). 24 | */ 25 | END_CAP, 26 | 27 | /** 28 | * whether the sides of the extruded geometry should have smooth normals 29 | */ 30 | SMOOTH_SIDES, 31 | 32 | /** 33 | * whether the caps (if any) should have smooth normals at the vertices they share with the sides 34 | */ 35 | SMOOTH_CAPS, 36 | 37 | /** 38 | * whether the texture's height dimension should be along the path (instead of along the shape's ring) 39 | */ 40 | TEX_HEIGHT_ALONG_PATH 41 | 42 | } 43 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/output/common/MeshOutput.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.output.common; 2 | 3 | import java.util.List; 4 | 5 | import org.osm2world.output.Output; 6 | import org.osm2world.scene.mesh.Mesh; 7 | import org.osm2world.scene.mesh.MeshStore; 8 | import org.osm2world.scene.mesh.MeshStore.MeshMetadata; 9 | import org.osm2world.world.data.WorldObject; 10 | 11 | /** 12 | * An {@link Output} that collects everything that is being drawn as {@link Mesh}es. 13 | * {@link Mesh}es are in-memory representation of 3D geometry suitable for use with typical graphics APIs. 14 | */ 15 | public class MeshOutput extends AbstractOutput implements DrawBasedOutput { 16 | 17 | protected final MeshStore meshStore = new MeshStore(); 18 | 19 | protected WorldObject currentWorldObject = null; 20 | 21 | @Override 22 | public void beginObject(WorldObject object) { 23 | this.currentWorldObject = object; 24 | } 25 | 26 | @Override 27 | public void drawMesh(Mesh mesh) { 28 | 29 | MeshMetadata metadata = (currentWorldObject != null) 30 | ? new MeshMetadata(currentWorldObject.getPrimaryMapElement().getElementWithId(), 31 | currentWorldObject.getClass()) 32 | : new MeshMetadata(null, null); 33 | 34 | meshStore.addMesh(mesh, metadata); 35 | 36 | } 37 | 38 | public List getMeshes() { 39 | return meshStore.meshes(); 40 | } 41 | 42 | public List getMeshesWithMetadata() { 43 | return meshStore.meshesWithMetadata(); 44 | } 45 | 46 | } -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/output/common/Primitive.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.output.common; 2 | 3 | import java.util.List; 4 | 5 | import org.osm2world.math.VectorXYZ; 6 | import org.osm2world.math.VectorXZ; 7 | 8 | public class Primitive { 9 | 10 | public static enum Type { 11 | CONVEX_POLYGON, 12 | TRIANGLES, TRIANGLE_STRIP, TRIANGLE_FAN 13 | } 14 | 15 | public final Type type; 16 | 17 | public final List vertices; 18 | 19 | public final List normals; 20 | 21 | public final List> texCoordLists; 22 | 23 | public Primitive(Type type, List vertices, 24 | List normals, List> texCoordLists) { 25 | this.type = type; 26 | this.vertices = vertices; 27 | this.normals = normals; 28 | this.texCoordLists = texCoordLists; 29 | } 30 | 31 | @Override 32 | public String toString() { 33 | return "{" + type + ", " + vertices + "}"; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/output/common/compression/Compression.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.output.common.compression; 2 | 3 | public enum Compression {NONE, ZIP, GZ} 4 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/output/common/lighting/GlobalLightingParameters.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.output.common.lighting; 2 | 3 | import java.awt.Color; 4 | 5 | import org.osm2world.math.VectorXYZ; 6 | 7 | /** 8 | * parameters that describe lighting affecting the entire scene; immutable 9 | */ 10 | public class GlobalLightingParameters { 11 | 12 | public final Color globalAmbientColor; 13 | 14 | /** 15 | * source of the scene's directional lighting; 16 | * null disables it and leaves only ambient lighting 17 | */ 18 | public final VectorXYZ lightFromDirection; 19 | 20 | public final Color lightColorDiffuse; 21 | public final Color lightColorSpecular; 22 | 23 | private GlobalLightingParameters( 24 | Color globalAmbientLight, VectorXYZ lightFromDirection, 25 | Color lightColorDiffuse, Color lightColorSpecular) { 26 | 27 | this.globalAmbientColor = globalAmbientLight; 28 | this.lightFromDirection = lightFromDirection; 29 | this.lightColorDiffuse = lightColorDiffuse; 30 | this.lightColorSpecular = lightColorSpecular; 31 | 32 | } 33 | 34 | public static final GlobalLightingParameters DEFAULT = 35 | new GlobalLightingParameters( 36 | new Color(1.0f, 1.0f, 1.0f), 37 | new VectorXYZ(1.0, 1.5, -1.0), 38 | Color.WHITE, 39 | Color.WHITE); 40 | 41 | } 42 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/output/common/rendering/Camera.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.output.common.rendering; 2 | 3 | import org.osm2world.math.VectorXYZ; 4 | 5 | /** 6 | * Describes the position and direction from which a view onto the virtual world is rendered. 7 | * For orthographic rendering, you can use {@link OrthographicUtil} to construct a suitable camera. 8 | */ 9 | public interface Camera { 10 | 11 | VectorXYZ pos(); 12 | 13 | VectorXYZ lookAt(); 14 | 15 | VectorXYZ up(); 16 | 17 | /** returns the view direction vector with length 1 */ 18 | default VectorXYZ getViewDirection() { 19 | return lookAt().subtract(pos()).normalize(); 20 | } 21 | 22 | /** 23 | * returns the vector that is orthogonal to the connection 24 | * between pos and lookAt and points to the right of it. 25 | * The result has length 1. 26 | */ 27 | default VectorXYZ getRight() { 28 | return getViewDirection().crossNormalized(up()); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/output/common/rendering/ImmutableCamera.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.output.common.rendering; 2 | 3 | import static org.osm2world.math.VectorXYZ.Y_UNIT; 4 | 5 | import org.osm2world.math.VectorXYZ; 6 | 7 | public record ImmutableCamera(VectorXYZ pos, VectorXYZ lookAt, VectorXYZ up) implements Camera { 8 | 9 | ImmutableCamera(VectorXYZ pos, VectorXYZ lookAt) { 10 | this(pos, lookAt, calculateUp(pos, lookAt)); 11 | } 12 | 13 | private static VectorXYZ calculateUp(VectorXYZ pos, VectorXYZ lookAt) { 14 | VectorXYZ direction = lookAt.subtract(pos).normalize(); 15 | VectorXYZ right = direction.crossNormalized(Y_UNIT); 16 | return right.crossNormalized(direction); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/output/common/rendering/OrthographicProjection.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.output.common.rendering; 2 | 3 | /** 4 | * An orthographic projection. 5 | * With this kind of projection, objects do not change size depending on their distance to the camera. 6 | * A popular example would be "isometric" video game graphics. 7 | * You can use {@link OrthographicUtil} to more comfortably set up typical projections. 8 | * 9 | * @param aspectRatio width / height 10 | * @param volumeHeight height of the viewing volume; only relevant for orthographic projection 11 | */ 12 | public record OrthographicProjection(double aspectRatio, double volumeHeight, 13 | double nearClippingDistance, double farClippingDistance) implements Projection { 14 | 15 | public OrthographicProjection(double aspectRatio, double volumeHeight) { 16 | this(aspectRatio, volumeHeight, -10000, 10000); 17 | } 18 | 19 | public OrthographicProjection withVolumeHeight(double newVolumeHeight) { 20 | return new OrthographicProjection(aspectRatio, newVolumeHeight, nearClippingDistance, farClippingDistance); 21 | } 22 | 23 | public OrthographicProjection withAspectRatio(double newAspectRatio) { 24 | return new OrthographicProjection(newAspectRatio, volumeHeight, nearClippingDistance, farClippingDistance); 25 | } 26 | 27 | @Override 28 | public Projection withClippingDistances(double nearClippingDistance, double farClippingDistance) { 29 | return new OrthographicProjection(aspectRatio, volumeHeight, nearClippingDistance, farClippingDistance); 30 | } 31 | 32 | @Override 33 | public boolean orthographic() { 34 | return true; 35 | } 36 | 37 | public double volumeWidth() { 38 | return aspectRatio() * volumeHeight(); 39 | } 40 | 41 | } -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/output/common/rendering/PerspectiveProjection.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.output.common.rendering; 2 | 3 | /** 4 | * A perspective projection. 5 | * This kind of projection produces a true 3D effect by making objects further from the camera appear smaller. 6 | * 7 | * @param aspectRatio width / height 8 | * @param vertAngle vertical viewing volume angle; only relevant for perspective projection 9 | */ 10 | public record PerspectiveProjection(double aspectRatio, double vertAngle, 11 | double nearClippingDistance, double farClippingDistance) implements Projection { 12 | 13 | public PerspectiveProjection(double aspectRatio, double vertAngle) { 14 | this(aspectRatio, vertAngle, 1, 50000); 15 | } 16 | 17 | public PerspectiveProjection withAspectRatio(double newAspectRatio) { 18 | return new PerspectiveProjection(newAspectRatio, vertAngle, 19 | nearClippingDistance, farClippingDistance); 20 | } 21 | 22 | @Override 23 | public Projection withClippingDistances(double nearClippingDistance, double farClippingDistance) { 24 | return new PerspectiveProjection(aspectRatio, vertAngle, nearClippingDistance, farClippingDistance); 25 | } 26 | 27 | @Override 28 | public boolean orthographic() { 29 | return false; 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/output/common/rendering/Projection.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.output.common.rendering; 2 | 3 | /** 4 | * configuration of the projection from 3D world to screen 5 | * (not the map projection). 6 | */ 7 | public interface Projection { 8 | 9 | /** whether this is an {@link OrthographicProjection} */ 10 | boolean orthographic(); 11 | 12 | /** width / height */ 13 | double aspectRatio(); 14 | 15 | double nearClippingDistance(); 16 | 17 | double farClippingDistance(); 18 | 19 | Projection withAspectRatio(double aspectRatio); 20 | 21 | Projection withClippingDistances(double nearClippingDistance, double farClippingDistance); 22 | 23 | } 24 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/output/frontend_pbf/package-info.java: -------------------------------------------------------------------------------- 1 | /** Output experimental Protobuf tiles in a custom format for WebGL rendering */ 2 | package org.osm2world.output.frontend_pbf; -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/output/gltf/data/Gltf.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.output.gltf.data; 2 | 3 | import java.util.List; 4 | 5 | import javax.annotation.Nullable; 6 | 7 | /** 8 | * a glTF asset. This is a simple mutable "struct" holding all data. 9 | * Refer to the spec at https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md for documentation. 10 | */ 11 | public class Gltf { 12 | 13 | public GltfAsset asset; 14 | public @Nullable List extensionsUsed; 15 | public @Nullable List extensionsRequired; 16 | public @Nullable List accessors; 17 | public @Nullable List animations; 18 | public @Nullable List buffers; 19 | public @Nullable List bufferViews; 20 | public @Nullable List cameras; 21 | public @Nullable List images; 22 | public @Nullable List materials; 23 | public @Nullable List meshes; 24 | public @Nullable List nodes; 25 | public @Nullable List samplers; 26 | public @Nullable Integer scene; 27 | public @Nullable List scenes; 28 | public @Nullable List skins; 29 | public @Nullable List textures; 30 | 31 | } 32 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/output/gltf/data/GltfAccessor.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.output.gltf.data; 2 | 3 | import java.util.Map; 4 | 5 | import javax.annotation.Nullable; 6 | 7 | public class GltfAccessor { 8 | 9 | public static final int TYPE_BYTE = 5120; 10 | public static final int TYPE_UNSIGNED_BYTE = 5121; 11 | public static final int TYPE_SHORT = 5122; 12 | public static final int TYPE_UNSIGNED_SHORT = 5123; 13 | public static final int TYPE_UNSIGNED_INT = 5125; 14 | public static final int TYPE_FLOAT = 5126; 15 | 16 | public @Nullable Integer bufferView; 17 | public @Nullable Integer byteOffset; 18 | public final int componentType; 19 | public @Nullable Boolean normalized; 20 | public final int count; 21 | public final String type; 22 | public @Nullable float[] max; 23 | public @Nullable float[] min; 24 | public @Nullable Object sparse; 25 | 26 | public @Nullable String name; 27 | public @Nullable Map extensions; 28 | public @Nullable Object extras; 29 | 30 | public GltfAccessor(int componentType, int count, String type) { 31 | 32 | if (count <= 0) { throw new IllegalArgumentException("invalid count: " + count); } 33 | 34 | this.componentType = componentType; 35 | this.count = count; 36 | this.type = type; 37 | 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/output/gltf/data/GltfAnimation.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.output.gltf.data; 2 | 3 | import java.util.Map; 4 | 5 | import javax.annotation.Nullable; 6 | 7 | public class GltfAnimation { 8 | 9 | // TODO implement (stub class) 10 | 11 | public @Nullable String name; 12 | public @Nullable Map extensions; 13 | public @Nullable Object extras; 14 | 15 | } 16 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/output/gltf/data/GltfAsset.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.output.gltf.data; 2 | 3 | public final class GltfAsset { 4 | 5 | public String version; 6 | public String generator; 7 | 8 | } 9 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/output/gltf/data/GltfBuffer.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.output.gltf.data; 2 | 3 | import java.util.Map; 4 | 5 | import javax.annotation.Nullable; 6 | 7 | public class GltfBuffer { 8 | 9 | public @Nullable String uri; 10 | public final int byteLength; 11 | 12 | public @Nullable String name; 13 | public @Nullable Map extensions; 14 | public @Nullable Object extras; 15 | 16 | public GltfBuffer(int byteLength) { 17 | this.byteLength = byteLength; 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/output/gltf/data/GltfBufferView.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.output.gltf.data; 2 | 3 | import java.util.Map; 4 | 5 | import javax.annotation.Nullable; 6 | 7 | public class GltfBufferView { 8 | 9 | public static final int TARGET_ARRAY_BUFFER = 34962; 10 | public static final int TARGET_ELEMENT_ARRAY_BUFFER = 34963; 11 | 12 | public final int buffer; 13 | public @Nullable Integer byteOffset; 14 | public final int byteLength; 15 | public @Nullable Integer byteStride; 16 | public @Nullable Integer target; 17 | 18 | public @Nullable String name; 19 | public @Nullable Map extensions; 20 | public @Nullable Object extras; 21 | 22 | public GltfBufferView(int buffer, int byteLength) { 23 | this.buffer = buffer; 24 | this.byteLength = byteLength; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/output/gltf/data/GltfCamera.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.output.gltf.data; 2 | 3 | import java.util.Map; 4 | 5 | import javax.annotation.Nullable; 6 | 7 | public class GltfCamera { 8 | 9 | // TODO implement (stub class) 10 | 11 | public @Nullable String name; 12 | public @Nullable Map extensions; 13 | public @Nullable Object extras; 14 | 15 | } 16 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/output/gltf/data/GltfImage.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.output.gltf.data; 2 | 3 | import java.util.Map; 4 | 5 | import javax.annotation.Nullable; 6 | 7 | public class GltfImage { 8 | 9 | public @Nullable String uri; 10 | public @Nullable String mimeType; 11 | public @Nullable Integer bufferView; 12 | 13 | public @Nullable String name; 14 | public @Nullable Map extensions; 15 | public @Nullable Object extras; 16 | 17 | } 18 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/output/gltf/data/GltfMaterial.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.output.gltf.data; 2 | 3 | import java.util.Map; 4 | 5 | import javax.annotation.Nullable; 6 | 7 | public class GltfMaterial { 8 | 9 | public static class TextureInfo { 10 | 11 | public int index; 12 | public @Nullable Integer texCoord; 13 | 14 | public @Nullable Map extensions; 15 | public @Nullable Object extras; 16 | 17 | } 18 | 19 | public static class NormalTextureInfo extends TextureInfo { 20 | public @Nullable Float scale; 21 | } 22 | 23 | public static class OcclusionTextureInfo extends TextureInfo { 24 | public @Nullable Float strength; 25 | } 26 | 27 | public static class PbrMetallicRoughness { 28 | 29 | public @Nullable float[] baseColorFactor; 30 | public @Nullable TextureInfo baseColorTexture; 31 | public @Nullable Float metallicFactor; 32 | public @Nullable Float roughnessFactor; 33 | public @Nullable TextureInfo metallicRoughnessTexture; 34 | 35 | public @Nullable Map extensions; 36 | public @Nullable Object extras; 37 | 38 | } 39 | 40 | public @Nullable PbrMetallicRoughness pbrMetallicRoughness; 41 | public @Nullable NormalTextureInfo normalTexture; 42 | public @Nullable OcclusionTextureInfo occlusionTexture; 43 | public @Nullable TextureInfo emissiveTexture; 44 | public @Nullable float[] emissiveFactor; 45 | public @Nullable String alphaMode; 46 | public @Nullable Float alphaCutoff; 47 | public @Nullable Boolean doubleSided; 48 | 49 | public @Nullable String name; 50 | public @Nullable Map extensions; 51 | public @Nullable Object extras; 52 | 53 | } 54 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/output/gltf/data/GltfMesh.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.output.gltf.data; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashMap; 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | import javax.annotation.Nullable; 9 | 10 | public class GltfMesh { 11 | 12 | public static final int POINTS = 0; 13 | public static final int LINES = 1; 14 | public static final int LINE_LOOP = 2; 15 | public static final int LINE_STRIP = 3; 16 | public static final int TRIANGLES = 4; 17 | public static final int TRIANGLE_STRIP = 5; 18 | public static final int TRIANGLE_FAN = 6; 19 | 20 | public static class Primitive { 21 | 22 | public Map attributes = new HashMap<>(); 23 | public @Nullable Integer indices; 24 | public @Nullable Integer material; 25 | public @Nullable Integer mode; 26 | 27 | public @Nullable Map extensions; 28 | public @Nullable Object extras; 29 | 30 | } 31 | 32 | public List primitives = new ArrayList<>(); 33 | public @Nullable List weights; 34 | 35 | public @Nullable String name; 36 | public @Nullable Map extensions; 37 | public @Nullable Object extras; 38 | 39 | } 40 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/output/gltf/data/GltfNode.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.output.gltf.data; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | 6 | import javax.annotation.Nullable; 7 | 8 | public class GltfNode { 9 | 10 | public @Nullable Integer camera; 11 | public @Nullable List children; 12 | public @Nullable Integer skin; 13 | public @Nullable float[] matrix; 14 | public @Nullable Integer mesh; 15 | public @Nullable float[] rotation; 16 | public @Nullable float[] scale; 17 | public @Nullable float[] translation; 18 | public @Nullable List weights; 19 | 20 | public @Nullable String name; 21 | public @Nullable Map extensions; 22 | public @Nullable Object extras; 23 | 24 | public TransformationMatrix getLocalTransform() { 25 | 26 | if (matrix != null) { 27 | return new TransformationMatrix(matrix); 28 | } else { 29 | 30 | float[] translation = this.translation != null ? this.translation : new float[] {0, 0, 0}; 31 | float[] rotation = this.rotation != null ? this.rotation : new float[] {0, 0, 0, 1}; 32 | float[] scale = this.scale != null ? this.scale : new float[] {1, 1, 1}; 33 | 34 | return TransformationMatrix.forTRS(translation, rotation, scale); 35 | 36 | } 37 | 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/output/gltf/data/GltfSampler.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.output.gltf.data; 2 | 3 | import java.util.Map; 4 | 5 | import javax.annotation.Nullable; 6 | 7 | public class GltfSampler { 8 | 9 | //TODO more constants, turn into enums with int field 10 | public static final int WRAP_CLAMP_TO_EDGE = 33071; 11 | public static final int WRAP_MIRRORED_REPEAT = 33648; 12 | public static final int WRAP_REPEAT = 10497; 13 | 14 | public static final int NEAREST = 9728; 15 | public static final int LINEAR = 9729; 16 | public static final int NEAREST_MIPMAP_NEAREST = 9984; 17 | public static final int LINEAR_MIPMAP_NEAREST = 9985; 18 | public static final int NEAREST_MIPMAP_LINEAR = 9986; 19 | public static final int LINEAR_MIPMAP_LINEAR = 9987; 20 | 21 | public @Nullable Integer minFilter; 22 | public @Nullable Integer magFilter; 23 | public @Nullable Integer wrapS; 24 | public @Nullable Integer wrapT; 25 | 26 | public @Nullable String name; 27 | public @Nullable Map extensions; 28 | public @Nullable Object extras; 29 | 30 | } 31 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/output/gltf/data/GltfScene.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.output.gltf.data; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | 6 | import javax.annotation.Nullable; 7 | 8 | public class GltfScene { 9 | 10 | public List nodes; 11 | 12 | public @Nullable String name; 13 | public @Nullable Map extensions; 14 | public @Nullable Object extras; 15 | 16 | } 17 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/output/gltf/data/GltfSkin.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.output.gltf.data; 2 | 3 | import java.util.Map; 4 | 5 | import javax.annotation.Nullable; 6 | 7 | public class GltfSkin { 8 | 9 | // TODO implement (stub class) 10 | 11 | public @Nullable String name; 12 | public @Nullable Map extensions; 13 | public @Nullable Object extras; 14 | 15 | } 16 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/output/gltf/data/GltfTexture.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.output.gltf.data; 2 | 3 | import java.util.Map; 4 | 5 | import javax.annotation.Nullable; 6 | 7 | public class GltfTexture { 8 | 9 | public @Nullable Integer sampler; 10 | public @Nullable Integer source; 11 | 12 | public @Nullable String name; 13 | public @Nullable Map extensions; 14 | public @Nullable Object extras; 15 | 16 | } 17 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/output/gltf/package-info.java: -------------------------------------------------------------------------------- 1 | /** Output glTF and glb models. */ 2 | package org.osm2world.output.gltf; -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/output/obj/package-info.java: -------------------------------------------------------------------------------- 1 | 2 | /** Output Wavefront .obj and .mtl files. */ 3 | package org.osm2world.output.obj; -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/output/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Export targets for the generated models. 3 | *

4 | * Each implementation of {@link org.osm2world.output.Output} 5 | * represents some output format which is supported by OSM2World. 6 | */ 7 | package org.osm2world.output; -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/output/povray/package-info.java: -------------------------------------------------------------------------------- 1 | /** Output .pov files for the POVRay raytracer. */ 2 | package org.osm2world.output.povray; -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/output/statistics/package-info.java: -------------------------------------------------------------------------------- 1 | /** Collect statistics about the scene created by OSM2World */ 2 | package org.osm2world.output.statistics; -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Parent package for all OSM2World classes and subpackages. 3 | * Contains {@link org.osm2world.O2WConverter}, the starting point for using OSM2World as a library. 4 | */ 5 | package org.osm2world; -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/scene/color/ColorNameDefinition.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.scene.color; 2 | 3 | import java.awt.Color; 4 | 5 | /** a mapping from color names to RGB colors */ 6 | public interface ColorNameDefinition { 7 | 8 | /** returns true if the given name is a known color name */ 9 | public default boolean contains(String name) { 10 | return get(name) != null; 11 | } 12 | 13 | /** returns the RGB color for that name, or null if it isn't a known color name */ 14 | public Color get(String name); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/scene/material/BlankTexture.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.scene.material; 2 | 3 | import java.awt.image.BufferedImage; 4 | 5 | import org.osm2world.scene.texcoord.NamedTexCoordFunction; 6 | import org.osm2world.util.Resolution; 7 | 8 | 9 | public final class BlankTexture extends RuntimeTexture { 10 | 11 | public static final BlankTexture INSTANCE = new BlankTexture(); 12 | private static final Resolution RESOLUTION = new Resolution(128, 128); 13 | 14 | private BlankTexture(TextureDataDimensions dimensions) { 15 | super(dimensions, Wrap.REPEAT, NamedTexCoordFunction.GLOBAL_X_Z); 16 | } 17 | 18 | private BlankTexture() { 19 | this(new TextureDataDimensions(1.0, 1.0)); 20 | } 21 | 22 | @Override 23 | protected BufferedImage createBufferedImage(Resolution resolution) { 24 | return new BufferedImage(resolution.width, resolution.height, BufferedImage.TYPE_INT_RGB); 25 | } 26 | 27 | @Override 28 | protected BufferedImage createBufferedImage() { 29 | return getBufferedImage(RESOLUTION); 30 | } 31 | 32 | @Override 33 | public float getAspectRatio() { 34 | return RESOLUTION.getAspectRatio(); 35 | } 36 | 37 | @Override 38 | public String toString() { 39 | return "Blank"; 40 | } 41 | 42 | @Override 43 | public boolean equals(Object obj) { 44 | return obj == this; 45 | } 46 | 47 | @Override 48 | public int hashCode() { 49 | return 42; 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/scene/material/ImageFileTexture.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.scene.material; 2 | 3 | import java.io.File; 4 | import java.util.function.Function; 5 | 6 | import javax.annotation.Nullable; 7 | 8 | import org.osm2world.scene.texcoord.TexCoordFunction; 9 | 10 | import com.google.common.base.Objects; 11 | 12 | public abstract class ImageFileTexture extends TextureData { 13 | 14 | /** 15 | * Path to the texture file. 16 | * Represents a permanent, already saved image file in contrast to {@link RuntimeTexture}'s temporary image file. 17 | */ 18 | protected final File file; 19 | 20 | protected ImageFileTexture(File file, TextureDataDimensions dimensions, Wrap wrap, 21 | Function texCoordFunction) { 22 | super(dimensions, wrap, texCoordFunction); 23 | this.file = file; 24 | } 25 | 26 | public static ImageFileTexture create(File file, TextureDataDimensions dimensions, Wrap wrap, 27 | @Nullable Function texCoordFunction) { 28 | if (file.getName().endsWith(".svg")) { 29 | return new SvgImageFileTexture(file, dimensions, wrap, texCoordFunction); 30 | } else { 31 | return new RasterImageFileTexture(file, dimensions, wrap, texCoordFunction); 32 | } 33 | } 34 | 35 | public File getFile() { 36 | return file; 37 | } 38 | 39 | @Override 40 | public String toString() { 41 | return file.getName(); 42 | } 43 | 44 | @Override 45 | public boolean equals(Object obj) { 46 | return obj instanceof ImageFileTexture 47 | && Objects.equal(this.file, ((ImageFileTexture)obj).file); 48 | } 49 | 50 | @Override 51 | public int hashCode() { 52 | return file.hashCode(); 53 | } 54 | 55 | } -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/scene/material/RasterImageFileTexture.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.scene.material; 2 | 3 | import static org.osm2world.scene.material.RasterImageFormat.JPEG; 4 | import static org.osm2world.scene.material.RasterImageFormat.PNG; 5 | 6 | import java.awt.image.BufferedImage; 7 | import java.io.File; 8 | import java.io.IOException; 9 | import java.util.function.Function; 10 | 11 | import javax.imageio.ImageIO; 12 | 13 | import org.osm2world.scene.texcoord.TexCoordFunction; 14 | 15 | public class RasterImageFileTexture extends ImageFileTexture { 16 | 17 | public RasterImageFileTexture(File file, TextureDataDimensions dimensions, Wrap wrap, 18 | Function texCoordFunction) { 19 | super(file, dimensions, wrap, texCoordFunction); 20 | } 21 | 22 | @Override 23 | protected BufferedImage createBufferedImage() { 24 | try { 25 | return ImageIO.read(this.file); 26 | } catch (IOException e) { 27 | throw new Error("Could not read texture file " + file, e); 28 | } 29 | } 30 | 31 | @Override 32 | public RasterImageFormat getRasterImageFormat() { 33 | return (getFile().getName().endsWith(".png")) ? PNG : JPEG; 34 | } 35 | 36 | } -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/scene/material/RasterImageFormat.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.scene.material; 2 | 3 | import java.awt.image.RenderedImage; 4 | import java.io.File; 5 | 6 | public enum RasterImageFormat { 7 | 8 | PNG, JPEG; 9 | 10 | /** returns a String that can be used for {@link javax.imageio.ImageIO#write(RenderedImage, String, File)} */ 11 | public String imageIOFormatName() { 12 | return toString().toLowerCase(); 13 | } 14 | 15 | public String mimeType() { 16 | return "image/" + toString().toLowerCase(); 17 | } 18 | 19 | public String fileExtension() { 20 | return switch (this) { 21 | case PNG -> "png"; 22 | case JPEG -> "jpg"; 23 | }; 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/scene/material/RuntimeTexture.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.scene.material; 2 | 3 | import java.util.function.Function; 4 | 5 | import org.osm2world.scene.texcoord.TexCoordFunction; 6 | 7 | /** 8 | * a texture that is only generated (or turned into an image from some input data) during application runtime 9 | */ 10 | public abstract class RuntimeTexture extends TextureData { 11 | 12 | protected RuntimeTexture(TextureDataDimensions dimensions, Wrap wrap, 13 | Function texCoordFunction) { 14 | super(dimensions, wrap, texCoordFunction); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/scene/material/UriTexture.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.scene.material; 2 | 3 | import java.awt.image.BufferedImage; 4 | import java.io.IOException; 5 | import java.net.URI; 6 | import java.util.Objects; 7 | import java.util.function.Function; 8 | 9 | import javax.imageio.ImageIO; 10 | 11 | import org.osm2world.scene.texcoord.TexCoordFunction; 12 | 13 | public class UriTexture extends RuntimeTexture { 14 | 15 | private final URI imageUri; 16 | 17 | public UriTexture(URI imageUri, TextureDataDimensions dimensions, Wrap wrap, 18 | Function texCoordFunction) { 19 | super(dimensions, wrap, texCoordFunction); 20 | this.imageUri = imageUri; 21 | } 22 | 23 | @Override protected BufferedImage createBufferedImage() { 24 | try { 25 | return ImageIO.read(imageUri.toURL()); 26 | } catch (IOException e) { 27 | throw new RuntimeException("Could not read texture from URI " + imageUri, e); 28 | } 29 | } 30 | 31 | @Override 32 | public String toString() { 33 | return imageUri.toString(); 34 | } 35 | 36 | @Override 37 | public final boolean equals(Object o) { 38 | return o instanceof UriTexture that 39 | && Objects.equals(imageUri, that.imageUri); 40 | } 41 | 42 | @Override 43 | public int hashCode() { 44 | return Objects.hashCode(imageUri); 45 | } 46 | 47 | } -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/scene/mesh/LODRange.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.scene.mesh; 2 | 3 | import java.util.Arrays; 4 | 5 | import javax.annotation.Nullable; 6 | 7 | /** a range between two {@link LevelOfDetail} values (inclusive) */ 8 | public record LODRange(LevelOfDetail min, LevelOfDetail max) { 9 | 10 | public LODRange { 11 | if (min.ordinal() > max.ordinal()) { 12 | throw new IllegalArgumentException(min + " is larger than " + max); 13 | } 14 | } 15 | 16 | public LODRange(LevelOfDetail lod) { 17 | this(lod, lod); 18 | } 19 | 20 | @Override 21 | public String toString() { 22 | return "LOD " + min.ordinal() + "-" + max.ordinal(); 23 | } 24 | 25 | public boolean contains(LevelOfDetail lod) { 26 | return min.ordinal() <= lod.ordinal() && lod.ordinal() <= max.ordinal(); 27 | } 28 | 29 | /** returns the intersection of the ranges, or null if the intersection is empty */ 30 | public static @Nullable LODRange intersection(LODRange... ranges) { 31 | if (ranges.length == 0) throw new IllegalArgumentException(); 32 | var min = Arrays.stream(ranges).map(it -> it.min).max(LevelOfDetail::compareTo).get(); 33 | var max = Arrays.stream(ranges).map(it -> it.max).min(LevelOfDetail::compareTo).get(); 34 | if (min.ordinal() > max.ordinal()) { 35 | return null; 36 | } else { 37 | return new LODRange(min, max); 38 | } 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/scene/mesh/LevelOfDetail.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.scene.mesh; 2 | 3 | import javax.annotation.Nullable; 4 | 5 | /** 6 | * level of detail, from lowest (0) to highest (4). 7 | * Describes a point on the spectrum of trade-offs between performance and quality. 8 | * OSM2World's levels do not strictly conform to any particular standard. 9 | */ 10 | public enum LevelOfDetail implements Comparable { 11 | 12 | LOD0, LOD1, LOD2, LOD3, LOD4; 13 | 14 | public static @Nullable LevelOfDetail fromInt(@Nullable Integer lod) { 15 | if (lod != null) { 16 | return switch (lod) { 17 | case 0, 1, 2, 3, 4 -> values()[lod]; 18 | default -> null; 19 | }; 20 | } 21 | return null; 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/scene/mesh/Mesh.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.scene.mesh; 2 | 3 | import org.osm2world.scene.material.Material; 4 | 5 | public class Mesh { 6 | 7 | public final Geometry geometry; 8 | public final Material material; 9 | public final LODRange lodRange; 10 | 11 | public Mesh(Geometry geometry, Material material) { 12 | this(geometry, material, LevelOfDetail.LOD0, LevelOfDetail.LOD4); 13 | } 14 | 15 | public Mesh(Geometry geometry, Material material, LevelOfDetail lod) { 16 | this(geometry, material, lod, lod); 17 | } 18 | 19 | public Mesh(Geometry geometry, Material material, LevelOfDetail lodRangeMin, LevelOfDetail lodRangeMax) { 20 | this(geometry, material, new LODRange(lodRangeMin, lodRangeMax)); 21 | } 22 | 23 | public Mesh(Geometry geometry, Material material, LODRange lodRange) { 24 | 25 | this.geometry = geometry; 26 | this.material = material; 27 | this.lodRange = lodRange; 28 | 29 | if (geometry instanceof TriangleGeometry tg && tg.texCoords.size() != material.getNumTextureLayers()) { 30 | throw new IllegalArgumentException("incorrect number of texCoord layers"); 31 | } 32 | 33 | } 34 | 35 | @Override 36 | public String toString() { 37 | return "Mesh(" + lodRange + ", " + geometry.getClass().getSimpleName() + ")"; 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/scene/model/ExternalResourceModel.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.scene.model; 2 | 3 | import java.util.List; 4 | 5 | import org.osm2world.scene.mesh.Mesh; 6 | 7 | /** 8 | * A model referencing an external resource, such as a URI 9 | */ 10 | public record ExternalResourceModel(String resourceIdentifier) implements Model { 11 | 12 | @Override 13 | public List buildMeshes(InstanceParameters params) { 14 | // TODO implement - right now this only works for the FrontendPbfTarget, others will just show nothing 15 | return List.of(); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/scene/model/Model.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.scene.model; 2 | 3 | import static org.osm2world.math.VectorXYZ.NULL_VECTOR; 4 | 5 | import java.util.List; 6 | 7 | import org.osm2world.scene.mesh.Mesh; 8 | 9 | /** 10 | * a single 3D model, defined in code or loaded from a file or other resource 11 | */ 12 | public interface Model { 13 | 14 | /** 15 | * returns the meshes making up this {@link Model} 16 | */ 17 | default List getMeshes() { 18 | return buildMeshes(new InstanceParameters(NULL_VECTOR, 0)); 19 | } 20 | 21 | /** 22 | * returns the meshes making up an instance of this {@link Model}. 23 | */ 24 | List buildMeshes(InstanceParameters params); 25 | 26 | } -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/scene/model/ModelInstance.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.scene.model; 2 | 3 | import java.util.List; 4 | 5 | import org.osm2world.output.CommonTarget; 6 | import org.osm2world.scene.mesh.Mesh; 7 | 8 | /** 9 | * one instance of a {@link Model} 10 | */ 11 | public record ModelInstance(Model model, InstanceParameters params) { 12 | 13 | /** 14 | * returns the model's meshes, with transformations based on {@link #params} already applied to them. 15 | */ 16 | public List getMeshes() { 17 | return model.buildMeshes(params); 18 | } 19 | 20 | /** 21 | * draws the result of {@link #getMeshes()} to any target 22 | */ 23 | public void render(CommonTarget target) { 24 | getMeshes().forEach(target::drawMesh); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/scene/model/ProceduralModel.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.scene.model; 2 | 3 | import java.util.List; 4 | 5 | import org.osm2world.output.CommonTarget; 6 | import org.osm2world.output.common.MeshOutput; 7 | import org.osm2world.scene.mesh.Mesh; 8 | 9 | /** 10 | * a model which is generated by code during runtime, 11 | * rather than being loaded as a static asset. 12 | */ 13 | public interface ProceduralModel extends Model { 14 | 15 | @Override 16 | default List buildMeshes(InstanceParameters params) { 17 | MeshOutput target = new MeshOutput(); 18 | this.render(target, params); 19 | return target.getMeshes(); 20 | } 21 | 22 | /** 23 | * draws an instance of the model to any {@link CommonTarget} 24 | * 25 | * @param target target for the model; != null 26 | */ 27 | void render(CommonTarget target, InstanceParameters params); 28 | 29 | } 30 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/scene/package-info.java: -------------------------------------------------------------------------------- 1 | /** OSM2World's internal representation of a 3D scene for a part of the world. */ 2 | package org.osm2world.scene; -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/scene/texcoord/FaceFitTexCoordFunction.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.scene.texcoord; 2 | 3 | import static org.osm2world.scene.texcoord.TexCoordUtil.applyPadding; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | import org.osm2world.math.VectorXYZ; 9 | import org.osm2world.math.VectorXZ; 10 | import org.osm2world.math.shapes.AxisAlignedRectangleXZ; 11 | import org.osm2world.math.shapes.FaceXYZ; 12 | import org.osm2world.math.shapes.SimplePolygonXZ; 13 | import org.osm2world.scene.material.TextureDataDimensions; 14 | 15 | /** 16 | * fits an image onto a flat polygon. 17 | * Vertices must represent the vertex loop of a {@link FaceXYZ} 18 | */ 19 | public record FaceFitTexCoordFunction(TextureDataDimensions textureDimensions) implements TexCoordFunction { 20 | 21 | @Override 22 | public List apply(List vs) { 23 | 24 | List result = new ArrayList<>(vs.size()); 25 | 26 | FaceXYZ face = new FaceXYZ(vs); 27 | SimplePolygonXZ faceXZ = face.toFacePlane(face); 28 | AxisAlignedRectangleXZ faceBbox = faceXZ.boundingBox(); 29 | 30 | for (VectorXZ v : faceXZ.vertices()) { 31 | VectorXZ vRelative = v.subtract(faceBbox.bottomLeft()); 32 | VectorXZ rawTexCoord = new VectorXZ(vRelative.x / faceBbox.sizeX(), vRelative.z / faceBbox.sizeZ()); 33 | result.add(applyPadding(rawTexCoord, textureDimensions)); 34 | } 35 | 36 | return result; 37 | 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/scene/texcoord/GlobalXYTexCoordFunction.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.scene.texcoord; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.osm2world.math.VectorXYZ; 7 | import org.osm2world.math.VectorXZ; 8 | import org.osm2world.scene.material.TextureDataDimensions; 9 | 10 | /** 11 | * like {@link GlobalXZTexCoordFunction}, but uses y instead of z dimension. 12 | * Better suited for certain vertical surfaces. 13 | */ 14 | public record GlobalXYTexCoordFunction(TextureDataDimensions textureDimensions) implements TexCoordFunction { 15 | 16 | @Override 17 | public List apply(List vs) { 18 | 19 | List result = new ArrayList<>(vs.size()); 20 | 21 | for (VectorXYZ v : vs) { 22 | result.add(new VectorXZ( 23 | v.x / textureDimensions.width(), 24 | v.y / textureDimensions.height())); 25 | } 26 | 27 | return result; 28 | 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/scene/texcoord/GlobalXZTexCoordFunction.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.scene.texcoord; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.osm2world.math.VectorXYZ; 7 | import org.osm2world.math.VectorXZ; 8 | import org.osm2world.scene.material.TextureDataDimensions; 9 | 10 | /** 11 | * uses x and z vertex coords together with the texture's width and height 12 | * to place a texture. This function works for all geometries, 13 | * but steep inclines or even vertical walls produce odd-looking results. 14 | */ 15 | public record GlobalXZTexCoordFunction(TextureDataDimensions textureDimensions) implements TexCoordFunction { 16 | 17 | @Override 18 | public List apply(List vs) { 19 | 20 | List result = new ArrayList<>(vs.size()); 21 | 22 | for (VectorXYZ v : vs) { 23 | result.add(TexCoordUtil.applyPadding(new VectorXZ( 24 | v.x / textureDimensions.width(), 25 | v.z / textureDimensions.height()), 26 | this.textureDimensions)); 27 | } 28 | 29 | return result; 30 | 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/scene/texcoord/GlobalZYTexCoordFunction.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.scene.texcoord; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.osm2world.math.VectorXYZ; 7 | import org.osm2world.math.VectorXZ; 8 | import org.osm2world.scene.material.TextureDataDimensions; 9 | 10 | /** 11 | * like {@link GlobalXZTexCoordFunction}, but uses y instead of x dimension. 12 | * Better suited for certain vertical surfaces. 13 | */ 14 | public record GlobalZYTexCoordFunction(TextureDataDimensions textureDimensions) implements TexCoordFunction { 15 | 16 | @Override 17 | public List apply(List vs) { 18 | 19 | List result = new ArrayList<>(vs.size()); 20 | 21 | for (VectorXYZ v : vs) { 22 | result.add(TexCoordUtil.applyPadding(new VectorXZ( 23 | v.z / textureDimensions.width(), 24 | v.y / textureDimensions.height()), 25 | textureDimensions)); 26 | } 27 | 28 | return result; 29 | 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/scene/texcoord/PrecomputedTexCoordFunction.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.scene.texcoord; 2 | 3 | import static java.util.Collections.*; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | import org.osm2world.math.VectorXYZ; 9 | import org.osm2world.math.VectorXZ; 10 | 11 | /** 12 | * a texture coordinate function that stores a known texture coordinate for each vertex. 13 | * Unlike {@link MapBasedTexCoordFunction}, this allows vertices in the same location to have different texture coords. 14 | */ 15 | public class PrecomputedTexCoordFunction implements TexCoordFunction { 16 | 17 | public final List texCoords; 18 | 19 | public PrecomputedTexCoordFunction(List texCoords) { 20 | this.texCoords = unmodifiableList(texCoords); 21 | } 22 | 23 | @Override 24 | public List apply(List vs) { 25 | if (vs.size() != texCoords.size()) { 26 | throw new IllegalArgumentException("incorrect number of vertices"); 27 | } 28 | return texCoords; 29 | } 30 | 31 | public static PrecomputedTexCoordFunction merge(List texCoordFunctions) { 32 | 33 | switch (texCoordFunctions.size()) { 34 | case 0: return new PrecomputedTexCoordFunction(emptyList()); 35 | case 1: return texCoordFunctions.get(0); 36 | } 37 | 38 | List mergedList = new ArrayList<>(); 39 | 40 | for (PrecomputedTexCoordFunction texCoordFunction : texCoordFunctions) { 41 | mergedList.addAll(texCoordFunction.texCoords); 42 | } 43 | 44 | return new PrecomputedTexCoordFunction(mergedList); 45 | 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/scene/texcoord/TexCoordFunction.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.scene.texcoord; 2 | 3 | import java.util.List; 4 | 5 | import org.osm2world.math.VectorXYZ; 6 | import org.osm2world.math.VectorXZ; 7 | import org.osm2world.output.Output; 8 | 9 | /** 10 | * the function used to calculate texture coordinates for each vertex from 11 | * a collection. Some implementations only make sense for certain geometries 12 | * (e.g. vertices forming triangle strips). 13 | *

14 | * The origin of OSM2World's texture coordinates is in the lower left corner of a texture image. 15 | * For output formats with a different convention, {@link Output} need to convert texture coordinates accordingly 16 | * (e.g. by calculating {@code z = 1.0 - z} for an origin in the top left corner). 17 | */ 18 | @FunctionalInterface 19 | public interface TexCoordFunction { 20 | 21 | /** 22 | * calculates a texture coordinate for each vertex 23 | */ 24 | public List apply(List vs); 25 | 26 | } 27 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/util/enums/ForwardBackward.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.util.enums; 2 | 3 | import javax.annotation.Nullable; 4 | 5 | public enum ForwardBackward { 6 | 7 | FORWARD, BACKWARD; 8 | 9 | public ForwardBackward invert() { 10 | return this == FORWARD ? BACKWARD : FORWARD; 11 | } 12 | 13 | public static @Nullable ForwardBackward of(String s) { 14 | if (s == null) return null; 15 | try { 16 | return ForwardBackward.valueOf(s.trim().toUpperCase()); 17 | } catch (IllegalArgumentException ex) { 18 | return null; 19 | } 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/util/enums/ForwardBackwardBoth.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.util.enums; 2 | 3 | import static java.util.Objects.requireNonNull; 4 | 5 | import javax.annotation.Nullable; 6 | 7 | public enum ForwardBackwardBoth { 8 | 9 | FORWARD, BACKWARD, BOTH; 10 | 11 | public ForwardBackwardBoth invert() { 12 | switch (this) { 13 | case FORWARD: return BACKWARD; 14 | case BACKWARD: return FORWARD; 15 | default: return BOTH; 16 | } 17 | } 18 | 19 | public static @Nullable ForwardBackwardBoth of(String s) { 20 | if (s == null) return null; 21 | try { 22 | return ForwardBackwardBoth.valueOf(s.trim().toUpperCase()); 23 | } catch (IllegalArgumentException ex) { 24 | return null; 25 | } 26 | } 27 | 28 | public static ForwardBackwardBoth of(ForwardBackward value) { 29 | switch (requireNonNull(value)) { 30 | case FORWARD: return FORWARD; 31 | case BACKWARD: return BACKWARD; 32 | default: throw new Error("unknown value"); 33 | } 34 | } 35 | 36 | public static @Nullable ForwardBackwardBoth ofNullable(@Nullable ForwardBackward value) { 37 | if (value == null) return null; 38 | switch (value) { 39 | case FORWARD: return FORWARD; 40 | case BACKWARD: return BACKWARD; 41 | default: throw new Error("unknown value"); 42 | } 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/util/enums/LeftRight.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.util.enums; 2 | 3 | import javax.annotation.Nullable; 4 | 5 | public enum LeftRight { 6 | 7 | LEFT, RIGHT; 8 | 9 | public LeftRight invert() { 10 | return this == LEFT ? RIGHT : LEFT; 11 | } 12 | 13 | public static @Nullable LeftRight of(String s) { 14 | if (s == null) return null; 15 | try { 16 | return LeftRight.valueOf(s.trim().toUpperCase()); 17 | } catch (IllegalArgumentException ex) { 18 | return null; 19 | } 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/util/enums/LeftRightBoth.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.util.enums; 2 | 3 | import static java.util.Objects.requireNonNull; 4 | 5 | import javax.annotation.Nullable; 6 | 7 | public enum LeftRightBoth { 8 | 9 | LEFT, RIGHT, BOTH; 10 | 11 | public static @Nullable LeftRightBoth of(String s) { 12 | if (s == null) return null; 13 | try { 14 | return LeftRightBoth.valueOf(s.trim().toUpperCase()); 15 | } catch (IllegalArgumentException ex) { 16 | return null; 17 | } 18 | } 19 | 20 | public static LeftRightBoth of(LeftRight value) { 21 | switch (requireNonNull(value)) { 22 | case LEFT: return LEFT; 23 | case RIGHT: return RIGHT; 24 | default: throw new Error("unknown value"); 25 | } 26 | } 27 | 28 | public static @Nullable LeftRightBoth ofNullable(@Nullable LeftRight value) { 29 | if (value == null) return null; 30 | switch (value) { 31 | case LEFT: return LEFT; 32 | case RIGHT: return RIGHT; 33 | default: throw new Error("unknown value"); 34 | } 35 | } 36 | 37 | public boolean isLeftOrBoth() { 38 | return this == LEFT || this == BOTH; 39 | } 40 | 41 | public boolean isRightOrBoth() { 42 | return this == RIGHT || this == BOTH; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/util/exception/InvalidGeometryException.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.util.exception; 2 | 3 | /** 4 | * exception that is used when attempting to construct geometry that 5 | * does not exhibit required properties - such as self-intersecting polygons. 6 | * In cases where these exceptions can be caused by problems in the data, 7 | * it makes sense to catch and report them. 8 | */ 9 | public class InvalidGeometryException extends RuntimeException { 10 | 11 | private static final long serialVersionUID = -7755970537446437611L; //generated serialVersionUID 12 | 13 | public InvalidGeometryException() { 14 | super(); 15 | } 16 | 17 | public InvalidGeometryException(String message, Throwable cause) { 18 | super(message, cause); 19 | } 20 | 21 | public InvalidGeometryException(String message) { 22 | super(message); 23 | } 24 | 25 | public InvalidGeometryException(Throwable cause) { 26 | super(cause); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/util/exception/TriangulationException.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.util.exception; 2 | 3 | /** 4 | * error caused by an unsuccessful triangulation attempt 5 | */ 6 | public class TriangulationException extends Exception { 7 | 8 | private static final long serialVersionUID = 1L; 9 | 10 | public TriangulationException(String message, Throwable cause) { 11 | super(message, cause); 12 | } 13 | 14 | public TriangulationException(String message) { 15 | super(message); 16 | } 17 | 18 | public TriangulationException(Throwable cause) { 19 | super(cause); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/util/functions/CheckedConsumer.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.util.functions; 2 | 3 | /** equivalent to a {@link java.util.function.Consumer} that throws checked exceptions */ 4 | @FunctionalInterface 5 | public interface CheckedConsumer { 6 | void accept(T t) throws E; 7 | } 8 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/util/functions/DefaultFactory.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.util.functions; 2 | 3 | 4 | /** 5 | * creates new instances of a class by calling the standard constructor. 6 | * In many cases, this is the simplest way of obtaining a {@link Factory} 7 | * for a given class. 8 | */ 9 | public class DefaultFactory implements Factory { 10 | 11 | private final Class c; 12 | 13 | public DefaultFactory(Class c) { 14 | this.c = c; 15 | } 16 | 17 | @Override 18 | public T get() { 19 | try { 20 | return c.newInstance(); 21 | } catch (InstantiationException e) { 22 | throw new Error(e); 23 | } catch (IllegalAccessException e) { 24 | throw new Error(e); 25 | } 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/util/functions/Factory.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.util.functions; 2 | 3 | import java.util.function.Supplier; 4 | 5 | /** 6 | * Creates instances of another object type. 7 | * Unlike {@link Supplier}, this must create a new instance for each call of {@link #get()}. 8 | * 9 | * @param the type of objects created by this factory 10 | */ 11 | @FunctionalInterface 12 | public interface Factory extends Supplier {} 13 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/util/package-info.java: -------------------------------------------------------------------------------- 1 | /** Utility classes that are used throughout OSM2World */ 2 | package org.osm2world.util; -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/util/test/TestFileUtil.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.util.test; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.nio.file.Files; 6 | 7 | import javax.annotation.Nonnull; 8 | 9 | public final class TestFileUtil { 10 | 11 | /** prevents instantiation */ 12 | private TestFileUtil() {} 13 | 14 | /** loads a test file as a resource */ 15 | public static @Nonnull File getTestFile(String name) { 16 | ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); 17 | var resource = classLoader.getResource(name); 18 | if (resource == null) throw new AssertionError("Test file '" + name + "' not found"); 19 | return new File(resource.getFile()); 20 | } 21 | 22 | /** creates a temporary file for use in tests */ 23 | public static File createTempFile(String prefix, String suffix) { 24 | try { 25 | var tempFile = Files.createTempFile(prefix, suffix).toFile(); 26 | tempFile.deleteOnExit(); 27 | return tempFile.getAbsoluteFile(); 28 | } catch (IOException e) { 29 | throw new AssertionError(e); 30 | } 31 | } 32 | 33 | /** creates a temporary file for use in tests */ 34 | public static File createTempFile(String suffix) { 35 | return createTempFile("o2w-test-", suffix); 36 | } 37 | 38 | /** creates a temporary directory for use in tests */ 39 | public static File createTempDirectory() { 40 | try { 41 | var tempDir = Files.createTempDirectory("o2w-test-").toFile(); 42 | tempDir.deleteOnExit(); 43 | return tempDir.getAbsoluteFile(); 44 | } catch (IOException e) { 45 | throw new AssertionError(e); 46 | } 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/util/test/package-info.java: -------------------------------------------------------------------------------- 1 | /** classes for use in unit tests */ 2 | package org.osm2world.util.test; -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/world/creation/WorldCreator.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.world.creation; 2 | 3 | import java.util.Arrays; 4 | import java.util.List; 5 | 6 | import javax.annotation.Nullable; 7 | 8 | import org.osm2world.conversion.O2WConfig; 9 | import org.osm2world.map_data.data.MapData; 10 | import org.osm2world.world.network.NetworkCalculator; 11 | 12 | public class WorldCreator { 13 | 14 | private List modules; 15 | 16 | public WorldCreator(@Nullable O2WConfig config, WorldModule... modules) { 17 | this(config, Arrays.asList(modules)); 18 | } 19 | 20 | public WorldCreator(@Nullable O2WConfig config, List modules) { 21 | 22 | this.modules = modules; 23 | 24 | if (config == null) { 25 | config = new O2WConfig(); 26 | } 27 | 28 | for (WorldModule module : modules) { 29 | module.setConfiguration(config); 30 | } 31 | 32 | } 33 | 34 | public void addRepresentationsTo(MapData mapData) { 35 | 36 | for (WorldModule module : modules) { 37 | module.applyTo(mapData); 38 | } 39 | 40 | NetworkCalculator.calculateNetworkInformationInMapData(mapData); 41 | 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/world/creation/WorldModule.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.world.creation; 2 | 3 | import org.osm2world.conversion.O2WConfig; 4 | import org.osm2world.map_data.data.MapData; 5 | import org.osm2world.map_data.data.MapElement; 6 | import org.osm2world.world.data.WorldObject; 7 | 8 | public interface WorldModule { 9 | 10 | /** 11 | * provides an {@link O2WConfig} that can be used to control aspects 12 | * of a WorldModule's behavior. 13 | * 14 | * This is guaranteed to be called before {@link #applyTo(MapData)}, 15 | * but not all parameters might be explicitly set in the configuration, 16 | * so defaults need to be available. 17 | */ 18 | public void setConfiguration(O2WConfig config); 19 | 20 | /** 21 | * adds {@link WorldObject}s to {@link MapElement}s 22 | */ 23 | public void applyTo(MapData mapData); 24 | 25 | } 26 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/world/data/AreaWorldObject.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.world.data; 2 | 3 | import javax.annotation.Nonnull; 4 | 5 | import org.osm2world.map_data.data.MapArea; 6 | import org.osm2world.math.shapes.PolygonShapeXZ; 7 | import org.osm2world.math.shapes.PolygonWithHolesXZ; 8 | 9 | public interface AreaWorldObject extends WorldObject { 10 | 11 | @Override 12 | MapArea getPrimaryMapElement(); 13 | 14 | /** 15 | * @see WorldObject#getOutlinePolygonXZ() 16 | * @return the {@link PolygonWithHolesXZ} covered by {@link #getPrimaryMapElement()} 17 | */ 18 | @Override 19 | default @Nonnull PolygonShapeXZ getOutlinePolygonXZ() { 20 | MapArea area = getPrimaryMapElement(); 21 | if (!area.getPolygon().getOuter().isClockwise()) { 22 | return area.getPolygon(); 23 | } else { 24 | return new PolygonWithHolesXZ( 25 | area.getPolygon().getOuter().makeCounterclockwise(), 26 | area.getPolygon().getHoles()); 27 | } 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/world/data/CachingProceduralWorldObject.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.world.data; 2 | 3 | import java.util.List; 4 | 5 | import javax.annotation.Nullable; 6 | 7 | import org.osm2world.scene.mesh.LevelOfDetail; 8 | import org.osm2world.scene.mesh.Mesh; 9 | import org.osm2world.scene.model.ModelInstance; 10 | 11 | /** 12 | * subtype of {@link ProceduralWorldObject} which caches internal results to avoid repeated calculations 13 | */ 14 | abstract public class CachingProceduralWorldObject implements ProceduralWorldObject { 15 | 16 | private ProceduralWorldObject.Target target = null; 17 | private @Nullable LevelOfDetail lod; 18 | 19 | private void fillTargetIfNecessary() { 20 | if (target == null || (lod != null && getConfiguredLod() != null && lod != getConfiguredLod())) { 21 | lod = getConfiguredLod(); 22 | target = new ProceduralWorldObject.Target(); 23 | buildMeshesAndModels(target); 24 | } 25 | } 26 | 27 | @Override 28 | public List buildMeshes() { 29 | fillTargetIfNecessary(); 30 | return target.meshes; 31 | } 32 | 33 | @Override 34 | public List getSubModels() { 35 | fillTargetIfNecessary(); 36 | return target.subModels; 37 | } 38 | 39 | /** 40 | * if results depend on LOD, returns the currently configured LOD. 41 | * Can be null if this {@link ProceduralWorldObject} always produces geometry for all LOD. 42 | */ 43 | protected @Nullable LevelOfDetail getConfiguredLod() { 44 | return null; 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/world/data/NodeModelInstance.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.world.data; 2 | 3 | import static java.lang.Math.PI; 4 | 5 | import java.util.List; 6 | 7 | import org.osm2world.map_data.data.MapNode; 8 | import org.osm2world.scene.mesh.Mesh; 9 | import org.osm2world.scene.model.InstanceParameters; 10 | import org.osm2world.scene.model.Model; 11 | import org.osm2world.scene.model.ModelInstance; 12 | 13 | public class NodeModelInstance extends NoOutlineNodeWorldObject { 14 | 15 | public final Model model; 16 | public final double direction; 17 | public final double scale; 18 | 19 | public NodeModelInstance(MapNode node, Model model, double direction, double scale) { 20 | super(node); 21 | this.model = model; 22 | this.direction = direction; 23 | this.scale = scale; 24 | } 25 | 26 | public NodeModelInstance(MapNode node, Model model, double direction) { 27 | this(node, model, direction, 1.0); 28 | } 29 | 30 | public NodeModelInstance(MapNode node, Model model) { 31 | this(node, model, PI); 32 | } 33 | 34 | @Override 35 | public List buildMeshes() { 36 | return new ModelInstance(model, new InstanceParameters(getBase(), direction)).getMeshes(); 37 | } 38 | 39 | @Override 40 | public String toString() { 41 | return model.getClass().getSimpleName() + "(" + node + ")"; 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/world/data/NodeWorldObject.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.world.data; 2 | 3 | import org.osm2world.map_data.data.MapNode; 4 | 5 | public interface NodeWorldObject extends WorldObject { 6 | 7 | @Override 8 | public MapNode getPrimaryMapElement(); 9 | 10 | } 11 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/world/data/WaySegmentWorldObject.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.world.data; 2 | 3 | import org.osm2world.map_data.data.MapWaySegment; 4 | import org.osm2world.math.VectorXZ; 5 | 6 | public interface WaySegmentWorldObject extends WorldObject { 7 | 8 | @Override 9 | public MapWaySegment getPrimaryMapElement(); 10 | 11 | /** 12 | * returns the start position. 13 | * Might be different from {@link MapWaySegment}'s start position; 14 | * as node features such as crossings require space, too. 15 | */ 16 | public default VectorXZ getStartPosition() { 17 | return getPrimaryMapElement().getStartNode().getPos(); 18 | } 19 | 20 | /** 21 | * returns the end position. 22 | * See {@link #getStartPosition()} for details. 23 | */ 24 | public default VectorXZ getEndPosition() { 25 | return getPrimaryMapElement().getEndNode().getPos(); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/world/modules/building/BuildingModule.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.world.modules.building; 2 | 3 | import static org.osm2world.util.FaultTolerantIterationUtil.forEach; 4 | 5 | import org.osm2world.map_data.data.MapArea; 6 | import org.osm2world.map_data.data.MapData; 7 | import org.osm2world.map_data.data.MapMultipolygonRelation; 8 | import org.osm2world.map_data.data.MapRelation; 9 | import org.osm2world.world.modules.common.ConfigurableWorldModule; 10 | 11 | /** 12 | * adds buildings to the world 13 | */ 14 | public class BuildingModule extends ConfigurableWorldModule { 15 | 16 | @Override 17 | public void applyTo(MapData mapData) { 18 | 19 | forEach(mapData.getMapRelations(), (MapRelation relation) -> { 20 | if (relation instanceof MapMultipolygonRelation multipolygonRelation) { 21 | 22 | String buildingValue = relation.getTags().getValue("building"); 23 | 24 | if (buildingValue != null && !buildingValue.equals("no")) { 25 | 26 | Building building = new Building(relation, config); 27 | multipolygonRelation.getAreas().get(0).addRepresentation(building); 28 | 29 | } 30 | 31 | } 32 | }); 33 | 34 | forEach(mapData.getMapAreas(), (MapArea area) -> { 35 | 36 | if (!area.getRepresentations().isEmpty()) return; 37 | if (area.getMemberships().stream().anyMatch(m -> m.getRelation() instanceof MapMultipolygonRelation)) return; 38 | 39 | String buildingValue = area.getTags().getValue("building"); 40 | 41 | if (buildingValue != null && !buildingValue.equals("no")) { 42 | 43 | Building building = new Building(area, config); 44 | area.addRepresentation(building); 45 | 46 | } 47 | 48 | }); 49 | 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/world/modules/building/WallElement.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.world.modules.building; 2 | 3 | import org.osm2world.math.shapes.SimplePolygonXZ; 4 | import org.osm2world.output.CommonTarget; 5 | 6 | /** 7 | * something that can be placed into a wall, such as a window or door 8 | */ 9 | interface WallElement { 10 | 11 | /** 12 | * returns the space on the 2D {@link WallSurface} occupied by this element. 13 | * The element is responsible for handling rendering inside this area. 14 | */ 15 | public SimplePolygonXZ outline(); 16 | 17 | /** 18 | * how deep the element is sunk into the wall. Will be used to render the bits of wall around it. 19 | * Can be 0 if the element is flat on the wall, or handles its own rendering of the inset walls. 20 | */ 21 | public double insetDistance(); 22 | 23 | public void renderTo(CommonTarget target, WallSurface surface); 24 | 25 | } -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/world/modules/building/Window.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.world.modules.building; 2 | 3 | interface Window extends WallElement {} -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/world/modules/building/WindowImplementation.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.world.modules.building; 2 | 3 | /** 4 | * how windows on building walls should be implemented. 5 | * This represents a trade-off between visuals and various performance factors. 6 | */ 7 | enum WindowImplementation { 8 | 9 | /** no windows at all */ 10 | NONE, 11 | /** a repeating texture image on a flat wall */ 12 | FLAT_TEXTURES, 13 | /** windows using a combination of geometry and textures */ 14 | INSET_TEXTURES, 15 | /** windows with actual geometry */ 16 | FULL_GEOMETRY; 17 | 18 | public static WindowImplementation getValue(String value, WindowImplementation defaultValue) { 19 | 20 | if (value != null) { 21 | try { 22 | return WindowImplementation.valueOf(value.toUpperCase()); 23 | } catch (IllegalArgumentException e) {} 24 | } 25 | 26 | return defaultValue; 27 | 28 | } 29 | 30 | } -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/world/modules/building/roof/DomeRoof.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.world.modules.building.roof; 2 | 3 | import static java.lang.Math.sqrt; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | import org.apache.commons.lang3.tuple.Pair; 9 | import org.osm2world.map_data.data.TagSet; 10 | import org.osm2world.math.shapes.PolygonWithHolesXZ; 11 | import org.osm2world.scene.material.Material; 12 | 13 | public class DomeRoof extends SpindleRoof { 14 | 15 | public DomeRoof(PolygonWithHolesXZ originalPolygon, TagSet tags, Material material) { 16 | super(originalPolygon, tags, material); 17 | } 18 | 19 | /** 20 | * number of height rings to approximate the round dome shape 21 | */ 22 | private static final int HEIGHT_RINGS = 10; 23 | 24 | @Override 25 | protected List> getSpindleSteps() { 26 | 27 | List> steps = new ArrayList<>(); 28 | 29 | for (int ring = 0; ring < HEIGHT_RINGS; ++ring) { 30 | double relativeHeight = ((double)ring) / (HEIGHT_RINGS - 1); 31 | steps.add(Pair.of(relativeHeight, sqrt(1.0 - relativeHeight * relativeHeight))); 32 | } 33 | 34 | return steps; 35 | 36 | } 37 | 38 | } -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/world/modules/building/roof/FlatRoof.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.world.modules.building.roof; 2 | 3 | import static java.util.Collections.emptyList; 4 | 5 | import java.util.Collection; 6 | 7 | import org.osm2world.map_data.data.TagSet; 8 | import org.osm2world.math.VectorXZ; 9 | import org.osm2world.math.shapes.LineSegmentXZ; 10 | import org.osm2world.math.shapes.PolygonWithHolesXZ; 11 | import org.osm2world.scene.material.Material; 12 | 13 | public class FlatRoof extends HeightfieldRoof { 14 | 15 | public FlatRoof(PolygonWithHolesXZ originalPolygon, TagSet tags, Material material) { 16 | super(originalPolygon, tags, material); 17 | } 18 | 19 | @Override 20 | public PolygonWithHolesXZ getPolygon() { 21 | return originalPolygon; 22 | } 23 | 24 | @Override 25 | public Collection getInnerPoints() { 26 | return emptyList(); 27 | } 28 | 29 | @Override 30 | public Collection getInnerSegments() { 31 | return emptyList(); 32 | } 33 | 34 | @Override 35 | public Double calculatePreliminaryHeight() { 36 | return 0.0; 37 | } 38 | 39 | @Override 40 | public Double getRoofHeightAt_noInterpolation(VectorXZ pos) { 41 | return 0.0; 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/world/modules/building/roof/HippedRoof.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.world.modules.building.roof; 2 | 3 | import static java.util.Arrays.asList; 4 | import static java.util.Collections.emptyList; 5 | 6 | import java.util.Collection; 7 | 8 | import org.osm2world.map_data.data.TagSet; 9 | import org.osm2world.math.VectorXZ; 10 | import org.osm2world.math.shapes.LineSegmentXZ; 11 | import org.osm2world.math.shapes.PolygonWithHolesXZ; 12 | import org.osm2world.scene.material.Material; 13 | 14 | public class HippedRoof extends RoofWithRidge { 15 | 16 | public HippedRoof(PolygonWithHolesXZ originalPolygon, TagSet tags, Material material) { 17 | super(1/3.0, originalPolygon, tags, material); 18 | } 19 | 20 | @Override 21 | public PolygonWithHolesXZ getPolygon() { 22 | return originalPolygon; 23 | } 24 | 25 | @Override 26 | public Collection getInnerPoints() { 27 | return emptyList(); 28 | } 29 | 30 | @Override 31 | public Collection getInnerSegments() { 32 | return asList( 33 | ridge, 34 | new LineSegmentXZ(ridge.p1, cap1.p1), 35 | new LineSegmentXZ(ridge.p1, cap1.p2), 36 | new LineSegmentXZ(ridge.p2, cap2.p1), 37 | new LineSegmentXZ(ridge.p2, cap2.p2)); 38 | } 39 | 40 | @Override 41 | public Double getRoofHeightAt_noInterpolation(VectorXZ pos) { 42 | if (ridge.p1.equals(pos) || ridge.p2.equals(pos)) { 43 | return roofHeight; 44 | } else if (getPolygon().getOuter().getVertexCollection().contains(pos)) { 45 | return 0.0; 46 | } else { 47 | return null; 48 | } 49 | } 50 | 51 | } -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/world/modules/building/roof/OnionRoof.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.world.modules.building.roof; 2 | 3 | import static java.util.Arrays.asList; 4 | 5 | import java.util.List; 6 | 7 | import org.apache.commons.lang3.tuple.Pair; 8 | import org.osm2world.map_data.data.TagSet; 9 | import org.osm2world.math.shapes.PolygonWithHolesXZ; 10 | import org.osm2world.scene.material.Material; 11 | 12 | public class OnionRoof extends SpindleRoof { 13 | 14 | public OnionRoof(PolygonWithHolesXZ originalPolygon, TagSet tags, Material material) { 15 | super(originalPolygon, tags, material); 16 | } 17 | 18 | @Override 19 | protected List> getSpindleSteps() { 20 | return asList( 21 | Pair.of(0.0, 1.0), 22 | Pair.of(0.15, 0.8), 23 | Pair.of(0.52, 1.0), 24 | Pair.of(0.72, 0.7), 25 | Pair.of(0.82, 0.15), 26 | Pair.of(1.00, 0.0)); 27 | } 28 | 29 | } -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/world/modules/common/ConfigurableWorldModule.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.world.modules.common; 2 | 3 | import javax.annotation.Nonnull; 4 | 5 | import org.osm2world.conversion.O2WConfig; 6 | import org.osm2world.world.creation.WorldModule; 7 | 8 | /** 9 | * simple superclass for {@link WorldModule}s that stores a configuration set by 10 | * {@link #setConfiguration(O2WConfig)} 11 | */ 12 | public abstract class ConfigurableWorldModule implements WorldModule { 13 | 14 | protected @Nonnull O2WConfig config = new O2WConfig(); 15 | 16 | @Override 17 | public void setConfiguration(@Nonnull O2WConfig config) { 18 | this.config = config; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/world/network/NetworkAreaWorldObject.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.world.network; 2 | 3 | import java.util.Collection; 4 | import java.util.List; 5 | 6 | import org.osm2world.map_data.data.MapArea; 7 | import org.osm2world.math.shapes.PolygonShapeXZ; 8 | import org.osm2world.world.data.AbstractAreaWorldObject; 9 | 10 | public abstract class NetworkAreaWorldObject extends AbstractAreaWorldObject { 11 | 12 | public NetworkAreaWorldObject(MapArea area) { 13 | super(area); 14 | } 15 | 16 | @Override 17 | public Collection getRawGroundFootprint() { 18 | return List.of(getOutlinePolygonXZ()); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/world/network/NetworkUtil.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.world.network; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.function.Predicate; 6 | 7 | import javax.annotation.Nullable; 8 | 9 | import org.osm2world.map_data.data.MapNode; 10 | import org.osm2world.map_data.data.MapWaySegment; 11 | import org.osm2world.world.data.WaySegmentWorldObject; 12 | 13 | /** methods related to networked features (road network, rail network, ...) */ 14 | public final class NetworkUtil { 15 | 16 | private NetworkUtil() {} 17 | 18 | /** 19 | * Returns the connected {@link NetworkWaySegmentWorldObject}s. 20 | * The result is ordered in the same fashion as {@link MapNode#getConnectedWaySegments()} 21 | * 22 | * @param type the type of network segment to look for 23 | */ 24 | public static final List getConnectedNetworkSegments( 25 | MapNode node, Class type, @Nullable Predicate additionalFilter) { 26 | 27 | List result = new ArrayList(); 28 | 29 | for (MapWaySegment segment : node.getConnectedWaySegments()) { 30 | for (WaySegmentWorldObject representation : segment.getRepresentations()) { 31 | if (type.isInstance(representation)) { 32 | @SuppressWarnings("unchecked") //the isInstance check ensures that this cast works 33 | S sRepresentation = (S)representation; 34 | if (additionalFilter == null || additionalFilter.test(sRepresentation)) { 35 | result.add(sRepresentation); 36 | } 37 | } 38 | } 39 | } 40 | 41 | return result; 42 | 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/world/network/NetworkWaySegmentWorldObject.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.world.network; 2 | 3 | import org.osm2world.math.VectorXZ; 4 | import org.osm2world.world.data.WaySegmentWorldObject; 5 | import org.osm2world.world.data.WorldObject; 6 | 7 | /** 8 | * A linear component of a network. 9 | * 10 | * "Networks" are sets of {@link WorldObject}s that have certain 11 | * frequently required characteristics. Most importantly, a network 12 | * consists of nodes, lines and areas linked with each other. 13 | * 14 | * Features using these types of representation include roads, 15 | * railways and rivers. 16 | */ 17 | public interface NetworkWaySegmentWorldObject extends WaySegmentWorldObject { 18 | 19 | /** 20 | * returns the line's width 21 | */ 22 | public double getWidth(); 23 | 24 | /** 25 | * Sets the calculated start of this network segment. 26 | * This may be moved from the start of the OSM way to make room for features (junctions, crossings, ...) at nodes. 27 | * To be used by {@link NetworkCalculator}. 28 | */ 29 | public void setStartCut(VectorXZ left, VectorXZ center, VectorXZ right); 30 | 31 | /** 32 | * Sets the calculated end of this network segment. 33 | * This may be moved from the start of the OSM way to make room for features (junctions, crossings, ...) at nodes. 34 | * To be used by {@link NetworkCalculator}. 35 | */ 36 | public void setEndCut(VectorXZ left, VectorXZ center, VectorXZ right); 37 | 38 | } 39 | -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/world/network/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Functionality used by groups of features that aren't isolated, but form a "network" of nodes, ways and areas. 3 | * Roads are the most prominent use case. 4 | */ 5 | package org.osm2world.world.network; -------------------------------------------------------------------------------- /core/src/main/java/org/osm2world/world/package-info.java: -------------------------------------------------------------------------------- 1 | /** Objects representing the three-dimensional "world" created by OSM2World */ 2 | package org.osm2world.world; -------------------------------------------------------------------------------- /core/src/test/java/org/osm2world/map_data/data/MapMetadataTest.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.map_data.data; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.osm2world.util.test.TestFileUtil.getTestFile; 5 | 6 | import java.io.File; 7 | import java.io.IOException; 8 | 9 | import org.imintel.mbtiles4j.MBTilesReadException; 10 | import org.junit.Test; 11 | import org.osm2world.math.geo.TileNumber; 12 | 13 | public class MapMetadataTest { 14 | 15 | @Test 16 | public void testMetadataFromFile() throws IOException { 17 | 18 | File jsonFile = getTestFile("metadata_only_locale.json"); 19 | 20 | assertEquals(new MapMetadata("AT", null), 21 | MapMetadata.metadataFromJson(jsonFile)); 22 | 23 | } 24 | 25 | @Test 26 | public void testMetadataForTile() throws MBTilesReadException, IOException { 27 | 28 | File tileMetadataDb = getTestFile("meta.mbtiles"); 29 | 30 | assertEquals(new MapMetadata("DE", true), 31 | MapMetadata.metadataForTile(new TileNumber(13, 4401, 2827), tileMetadataDb)); 32 | 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /core/src/test/java/org/osm2world/map_elevation/creation/SRTMDataTest.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.map_elevation.creation; 2 | 3 | import static org.osm2world.util.test.TestFileUtil.getTestFile; 4 | 5 | import java.io.File; 6 | import java.io.IOException; 7 | import java.util.List; 8 | 9 | import org.junit.Assert; 10 | import org.junit.Test; 11 | import org.osm2world.math.geo.LatLon; 12 | import org.osm2world.math.geo.LatLonBounds; 13 | import org.osm2world.math.geo.OrthographicAzimuthalMapProjection; 14 | import org.osm2world.math.shapes.AxisAlignedRectangleXZ; 15 | 16 | public class SRTMDataTest { 17 | 18 | @Test 19 | public void testGetSites() throws IOException { 20 | 21 | File srtmDir = getTestFile("srtm"); 22 | 23 | var projection = new OrthographicAzimuthalMapProjection(new LatLon(4, 33)); 24 | var srtmData = new SRTMData(srtmDir, projection); 25 | 26 | var bounds1 = new LatLonBounds(4.1, 33.1, 4.2, 33.2); 27 | Assert.assertFalse(srtmData.getSites(projectBounds(projection, bounds1)).isEmpty()); 28 | 29 | var bounds2 = new LatLonBounds(4.1, 34.1, 4.2, 34.2); 30 | Assert.assertFalse(srtmData.getSites(projectBounds(projection, bounds2)).isEmpty()); 31 | 32 | } 33 | 34 | private static AxisAlignedRectangleXZ projectBounds(OrthographicAzimuthalMapProjection projection, LatLonBounds latLonBounds) { 35 | return AxisAlignedRectangleXZ.bbox(List.of( 36 | projection.toXZ(latLonBounds.getMin()), projection.toXZ(latLonBounds.getMax()))); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /core/src/test/java/org/osm2world/math/AngleTest.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.math; 2 | 3 | import static java.lang.Math.PI; 4 | import static org.junit.Assert.assertEquals; 5 | 6 | import org.junit.Test; 7 | 8 | public class AngleTest { 9 | 10 | @Test 11 | public void testFitToRange() { 12 | assertEquals(0, Angle.ofRadians(0).radians, 0); 13 | assertEquals(PI, Angle.ofRadians(PI).radians, 0); 14 | assertEquals(0, Angle.ofRadians(2 * PI).radians, 0); 15 | assertEquals(PI, Angle.ofRadians(3 * PI).radians, 0); 16 | assertEquals(1.5 * PI, Angle.ofRadians(-PI / 2).radians, 0); 17 | } 18 | 19 | @Test 20 | public void testOfDegrees() { 21 | assertEquals(0, Angle.ofDegrees(0).radians, 0); 22 | assertEquals(PI, Angle.ofDegrees(180).radians, 0); 23 | assertEquals(0, Angle.ofDegrees(360).radians, 0); 24 | assertEquals(PI, Angle.ofDegrees(540).radians, 0); 25 | assertEquals(1.5 * PI, Angle.ofDegrees(-90).radians, 0); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /core/src/test/java/org/osm2world/math/VectorXYZTest.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.math; 2 | 3 | import static org.osm2world.math.VectorXYZ.*; 4 | import static org.osm2world.test.TestUtil.assertAlmostEquals; 5 | 6 | import org.junit.Test; 7 | 8 | public class VectorXYZTest { 9 | 10 | @Test 11 | public void testRotateX() { 12 | 13 | assertAlmostEquals(1, 0, 0, X_UNIT.rotateX(-0.42)); 14 | assertAlmostEquals(0, 0, 1, Y_UNIT.rotateX(Math.PI/2)); 15 | assertAlmostEquals(0,-1, 0, Z_UNIT.rotateX(Math.PI/2)); 16 | 17 | } 18 | 19 | @Test 20 | public void testRotateY() { 21 | 22 | assertAlmostEquals(0, 0, 1, X_UNIT.rotateY(-Math.PI/2)); 23 | assertAlmostEquals(0, 1, 0, Y_UNIT.rotateY(Math.PI*0.42)); 24 | assertAlmostEquals(1, 0, 0, Z_UNIT.rotateY(Math.PI/2)); 25 | 26 | } 27 | 28 | @Test 29 | public void testRotateZ() { 30 | 31 | assertAlmostEquals(0, 1, 0, X_UNIT.rotateZ(Math.PI/2)); 32 | assertAlmostEquals(0,-1, 0, Y_UNIT.rotateZ(Math.PI)); 33 | assertAlmostEquals(0, 0, 1, Z_UNIT.rotateZ(0.42)); 34 | 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /core/src/test/java/org/osm2world/math/datastructures/IndexGridTest.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.math.datastructures; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import org.junit.Test; 6 | import org.osm2world.math.VectorXZ; 7 | import org.osm2world.math.shapes.AxisAlignedRectangleXZ; 8 | 9 | public class IndexGridTest { 10 | 11 | @Test 12 | public void testCellCoords() { 13 | 14 | IndexGrid grid = new IndexGrid<>(new AxisAlignedRectangleXZ(-10, -10, 10, 10), 2, 2); 15 | 16 | assertEquals(2, grid.getCellArray().length); 17 | assertEquals(2, grid.getCellArray()[0].length); 18 | 19 | assertEquals(0, grid.cellXForCoord(-20)); 20 | assertEquals(0, grid.cellXForCoord(-5)); 21 | assertEquals(1, grid.cellXForCoord(5)); 22 | assertEquals(1, grid.cellXForCoord(20)); 23 | 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /core/src/test/java/org/osm2world/math/geo/MetricMapProjectionTest.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.math.geo; 2 | 3 | public class MetricMapProjectionTest extends AbstractMapProjectionTest { 4 | 5 | @Override 6 | protected MapProjection createProjection(LatLon origin) { 7 | return new MetricMapProjection(origin); 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /core/src/test/java/org/osm2world/math/geo/OrthographicAzimuthalMapProjectionTest.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.math.geo; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.osm2world.test.TestUtil.assertAlmostEquals; 5 | 6 | import org.junit.Test; 7 | import org.osm2world.math.VectorXZ; 8 | 9 | public class OrthographicAzimuthalMapProjectionTest extends AbstractMapProjectionTest { 10 | 11 | @Override 12 | protected MapProjection createProjection(LatLon origin) { 13 | return new OrthographicAzimuthalMapProjection(origin); 14 | } 15 | 16 | @Test 17 | public void testToXZ() { 18 | 19 | MapProjection proj = createProjection(new LatLon(0, 0)); 20 | 21 | VectorXZ posOrigin = proj.toXZ(0, 0); 22 | assertAlmostEquals(0, 0, posOrigin); 23 | assertEquals(0, proj.toLat(posOrigin), DELTA); 24 | assertEquals(0, proj.toLon(posOrigin), DELTA); 25 | 26 | VectorXZ posE = proj.toXZ(0, 0.000009); 27 | assertAlmostEquals(1, 0, posE); 28 | assertEquals(0, proj.toLat(posE), DELTA); 29 | assertEquals(0.000009, proj.toLon(posE), DELTA); 30 | 31 | VectorXZ posN = proj.toXZ(0.000009, 0); 32 | assertAlmostEquals(0, 1, posN); 33 | assertEquals(0.000009, proj.toLat(posN), DELTA); 34 | assertEquals(0, proj.toLon(posN), DELTA); 35 | 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /core/src/test/java/org/osm2world/math/geo/TileBoundsTest.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.math.geo; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import java.util.List; 6 | import java.util.Set; 7 | 8 | import org.junit.Test; 9 | 10 | public class TileBoundsTest { 11 | 12 | @Test 13 | public void testAround() { 14 | 15 | var r1 = TileBounds.around(List.of(new TileNumber(13, 100, 100))); 16 | assertEquals(Set.of(new TileNumber(13, 100, 100)), r1.getTiles()); 17 | 18 | var r2 = TileBounds.around(List.of(new TileNumber(1, 0, 0), new TileNumber(2, 2, 2))); 19 | assertEquals(2, r2.getTiles().iterator().next().zoom); 20 | assertEquals(9, r2.getTiles().size()); 21 | 22 | var r3 = TileBounds.around(List.of(new TileNumber(1, 0, 0), new TileNumber(2, 1, 1)), 1); 23 | assertEquals(Set.of(new TileNumber(1, 0, 0)), r3.getTiles()); 24 | 25 | 26 | } 27 | 28 | } -------------------------------------------------------------------------------- /core/src/test/java/org/osm2world/math/shapes/AxisAlignedRectangleTest.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.math.shapes; 2 | 3 | import static java.util.Arrays.asList; 4 | import static org.junit.Assert.assertEquals; 5 | import static org.osm2world.math.shapes.AxisAlignedRectangleXZ.bboxUnion; 6 | 7 | import org.junit.Test; 8 | 9 | public class AxisAlignedRectangleTest { 10 | 11 | @Test 12 | public void testBboxUnion() { 13 | 14 | AxisAlignedRectangleXZ box1 = new AxisAlignedRectangleXZ(5, 5, 10, 10); 15 | AxisAlignedRectangleXZ box2 = new AxisAlignedRectangleXZ(7, 3, 20, 10); 16 | 17 | AxisAlignedRectangleXZ result = bboxUnion(asList(box1, box2)); 18 | 19 | assertEquals(5, result.minX, 0); 20 | assertEquals(3, result.minZ, 0); 21 | assertEquals(20, result.maxX, 0); 22 | assertEquals(10, result.maxZ, 0); 23 | 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /core/src/test/java/org/osm2world/math/shapes/CircleXZTest.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.math.shapes; 2 | 3 | import static org.osm2world.test.TestUtil.assertAlmostEquals; 4 | 5 | import org.junit.Test; 6 | import org.osm2world.math.VectorXZ; 7 | 8 | public class CircleXZTest extends PolylineXZTest { 9 | 10 | @Test 11 | public void testTransform() { 12 | 13 | CircleXZ input = new CircleXZ(new VectorXZ(0, 0), 5); 14 | CircleXZ expected = new CircleXZ(new VectorXZ(10, 3), 5); 15 | 16 | assertAlmostEquals(expected.vertices(), input.transform(v -> v.add(10, 3)).vertices()); 17 | 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /core/src/test/java/org/osm2world/math/shapes/LineXZTest.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.math.shapes; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.junit.Assert.assertNull; 5 | import static org.osm2world.test.TestUtil.assertAlmostEquals; 6 | 7 | import org.junit.Test; 8 | import org.osm2world.math.VectorXZ; 9 | 10 | public class LineXZTest { 11 | 12 | @Test 13 | public void testGetIntersection() { 14 | 15 | var line = new LineXZ(new VectorXZ(-1, -1), new VectorXZ(1, 1)); 16 | 17 | var l1 = new LineSegmentXZ(new VectorXZ(1, -1), new VectorXZ(-1, 1)); 18 | assertEquals(new VectorXZ(0, 0), line.getIntersection(l1)); 19 | assertEquals(new VectorXZ(0, 0), line.getIntersection(l1.toLineXZ())); 20 | 21 | var l2 = new LineSegmentXZ(new VectorXZ(1, -1), new VectorXZ(0.5, -0.5)); 22 | assertNull(line.getIntersection(l2)); 23 | assertEquals(new VectorXZ(0, 0), line.getIntersection(l2.toLineXZ())); 24 | 25 | } 26 | 27 | @Test 28 | public void testGetIntersection2() { 29 | 30 | var line = new LineXZ(new VectorXZ(-10, 5), new VectorXZ(+10, 5)); 31 | 32 | var l1 = new LineSegmentXZ(new VectorXZ(0, 10), new VectorXZ(0, 0)); 33 | assertAlmostEquals(0, 5, line.getIntersection(l1)); 34 | 35 | var l2 = new LineSegmentXZ(new VectorXZ(10, 0), new VectorXZ(0, 10)); 36 | assertAlmostEquals(5, 5, line.getIntersection(l2)); 37 | 38 | } 39 | 40 | } -------------------------------------------------------------------------------- /core/src/test/java/org/osm2world/math/shapes/TriangleXZTest.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.math.shapes; 2 | 3 | import static org.junit.Assert.assertFalse; 4 | import static org.junit.Assert.assertTrue; 5 | import static org.osm2world.test.TestUtil.assertAlmostEquals; 6 | 7 | import org.junit.Test; 8 | import org.osm2world.math.VectorXZ; 9 | 10 | public class TriangleXZTest { 11 | 12 | private final TriangleXZ triangleCW = new TriangleXZ( 13 | new VectorXZ( 0, 0), 14 | new VectorXZ(-1, 1), 15 | new VectorXZ(+1, 0)); 16 | 17 | private final TriangleXZ triangleCCW = new TriangleXZ( 18 | new VectorXZ( 0, 0), 19 | new VectorXZ(-1, 1), 20 | new VectorXZ(-2, 0)); 21 | 22 | @Test 23 | public void testIsClockwise() { 24 | assertTrue(triangleCW.isClockwise()); 25 | assertFalse(triangleCW.reverse().isClockwise()); 26 | assertFalse(triangleCCW.isClockwise()); 27 | assertTrue(triangleCCW.reverse().isClockwise()); 28 | } 29 | 30 | @Test 31 | public void testGetArea() { 32 | assertAlmostEquals(triangleCW.getArea(), 0.5); 33 | assertAlmostEquals(triangleCCW.getArea(), 1); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /core/src/test/java/org/osm2world/osm/creation/OverpassReaderTest.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.osm.creation; 2 | 3 | import static org.junit.Assert.assertFalse; 4 | 5 | import java.io.IOException; 6 | 7 | import org.junit.Test; 8 | import org.osm2world.math.geo.LatLon; 9 | import org.osm2world.math.geo.LatLonBounds; 10 | import org.osm2world.osm.data.OSMData; 11 | 12 | public class OverpassReaderTest { 13 | 14 | @Test 15 | public void testBoundingBox() throws IOException { 16 | 17 | var reader = new OverpassReader(); 18 | 19 | OSMData data = reader.getData(new LatLonBounds( 20 | new LatLon(50.746, 7.154), new LatLon(50.748, 7.157))); 21 | 22 | assertFalse(data.getNodes().isEmpty()); 23 | assertFalse(data.getWays().isEmpty()); 24 | assertFalse(data.getRelations().isEmpty()); 25 | 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /core/src/test/java/org/osm2world/scene/material/TextureTestUtil.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.scene.material; 2 | 3 | import static org.osm2world.scene.texcoord.NamedTexCoordFunction.GLOBAL_X_Z; 4 | 5 | import java.awt.*; 6 | import java.awt.image.BufferedImage; 7 | import java.util.function.BiConsumer; 8 | 9 | import org.osm2world.scene.material.TextureData.Wrap; 10 | import org.osm2world.util.Resolution; 11 | 12 | class TextureTestUtil { 13 | 14 | /** prevents instantiation */ 15 | private TextureTestUtil() { } 16 | 17 | static final TextureData drawTestTexture(BiConsumer drawImpl) { 18 | return new RuntimeTexture(new TextureDataDimensions(1, 1), Wrap.REPEAT, GLOBAL_X_Z) { 19 | @Override 20 | protected BufferedImage createBufferedImage() { 21 | Resolution res = new Resolution(128, 128); 22 | BufferedImage image = new BufferedImage(res.width, res.height, BufferedImage.TYPE_INT_ARGB); 23 | drawImpl.accept(res, image.createGraphics()); 24 | return image; 25 | } 26 | }; 27 | } 28 | 29 | static final TextureData drawSingleColorTexture(Color color) { 30 | return drawTestTexture((res, g2d) -> { 31 | g2d.setBackground(color); 32 | g2d.clearRect(0, 0, res.width, res.height); 33 | }); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /core/src/test/java/org/osm2world/scene/mesh/LODRangeTest.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.scene.mesh; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.junit.Assert.assertNull; 5 | import static org.osm2world.scene.mesh.LevelOfDetail.*; 6 | 7 | import org.junit.Test; 8 | 9 | public class LODRangeTest { 10 | 11 | @Test 12 | public void testIntersection() { 13 | 14 | assertEquals(new LODRange(LOD1, LOD3), LODRange.intersection(new LODRange(LOD1, LOD3))); 15 | assertEquals(new LODRange(LOD1, LOD3), LODRange.intersection(new LODRange(LOD0, LOD3), new LODRange(LOD1, LOD4))); 16 | assertEquals(new LODRange(LOD2), LODRange.intersection(new LODRange(LOD1, LOD2), new LODRange(LOD2, LOD4))); 17 | assertEquals(new LODRange(LOD2), LODRange.intersection(new LODRange(LOD1, LOD2), new LODRange(LOD1, LOD3), new LODRange(LOD2, LOD4))); 18 | assertNull(LODRange.intersection(new LODRange(LOD0, LOD1), new LODRange(LOD2, LOD3))); 19 | 20 | } 21 | 22 | } -------------------------------------------------------------------------------- /core/src/test/java/org/osm2world/scene/mesh/MeshStoreTest.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.scene.mesh; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.osm2world.scene.mesh.MeshStore.ClipToBounds.clipToBounds; 5 | import static org.osm2world.scene.mesh.MeshStore.ClipToBounds.getSegmentsCCW; 6 | import static org.osm2world.test.TestUtil.assertAlmostEquals; 7 | 8 | import org.junit.Test; 9 | import org.osm2world.math.VectorXYZ; 10 | import org.osm2world.math.VectorXZ; 11 | import org.osm2world.math.shapes.AxisAlignedRectangleXZ; 12 | import org.osm2world.math.shapes.TriangleXYZ; 13 | import org.osm2world.math.shapes.TriangleXZ; 14 | 15 | public class MeshStoreTest { 16 | 17 | @Test 18 | public void testClipToBounds() { 19 | 20 | var tOrig = new TriangleXYZ(new VectorXYZ(0, 0, 0), new VectorXYZ(10, 0, 0), new VectorXYZ(0, 0, 10)); 21 | 22 | var bbox = new AxisAlignedRectangleXZ(-10, 5, +10, 15); 23 | var result1 = clipToBounds(tOrig, getSegmentsCCW(bbox)); 24 | assertEquals(1, result1.size()); 25 | var expectedResult1 = new TriangleXYZ(new VectorXYZ(0, 0, 5), new VectorXYZ(5, 0, 5), new VectorXYZ(0, 0, 10)); 26 | assertAlmostEquals(expectedResult1.getCenter(), result1.iterator().next().getCenter()); 27 | assertAlmostEquals(expectedResult1.getArea(), result1.iterator().next().getArea()); 28 | 29 | var tSmall = new TriangleXZ(new VectorXZ(2, 2), new VectorXZ(8, 2), new VectorXZ(2, 8)); 30 | var result2 = clipToBounds(tOrig, getSegmentsCCW(tSmall)); 31 | assertEquals(1, result2.size()); 32 | assertAlmostEquals(tSmall.getCenter().xyz(0), result2.iterator().next().getCenter()); 33 | assertAlmostEquals(tSmall.getArea(), result2.iterator().next().getArea()); 34 | 35 | } 36 | 37 | } -------------------------------------------------------------------------------- /core/src/test/java/org/osm2world/scene/mesh/MeshTestUtil.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.scene.mesh; 2 | 3 | import static org.junit.Assert.assertTrue; 4 | 5 | import java.util.List; 6 | 7 | import org.osm2world.math.VectorXYZ; 8 | import org.osm2world.math.shapes.TriangleXYZ; 9 | 10 | final class MeshTestUtil { 11 | 12 | private MeshTestUtil() {} 13 | 14 | /** 15 | * asserts that the collection contains two triangles which together form the quad. 16 | * 17 | * @throws AssertionError if the condition is not fulfilled 18 | */ 19 | static final void assertContainsQuad(List collection, 20 | VectorXYZ a, VectorXYZ b, VectorXYZ c, VectorXYZ d) { 21 | 22 | assertTrue(containsTriangle(collection, a, b, c) && containsTriangle(collection, a, c, d) 23 | || containsTriangle(collection, a, b, d) && containsTriangle(collection, b, c, d)); 24 | 25 | } 26 | 27 | /** 28 | * returns true iff the collection contains the triangle defined by the vertices. 29 | * The winding is checked, but otherwise the order of vertices does not matter. 30 | */ 31 | static final boolean containsTriangle(List collection, 32 | VectorXYZ v1, VectorXYZ v2, VectorXYZ v3) { 33 | 34 | for (TriangleXYZ t : collection) { 35 | 36 | if ((v1.equals(t.v1) && v2.equals(t.v2) && v3.equals(t.v3)) 37 | || v2.equals(t.v1) && v3.equals(t.v2) && v1.equals(t.v3) 38 | || v3.equals(t.v1) && v1.equals(t.v2) && v2.equals(t.v3)) { 39 | return true; 40 | } 41 | 42 | } 43 | 44 | return false; 45 | 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /core/src/test/java/org/osm2world/scene/mesh/MeshUtilTest.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.scene.mesh; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.osm2world.scene.mesh.MeshUtil.createBox; 5 | 6 | import java.awt.*; 7 | import java.util.List; 8 | 9 | import org.junit.Test; 10 | import org.osm2world.math.VectorXYZ; 11 | import org.osm2world.math.VectorXZ; 12 | import org.osm2world.scene.material.TextureDataDimensions; 13 | 14 | public class MeshUtilTest { 15 | 16 | @Test 17 | public void testCreateBox() { 18 | 19 | Geometry result = createBox(new VectorXYZ(0, 0, 0), new VectorXZ(0, -1), 5, 3, 2, 20 | Color.RED, List.of(new TextureDataDimensions(1, 1))); 21 | 22 | assertEquals(12, result.asTriangles().triangles.size()); 23 | 24 | } 25 | 26 | } -------------------------------------------------------------------------------- /core/src/test/java/org/osm2world/scene/texcoord/TexCoordUtilTest.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.scene.texcoord; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import org.junit.Test; 6 | import org.osm2world.math.VectorXZ; 7 | import org.osm2world.scene.material.TextureDataDimensions; 8 | 9 | public class TexCoordUtilTest { 10 | 11 | @Test 12 | public void testApplyPadding() { 13 | 14 | var dim = new TextureDataDimensions(1, 1, null, null, 0.1); 15 | 16 | assertEquals(0.1, TexCoordUtil.applyPadding(new VectorXZ(0, 0), dim).x, 1e-5); 17 | assertEquals(0.3, TexCoordUtil.applyPadding(new VectorXZ(0.25, 0), dim).x, 1e-5); 18 | assertEquals(0.5, TexCoordUtil.applyPadding(new VectorXZ(0.5, 0), dim).x, 1e-5); 19 | assertEquals(0.7, TexCoordUtil.applyPadding(new VectorXZ(0.75, 0), dim).x, 1e-5); 20 | assertEquals(0.9, TexCoordUtil.applyPadding(new VectorXZ(1.0, 0), dim).x, 1e-5); 21 | 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /core/src/test/java/org/osm2world/util/ResolutionTest.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.util; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import org.junit.Test; 6 | 7 | public class ResolutionTest { 8 | 9 | @Test 10 | public void testAspectRatio() { 11 | 12 | var r1 = new Resolution(1000, 500); 13 | var r2 = new Resolution("256x256"); 14 | var r3 = new Resolution("64,128"); 15 | 16 | assertEquals(2.0f, r1.getAspectRatio(), 0f); 17 | assertEquals(1.0f, r2.getAspectRatio(), 0f); 18 | assertEquals(0.5f, r3.getAspectRatio(), 0f); 19 | 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /core/src/test/java/org/osm2world/util/color/LColorTest.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.util.color; 2 | 3 | import static java.awt.Color.*; 4 | import static java.util.Arrays.asList; 5 | import static org.osm2world.test.TestUtil.assertAlmostEquals; 6 | 7 | import java.awt.Color; 8 | 9 | import org.junit.Test; 10 | import org.osm2world.scene.color.LColor; 11 | 12 | public class LColorTest { 13 | 14 | @Test 15 | public void testAwtConversion() { 16 | 17 | assertAlmostEquals(RED, new LColor(1, 0, 0).toAWT()); 18 | 19 | for (Color testColor : asList(RED, GREEN, BLUE, BLACK, WHITE, YELLOW)) { 20 | assertAlmostEquals(testColor, LColor.fromAWT(testColor).toAWT()); 21 | } 22 | 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /core/src/test/java/org/osm2world/world/modules/common/WorldModuleParseUtilTest.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.world.modules.common; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import org.junit.Test; 6 | import org.osm2world.map_data.data.Tag; 7 | import org.osm2world.map_data.data.TagSet; 8 | 9 | public class WorldModuleParseUtilTest { 10 | 11 | @Test 12 | public void testInheritTags() { 13 | 14 | TagSet ownTags = TagSet.of( 15 | new Tag("key0", "valA"), 16 | new Tag("key1", "valB")); 17 | 18 | TagSet parentTags = TagSet.of( 19 | new Tag("key1", "valX"), 20 | new Tag("key2", "valY")); 21 | 22 | TagSet result = WorldModuleParseUtil.inheritTags(ownTags, parentTags); 23 | 24 | assertEquals(3, result.size()); 25 | assertEquals("valA", result.getValue("key0")); 26 | assertEquals("valB", result.getValue("key1")); 27 | assertEquals("valY", result.getValue("key2")); 28 | 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /core/src/test/java/org/osm2world/world/modules/traffic_sign/TrafficSignIdentifierTest.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.world.modules.traffic_sign; 2 | 3 | import static org.junit.Assert.*; 4 | import static org.osm2world.world.modules.traffic_sign.TrafficSignIdentifier.parseTrafficSignValue; 5 | 6 | import java.util.List; 7 | 8 | import org.junit.Test; 9 | 10 | public class TrafficSignIdentifierTest { 11 | 12 | @Test 13 | public void testHumanReadableValue() { 14 | TrafficSignIdentifier result = parseTrafficSignValue("city_limit").get(0); 15 | assertNull(result.country); 16 | assertEquals("city_limit", result.sign); 17 | assertNull(result.bracketText); 18 | assertNull(result.subType()); 19 | assertEquals("SIGN_CITY_LIMIT", result.configKey()); 20 | assertEquals("SIGN_CITY_LIMIT", result.configKeyWithoutSubType()); 21 | } 22 | 23 | @Test 24 | public void testComplexValue() { 25 | TrafficSignIdentifier result = parseTrafficSignValue("DE:327-50[800]").get(0); 26 | assertEquals("DE", result.country); 27 | assertEquals("327-50", result.sign); 28 | assertEquals("800", result.bracketText); 29 | assertEquals("50", result.subType()); 30 | assertEquals("SIGN_DE_327_50", result.configKey()); 31 | assertEquals("SIGN_DE_327", result.configKeyWithoutSubType()); 32 | } 33 | 34 | @Test 35 | public void testMultipleValues() { 36 | List result = parseTrafficSignValue("DE:260,1020-30; 265[3.8] "); 37 | assertEquals(3, result.size()); 38 | assertEquals("DE:260", result.get(0).toString()); 39 | assertEquals("DE:1020-30", result.get(1).toString()); 40 | assertEquals("DE:265[3.8]", result.get(2).toString()); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /core/src/test/resources/coastline_big_island.osm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /core/src/test/resources/config/parentConfig.properties: -------------------------------------------------------------------------------- 1 | include = testConfig_01.properties 2 | include = testConfig_02.properties 3 | 4 | parentProperty = 3.14 5 | -------------------------------------------------------------------------------- /core/src/test/resources/config/testConfig_01.properties: -------------------------------------------------------------------------------- 1 | treesPerSquareMeter = 0.02 2 | 3 | keepOsmElements = false 4 | -------------------------------------------------------------------------------- /core/src/test/resources/config/testConfig_02.properties: -------------------------------------------------------------------------------- 1 | stringProperty = foobar 2 | 3 | # should overwrite the value in the first file 4 | keepOsmElements = true 5 | -------------------------------------------------------------------------------- /core/src/test/resources/config/textures/test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tordanik/OSM2World/a07943134bfba721502e2225ac1389edbb610bc1/core/src/test/resources/config/textures/test.png -------------------------------------------------------------------------------- /core/src/test/resources/gltf/BoxVertexColors/BoxVertexColors.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tordanik/OSM2World/a07943134bfba721502e2225ac1389edbb610bc1/core/src/test/resources/gltf/BoxVertexColors/BoxVertexColors.glb -------------------------------------------------------------------------------- /core/src/test/resources/gltf/BoxVertexColors/buffer.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tordanik/OSM2World/a07943134bfba721502e2225ac1389edbb610bc1/core/src/test/resources/gltf/BoxVertexColors/buffer.bin -------------------------------------------------------------------------------- /core/src/test/resources/gltf/SimpleMeshes/triangle.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tordanik/OSM2World/a07943134bfba721502e2225ac1389edbb610bc1/core/src/test/resources/gltf/SimpleMeshes/triangle.bin -------------------------------------------------------------------------------- /core/src/test/resources/gltf/Triangle/Triangle.gltf: -------------------------------------------------------------------------------- 1 | { 2 | "scene" : 0, 3 | "scenes" : [ 4 | { 5 | "nodes" : [ 0 ] 6 | } 7 | ], 8 | 9 | "nodes" : [ 10 | { 11 | "mesh" : 0 12 | } 13 | ], 14 | 15 | "meshes" : [ 16 | { 17 | "primitives" : [ { 18 | "attributes" : { 19 | "POSITION" : 1 20 | }, 21 | "indices" : 0 22 | } ] 23 | } 24 | ], 25 | 26 | "buffers" : [ 27 | { 28 | "uri" : "simpleTriangle.bin", 29 | "byteLength" : 44 30 | } 31 | ], 32 | "bufferViews" : [ 33 | { 34 | "buffer" : 0, 35 | "byteOffset" : 0, 36 | "byteLength" : 6, 37 | "target" : 34963 38 | }, 39 | { 40 | "buffer" : 0, 41 | "byteOffset" : 8, 42 | "byteLength" : 36, 43 | "target" : 34962 44 | } 45 | ], 46 | "accessors" : [ 47 | { 48 | "bufferView" : 0, 49 | "byteOffset" : 0, 50 | "componentType" : 5123, 51 | "count" : 3, 52 | "type" : "SCALAR", 53 | "max" : [ 2 ], 54 | "min" : [ 0 ] 55 | }, 56 | { 57 | "bufferView" : 1, 58 | "byteOffset" : 0, 59 | "componentType" : 5126, 60 | "count" : 3, 61 | "type" : "VEC3", 62 | "max" : [ 1.0, 1.0, 0.0 ], 63 | "min" : [ 0.0, 0.0, 0.0 ] 64 | } 65 | ], 66 | 67 | "asset" : { 68 | "version" : "2.0" 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /core/src/test/resources/gltf/Triangle/Triangle_embedded.gltf: -------------------------------------------------------------------------------- 1 | { 2 | "scene" : 0, 3 | "scenes" : [ 4 | { 5 | "nodes" : [ 0 ] 6 | } 7 | ], 8 | 9 | "nodes" : [ 10 | { 11 | "mesh" : 0 12 | } 13 | ], 14 | 15 | "meshes" : [ 16 | { 17 | "primitives" : [ { 18 | "attributes" : { 19 | "POSITION" : 1 20 | }, 21 | "indices" : 0 22 | } ] 23 | } 24 | ], 25 | 26 | "buffers" : [ 27 | { 28 | "uri" : "data:application/octet-stream;base64,AAABAAIAAAAAAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAACAPwAAAAA=", 29 | "byteLength" : 44 30 | } 31 | ], 32 | "bufferViews" : [ 33 | { 34 | "buffer" : 0, 35 | "byteOffset" : 0, 36 | "byteLength" : 6, 37 | "target" : 34963 38 | }, 39 | { 40 | "buffer" : 0, 41 | "byteOffset" : 8, 42 | "byteLength" : 36, 43 | "target" : 34962 44 | } 45 | ], 46 | "accessors" : [ 47 | { 48 | "bufferView" : 0, 49 | "byteOffset" : 0, 50 | "componentType" : 5123, 51 | "count" : 3, 52 | "type" : "SCALAR", 53 | "max" : [ 2 ], 54 | "min" : [ 0 ] 55 | }, 56 | { 57 | "bufferView" : 1, 58 | "byteOffset" : 0, 59 | "componentType" : 5126, 60 | "count" : 3, 61 | "type" : "VEC3", 62 | "max" : [ 1.0, 1.0, 0.0 ], 63 | "min" : [ 0.0, 0.0, 0.0 ] 64 | } 65 | ], 66 | 67 | "asset" : { 68 | "version" : "2.0" 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /core/src/test/resources/gltf/Triangle/simpleTriangle.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tordanik/OSM2World/a07943134bfba721502e2225ac1389edbb610bc1/core/src/test/resources/gltf/Triangle/simpleTriangle.bin -------------------------------------------------------------------------------- /core/src/test/resources/gltf/TriangleWithoutIndices/TriangleWithoutIndices.gltf: -------------------------------------------------------------------------------- 1 | { 2 | "scene" : 0, 3 | "scenes" : [ 4 | { 5 | "nodes" : [ 0 ] 6 | } 7 | ], 8 | 9 | "nodes" : [ 10 | { 11 | "mesh" : 0 12 | } 13 | ], 14 | 15 | "meshes" : [ 16 | { 17 | "primitives" : [ { 18 | "attributes" : { 19 | "POSITION" : 0 20 | } 21 | } ] 22 | } 23 | ], 24 | 25 | "buffers" : [ 26 | { 27 | "uri" : "triangleWithoutIndices.bin", 28 | "byteLength" : 36 29 | } 30 | ], 31 | "bufferViews" : [ 32 | { 33 | "buffer" : 0, 34 | "byteOffset" : 0, 35 | "byteLength" : 36, 36 | "target" : 34962 37 | } 38 | ], 39 | "accessors" : [ 40 | { 41 | "bufferView" : 0, 42 | "byteOffset" : 0, 43 | "componentType" : 5126, 44 | "count" : 3, 45 | "type" : "VEC3", 46 | "max" : [ 1.0, 1.0, 0.0 ], 47 | "min" : [ 0.0, 0.0, 0.0 ] 48 | } 49 | ], 50 | 51 | "asset" : { 52 | "version" : "2.0" 53 | } 54 | } 55 | 56 | -------------------------------------------------------------------------------- /core/src/test/resources/gltf/TriangleWithoutIndices/TriangleWithoutIndices_embedded.gltf: -------------------------------------------------------------------------------- 1 | { 2 | "scene" : 0, 3 | "scenes" : [ 4 | { 5 | "nodes" : [ 0 ] 6 | } 7 | ], 8 | 9 | "nodes" : [ 10 | { 11 | "mesh" : 0 12 | } 13 | ], 14 | 15 | "meshes" : [ 16 | { 17 | "primitives" : [ { 18 | "attributes" : { 19 | "POSITION" : 0 20 | } 21 | } ] 22 | } 23 | ], 24 | 25 | "buffers" : [ 26 | { 27 | "uri" : "data:application/octet-stream;base64,AAAAAAAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAgD8AAAAA", 28 | "byteLength" : 36 29 | } 30 | ], 31 | "bufferViews" : [ 32 | { 33 | "buffer" : 0, 34 | "byteOffset" : 0, 35 | "byteLength" : 36, 36 | "target" : 34962 37 | } 38 | ], 39 | "accessors" : [ 40 | { 41 | "bufferView" : 0, 42 | "byteOffset" : 0, 43 | "componentType" : 5126, 44 | "count" : 3, 45 | "type" : "VEC3", 46 | "max" : [ 1.0, 1.0, 0.0 ], 47 | "min" : [ 0.0, 0.0, 0.0 ] 48 | } 49 | ], 50 | 51 | "asset" : { 52 | "version" : "2.0" 53 | } 54 | } -------------------------------------------------------------------------------- /core/src/test/resources/gltf/TriangleWithoutIndices/triangleWithoutIndices.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tordanik/OSM2World/a07943134bfba721502e2225ac1389edbb610bc1/core/src/test/resources/gltf/TriangleWithoutIndices/triangleWithoutIndices.bin -------------------------------------------------------------------------------- /core/src/test/resources/josmTest01.osm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /core/src/test/resources/josm_emoji.osm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /core/src/test/resources/meta.mbtiles: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tordanik/OSM2World/a07943134bfba721502e2225ac1389edbb610bc1/core/src/test/resources/meta.mbtiles -------------------------------------------------------------------------------- /core/src/test/resources/metadata_only_locale.json: -------------------------------------------------------------------------------- 1 | { 2 | locale: "AT" 3 | } 4 | -------------------------------------------------------------------------------- /core/src/test/resources/sameCoordNodes.osm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /core/src/test/resources/self_intersection.osm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /core/src/test/resources/simpleTest01.gol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tordanik/OSM2World/a07943134bfba721502e2225ac1389edbb610bc1/core/src/test/resources/simpleTest01.gol -------------------------------------------------------------------------------- /core/src/test/resources/simpleTest01.osm.pbf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tordanik/OSM2World/a07943134bfba721502e2225ac1389edbb610bc1/core/src/test/resources/simpleTest01.osm.pbf -------------------------------------------------------------------------------- /core/src/test/resources/srtm/N04E033.hgt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tordanik/OSM2World/a07943134bfba721502e2225ac1389edbb610bc1/core/src/test/resources/srtm/N04E033.hgt -------------------------------------------------------------------------------- /core/src/test/resources/srtm/N04E034.SRTMGL3.hgt.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tordanik/OSM2World/a07943134bfba721502e2225ac1389edbb610bc1/core/src/test/resources/srtm/N04E034.SRTMGL3.hgt.zip -------------------------------------------------------------------------------- /core/src/test/resources/validFile.osm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /desktop/src/main/java/org/osm2world/console/commands/GuiCommand.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.console.commands; 2 | 3 | import java.io.File; 4 | import java.util.Map; 5 | import java.util.concurrent.Callable; 6 | 7 | import javax.swing.*; 8 | 9 | import org.osm2world.console.commands.mixins.ConfigOptions; 10 | import org.osm2world.scene.mesh.LevelOfDetail; 11 | import org.osm2world.viewer.view.ViewerFrame; 12 | 13 | import picocli.CommandLine; 14 | 15 | @CommandLine.Command(name = "gui", description = "Start the graphical user interface.") 16 | public class GuiCommand implements Callable { 17 | 18 | @CommandLine.Mixin 19 | ConfigOptions configOptions = new ConfigOptions(); 20 | 21 | @Override 22 | public Integer call() { 23 | 24 | try { 25 | UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 26 | } catch(Exception e) { 27 | System.out.println("Error setting native look and feel: " + e); 28 | } 29 | 30 | File input = null; // TODO support input 31 | LevelOfDetail lod = null; // TODO support lod 32 | 33 | var viewerFrame = new ViewerFrame(configOptions.getO2WConfig(Map.of()), lod, configOptions.getConfigFiles(), input); 34 | viewerFrame.setVisible(true); 35 | 36 | return -1; // tells the main method not to call System.exit 37 | 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /desktop/src/main/java/org/osm2world/console/commands/RootCommand.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.console.commands; 2 | 3 | import static picocli.CommandLine.Command; 4 | import static picocli.CommandLine.HelpCommand; 5 | 6 | import java.util.concurrent.Callable; 7 | 8 | import org.osm2world.GlobalValues; 9 | 10 | @Command(name = "osm2world", 11 | mixinStandardHelpOptions = true, 12 | version = GlobalValues.VERSION_STRING, 13 | description = "Creates 3D models from OpenStreetMap data", 14 | subcommands = {HelpCommand.class, ConvertCommand.class, GuiCommand.class, ParamsCommand.class}) 15 | public class RootCommand implements Callable { 16 | 17 | @Override 18 | public Integer call() { 19 | return 0; 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /desktop/src/main/java/org/osm2world/console/commands/converters/LodConverter.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.console.commands.converters; 2 | 3 | import org.osm2world.scene.mesh.LevelOfDetail; 4 | 5 | import picocli.CommandLine; 6 | 7 | public class LodConverter implements CommandLine.ITypeConverter { 8 | 9 | @Override 10 | public LevelOfDetail convert(String value) throws Exception { 11 | 12 | try { 13 | value = value.toUpperCase(); 14 | value = value.replace("LOD", ""); 15 | int intValue = Integer.parseInt(value); 16 | var lod = LevelOfDetail.fromInt(intValue); 17 | if (lod != null) { 18 | return lod; 19 | } 20 | } catch (NumberFormatException ignored) {} 21 | 22 | throw new IllegalArgumentException("Not a valid LOD value"); 23 | 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /desktop/src/main/java/org/osm2world/console/commands/mixins/ConfigOptions.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.console.commands.mixins; 2 | 3 | import java.io.File; 4 | import java.util.List; 5 | import java.util.Map; 6 | 7 | import org.osm2world.conversion.O2WConfig; 8 | 9 | import picocli.CommandLine; 10 | 11 | public class ConfigOptions { 12 | 13 | @CommandLine.Option(names = {"--config"}, description = "properties file(s) with configuration parameters") 14 | private List config = List.of(); 15 | 16 | public static final File STANDARD_PROPERTIES_FILE = new File("standard.properties"); 17 | 18 | public List getConfigFiles() { 19 | 20 | if (config.isEmpty() && STANDARD_PROPERTIES_FILE.isFile()) { 21 | System.out.println("No --config parameter, using default style (" + STANDARD_PROPERTIES_FILE + ").\n"); 22 | return List.of(STANDARD_PROPERTIES_FILE); 23 | } else { 24 | return config; 25 | } 26 | 27 | } 28 | 29 | public O2WConfig getO2WConfig(Map extraProperties) { 30 | 31 | File[] configFiles = getConfigFiles().toArray(new File[0]); 32 | 33 | try { 34 | return new O2WConfig(extraProperties, configFiles); 35 | } catch (Exception e) { 36 | System.err.println("could not read config, ignoring it:\n" + e); 37 | return new O2WConfig(); 38 | } 39 | 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /desktop/src/main/java/org/osm2world/console/commands/mixins/InputOptions.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.console.commands.mixins; 2 | 3 | import java.io.File; 4 | 5 | import org.osm2world.osm.creation.OverpassReader; 6 | 7 | import picocli.CommandLine; 8 | 9 | public class InputOptions { 10 | 11 | public enum InputMode {FILE, OVERPASS} 12 | 13 | @CommandLine.Option(names = {"--input_mode"}, description = "input mode (FILE or OVERPASS)", 14 | paramLabel = "", defaultValue = "FILE") 15 | public InputMode inputMode; 16 | 17 | @CommandLine.Option(names = {"--input", "-i"}, required = true, description = "input file with data in OSM format", 18 | paramLabel = "") 19 | public File input; 20 | 21 | @CommandLine.Option(names = {"--overpass_url"}, description = "Overpass API instance to use", 22 | defaultValue = OverpassReader.DEFAULT_API_URL, paramLabel = "") 23 | public String overpassURL; 24 | 25 | } 26 | -------------------------------------------------------------------------------- /desktop/src/main/java/org/osm2world/console/commands/mixins/LoggingOptions.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.console.commands.mixins; 2 | 3 | import java.io.File; 4 | 5 | import javax.annotation.Nullable; 6 | 7 | import picocli.CommandLine; 8 | 9 | public class LoggingOptions { 10 | 11 | @CommandLine.Option(names = {"--logDir"}, description = "output directory for log files", paramLabel = "") 12 | public @Nullable File logDir; 13 | 14 | } 15 | -------------------------------------------------------------------------------- /desktop/src/main/java/org/osm2world/console/commands/mixins/MetadataOptions.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.console.commands.mixins; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | 8 | import javax.annotation.Nullable; 9 | 10 | import org.imintel.mbtiles4j.MBTilesReadException; 11 | import org.osm2world.map_data.data.MapMetadata; 12 | import org.osm2world.math.geo.TileNumber; 13 | 14 | import picocli.CommandLine; 15 | 16 | public class MetadataOptions { 17 | 18 | @CommandLine.Option(names = {"--metadataFile"}, description = "path to a JSON file with metadata, " + 19 | "or an mbtiles file with such JSON data for multiple tiles", paramLabel = "") 20 | public @Nullable File metadataFile; 21 | 22 | public static Map configOptionsFromMetadata(@Nullable File metadataFile, @Nullable TileNumber tile) 23 | throws IOException { 24 | 25 | Map result = new HashMap<>(); 26 | 27 | if (metadataFile != null) { 28 | 29 | MapMetadata metadata = null; 30 | 31 | if (metadataFile.getName().endsWith(".mbtiles")) { 32 | if (tile != null) { 33 | try { 34 | metadata = MapMetadata.metadataForTile(tile, metadataFile); 35 | } catch (MBTilesReadException e) { 36 | System.err.println("Cannot read tile metadata: " + e); 37 | } 38 | } 39 | } else { 40 | metadata = MapMetadata.metadataFromJson(metadataFile); 41 | } 42 | 43 | if (metadata != null && metadata.land() == Boolean.FALSE) { 44 | result.put("isAtSea", true); 45 | } 46 | 47 | } 48 | 49 | return result; 50 | 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /desktop/src/main/java/org/osm2world/console/package-info.java: -------------------------------------------------------------------------------- 1 | /** Command line interface for OSM2World. */ 2 | package org.osm2world.console; -------------------------------------------------------------------------------- /desktop/src/main/java/org/osm2world/viewer/Viewer.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.viewer; 2 | 3 | import javax.swing.*; 4 | 5 | import org.osm2world.conversion.O2WConfig; 6 | import org.osm2world.viewer.view.ViewerFrame; 7 | 8 | public class Viewer { 9 | 10 | private Viewer(String[] args) { 11 | 12 | try { 13 | UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 14 | } catch(Exception e) { 15 | System.out.println("Error setting native look and feel: " + e); 16 | } 17 | 18 | new ViewerFrame(new O2WConfig(), null, null, null).setVisible(true); 19 | 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /desktop/src/main/java/org/osm2world/viewer/control/actions/ExitAction.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.viewer.control.actions; 2 | 3 | import java.awt.event.ActionEvent; 4 | import java.awt.event.KeyEvent; 5 | 6 | import javax.swing.AbstractAction; 7 | import javax.swing.KeyStroke; 8 | 9 | /** 10 | * closes the application */ 11 | public class ExitAction extends AbstractAction { 12 | 13 | private static final long serialVersionUID = -7239839993534668987L; //generated serialVersionUID 14 | 15 | public ExitAction() { 16 | super("Exit"); 17 | putValue(SHORT_DESCRIPTION, "Closes the application"); 18 | putValue(MNEMONIC_KEY, KeyEvent.VK_X); 19 | putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke( 20 | KeyEvent.VK_Q, ActionEvent.CTRL_MASK)); 21 | } 22 | 23 | @Override 24 | public void actionPerformed(ActionEvent e) { 25 | System.exit(0); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /desktop/src/main/java/org/osm2world/viewer/control/actions/HelpControlsAction.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.viewer.control.actions; 2 | 3 | import java.awt.event.ActionEvent; 4 | 5 | import javax.swing.*; 6 | 7 | public class HelpControlsAction extends AbstractAction { 8 | 9 | private static final long serialVersionUID = 9195787581575616092L; //generated serialVersionUID 10 | 11 | public HelpControlsAction() { 12 | super("Controls"); 13 | } 14 | 15 | @Override 16 | public void actionPerformed(ActionEvent arg0) { 17 | JOptionPane.showMessageDialog(null, "OSM2World GUI Controls:\n" 18 | + "* left mouse button moves the camera position\n" 19 | + "* right mouse button rotates the camera direction\n" 20 | + "* mouse wheel or touchpad zoom moves the camera closer to or away from the ground\n" 21 | + "* various forms of keyboard input are supported", 22 | "About OSM2World", JOptionPane.INFORMATION_MESSAGE); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /desktop/src/main/java/org/osm2world/viewer/control/actions/SetLodAction.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.viewer.control.actions; 2 | 3 | import java.awt.event.ActionEvent; 4 | import java.io.Serial; 5 | 6 | import javax.swing.*; 7 | 8 | import org.osm2world.conversion.O2WConfig; 9 | import org.osm2world.scene.mesh.LevelOfDetail; 10 | import org.osm2world.viewer.model.Data; 11 | import org.osm2world.viewer.model.RenderOptions; 12 | import org.osm2world.viewer.view.ViewerFrame; 13 | 14 | public class SetLodAction extends AbstractAction { 15 | 16 | @Serial 17 | private static final long serialVersionUID = 1L; 18 | 19 | LevelOfDetail lod; 20 | ViewerFrame viewerFrame; 21 | Data data; 22 | RenderOptions renderOptions; 23 | 24 | public SetLodAction(LevelOfDetail lod, ViewerFrame viewerFrame, Data data, RenderOptions renderOptions) { 25 | 26 | super(lod.name()); 27 | 28 | putValue(SELECTED_KEY, lod == renderOptions.getLod()); 29 | 30 | this.lod = lod; 31 | this.viewerFrame = viewerFrame; 32 | this.data = data; 33 | this.renderOptions = renderOptions; 34 | 35 | } 36 | 37 | @Override 38 | public void actionPerformed(ActionEvent e) { 39 | 40 | renderOptions.setLod(lod); 41 | 42 | O2WConfig config = data.getConfig().withProperty("lod", lod.ordinal()); 43 | data.setConfig(config); 44 | 45 | putValue(SELECTED_KEY, lod == renderOptions.getLod()); 46 | 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /desktop/src/main/java/org/osm2world/viewer/control/actions/StatisticsAction.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.viewer.control.actions; 2 | 3 | import java.awt.event.ActionEvent; 4 | import java.util.Observable; 5 | import java.util.Observer; 6 | 7 | import javax.swing.*; 8 | 9 | import org.osm2world.scene.mesh.LevelOfDetail; 10 | import org.osm2world.output.statistics.StatisticsOutput; 11 | import org.osm2world.scene.Scene; 12 | import org.osm2world.viewer.model.Data; 13 | import org.osm2world.viewer.view.StatisticsDialog; 14 | import org.osm2world.viewer.view.ViewerFrame; 15 | 16 | 17 | public class StatisticsAction extends AbstractAction implements Observer { 18 | 19 | private static final long serialVersionUID = -7894095901533692645L; 20 | private final ViewerFrame viewerFrame; 21 | private final Data data; 22 | 23 | public StatisticsAction(ViewerFrame viewerFrame, Data data) { 24 | 25 | super("Statistics"); 26 | putValue(SHORT_DESCRIPTION, "Shows statistics for the current scene"); 27 | 28 | this.viewerFrame = viewerFrame; 29 | this.data = data; 30 | 31 | setEnabled(false); 32 | data.addObserver(this); 33 | 34 | } 35 | 36 | @Override 37 | public void update(Observable o, Object arg) { 38 | setEnabled(data.getConversionResults() != null); 39 | } 40 | 41 | @Override 42 | public void actionPerformed(ActionEvent arg0) { 43 | 44 | Scene conversionResults = data.getConversionResults(); 45 | 46 | LevelOfDetail lod = data.getConfig().getLod(); 47 | StatisticsOutput stats = new StatisticsOutput(lod); 48 | 49 | stats.outputScene(conversionResults); 50 | new StatisticsDialog(viewerFrame, stats).setVisible(true); 51 | 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /desktop/src/main/java/org/osm2world/viewer/control/actions/ToggleBackfaceCullingAction.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.viewer.control.actions; 2 | 3 | import java.awt.event.ActionEvent; 4 | 5 | import javax.swing.AbstractAction; 6 | 7 | import org.osm2world.viewer.model.Data; 8 | import org.osm2world.viewer.model.RenderOptions; 9 | import org.osm2world.viewer.view.ViewerFrame; 10 | 11 | public class ToggleBackfaceCullingAction extends AbstractAction { 12 | 13 | private static final long serialVersionUID = 3993313015641228064L; 14 | private final ViewerFrame viewerFrame; 15 | private final Data data; 16 | private final RenderOptions renderOptions; 17 | 18 | public ToggleBackfaceCullingAction(ViewerFrame viewerFrame, Data data, 19 | RenderOptions renderOptions) { 20 | 21 | super("Backface culling"); 22 | putValue(SHORT_DESCRIPTION, "Switches backface culling on and off"); 23 | putValue(SELECTED_KEY, renderOptions.isBackfaceCulling()); 24 | 25 | this.viewerFrame = viewerFrame; 26 | this.data = data; 27 | this.renderOptions = renderOptions; 28 | 29 | } 30 | 31 | @Override 32 | public void actionPerformed(ActionEvent e) { 33 | 34 | renderOptions.setBackfaceCulling(!renderOptions.isBackfaceCulling()); 35 | putValue(SELECTED_KEY, renderOptions.isBackfaceCulling()); 36 | 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /desktop/src/main/java/org/osm2world/viewer/control/actions/ToggleOrthographicProjectionAction.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.viewer.control.actions; 2 | 3 | import java.awt.event.ActionEvent; 4 | import java.awt.event.KeyEvent; 5 | 6 | import javax.swing.*; 7 | 8 | import org.osm2world.viewer.model.Data; 9 | import org.osm2world.viewer.model.Defaults; 10 | import org.osm2world.viewer.model.RenderOptions; 11 | import org.osm2world.viewer.view.ViewerFrame; 12 | 13 | 14 | public class ToggleOrthographicProjectionAction extends AbstractAction { 15 | 16 | private static final long serialVersionUID = 8546764815038965935L; 17 | private final ViewerFrame viewerFrame; 18 | private final Data data; 19 | private final RenderOptions renderOptions; 20 | 21 | public ToggleOrthographicProjectionAction(ViewerFrame viewerFrame, Data data, 22 | RenderOptions renderOptions) { 23 | 24 | super("Orthographic projection"); 25 | putValue(SHORT_DESCRIPTION, "Switches between orthographic and perspective projection"); 26 | putValue(MNEMONIC_KEY, KeyEvent.VK_C); 27 | putValue(SELECTED_KEY, renderOptions.projection.orthographic()); 28 | 29 | this.viewerFrame = viewerFrame; 30 | this.data = data; 31 | this.renderOptions = renderOptions; 32 | 33 | } 34 | 35 | @Override 36 | public void actionPerformed(ActionEvent e) { 37 | 38 | if (renderOptions.projection.orthographic()) { 39 | renderOptions.projection = Defaults.PERSPECTIVE_PROJECTION; 40 | } else { 41 | renderOptions.projection = Defaults.ORTHOGRAPHIC_PROJECTION; 42 | } 43 | 44 | putValue(SELECTED_KEY, renderOptions.projection.orthographic()); 45 | 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /desktop/src/main/java/org/osm2world/viewer/control/actions/ToggleWireframeAction.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.viewer.control.actions; 2 | 3 | import java.awt.event.ActionEvent; 4 | import java.awt.event.KeyEvent; 5 | 6 | import javax.swing.AbstractAction; 7 | 8 | import org.osm2world.viewer.model.Data; 9 | import org.osm2world.viewer.model.RenderOptions; 10 | import org.osm2world.viewer.view.ViewerFrame; 11 | 12 | 13 | public class ToggleWireframeAction extends AbstractAction { 14 | 15 | private static final long serialVersionUID = 6710342251037183143L; 16 | private final ViewerFrame viewerFrame; 17 | private final Data data; 18 | private final RenderOptions renderOptions; 19 | 20 | public ToggleWireframeAction(ViewerFrame viewerFrame, Data data, 21 | RenderOptions renderOptions) { 22 | 23 | super("Wireframe view"); 24 | putValue(SHORT_DESCRIPTION, "Switches between wireframe and solid view"); 25 | putValue(MNEMONIC_KEY, KeyEvent.VK_F); 26 | putValue(SELECTED_KEY, renderOptions.isWireframe()); 27 | 28 | this.viewerFrame = viewerFrame; 29 | this.data = data; 30 | this.renderOptions = renderOptions; 31 | 32 | } 33 | 34 | @Override 35 | public void actionPerformed(ActionEvent e) { 36 | 37 | renderOptions.setWireframe(!renderOptions.isWireframe()); 38 | putValue(SELECTED_KEY, renderOptions.isWireframe()); 39 | 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /desktop/src/main/java/org/osm2world/viewer/control/actions/ToggleWorldObjectsAction.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.viewer.control.actions; 2 | 3 | import java.awt.event.ActionEvent; 4 | import java.awt.event.KeyEvent; 5 | 6 | import javax.swing.AbstractAction; 7 | 8 | import org.osm2world.viewer.model.Data; 9 | import org.osm2world.viewer.model.RenderOptions; 10 | import org.osm2world.viewer.view.ViewerFrame; 11 | 12 | 13 | public class ToggleWorldObjectsAction extends AbstractAction { 14 | 15 | private static final long serialVersionUID = -5751259322056033212L; 16 | private final ViewerFrame viewerFrame; 17 | private final Data data; 18 | private final RenderOptions renderOptions; 19 | 20 | public ToggleWorldObjectsAction(ViewerFrame viewerFrame, Data data, 21 | RenderOptions renderOptions) { 22 | 23 | super("World objects"); 24 | putValue(SHORT_DESCRIPTION, "Controls whether world objects are displayed"); 25 | putValue(MNEMONIC_KEY, KeyEvent.VK_W); 26 | putValue(SELECTED_KEY, renderOptions.isShowWorldObjects()); 27 | 28 | this.viewerFrame = viewerFrame; 29 | this.data = data; 30 | this.renderOptions = renderOptions; 31 | 32 | } 33 | 34 | @Override 35 | public void actionPerformed(ActionEvent e) { 36 | 37 | renderOptions.setShowWorldObjects(!renderOptions.isShowWorldObjects()); 38 | putValue(SELECTED_KEY, renderOptions.isShowWorldObjects()); 39 | 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /desktop/src/main/java/org/osm2world/viewer/model/Defaults.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.viewer.model; 2 | 3 | import org.osm2world.output.common.rendering.OrthographicProjection; 4 | import org.osm2world.output.common.rendering.PerspectiveProjection; 5 | 6 | public final class Defaults { 7 | 8 | private Defaults() { } 9 | 10 | public static final PerspectiveProjection PERSPECTIVE_PROJECTION 11 | = new PerspectiveProjection(4/3.0, 50, 1, 100000); 12 | 13 | public static final OrthographicProjection ORTHOGRAPHIC_PROJECTION 14 | = new OrthographicProjection(4/3.0, 45, -10000, 10000); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /desktop/src/main/java/org/osm2world/viewer/model/MessageManager.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.viewer.model; 2 | 3 | import java.util.Iterator; 4 | import java.util.LinkedList; 5 | 6 | /** 7 | * receives and stores the messages that are displayed to the user 8 | */ 9 | public class MessageManager { //TODO: isn't this a *model* class...? 10 | 11 | public static final long DEFAULT_MILLISECONDS_TO_LIVE = 3000; 12 | 13 | public static class Message { 14 | public final String messageString; 15 | public final long expiration; 16 | public Message(String messageString, long expiration) { 17 | this.messageString = messageString; 18 | this.expiration = expiration; 19 | } 20 | } 21 | 22 | private LinkedList messages = new LinkedList(); 23 | 24 | private void addMessage(String message, long millisecondsToLive) { 25 | long expiration = System.currentTimeMillis() + millisecondsToLive; 26 | messages.add(new Message(message, expiration )); 27 | } 28 | 29 | public void addMessage(String message) { 30 | addMessage(message, DEFAULT_MILLISECONDS_TO_LIVE); 31 | } 32 | 33 | public LinkedList getLiveMessages() { 34 | removeExpiredMessages(); 35 | return messages; 36 | } 37 | 38 | private void removeExpiredMessages() { 39 | long now = System.currentTimeMillis(); 40 | for (Iterator messageIterator = messages.iterator(); messageIterator.hasNext();) { 41 | Message message = messageIterator.next(); 42 | if (now > message.expiration) { 43 | messageIterator.remove(); 44 | } 45 | } 46 | } 47 | 48 | } -------------------------------------------------------------------------------- /desktop/src/main/java/org/osm2world/viewer/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Basic graphical interface for OSM2World. 3 | * The graphical interface is based on Swing and JOGL. 4 | */ 5 | package org.osm2world.viewer; -------------------------------------------------------------------------------- /desktop/src/main/java/org/osm2world/viewer/view/ProgressDialog.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.viewer.view; 2 | 3 | import java.awt.BorderLayout; 4 | 5 | import javax.swing.JDialog; 6 | import javax.swing.JPanel; 7 | import javax.swing.JProgressBar; 8 | import javax.swing.JTextField; 9 | 10 | public class ProgressDialog extends JDialog { 11 | 12 | private static final long serialVersionUID = -1016979607905010257L; //generated serialVersionUID 13 | private final JProgressBar progressBar; 14 | private final JTextField statusField; 15 | 16 | public ProgressDialog(ViewerFrame viewerFrame, String title) { 17 | 18 | super(viewerFrame, title); 19 | 20 | JPanel panel = new JPanel(); 21 | BorderLayout layout = new BorderLayout(); 22 | panel.setLayout(layout); 23 | 24 | progressBar = new JProgressBar(); 25 | panel.add(progressBar, BorderLayout.CENTER); 26 | 27 | statusField = new JTextField(50); 28 | statusField.setEditable(false); 29 | panel.add(statusField, BorderLayout.SOUTH); 30 | 31 | this.add(panel); 32 | 33 | setProgress(null); 34 | 35 | this.pack(); 36 | this.setVisible(true); 37 | 38 | } 39 | 40 | public void setText(String text) { 41 | statusField.setText(text); 42 | } 43 | 44 | /** 45 | * @param progress progress percentage or null for indeterminate progress 46 | */ 47 | public void setProgress(Integer progress) { 48 | if (progress == null) { 49 | progressBar.setIndeterminate(true); 50 | } else { 51 | progressBar.setIndeterminate(false); 52 | progressBar.setValue(progress); 53 | } 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /desktop/src/main/java/org/osm2world/viewer/view/TextRenderer.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.viewer.view; 2 | 3 | import java.awt.Color; 4 | 5 | public interface TextRenderer { 6 | 7 | //public abstract void drawText(String string, Vector3D pos, Color color); 8 | 9 | /** 10 | * Draw text beginning at the topleft corner of the window with offset x and y. 11 | * @param string the text to draw 12 | * @param x left offset 13 | * @param y top offset 14 | * @param color text color 15 | */ 16 | public abstract void drawTextTop(String string, float x, float y, Color color); 17 | 18 | /** 19 | * Draw text beginning at the bottomleft corner of the window with offset x and y. 20 | * @param string the text to draw 21 | * @param x left offset 22 | * @param y bottom offset 23 | * @param color text color 24 | */ 25 | public abstract void drawTextBottom(String string, float x, float y, Color color); 26 | 27 | /** 28 | * Reshape the rendering region of the text renderer. Has to be called when the canvas size changes. 29 | */ 30 | public abstract void reshape(int width, int height); 31 | 32 | /** 33 | * Set the scale factor to apply to the whole textrendering. Scales offsets and fontsize. Default is 1 34 | */ 35 | public abstract void setScale(float scale); 36 | 37 | /** 38 | * Free all resources. 39 | */ 40 | public abstract void destroy(); 41 | } 42 | -------------------------------------------------------------------------------- /desktop/src/main/java/org/osm2world/viewer/view/TextRendererShader.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.viewer.view; 2 | 3 | import java.awt.Color; 4 | 5 | import com.jogamp.opengl.GL2ES2; 6 | 7 | public class TextRendererShader implements org.osm2world.viewer.view.TextRenderer { 8 | 9 | // TODO: this is currently unimplemented after the incompatible upgrade to JOGL 1.4 10 | 11 | public TextRendererShader(GL2ES2 gl) {} 12 | 13 | @Override 14 | public void destroy() {} 15 | 16 | @Override 17 | public void drawTextTop(String string, float x, float y, Color color) {} 18 | 19 | @Override 20 | public void drawTextBottom(String string, float x, float y, Color color) {} 21 | 22 | @Override 23 | public void reshape(int width, int height) {} 24 | 25 | @Override 26 | public void setScale(float scale) {} 27 | 28 | } 29 | -------------------------------------------------------------------------------- /desktop/src/main/java/org/osm2world/viewer/view/debug/EleConnectorDebugView.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.viewer.view.debug; 2 | 3 | import static java.awt.Color.BLUE; 4 | 5 | import java.awt.*; 6 | 7 | import org.osm2world.map_elevation.data.EleConnector; 8 | import org.osm2world.output.jogl.JOGLOutput; 9 | import org.osm2world.world.data.WorldObject; 10 | 11 | /** 12 | * shows all {@link EleConnector}s 13 | */ 14 | public class EleConnectorDebugView extends DebugView { 15 | 16 | private static final Color CONNECTOR_COLOR = BLUE; 17 | private static final float CONNECTOR_HALF_WIDTH = 0.25f; 18 | 19 | @Override 20 | public String getDescription() { 21 | return "shows all elevation connectors"; 22 | } 23 | 24 | @Override 25 | public boolean canBeUsed() { 26 | return scene != null; 27 | } 28 | 29 | @Override 30 | protected void fillTarget(JOGLOutput target) { 31 | 32 | for (WorldObject worldObject : scene.getWorldObjects()) { 33 | for (EleConnector eleConnector : worldObject.getEleConnectors()) { 34 | if (eleConnector.getPosXYZ() == null) { 35 | continue; //TODO shouldn't happen 36 | } 37 | drawBoxAround(target, eleConnector.getPosXYZ(), 38 | CONNECTOR_COLOR, CONNECTOR_HALF_WIDTH); 39 | } 40 | } 41 | 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /desktop/src/main/java/org/osm2world/viewer/view/debug/FaceDebugView.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.viewer.view.debug; 2 | 3 | import java.awt.*; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | 7 | import org.osm2world.math.VectorXYZ; 8 | import org.osm2world.math.VectorXZ; 9 | import org.osm2world.output.common.FaceOutput; 10 | import org.osm2world.scene.material.Material; 11 | import org.osm2world.output.jogl.JOGLOutput; 12 | import org.osm2world.world.data.WorldObject; 13 | 14 | /** 15 | * shows decomposition of {@link WorldObject}s into faces 16 | * as they would be written to any {@link FaceOutput} 17 | */ 18 | public class FaceDebugView extends DebugView { 19 | 20 | private static final Color BORDER_COLOR = new Color(0, 0, 1.0f); 21 | 22 | @Override 23 | public String getDescription() { 24 | return "shows decomposition of WorldObjects into faces"; 25 | } 26 | 27 | @Override 28 | public boolean canBeUsed() { 29 | return scene != null; 30 | } 31 | 32 | private static class FaceSink extends FaceOutput { 33 | 34 | public final List> faces = 35 | new ArrayList>(); 36 | 37 | @Override 38 | public boolean reconstructFaces() { 39 | return true; 40 | } 41 | 42 | @Override 43 | public void drawFace(Material material, List vs, 44 | List normals, List> texCoordLists) { 45 | faces.add(vs); 46 | } 47 | 48 | } 49 | 50 | @Override 51 | protected void fillTarget(JOGLOutput target) { 52 | 53 | FaceSink faceSink = new FaceSink(); 54 | faceSink.outputScene(scene); 55 | 56 | for (List face : faceSink.faces) { 57 | target.drawLineLoop(BORDER_COLOR, 2, face); 58 | } 59 | 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /desktop/src/main/java/org/osm2world/viewer/view/debug/InverseDistanceWeightingInterpolatorDebugView.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.viewer.view.debug; 2 | 3 | import org.osm2world.map_elevation.creation.InverseDistanceWeightingInterpolator; 4 | import org.osm2world.viewer.model.RenderOptions; 5 | 6 | 7 | public class InverseDistanceWeightingInterpolatorDebugView extends TerrainInterpolatorDebugView { 8 | 9 | public InverseDistanceWeightingInterpolatorDebugView(RenderOptions renderOptions) { 10 | super(renderOptions); 11 | } 12 | 13 | @Override 14 | protected InverseDistanceWeightingInterpolator buildInterpolator() { 15 | return new InverseDistanceWeightingInterpolator(1); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /desktop/src/main/java/org/osm2world/viewer/view/debug/LeastSquaresInterpolatorDebugView.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.viewer.view.debug; 2 | 3 | import org.osm2world.map_elevation.creation.LeastSquaresInterpolator; 4 | import org.osm2world.viewer.model.RenderOptions; 5 | 6 | 7 | public class LeastSquaresInterpolatorDebugView extends TerrainInterpolatorDebugView { 8 | 9 | public LeastSquaresInterpolatorDebugView(RenderOptions renderOptions) { 10 | super(renderOptions); 11 | } 12 | 13 | @Override 14 | protected LeastSquaresInterpolator buildInterpolator() { 15 | return new LeastSquaresInterpolator(); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /desktop/src/main/java/org/osm2world/viewer/view/debug/LinearInterpolatorDebugView.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.viewer.view.debug; 2 | 3 | import org.osm2world.map_elevation.creation.LinearInterpolator; 4 | import org.osm2world.viewer.model.RenderOptions; 5 | 6 | public class LinearInterpolatorDebugView extends TerrainInterpolatorDebugView { 7 | 8 | public LinearInterpolatorDebugView(RenderOptions renderOptions) { 9 | super(renderOptions); 10 | } 11 | 12 | @Override 13 | protected LinearInterpolator buildInterpolator() { 14 | return new LinearInterpolator(); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /desktop/src/main/java/org/osm2world/viewer/view/debug/MapDataBoundsDebugView.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.viewer.view.debug; 2 | 3 | import java.awt.*; 4 | import java.util.List; 5 | 6 | import org.osm2world.math.VectorXZ; 7 | import org.osm2world.output.jogl.JOGLOutput; 8 | 9 | /** 10 | * shows the bounding boxes of map data 11 | */ 12 | public class MapDataBoundsDebugView extends DebugView { 13 | 14 | @Override 15 | public String getDescription() { 16 | return "shows the bounding boxes of map data"; 17 | } 18 | 19 | @Override 20 | public boolean canBeUsed() { 21 | return scene != null; 22 | } 23 | 24 | private static final Color DATA_BB_COLOR = Color.YELLOW; 25 | private static final Color FILE_BB_COLOR = Color.GREEN; 26 | 27 | @Override 28 | protected void fillTarget(JOGLOutput target) { 29 | 30 | List vs = scene.getBoundary().polygonXZ().vertices(); 31 | target.drawLineLoop(DATA_BB_COLOR, 1, VectorXZ.listXYZ(vs, 0)); 32 | 33 | vs = scene.getBoundary().polygonXZ().vertices(); 34 | target.drawLineLoop(FILE_BB_COLOR, 1, VectorXZ.listXYZ(vs, 0)); 35 | 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /desktop/src/main/java/org/osm2world/viewer/view/debug/NaturalNeighborInterpolatorDebugView.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.viewer.view.debug; 2 | 3 | import org.osm2world.map_elevation.creation.NaturalNeighborInterpolator; 4 | import org.osm2world.viewer.model.RenderOptions; 5 | 6 | 7 | public class NaturalNeighborInterpolatorDebugView extends TerrainInterpolatorDebugView { 8 | 9 | public NaturalNeighborInterpolatorDebugView(RenderOptions renderOptions) { 10 | super(renderOptions); 11 | } 12 | 13 | @Override 14 | protected NaturalNeighborInterpolator buildInterpolator() { 15 | return new NaturalNeighborInterpolator(); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /desktop/src/main/java/org/osm2world/viewer/view/debug/SkyboxView.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.viewer.view.debug; 2 | 3 | import static java.lang.Math.sqrt; 4 | 5 | import org.osm2world.math.VectorXZ; 6 | import org.osm2world.output.common.lighting.GlobalLightingParameters; 7 | import org.osm2world.scene.material.Materials; 8 | import org.osm2world.output.jogl.JOGLOutput; 9 | import org.osm2world.output.jogl.JOGLRenderingParameters; 10 | 11 | public class SkyboxView extends DebugView { 12 | 13 | @Override 14 | public String getDescription() { 15 | return "shows a skybox in the background"; 16 | } 17 | 18 | @Override 19 | public boolean canBeUsed() { 20 | return scene != null; 21 | } 22 | 23 | @Override 24 | protected void fillTarget(JOGLOutput target) { 25 | 26 | target.setGlobalLightingParameters(GlobalLightingParameters.DEFAULT); 27 | 28 | // disable backface culling 29 | target.setRenderingParameters( 30 | new JOGLRenderingParameters(null, false, true)); 31 | 32 | // draw the skybox close to the limits of the viewing distance 33 | double skyboxSize = 1.95 * projection.farClippingDistance() / sqrt(3); 34 | 35 | target.drawBox(Materials.SKYBOX, 36 | camera.pos().add(0, -skyboxSize / 2, 0), 37 | VectorXZ.Z_UNIT, skyboxSize, skyboxSize, skyboxSize); 38 | 39 | target.finish(); 40 | 41 | } 42 | 43 | @Override 44 | protected void updateTarget(JOGLOutput target, boolean viewChanged) { 45 | if (viewChanged) { 46 | target.reset(); 47 | fillTarget(target); 48 | } 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /desktop/src/main/java/org/osm2world/viewer/view/debug/WorldObjectNormalsDebugView.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.viewer.view.debug; 2 | 3 | import java.awt.*; 4 | 5 | import org.osm2world.math.VectorXYZ; 6 | import org.osm2world.output.common.Primitive; 7 | import org.osm2world.scene.material.Material; 8 | import org.osm2world.scene.material.Material.Interpolation; 9 | import org.osm2world.output.jogl.JOGLOutput; 10 | import org.osm2world.output.jogl.PrimitiveBuffer; 11 | 12 | public class WorldObjectNormalsDebugView extends DebugView { 13 | 14 | private static final Color FLAT_NORMALS_COLOR = Color.YELLOW; 15 | private static final Color SMOOTH_NORMALS_COLOR = Color.ORANGE; 16 | 17 | @Override 18 | public String getDescription() { 19 | return "draws world object normals as arrows"; 20 | } 21 | 22 | @Override 23 | public boolean canBeUsed() { 24 | return scene != null; 25 | } 26 | 27 | @Override 28 | protected void fillTarget(JOGLOutput target) { 29 | 30 | final PrimitiveBuffer primitiveBuffer = new PrimitiveBuffer(); 31 | 32 | primitiveBuffer.outputScene(scene); 33 | 34 | for (Material material : primitiveBuffer .getMaterials()) { 35 | 36 | Color color = material.getInterpolation() == Interpolation.FLAT ? 37 | FLAT_NORMALS_COLOR : SMOOTH_NORMALS_COLOR; 38 | 39 | for (Primitive primitive : primitiveBuffer.getPrimitives(material)) { 40 | 41 | for (int i = 0; i < primitive.vertices.size(); i++) { 42 | VectorXYZ v = primitive.vertices.get(i); 43 | VectorXYZ n = primitive.normals.get(i); 44 | if (n != null) { 45 | drawArrow(target, color, 0.3f, v, v.add(n)); 46 | } 47 | } 48 | 49 | } 50 | 51 | } 52 | 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /desktop/src/main/resources/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tordanik/OSM2World/a07943134bfba721502e2225ac1389edbb610bc1/desktop/src/main/resources/logo.png -------------------------------------------------------------------------------- /desktop/src/test/resources/testWall.osm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /opengl/src/main/java/org/osm2world/output/image/ImageOutputFormat.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.output.image; 2 | 3 | public enum ImageOutputFormat { 4 | PNG, 5 | PPM, 6 | GD 7 | } 8 | -------------------------------------------------------------------------------- /opengl/src/main/java/org/osm2world/output/image/package-info.java: -------------------------------------------------------------------------------- 1 | /** Render scenes to raster images. */ 2 | package org.osm2world.output.image; -------------------------------------------------------------------------------- /opengl/src/main/java/org/osm2world/output/jogl/NonAreaPrimitive.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.output.jogl; 2 | 3 | import java.awt.*; 4 | import java.util.List; 5 | 6 | import org.osm2world.math.VectorXYZ; 7 | 8 | /** 9 | * represents points and lines to be drawn by a {@link JOGLOutput}. 10 | */ 11 | class NonAreaPrimitive { 12 | 13 | static enum Type { 14 | POINTS, LINES, LINE_STRIP, LINE_LOOP 15 | } 16 | 17 | public final Type type; 18 | public final Color color; 19 | public final int width; 20 | public final List vs; 21 | 22 | public NonAreaPrimitive(Type type, Color color, int width, 23 | List vs) { 24 | 25 | this.type = type; 26 | this.color = color; 27 | this.width = width; 28 | this.vs = vs; 29 | 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /opengl/src/main/java/org/osm2world/output/jogl/PrimitiveBuffer.java: -------------------------------------------------------------------------------- 1 | package org.osm2world.output.jogl; 2 | 3 | import java.util.Collection; 4 | import java.util.List; 5 | import java.util.Set; 6 | 7 | import org.osm2world.math.VectorXYZ; 8 | import org.osm2world.math.VectorXZ; 9 | import org.osm2world.output.common.Primitive; 10 | import org.osm2world.output.common.Primitive.Type; 11 | import org.osm2world.output.common.PrimitiveOutput; 12 | import org.osm2world.scene.material.Material; 13 | 14 | import com.google.common.collect.HashMultimap; 15 | import com.google.common.collect.Multimap; 16 | 17 | /** 18 | * Storage for low-level rendering information (vertex and primitive data) 19 | * that can be displayed using graphics APIs, e.g. OpenGL. 20 | * Higher-level information, such as object coherence, OSM attributes 21 | * or representations, isn't present in a PrimitiveBuffer. 22 | */ 23 | public class PrimitiveBuffer extends PrimitiveOutput { 24 | 25 | private Multimap primitiveMap = HashMultimap.create(); 26 | 27 | @Override 28 | protected void drawPrimitive(Type type, Material material, 29 | List vertices, List normals, 30 | List> texCoordLists) { 31 | primitiveMap.put(material, 32 | new Primitive(type, vertices, normals, texCoordLists)); 33 | } 34 | 35 | /** 36 | * returns all materials used in the buffer 37 | */ 38 | public Set getMaterials() { 39 | return primitiveMap.keySet(); 40 | } 41 | 42 | /** 43 | * returns all primitives that use a given material 44 | */ 45 | public Collection getPrimitives(Material material) { 46 | return primitiveMap.get(material); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /opengl/src/main/java/org/osm2world/output/jogl/package-info.java: -------------------------------------------------------------------------------- 1 | /** Display scenes using OpenGL real-time rendering. */ 2 | package org.osm2world.output.jogl; -------------------------------------------------------------------------------- /opengl/src/main/resources/shaders/background.fragment: -------------------------------------------------------------------------------- 1 | /* Simple fragment shader for drawing a 2d geometry with texture to screen 2 | */ 3 | #version 130 4 | 5 | uniform mat4 ModelViewMatrix; 6 | 7 | // corresponds with output from vertex shader, gets interpolated 8 | in vec2 TexCoord; 9 | 10 | // output to buffer 11 | out vec4 FragColor; 12 | 13 | uniform sampler2D Tex; 14 | 15 | 16 | void main() 17 | { 18 | FragColor = texture2D(Tex, TexCoord); 19 | } 20 | -------------------------------------------------------------------------------- /opengl/src/main/resources/shaders/background.vertex: -------------------------------------------------------------------------------- 1 | /* Simple vertex shader for drawing a 2d geometry with texture to screen 2 | */ 3 | #version 130 4 | 5 | // per vertex input 6 | in vec2 VertexPosition; 7 | in vec2 VertexTexCoord; 8 | 9 | // input for at least primitives 10 | uniform mat4 ModelViewProjectionMatrix; 11 | 12 | // output to fragment shader for interpolation 13 | out vec2 TexCoord; 14 | 15 | void main() 16 | { 17 | TexCoord = VertexTexCoord; 18 | gl_Position = ModelViewProjectionMatrix * vec4(VertexPosition.x, VertexPosition.y, 0.0, 1.0); 19 | } 20 | -------------------------------------------------------------------------------- /opengl/src/main/resources/shaders/nonarea.fragment: -------------------------------------------------------------------------------- 1 | /* Simple fragment shader with static color, no lighting, no textures 2 | */ 3 | #version 130 4 | 5 | // corresponds with output from vertex shader, gets interpolated 6 | in vec4 Color; 7 | 8 | // output to buffer 9 | out vec4 FragColor; 10 | 11 | void main() 12 | { 13 | FragColor = Color; 14 | } 15 | -------------------------------------------------------------------------------- /opengl/src/main/resources/shaders/nonarea.vertex: -------------------------------------------------------------------------------- 1 | /* Simple vertex shader with static color, no lighting, no textures 2 | */ 3 | #version 130 4 | 5 | // per vertex input 6 | in vec3 VertexPosition; 7 | in vec4 VertexColor; 8 | 9 | // input for at least primitives 10 | uniform mat4 ModelViewProjectionMatrix; 11 | 12 | // output to fragment shader for interpolation 13 | out vec4 Color; 14 | 15 | void main() 16 | { 17 | Color = VertexColor; 18 | gl_Position = ModelViewProjectionMatrix * vec4(VertexPosition, 1.0); 19 | } 20 | -------------------------------------------------------------------------------- /opengl/src/main/resources/shaders/shadowmap.fragment: -------------------------------------------------------------------------------- 1 | /* Simple fragment shader with texture layers for depth buffer calculation 2 | */ 3 | #version 130 4 | // TODO: set from java to match MAX_TEXTURE_LAYERS there 5 | #define MAX_TEXTURE_LAYERS 4 6 | 7 | // corresponds with output from vertex shader, gets interpolated 8 | in vec2 TexCoord0; 9 | in vec2 TexCoord1; 10 | in vec2 TexCoord2; 11 | in vec2 TexCoord3; 12 | 13 | uniform bool useTexture[MAX_TEXTURE_LAYERS]; 14 | uniform sampler2D Tex[MAX_TEXTURE_LAYERS]; 15 | 16 | uniform bool useAlphaTreshold; 17 | uniform float alphaTreshold; 18 | 19 | void main() 20 | { 21 | float alpha = 1.0; 22 | 23 | // apply textures 24 | // TODO: autogenerate based on MAX_TEXTURE_LAYERS 25 | if ( useTexture[0] ) { 26 | alpha = texture( Tex[0], TexCoord0 ).a; 27 | } 28 | if ( useTexture[1] ) { 29 | float layerAlpha = texture( Tex[1], TexCoord1 ).a; 30 | alpha = mix(alpha, 1, layerAlpha); 31 | } 32 | if ( useTexture[2] ) { 33 | float layerAlpha = texture( Tex[2], TexCoord2 ).a; 34 | alpha = mix(alpha, 1, layerAlpha); 35 | } 36 | if ( useTexture[3] ) { 37 | float layerAlpha = texture( Tex[3], TexCoord3 ).a; 38 | alpha = mix(alpha, 1, layerAlpha); 39 | } 40 | 41 | if ( useAlphaTreshold ) { 42 | if ( alpha < alphaTreshold ) 43 | alpha = 0.0; 44 | else 45 | alpha = 1.0; 46 | } 47 | 48 | if( alpha < 0.01 ) 49 | discard; 50 | 51 | // nothing to output, only depth buffer needed 52 | } 53 | -------------------------------------------------------------------------------- /opengl/src/main/resources/shaders/shadowmap.vertex: -------------------------------------------------------------------------------- 1 | /* Simple vertex shader with vertex position texture layers computation 2 | */ 3 | #version 130 4 | 5 | // per vertex input 6 | in vec3 VertexPosition; 7 | in vec2 VertexTexCoord0; 8 | in vec2 VertexTexCoord1; 9 | in vec2 VertexTexCoord2; 10 | in vec2 VertexTexCoord3; 11 | 12 | // input for at least primitives 13 | uniform mat4 ModelViewProjectionMatrix; 14 | 15 | // output to fragment shader for interpolation 16 | out vec2 TexCoord0; 17 | out vec2 TexCoord1; 18 | out vec2 TexCoord2; 19 | out vec2 TexCoord3; 20 | 21 | void main() 22 | { 23 | TexCoord0 = VertexTexCoord0; 24 | TexCoord1 = VertexTexCoord1; 25 | TexCoord2 = VertexTexCoord2; 26 | TexCoord3 = VertexTexCoord3; 27 | 28 | gl_Position = ModelViewProjectionMatrix * vec4(VertexPosition, 1.0); 29 | } 30 | -------------------------------------------------------------------------------- /opengl/src/main/resources/shaders/shadowvolume.fragment: -------------------------------------------------------------------------------- 1 | /* Empty fragment shader. Only depth buffer will be calculated. 2 | */ 3 | #version 130 4 | 5 | void main() 6 | { 7 | // nothing to output, only depth buffer needed 8 | } 9 | -------------------------------------------------------------------------------- /opengl/src/main/resources/shaders/shadowvolume.vertex: -------------------------------------------------------------------------------- 1 | /* Simple vertex shader with vertex position 2 | */ 3 | #version 130 4 | 5 | // per vertex input 6 | in vec4 VertexPosition; 7 | 8 | // input for at least primitives 9 | uniform mat4 ModelViewProjectionMatrix; 10 | 11 | void main() 12 | { 13 | gl_Position = ModelViewProjectionMatrix * VertexPosition; 14 | } 15 | --------------------------------------------------------------------------------