포인트 목록이 있는데 시계 방향인지 어떻게 알 수 있습니까?
예를 들면 다음과 같습니다.
point[0] = (5,0)
point[1] = (6,4)
point[2] = (4,5)
point[3] = (1,5)
point[4] = (1,0)
시계 반대 방향 (또는 일부 사람들에게는 반 시계 방향)이라고 말할 것입니다.
답변
초승달 모양과 같은 볼록하지 않은 다각형의 경우 제안 된 방법 중 일부가 실패합니다. 다음은 볼록하지 않은 다각형에서 작동하는 간단한 것입니다 (그림 8과 같이 자체 교차 다각형에서도 작동하여 대부분 시계 방향 인지 여부를 알려줍니다 ).
모서리에 대한 합, (x 2 -x 1 ) (y 2 + y 1 ). 결과가 양수이면 곡선은 시계 방향이고, 음수이면 곡선은 시계 반대 방향입니다. (결과는 +/- 규칙으로 닫힌 영역의 두 배입니다.)
point[0] = (5,0) edge[0]: (6-5)(4+0) = 4
point[1] = (6,4) edge[1]: (4-6)(5+4) = -18
point[2] = (4,5) edge[2]: (1-4)(5+5) = -30
point[3] = (1,5) edge[3]: (1-1)(0+5) = 0
point[4] = (1,0) edge[4]: (5-1)(0+0) = 0
---
-44 counter-clockwise
답변
외적은 두 벡터의 수직 다움의 정도를 측정한다. 다각형의 각 가장자리가 3 차원 xyz 공간의 xy 평면에있는 벡터라고 가정합니다. 그런 다음 두 개의 연속 모서리의 교차 곱은 z 방향의 벡터입니다 (두 번째 세그먼트가 시계 방향이면 양수 z 방향, 시계 반대 방향이면 z 방향 빼기). 이 벡터의 크기는 두 개의 원래 가장자리 사이의 각도 사인에 비례하므로 가장자리가 수직 일 때 최대 값에 도달하고 가장자리가 동일 선상에있을 때 테이퍼링이 사라집니다 (병렬).
따라서 다각형의 각 정점 (점)에 대해 두 개의 인접한 모서리의 곱의 크기를 계산합니다.
Using your data:
point[0] = (5, 0)
point[1] = (6, 4)
point[2] = (4, 5)
point[3] = (1, 5)
point[4] = (1, 0)
그래서 연속 에지 라벨
edgeA
의 세그먼트 point0
로 point1
및
edgeB
사이 point1
에이 point2
…
edgeE
사이 point4
와 point0
.
그런 다음 정점 A ( point0
)는
edgeE
[From point4
to point0
]
edgeA
[From point0
to`point1 ‘사이에 있습니다.
이 두 가장자리는 그 자체로 벡터이며, 시작점과 끝점의 좌표를 빼서 x 및 y 좌표를 결정할 수 있습니다.
edgeE
= point0
– point4
= (1, 0) - (5, 0)
= (-4, 0)
및
edgeA
= point1
– point0
= (6, 4) - (1, 0)
= (5, 4)
및
이 두 인접한 모서리의 곱은 좌표축 세를 나타내는 기호 아래 두 벡터의 좌표를 넣어 구성되어 다음과 같은 행렬의 행렬식을 계산한다 ( i
, j
, k
). 교차 곱 개념이 3 차원 구조이기 때문에 세 번째 값이 0 인 좌표가 있으므로 교차 곱을 적용하기 위해 이러한 2 차원 벡터를 3 차원으로 확장합니다.
i j k
-4 0 0
1 4 0
모든 교차 곱이 곱해지는 두 벡터의 평면에 수직 인 벡터를 생성한다는 점을 감안할 때, 위의 행렬의 결정 요인에는 k
(또는 z 축) 성분 만 있습니다. z 축 구성 요소
의 크기를 계산하는 공식 k
은
a1*b2 - a2*b1 = -4* 4 - 0* 1
= -16
이 값의 크기 ( -16
)는 2 개의 원래 벡터 사이의 각도 사인 값에 2 개의 벡터 크기의 곱을 곱한 값입니다.
실제로 그 값에 대한 다른 공식은
A X B (Cross Product) = |A| * |B| * sin(AB)
입니다.
따라서 각도 측정으로 돌아가려면이 값 ( -16
)을 두 벡터 크기의 곱으로 나눠야합니다 .
|A| * |B|
= 4 * Sqrt(17)
=16.4924...
따라서 sin (AB) = -16 / 16.4924
=-.97014...
이것은 정점 뒤의 다음 세그먼트가 왼쪽 또는 오른쪽으로 구부러 졌는지 여부와 그 정도를 측정 한 것입니다. 아크 사인을 취할 필요가 없습니다. 우리가 관심을 가질 것은 그 규모뿐 아니라 물론 그 징후 (긍정적이든 부정적이든)입니다!
닫힌 패스 주위의 다른 4 개의 점마다이 작업을 수행하고 각 정점에서이 계산의 값을 더합니다.
최종 합이 양수이면 시계 방향, 음수, 시계 반대 방향으로 이동합니다.
답변
나는 이것이 꽤 오래된 질문이라고 생각하지만 어쨌든 또 다른 솔루션을 버릴 것입니다. 직접적이고 수학적으로 집중적이지 않기 때문에 기본 대수학 만 사용합니다. 다각형의 부호있는 영역을 계산하십시오. 음수이면 포인트가 시계 방향이며 양수이면 반 시계 방향입니다. (베타의 솔루션과 매우 유사합니다.)
부호있는 영역을 계산하십시오. A = 1/2 * (x 1 * y 2 -x 2 * y 1 + x 2 * y 3 -x 3 * y 2 + … + x n * y 1 -x 1 * y n )
또는 의사 코드에서 :
signedArea = 0
for each point in points:
x1 = point[0]
y1 = point[1]
if point is last point
x2 = firstPoint[0]
y2 = firstPoint[1]
else
x2 = nextPoint[0]
y2 = nextPoint[1]
end if
signedArea += (x1 * y2 - x2 * y1)
end for
return signedArea / 2
주문 만 확인하는 경우 2로 나눌 필요가 없습니다.
답변
y가 가장 작은 정점을 찾으십시오 (동점이있는 경우 가장 큰 x). 정점하자 A
하고 목록에서 이전 정점 수 B
와 목록의 다음 정점 수 C
. 이제 계산 기호 의 십자가 제품을 AB
하고 AC
.
참고 문헌 :
-
간단한 다각형의 방향을 어떻게 찾습니까? 에서
자주 묻는 질문 : comp.graphics.algorithms를 . -
Wikipedia에서의 커브 방향 .
답변
이 답변을 기반으로 한 알고리즘의 간단한 C # 구현은 다음과 같습니다 .
우리가 가지고 있다고 가정 해 봅시다 Vector
유형 X
과 Y
유형의 속성double
.
public bool IsClockwise(IList<Vector> vertices)
{
double sum = 0.0;
for (int i = 0; i < vertices.Count; i++) {
Vector v1 = vertices[i];
Vector v2 = vertices[(i + 1) % vertices.Count];
sum += (v2.X - v1.X) * (v2.Y + v1.Y);
}
return sum > 0.0;
}
%
모듈로 연산을 수행하는 모듈로 또는 나머지 연산자입니다. Wikipedia에 따르면 을 다른 숫자로 나눈 후 나머지를 찾는 입니다.
답변
꼭짓점 중 하나에서 시작하여 각 변의 각도를 계산하십시오.
첫 번째와 마지막은 0입니다 (그래서 건너 뛰십시오). 나머지의 경우, 각도의 사인은 정규화의 교차 곱에 의해 (point [n] -point [0]) 및 (point [n-1] -point [0])의 단위 길이로 주어집니다.
값의 합이 양수이면 다각형이 시계 반대 방향으로 그려집니다.
답변
가치있는 점을 위해이 믹스 인을 사용하여 Google Maps API v3 앱의 와인딩 순서를 계산했습니다.
이 코드는 다각형 영역의 부작용을 활용합니다. 꼭지점의 시계 방향 권선 순서는 양수 영역을 생성하는 반면 동일한 꼭지점의 시계 반대 방향 권선 순서는 음수 값과 동일한 영역을 생성합니다. 이 코드는 또한 Google Maps 지오메트리 라이브러리에서 일종의 개인 API를 사용합니다. 나는 그것을 사용하는 것이 편안하다고 생각했습니다-당신의 책임하에 사용하십시오.
샘플 사용법 :
var myPolygon = new google.maps.Polygon({/*options*/});
var isCW = myPolygon.isPathClockwise();
단위 테스트 @ http://jsfiddle.net/stevejansen/bq2ec/의 전체 예
/** Mixin to extend the behavior of the Google Maps JS API Polygon type
* to determine if a polygon path has clockwise of counter-clockwise winding order.
*
* Tested against v3.14 of the GMaps API.
*
* @author stevejansen_github@icloud.com
*
* @license http://opensource.org/licenses/MIT
*
* @version 1.0
*
* @mixin
*
* @param {(number|Array|google.maps.MVCArray)} [path] - an optional polygon path; defaults to the first path of the polygon
* @returns {boolean} true if the path is clockwise; false if the path is counter-clockwise
*/
(function() {
var category = 'google.maps.Polygon.isPathClockwise';
// check that the GMaps API was already loaded
if (null == google || null == google.maps || null == google.maps.Polygon) {
console.error(category, 'Google Maps API not found');
return;
}
if (typeof(google.maps.geometry.spherical.computeArea) !== 'function') {
console.error(category, 'Google Maps geometry library not found');
return;
}
if (typeof(google.maps.geometry.spherical.computeSignedArea) !== 'function') {
console.error(category, 'Google Maps geometry library private function computeSignedArea() is missing; this may break this mixin');
}
function isPathClockwise(path) {
var self = this,
isCounterClockwise;
if (null === path)
throw new Error('Path is optional, but cannot be null');
// default to the first path
if (arguments.length === 0)
path = self.getPath();
// support for passing an index number to a path
if (typeof(path) === 'number')
path = self.getPaths().getAt(path);
if (!path instanceof Array && !path instanceof google.maps.MVCArray)
throw new Error('Path must be an Array or MVCArray');
// negative polygon areas have counter-clockwise paths
isCounterClockwise = (google.maps.geometry.spherical.computeSignedArea(path) < 0);
return (!isCounterClockwise);
}
if (typeof(google.maps.Polygon.prototype.isPathClockwise) !== 'function') {
google.maps.Polygon.prototype.isPathClockwise = isPathClockwise;
}
})();