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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9439495/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 17:02:18  来源:igfitidea点击:

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

iphoneiosxcodelocationgpx

提问by lichen19853

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?

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

采纳答案by JiaYow

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

我不认为(知道)这可以直接在 GPX 中实现,但是您可以使用 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)

等等。我从WWDC11 视频(测试您的位置感知应用程序)中获取了这个示例

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.

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

回答by BB9z

Xcode support simulate speed change with a GPX file.

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

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.

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

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

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

大约-1速度

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:

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

回答by Stanislav Dvoychenko

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:

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

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

我创建了一步一步的演练,了解我如何使用带有自动化和泄漏的位置模拟来抓取屏幕截图并查找泄漏

回答by Senseful

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.

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

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.

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

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

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 = 2is just a guess. If you have a more accurate value, please post it in a comment.

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

回答by Awais Fayyaz

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

更新:2018 年 10 月(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.

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

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


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

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

Select your gpx file from menu

从菜单中选择您的 gpx 文件



Demo

演示

enter image description here

在此处输入图片说明

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

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

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

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

回答by bernhard

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 AppleDocfor more details)

(查看此AppleDoc了解更多详细信息)

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

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