Can't seem to map latitude and longitude coordinates correctly in Processing 3

#1

Hi there,

I’m trying to make a very basic Processing sketch, where I map out the latitude and longitude points that my watch tracks on my bike rides.

I’m able to parse the XML data from the location source, and I’ve set up a data folder with the XML file. I don’t seem to have a problem with parsing the data.

However, I am trying to Map the lat/long GPS data to the screen dimensions, and I don’t think it’s working out right.

I’ve looked around at many sources, and there never seems to be a good simple example for how to do this. I think the range I’m dealing with deals with small lat/long changes, e.g.:

float mainx = map(pointLat, 37.751, 37.792, 0, width); 
float mainy = map(pointLong, -122.39, -122.494, 0, height);

The examples I’ve seen online all have much larger ranges so maybe that’s an issue? I’m not sure.

Anyways, here’s my Processing code and an image of the output. Any help is appreciated, as I’ve gotten stuck and I think this is the last bit to fix.

Thanks!
Aaron

// Example XML
//<Workout workoutActivityType="HKWorkoutActivityTypeCycling" duration="44.19382538398107" durationUnit="min" totalDistance="7.644061515836529" totalDistanceUnit="mi" totalEnergyBurned="300.3060000000002" totalEnergyBurnedUnit="kcal" sourceName="Aaron’s Apple Watch" sourceVersion="4.3" creationDate="2018-05-01 08:35:07 -0700" startDate="2018-05-01 07:50:51 -0700" endDate="2018-05-01 08:35:03 -0700">
//<MetadataEntry key="HKTimeZone" value="America/Los_Angeles"/>
//<MetadataEntry key="HKWeatherTemperature" value="49 degF"/>
//<MetadataEntry key="HKWeatherHumidity" value="82 %"/>
//<WorkoutRoute sourceName="Watch" sourceVersion="11.3" creationDate="2018-05-01 08:58:53 -0700" startDate="2018-05-01 07:51:11 -0700" endDate="2018-05-01 08:34:52 -0700">
// <MetadataEntry key="HKMetadataKeySyncVersion" value="2"/>
// <MetadataEntry key="HKMetadataKeySyncIdentifier" value="F2BEA6D4-4E7E-4867-AAF4-05586B2F753D"/>
// <Location date="2018-05-01 07:51:11 -0700" latitude="37.7514" longitude="-122.493" altitude="74.0396" horizontalAccuracy="2.43753" verticalAccuracy="1.71176" course="28.125" speed="1.56585"/>
 
gpsPoint[] GPSPOINT;

XML xml;

void setup() {
  size(721, 361); //1024, 768
  background(255);
  smooth();
  
  xml = loadXML("data/bikeRides.xml");
  XML[] workoutRoutes = xml.getChildren("Workout/WorkoutRoute");
  
  println("num of workouts " + workoutRoutes.length);
  
  // Parse inside Workouts, workout O
  for (int i = 0; i < workoutRoutes.length; i++) {
    //int workoutNumber = i+1;
    //println("Workout # " + workoutNumber + " //////" );
    
    //workout #1, list Locations, workout 0, Locations in there, go into an Array, get OVERWRITTEN every time?  empty Location array everyime
    XML[] locations = null;
    locations = workoutRoutes[i].getChildren("Location");
    println("number of locations in workout: " + locations.length);
        
    //initialize object with number in array, which is number of locations
    GPSPOINT = new gpsPoint[locations.length];
    
    //add xvalue and yvalue into object
    for (int a = 0; a < locations.length; a++){

      //get lat and long
      float pointLat = locations[a].getFloat("latitude");
      float pointLong = locations[a].getFloat("longitude");
  
      // convert and remap Lat and Long based on range
      float mainx = map(pointLat, 37.751, 37.792, 0, width); 
      float mainy = map(pointLong, -122.39, -122.494, 0, height); 
      
      GPSPOINT[a] = new gpsPoint(mainx, mainy);
      GPSPOINT[a].display();
   
    }
  }
}

void draw() {  
}

class gpsPoint {
  
  float prevX;
  float prevY;
  float newX;
  float newY;
  
  gpsPoint(float previousX, float previousY){
    prevX = previousX;
    prevY = previousY;
  }
    
  void display() {
    stroke(0, 50);
    point(prevX, prevY);
  }
}

1 Like
#2

I think so. The difference between the minimum latitude and the maximum latitude is too low.
Can you check in your XML file if there’s a value higher than 37.792?

#3

