When using GPX in Xcode to simulate location changes, is there a way to control the speed?

百般思念 提交于 2019-12-17 08:28:06

问题


I'm using the following GPX file in Xcode 4.2 to simulate a location change. It works well, but I can't control the speed of the location change. stamp seems to be not working. Does anyone have a solution for this?

<?xml version="1.0"?>
<gpx version="1.1" creator="Xcode"> 
    <wpt lat="37.331705" lon="-122.030237"></wpt>
    <wpt lat="37.331705" lon="-122.030337"></wpt>
    <wpt lat="37.331705" lon="-122.030437"></wpt>
    <wpt lat="37.331705" lon="-122.030537"></wpt>
</gpx>

回答1:


I don't think (know) that this is possible in the GPX directly, but you can test location change with Instruments/Automation.

You'd use a script like:

var target = UIATarget.localTarget();
target.setLocation(<location);
target.delay(5);
target.setLocation(...);

And so on. I took this example from the WWDC11 video (Testing your location-aware applications)

I'm aware that this doesn't actually let you define the speed, but the delays somehow account for that I hope. Maybe that'll help you.




回答2:


Xcode support simulate speed change with a GPX file.

Provide one or more waypoints containing a latitude/longitude pair. If you provide one waypoint, Xcode will simulate that specific location. If you provide multiple waypoints, Xcode will simulate a route visitng each waypoint.

Optionally provide a time element for each waypoint. Xcode will interpolate movement at a rate of speed based on the time elapsed between each waypoint. If you do not provide a time element, then Xcode will use a fixed rate of speed. Waypoints must be sorted by time in ascending order.

Write like this:

<wpt lat="39.96104510" lon="116.4450860">
    <time>2010-01-01T00:00:00Z</time>
</wpt>
<wpt lat="39.96090940" lon="116.4451400">
    <time>2010-01-01T00:00:05Z</time>
</wpt>
...
<wpt lat="39.96087240" lon="116.4450430">
    <time>2010-01-01T00:00:09Z</time>
</wpt>

About -1 speed

The CoreLocation object’s speed will always be -1 during simulation. A possible workaround is save a last location then calculate the speed ourselves. Sample code:

CLLocationSpeed speed = location.speed;
if (speed < 0) {
    // A negative value indicates an invalid speed. Try calculate manually.
    CLLocation *lastLocation = self.lastLocation;
    NSTimeInterval time = [location.timestamp timeIntervalSinceDate:lastLocation.timestamp];

    if (time <= 0) {
        // If there are several location manager work at the same time, an outdated cache location may returns and should be ignored.
        return;
    }

    CLLocationDistance distanceFromLast = [lastLocation distanceFromLocation:location];
    if (distanceFromLast < DISTANCE_THRESHOLD
        || time < DURATION_THRESHOLD) {
        // Optional, dont calculate if two location are too close. This may avoid gets unreasonable value.
        return;
    }
    speed = distanceFromLast/time;
    self.lastLocation = location;
}



回答3:


I don't think you can do it with GPX files. But it is easy with Automation tool within Intruments. Here is one of the scripts I use myself for my app testing and screenshots gathering:

var target = UIATarget.localTarget();

// speed is in meters/sec
var points = [
          {location:{latitude:48.8899,longitude:14.2}, options:{speed:8, altitude:200, horizontalAccuracy:10, verticalAccuracy:15}},
          {location:{latitude:48.8899,longitude:14.9}, options:{speed:11, altitude:200, horizontalAccuracy:10, verticalAccuracy:15}},
          {location:{latitude:48.8899,longitude:14.6}, options:{speed:12, altitude:200, horizontalAccuracy:10, verticalAccuracy:15}},
          {location:{latitude:48.8899,longitude:14.7}, options:{speed:13, altitude:200, horizontalAccuracy:10, verticalAccuracy:15}},
          {location:{latitude:49.2,longitude:14.10}, options:{speed:15, altitude:200, horizontalAccuracy:10, verticalAccuracy:15}},
          {location:{latitude:49.4,longitude:14.8}, options:{speed:15, altitude:200, horizontalAccuracy:10, verticalAccuracy:15}},
          {location:{latitude:48.8899,longitude:14.9}, options:{speed:9, altitude:200, horizontalAccuracy:10, verticalAccuracy:15}},
          {location:{latitude:48.8899,longitude:15.1}, options:{speed:8, altitude:200, horizontalAccuracy:10, verticalAccuracy:15}},
          {location:{latitude:48.8899,longitude:16.1}, options:{speed:3, altitude:200, horizontalAccuracy:10, verticalAccuracy:15}},
          ];

for (var i = 0; i < points.length; i++)
{
target.setLocationWithOptions(points[i].location,points[i].options);
target.captureScreenWithName(i+"_.png");
target.delay(1.0);
}

I created step by step walkthrough for how I used location simulation with Automation and Leaks to grab screenshots and find leaks




回答4:


If you don't want to deal with automator, you can get it working with just a GPX file. The trick is to create a bunch of points.

For example, instead of creating just 2 points to go from A to B, create a bunch of intermediary points between them. This works because the location simulator takes constant time to travel from one point to another, no matter the distance between the two points.

Rather than having to create a bunch of points manually, you can use the following code.

