题 在Xcode中使用GPX来模拟位置变化时,有没有办法控制速度?


我在Xcode 4.2中使用以下GPX文件来模拟位置更改。它运作良好,但我无法控制位置变化的速度。邮票似乎不起作用。有人有解决方案吗?

<?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>

19
2018-02-24 23:26


起源




答案:


我不认为(知道)直接在GPX中这是可能的,但您可以使用Instruments / Automation测试位置变化。

您将使用如下脚本:

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

等等。我从WWDC11视频中拿了这个例子 https://developer.apple.com/videos/play/wwdc2011/518/ (测试位置感知应用程序)

我知道这实际上并没有让你定义速度,但延迟以某种方式解释了我的希望。也许那会对你有所帮助。


10
2018-02-24 23:35



谢谢JiaYow,这正是我正在寻找的!我尝试过,效果很好。使用Instruments似乎让我在控制台中失去了NSLog。 - lichen19853
UI自动化部分从视频中的31:10开始。 - Timuçin


Xcode支持使用GPX文件模拟速度变化。

提供包含纬度/经度对的一个或多个航路点。如果您提供一个航点,Xcode将模拟该特定位置。如果您提供多个航点,Xcode将模拟每个航点的航线。

可选地为每个航点提供时间元素。 Xcode将根据每个航点之间经过的时间以速度插入运动。如果您不提供时间元素,则Xcode将使用固定的速率。航点必须按时间按升序排序。

像这样写:

<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>

大约-1速度

在模拟过程中,CoreLocation对象的速度始终为-1。可能的解决方法是保存最后一个位置,然后自己计算速度。示例代码:

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;
}

17
2018-04-05 03:24



出于某种原因,具有gpx标准的网站(www.topografix.com/gpx_manual.asp)提供了这样的示例: <time>2002-02-10T21:01:29.250Z</time>。注意一秒的分数。必须删除分数才能在XCode中加载它。 - jmathew
@jmathew您可以使用正则表达式替换这些数字“\。\ d {3} Z”=>“Z” - BB9z
当我尝试这个Xcode将读取文件,但仍然表明速度是“-1.00 mps”。如果所有时间值都相同,它也会从Xcode中得到一个错误,它希望它们递增(尽管它们似乎没有发生...... - Kendall Helmstetter Gelner
@KendallHelmstetterGelner经过的时间必须是每个航路点不相等。 - BB9z
-1 mps是在我将所有时间值更改为不同之后,我让它们每次前进一秒但CoreLocation对象返回给我仍然声称速度为-1 mps。这是在Xcode8beta6中。 - Kendall Helmstetter Gelner


我不认为你可以用GPX文件做到这一点。但是使用Intruments中的自动化工具很容易。这是我自己用于我的应用测试和截图收集的脚本之一:

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);
}

我创建 一步一步的演练 我如何使用Automation和Leaks的位置模拟来获取截图并找到泄漏点


14
2017-07-29 12:32



你知道我们如何在应用程序在后台运行时更改位置吗?即这个问题在这里: stackoverflow.com/questions/22344858/... - Calvin


如果您不想处理automator,可以使用GPX文件。诀窍是创建一堆点。

例如,不是仅创建从A到B的2个点,而是在它们之间创建一堆中间点。这是有效的,因为无论两点之间的距离如何,位置模拟器都需要从一个点到另一个点的恒定时间。

您可以使用以下代码,而不必手动创建一堆点。

说明:

  1. 粘贴下面的代码,根据自己的喜好调整kDesiredSpeed常量。
  2. 将UITapGestureRecognizer添加到地图视图中,将其链接到mapViewTapped:
  3. 添加调用startRecordingPoints和stopRecordingPoints的按钮。
  4. 运行该应用程序。
  5. 点击startRecordingPoints按钮。
  6. 点击路线应该开始的位置。
  7. 点按地图中的其他位置。这将在最后一个节点和新节点之间生成X个点,以使其看起来以您想要的速度移动。
  8. 根据需要多次重复上一步。
  9. 按停止录制。
  10. 复制控制台输出。
  11. 文件>新文件...
  12. 选择“资源> GPX文件”
  13. 粘贴内容并保存文件。
  14. 点击调试器中的位置箭头,然后选择您的GPX文件。
  15. 坐下来观看,因为位置以您想要的速度更新!

码:

@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;
}

免责声明:  kAppleTravelTime = 2 只是一个猜测。如果您有更准确的价值,请在评论中发布。


9
2018-04-17 08:18





还有一种方法可以让您传递速度和其他一些属性:

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

(检查一下 AppleDoc 更多细节)

您仍然可以在控制台应用程序中看到您的NSLog(/Applications/Utilities/Console.app)。只需添加过滤器即可获得正确的结果。


2
2018-03-30 09:56