So in your mapping operation, assuming that your field GPSPOINT has two points, which you use as part of the mapping op, then your data points would be located at the corners of your sketch, exactly opposite to each other.
The map ranges in your map() function should be larger than the min-max values in your data set to be able to display all the data, assuming you have no zooming operation in effect. In fact, changing these ranges in the map() function will allow you to zoom in and out of your sketch.

Just to have an idea of your data, if you get a data set in xml or kml (the gps google format from google maps), you should be able to find an online web app that will draw those points for you. Then you can see if the difference of those values is indeed small. From my experience and using phone device’s gps data, you should be able to tell those two points appart. I think you just need to change the ranges of your map function.

Additionally, you should consider trying the unfolding map library to plot your data.

Lastly, GPSPOINT is not a good name for your data set. Make it plural and titleCase like gpsPoints.

Kf

2 Likes
#4

If you post to multiple sites, please link between those posts so we know what help you’ve already received.

This question has also been posted here.

1 Like
#5

Thanks for the feedback and help!

So I got it working in terms of lat/long showing up in the correct proportions. Although now, it’s rotated incorrectly.

I’ve attached an image. The Left image is how it looks, and the Right image is how it should look. It looks like the the dots/GPS need to be rotated 90deg counterclockwise.

Did I map() this incorrectly?

// convert and remap Lat and Long based on range
// -122.5367,37.6659,-122.3383,37.8174
float mainx = map(pointLat, 37.6659, 37.8174, 0, width); 
float mainy = map(pointLong, -122.5367, -122.3383, 0, height);

Here’s my full code:

// Example XML
//<Workout workoutActivityType="HKWorkoutActivityTypeCycling" duration="44.19382538398107" durationUnit="min" totalDistance="7.644061515836529" totalDistanceUnit="mi" totalEnergyBurned="300.3060000000002" totalEnergyBurnedUnit="kcal" sourceName="Aaron’s Apple Watch" sourceVersion="4.3" creationDate="2018-05-01 08:35:07 -0700" startDate="2018-05-01 07:50:51 -0700" endDate="2018-05-01 08:35:03 -0700">
//<MetadataEntry key="HKTimeZone" value="America/Los_Angeles"/>
//<MetadataEntry key="HKWeatherTemperature" value="49 degF"/>
//<MetadataEntry key="HKWeatherHumidity" value="82 %"/>
//<WorkoutRoute sourceName="Watch" sourceVersion="11.3" creationDate="2018-05-01 08:58:53 -0700" startDate="2018-05-01 07:51:11 -0700" endDate="2018-05-01 08:34:52 -0700">
// <MetadataEntry key="HKMetadataKeySyncVersion" value="2"/>
// <MetadataEntry key="HKMetadataKeySyncIdentifier" value="F2BEA6D4-4E7E-4867-AAF4-05586B2F753D"/>
// <Location date="2018-05-01 07:51:11 -0700" latitude="37.7514" longitude="-122.493" altitude="74.0396" horizontalAccuracy="2.43753" verticalAccuracy="1.71176" course="28.125" speed="1.56585"/>
 
gpsPoint[] gpsPoints;

PImage backgroundMap;

float mapScreenWidth,mapScreenHeight;  // Dimension of map in pixels.

XML xml;

void setup() {
  size(400, 386); // 7x7
  //background(255);
  backgroundMap   = loadImage("img/7x7.png");
  mapScreenWidth  = width;
  mapScreenHeight = height;
  image(backgroundMap,0,0,mapScreenWidth,mapScreenHeight);
  smooth();
  
  xml = loadXML("data/bikeRides.xml");
  XML[] workoutRoutes = xml.getChildren("Workout/WorkoutRoute");
  
  println("num of workouts " + workoutRoutes.length);
  
  // Parse inside Workouts, workout O
  for (int i = 0; i < workoutRoutes.length; i++) {
    //int workoutNumber = i+1;
    //println("Workout # " + workoutNumber + " //////" );
    
    //workout #1, list Locations, workout 0, Locations in there, go into an Array, get OVERWRITTEN every time?  empty Location array everyime
    XML[] locations = null;
    locations = workoutRoutes[i].getChildren("Location");
    println("number of locations in workout: " + locations.length);
        
    //initialize object with number in array, which is number of locations
    gpsPoints = new gpsPoint[locations.length];
    
    //add xvalue and yvalue into object
    for (int a = 0; a < locations.length; a++){

      //get lat and long
      float pointLat = locations[a].getFloat("latitude");
      float pointLong = locations[a].getFloat("longitude");
  
      // convert and remap Lat and Long based on range
      // -122.5367,37.6659,-122.3383,37.8174
      float mainx = map(pointLat, 37.6659, 37.8174, 0, width); 
      float mainy = map(pointLong, -122.5367, -122.3383, 0, height); 
      
      gpsPoints[a] = new gpsPoint(mainx, mainy);
      gpsPoints[a].display();
   
    }
  }
}

