Problems with OSM2World Precision

Hello,

I am using OSM2World to create a 3D traffic simulation. I plan to move the vehicles by following waypoint routes. These waypoints are created from OSM files. The .objs generated by OSM2World are quite impressive, but I think there is some problem with precision. I checked if the distance bewteen 2 points in the .obj file is the same as the distance in Google Maps, and it’s not. The waypoints I generate from the OSM file are not aligned with the 3d model, so the vehicles won’t move on the roads.

I have read this thread of 5 years ago https://forum.openstreetmap.org/viewtopic.php?id=22336 and I’m trying to do what the user vinnieb said in his last message: I’m using jcoord library to perform the conversion bewteen latitude and longitude and Mercator projections.

So far, I have modified the MetricMapProjection.java class. I have modified the calcPos and setOrigin methods using the jcoord library. This is the code

package org.osm2world.core.map_data.creation;

import static org.osm2world.core.map_data.creation.MercatorProjection.*;

import org.osm2world.core.math.VectorXZ;

import uk.me.jstott.jcoord.LatLng;
import uk.me.jstott.jcoord.UTMRef;

/**
 * Map projection that is intended to use the "dense" space
 * of floating point values by making all coordinates relative to
 * the origin. 1 meter distance is roughly represented by 1 internal unit.
 */
public class MetricMapProjection extends OriginMapProjection {
  
  private double originX;
  private double originY;
  private double scaleFactor;
    
  public VectorXZ calcPos(double lat, double lon) {
    
    if (origin == null) throw new IllegalStateException("the origin needs to be set first");
    
    //double x = lonToX(lat, lon) * scaleFactor - originX;
    //double y = latToY(lat, lon) * scaleFactor - originY;
    
    LatLng coord=new LatLng(lat,lon);
    UTMRef mercator=coord.toUTMRef();
    double x = mercator.getEasting();
    double y = mercator.getNorthing();
    /* snap to som cm precision, seems to reduce geometry exceptions */
    x = Math.round(x * 1000) / 1000.0d;
    y = Math.round(y * 1000) / 1000.0d;

    return new VectorXZ(x, y); // x and z(!) are 2d here
  }

  @Override
  public VectorXZ calcPos(LatLon latlon) {
    return calcPos(latlon.lat, latlon.lon);
  }

  @Override
  public double calcLat(VectorXZ pos) {
    
    if (origin == null) throw new IllegalStateException("the origin needs to be set first");
    
    return yToLat((pos.z + originY) / scaleFactor);
    
  }

  @Override
  public double calcLon(VectorXZ pos) {
    
    if (origin == null) throw new IllegalStateException("the origin needs to be set first");
    
    return xToLon((pos.x + originX) / scaleFactor);
    
  }

  @Override
  public VectorXZ getNorthUnit() {
    return VectorXZ.Z_UNIT;
  }

  @Override
  public void setOrigin(LatLon origin) {
    super.setOrigin(origin);

    //this.scaleFactor = earthCircumference(origin.lat);
    //this.originY = latToY(origin.lat, origin.lon) * scaleFactor;
    //this.originX = lonToX(origin.lon, origin.lat) * scaleFactor;
    LatLng coord=new LatLng(origin.lat,origin.lon);
    UTMRef mercator=coord.toUTMRef();
    this.originX = mercator.getEasting();
    this.originY = mercator.getNorthing();
  }
}

I was able to generate the .obj but some parts of the terrain were missing. I also got these exceptions.

