【问题标题】:When using GPX in Xcode to simulate location changes, is there a way to control the speed?在Xcode中使用GPX模拟位置变化时,有没有办法控制速度?
【发布时间】:2012-03-15 10:03:52
【问题描述】:

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

【问题讨论】:

    标签: iphone ios xcode location gpx


    【解决方案1】:

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

    【讨论】:

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

    我不认为你可以用 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);
    }
    

    我创建了 step by step walkthrough 用于我如何使用带有自动化和泄漏的位置模拟来抓取屏幕截图并查找泄漏

    【讨论】:

    【解决方案3】:

    我不认为(知道)这可以直接在 GPX 中实现,但您可以使用 Instruments/Automation 测试位置更改。

    你会使用这样的脚本:

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

    等等。这个例子来自WWDC11 video(测试你的位置感知应用程序)

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

    【讨论】:

    • 谢谢JiaYow,这正是我要找的!我试过了,效果很好。不过,使用 Instruments 似乎让我在控制台中丢失了 NSLog。
    • UI 自动化部分在视频中的 31:10 开始。
    【解决方案4】:

    如果您不想处理 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 只是一个猜测。如果您有更准确的值,请在评论中发布。

    【讨论】:

      【解决方案5】:

      更新:2018 年 10 月(Swift 4、Xcode 9.4)

      我找到了一个非常简单的解决方案。虽然它不允许指定精确的速度,但是可以通过指定 gps 点之间的距离来控制速度。速度与两个 gps 点之间的距离成正比。

      1. gpxGenerator.com 生成 GPX 点
      2. 在 Xcode 中,从文件创建一个新的 GPX -> 新文件(或命令 N)。搜索 gpx
      3. 将您从 gpxGenerator.com 获得的 GPX 点粘贴到该 gpx 文件中
      4. 删除所有时间标签(这是它的核心。不要忽略这一步)
      5. 运行您的应用程序并从调试菜单中选择您的 gpx 文件。 (见屏幕截图) 在我的例子中,它的名字是SanFranciscoToNewYork

      就是这样。现在,模拟器或真实设备应该用 sp 模拟 gpx 文件中的点


      演示

      正如您在演示中看到的那样,标记移动得非常快。这不是默认的慢速。我

      注意:This 是我用于演示的示例 GPX 文件

      【讨论】:

      • 这个返回速度也是-1
      • 这个正则表达式可用于查找和替换所有时间戳&lt;time&gt;[0-9-T:Z]+&lt;/time&gt;
      【解决方案6】:

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

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

      (查看AppleDoc了解更多详情)

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

      【讨论】:

        猜你喜欢
        • 2018-04-26
        • 1970-01-01
        • 1970-01-01
        • 2011-07-29
        • 2019-07-06
        • 2022-01-16
        • 1970-01-01
        • 2010-10-28
        相关资源
        最近更新 更多