void draw() {  
}

class gpsPoint {
  
  float prevX;
  float prevY;
  float newX;
  float newY;
  
  gpsPoint(float previousX, float previousY){
    prevX = previousX;
    prevY = previousY;
  }
    
  void display() {
    stroke(0, 50);
    point(prevX, prevY);
  }
}
1 Like
#6

Like somebody mentioned in your StackOverflow post, it looks like you’re switching latitude and longitude.

1 Like
#7

Should be instead

float mainy = map(pointLat, 37.6659, 37.8174, 0, height); //Notice two changes: field name(mainy) and dimension (height)

Do the same changes for the other coordiante. Keep in mind that positive is down in Processing so you might want to do this instead:

float mainy = map(pointLat, 37.6659, 37.8174, height,0); //Revert the last two fields

Kf

1 Like
#8

Thank you for the help! That resolved it!

#9

Hi All,

I’m attempting to adapt some of the provided examples above to draw lines between the points in my XML data.

Here’s a sample of my XML data

<dataPoint>
		<id>474781744</id>
		<timestamp>7/12/2012 3:01</timestamp>
		<longitude>147.388981</longitude>
		<latitude>-36.356586</latitude>
	</dataPoint>
	<dataPoint>
		<id>474781745</id>
		<timestamp>7/12/2012 3:31</timestamp>
		<longitude>147.390586</longitude>
		<latitude>-36.3578</latitude>
	</dataPoint>

And here’s what I’ve come up with for my sketch:

gpsPoint[] gpsPoints1;

XML xml;

PImage background;

float mapScreenWidth, mapScreenHeight;

void setup() {
  size(3840, 2160);
  background(255);
  xml = loadXML("sheepData_001.xml");
  background = loadImage("img/paddock.png");
  mapScreenWidth = width;
  mapScreenHeight = height;
  image(background, 0, 0, mapScreenWidth, mapScreenHeight);
  smooth();
  
  XML[] point = xml.getChildren("dataPoint");
  
  

  for (int i = 0; i < point.length; i++) {
    XML idElement = point[i].getChild("id");
    int event = idElement.getIntContent();
    
    XML timeElement = point[i].getChild("timestamp");
    String time = timeElement.getContent();
    
    XML longElement = point[i].getChild("longitude");
    float longitude = longElement.getFloatContent();
    
    XML latElement = point[i].getChild("latitude");
    float latitude = latElement.getFloatContent();
    
    println(event + "," + time + "," + longitude + "," + latitude);
  
  
    
  
    gpsPoints1 = new gpsPoint[point.length];
  
    for (int a = 0; a < point.length-1; a++){
      
      XML longData1 = point[a].getChild("longitude");
      float pointLong1 = longData1.getFloatContent();
      
      XML longData2 = point[a+1].getChild("longitude");
      float pointLong2 = longData2.getFloatContent();
      
      XML latData1 = point[a].getChild("latitude");
      float pointLat1 = latData1.getFloatContent();
      
      XML latData2 = point[a+1].getChild("latitude");
      float pointLat2 = latData2.getFloatContent();
  
      float mainx = map(pointLong1, 147.3538, 147.3922, 0, width);
      float mainy = map(pointLat1, -36.3228, -36.3179, 0, height);
      float mainx2 = map(pointLong2, 147.3538, 147.3922, 0, width);
      float mainy2 = map(pointLat2, -36.3228, -36.3179, 0, height);
      
      gpsPoints1[a] = new gpsPoint(mainx, mainy, mainx2, mainy2);
      gpsPoints1[a].display();
    }
    
  }
  println("num of points " + point.length);
}
void draw() {  
}

class gpsPoint {

  float prevX;
  float prevY;
  float newX;
  float newY;

  gpsPoint(float previousX, float previousY, float nextX, float nextY){
    prevX = previousX;
    prevY = previousY;
    newX = nextX;
    newY = nextY;
  }
  
  
  void display() {
    stroke(0);
    strokeWeight(2);
    point(prevX, prevY);
    line(prevX, prevY, newX, newY);
  }
}

It seems to function okay, but the lines I’m getting don’t seem to fully represent the point data that I get by removing all of the secondary point grabbing and go back to just plotting lines from the data.


This image is a side by side of the points and then lines I’m getting.

Anyone notice anything that I’m doing in my code that would throw my lines off? I know there’s likely a better way to get the secondary points, but it’s working thus far in terms of running.

Thanks in advance