No parameters, running graphical interface.
If you want to use the command line, use the --help parameter for a list of available parameters.
FPSAnimator P1:Thread[main-FPSAWTAnimator-Timer0,5,main]: Task[thread Thread[main-FPSAWTAnimator-Timer0,5,main], stopped false, paused false shouldRun true, shouldStop false -- started true, animating true, paused false, drawable 1, drawablesEmpty false]
ignored exception:
org.osm2world.core.math.InvalidGeometryException: a polygon's area must be positive, but it's 0.0 for this polygon.
This problem can be caused by broken polygon data or imprecise calculations
Polygon vertices: [(289104.7191349752,4721275.396499669), (289101.9460918575,4721281.91251892), (289101.9460918576,4721281.91251892), (289104.7191349752,4721275.396499669)]
  at org.osm2world.core.math.SimplePolygonXZ.assertNonzeroArea(SimplePolygonXZ.java:328)
  at org.osm2world.core.math.SimplePolygonXZ.calculateArea(SimplePolygonXZ.java:48)
  at org.osm2world.core.math.SimplePolygonXZ.getArea(SimplePolygonXZ.java:62)
  at org.osm2world.core.math.PolygonWithHolesXZ.getArea(PolygonWithHolesXZ.java:139)
  at org.osm2world.core.math.PolygonWithHolesXZ.<init>(PolygonWithHolesXZ.java:24)
  at org.osm2world.core.math.JTSConversionUtil.polygonXZFromJTSPolygon(JTSConversionUtil.java:92)
  at org.osm2world.core.math.JTSConversionUtil.polygonsXZFromJTSGeometry(JTSConversionUtil.java:115)
  at org.osm2world.core.math.algorithms.CAGUtil.subtractPolygons(CAGUtil.java:73)
  at org.osm2world.core.world.modules.SurfaceAreaModule$SurfaceArea.getTriangulationXZ(SurfaceAreaModule.java:256)
  at org.osm2world.core.world.data.AbstractAreaWorldObject.getEleConnectors(AbstractAreaWorldObject.java:54)
  at org.osm2world.core.world.data.AbstractAreaWorldObject.getEleConnectors(AbstractAreaWorldObject.java:1)
  at org.osm2world.core.ConversionFacade$1.perform(ConversionFacade.java:380)
  at org.osm2world.core.ConversionFacade$1.perform(ConversionFacade.java:1)
  at org.osm2world.core.util.FaultTolerantIterationUtil.iterate(FaultTolerantIterationUtil.java:20)
  at org.osm2world.core.ConversionFacade.calculateElevations(ConversionFacade.java:376)
  at org.osm2world.core.ConversionFacade.createRepresentations(ConversionFacade.java:309)
  at org.osm2world.viewer.model.Data.loadOSMData(Data.java:70)
  at org.osm2world.viewer.control.actions.AbstractLoadOSMAction$LoadOSMThread.run(AbstractLoadOSMAction.java:83)
this exception occurred for the following input:
SurfaceArea(w0)

I’m very new to mapping software and I don’t know if I am doing the changes in the correct places, so any help or information is appreciated.

Thanks to anyone who reads this.

After two days I found the solution. I was using elliptical mercator and OSM2World uses Spherical Mercator. I see that there’s a latToYElliptical method in the Mercator class in OSM2World. However, there is not a lonToXElliptical method, so I guess I will have to code it myself. I will also have to scale the values bewteen 0 and 1. Any help is appreciated.

Yes, this is the right location for modifying the projection.

One oddity I noticed with your code is that your coordinates don’t appear to be relative to your origin, and you have very large values as a result – values that are large enough to result in noticeable floating point inaccuracies during a quick test I did. I would intuitively modify your calcPos implementation as such:

    double x = mercator.getEasting() - originX;
    double y = mercator.getNorthing() - originY;

Of course, that is going to shift the output coordinates in the OBJ by a fixed amount, not sure if that’s a problem for your use case? It could be solved by modifying the resulting .obj file, adding the origin’s coordinates back onto the coords. (You can do that outside OSM2World, or hack it into the ObjTarget.)

That being said, missing terrain chunks are unfortunately a known bug even with unaltered projection code at the moment. Until that is fixed, you sadly aren’t going to get rid of exceptions related to SurfaceArea(w0) without disabling generation of empty terrain entirely. :frowning:

It shouldn’t be a problem. I’ll try it, thanks!

I don’t really need the terrains. Actually, I tried to disable that option yesterday, but I got the error

input file parameter is required (or choose a different input mode)

I run the program with the command

java -jar OSM2World.jar --config conf

where conf is a file containing the line

createTerain = false

According to the instructions in this wiki I think the conf file is correct https://wiki.openstreetmap.org/wiki/OSM2World/Configuration_file Could you tell me what I am doing wrong?

Thanks!

Ah, that error message isn’t particularly intuitive.

OSM2World can be run in two ways: Using only the command line, or through the graphical interface.

The first mode involves specifying an input and output file as parameters. The second normally requires the --gui parameter.

For convenience, OSM2World will assume --gui if no parameters are specified. But if you specify any parameter at all, such as --config, then that convenience function will not kick in anymore.

tl;dr: What you want to do is probably

java -jar OSM2World.jar --gui --config conf

Oh, so it was that. Thank you really much, now everything its working.

By the way, I’d like to propose a feature which I consider quite useful for OSM2World. It would be nice that users could choose the type of projection. Proj.4 has a set of standards and libraries to perform these conversions. I think they could be specified as an input parameter like the --proj parameter of SUMo , which offers this feature.

Thank you again for your time.