座標の配列 (地理座標ですが、それは重要ではありません) があり、既にあるパスに「続く」パスが必要です。
次の画像のようなものが必要です。パスがまったく同じではない (単純なオフセットではない) ことがわかります。
それを行うために使用できるライブラリや、これを実装する方法に関するポインタはありますか?
座標の配列 (地理座標ですが、それは重要ではありません) があり、既にあるパスに「続く」パスが必要です。
次の画像のようなものが必要です。パスがまったく同じではない (単純なオフセットではない) ことがわかります。
それを行うために使用できるライブラリや、これを実装する方法に関するポインタはありますか?
実用的な解決策を見つけるのにあまりにも多くの時間を費やした後、私は自分自身をコーディングすることになりました:
CGContextBeginPath(context);
CGMutablePathRef path = CGPathCreateMutable();
MKMapPoint *mapPoints = itineraryPath.points;
CGPoint previousEdgeNormal = CGPointZero;
CGPoint previousDrawnPoint = CGPointZero;
float offsetDistance = self.pathWidth*2.5;
for(int i = 0; i < itineraryPath.pointCount; i++) {
if(i < itineraryPath.pointCount-1) {
MKMapPoint mapPoint = mapPoints[i];
CGPoint point = [self pointForMapPoint:mapPoint];
MKMapPoint secondMapPoint = mapPoints[i+1];
CGPoint secondPoint = [self pointForMapPoint:secondMapPoint];
float xDelta = point.x-secondPoint.x;
float yDelta = point.y-secondPoint.y;
float factor = xDelta > 0 ? -1 : 1;
float segmentLength = sqrt(pow(xDelta, 2.0)+pow(yDelta, 2.0));
float yDeltaAngle = asin(sin(M_PI/2*factor)*yDelta/segmentLength);
float opposedAngle = M_PI/2-yDeltaAngle;
float remainingAngle = M_PI/2-opposedAngle;
float yOffset = sin(opposedAngle)*offsetDistance/sin(M_PI/2)*factor;
float xOffset = sin(remainingAngle)*offsetDistance/sin(M_PI/2)*factor;
CGPoint offsetFirstPoint = CGPointMake(point.x+xOffset, point.y+yOffset);
CGPoint offsetSecondPoint = CGPointMake(secondPoint.x+xOffset, secondPoint.y+yOffset);
if(i == mapPointIndex) {
CGPathMoveToPoint(path, NULL, offsetFirstPoint.x, offsetFirstPoint.y);
previousDrawnPoint = offsetFirstPoint;
}
else {
float xNormalDifference = previousEdgeNormal.x-offsetFirstPoint.x;
float yNormalDifference = previousEdgeNormal.y-offsetFirstPoint.y;
float xAverage = (xNormalDifference)/2;
float yAverage = (yNormalDifference)/2;
CGPoint normalAveragePoint = CGPointMake(offsetFirstPoint.x+xAverage, offsetFirstPoint.y+yAverage);
CGPathAddLineToPoint(path, NULL, normalAveragePoint.x, normalAveragePoint.y);
previousDrawnPoint = normalAveragePoint;
}
previousEdgeNormal = offsetSecondPoint;
}
else
CGPathAddLineToPoint(path, NULL, previousEdgeNormal.x, previousEdgeNormal.y);
}
唯一の注意点は、鋭角をまだうまく処理できないことです。
しかし、それ以外の場合はかなりきちんとしたものになります(右は元のパス、左はオフセットです)
必要なものは、平行曲線と呼ばれます: http://en.wikipedia.org/wiki/Parallel_curve
これを生成する 1 つの方法は、各ポイントで元のカーブの法線を計算し、その法線を使用してそれらのポイントをオフセットすることです。直線セグメントしかない場合、これは非常に簡単です。円弧とベジエ曲線の場合は、制御点を変更する方法も理解する必要があります。