Instructions:

  1. Paste the code below, tweaking the kDesiredSpeed constant to your liking.
  2. Add a UITapGestureRecognizer to your map view, linking it up to mapViewTapped:
  3. Add buttons that call startRecordingPoints and stopRecordingPoints.
  4. Run the app.
  5. Tap the startRecordingPoints button.
  6. Tap where the route should start.
  7. Tap another location in the map. This will generate X amount of points between the last node and the new node so that it will appear to move at the speed you want.
  8. Repeat the previous step as many times as you want.
  9. Press stop recording.
  10. Copy the console output.
  11. File > New File...
  12. Choose Resource > GPX File
  13. Paste the contents and save the file.
  14. Tap the location arrow in the debugger and choose your GPX file.
  15. Sit back and watch as the location is updated at exactly the speed you want!

Code:

@property (strong, nonatomic) CLLocation *lastRecordedPoint;
@property (strong, nonatomic) NSMutableString *recordingOutput;

...

- (IBAction)mapViewTapped:(UITapGestureRecognizer *)sender {
    if (sender.state != UIGestureRecognizerStateEnded || !self.recordingOutput) {
        return;
    }

    CLLocationCoordinate2D coord = [self.mapView convertPoint:[sender locationInView:self.mapView]
                                         toCoordinateFromView:self.mapView];
    [self recordPoint:coord];
}

- (void)recordPoint:(CLLocationCoordinate2D)newPoint {
    const CGFloat kAppleTravelTime = 2; // the default time it takes to travel from one point to another
    const CGFloat kDesiredSpeed = 6; // meters per sec
    const CGFloat kDesiredDistanceBetweenPoints = kDesiredSpeed * kAppleTravelTime;
    NSString * const kFormatString = @"    <wpt lat=\"%f\" lon=\"%f\"></wpt>\n";

    CLLocation *newLocation = [[CLLocation alloc] initWithLatitude:newPoint.latitude longitude:newPoint.longitude];
    NSInteger numberOfPoints = 1;
    if (self.lastRecordedPoint) {
        CLLocationDistance distance = [self.lastRecordedPoint distanceFromLocation:newLocation];
        numberOfPoints = MAX(round(distance / kDesiredDistanceBetweenPoints), 1);
        CGFloat deltaLatitude = newPoint.latitude - self.lastRecordedPoint.coordinate.latitude;
        CGFloat deltaLongitude = newPoint.longitude - self.lastRecordedPoint.coordinate.longitude;
        for (NSInteger i = 0; i < numberOfPoints; i++) {
            CLLocationDegrees latitude = self.lastRecordedPoint.coordinate.latitude + (numberOfPoints/distance * deltaLatitude) * (i+1);
            CLLocationDegrees longitude = self.lastRecordedPoint.coordinate.longitude + (numberOfPoints/distance * deltaLongitude) * (i+1);
            [self.recordingOutput appendFormat:kFormatString, latitude, longitude];
        }
    } else {
        [self.recordingOutput appendFormat:kFormatString, newPoint.latitude, newPoint.longitude];
    }
    NSLog(@"Recorded %ld point(s) to: %f,%f", (long)numberOfPoints, newPoint.latitude, newPoint.longitude);

    self.lastRecordedPoint = newLocation;
}


- (void)startRecordingPoints {
    NSLog(@"Started recording points. Tap anywhere on the map to begin recording points.");
    self.recordingOutput = [NSMutableString string];
    [self.recordingOutput appendString:@"<?xml version=\"1.0\"?>\n<gpx version=\"1.1\" creator=\"Xcode\">\n"];
    self.lastRecordedPoint = nil;
}

- (void)stopRecordingPoints {
    [self.recordingOutput appendString:@"</gpx>"];
    NSLog(@"Done recording, here is your gpx file: \n%@", self.recordingOutput);
    self.recordingOutput = nil;
}

Disclaimer: kAppleTravelTime = 2 is just a guess. If you have a more accurate value, please post it in a comment.




回答5:


Update : Oct, 2018 (Swift 4, Xcode 9.4)

I have found a very simple solution. although it does not allow to specify exact speed, however speed can be controller by specifying the distance between gps points. The speed is directly proportional to distance between two gps points.

  1. Generate GPX points from gpxGenerator.com
  2. In Xcode, Create a new GPX from file -> New File ( Or Command N). Search for gpx
  3. Paste the GPX Points that you got from gpxGenerator.com in that gpx file
  4. Delete all the time tags (that's the meat of it. Don't Ignore this step)
  5. Run you app and select your gpx file from debug menu. (see screen shot) In my case, its name is SanFranciscoToNewYork

That's all. Now, the simulator or real device should simulate the points in your gpx file with sp


Demo

As you can see in the demo, the marker is moving very fast. It's not the default slow speed. I

Note: This is my sample GPX File that i used for the demo




回答6:


There is also a method which lets you pass in the speed and some other properties:

target.setLocationWithOptions({latitude: 46.546928, longitude: 11.867127}, {altitude: 200.0, speed: 5});

(Check this AppleDoc for more details)

You can still see your NSLog's in the console application (/Applications/Utilities/Console.app). Just add a filter to get proper results.



来源:https://stackoverflow.com/questions/9439495/when-using-gpx-in-xcode-to-simulate-location-changes-is-there-a-way-to-control

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!