다각형에서의 간단한 HitTest


#1

예시

========[FIX 04-12]========
@ChulseungYoo 님께서 조금더 좋은 아이디어를 주셔서 수정 헙니다.

역시 무언가 있었습니다. ofPolyline::inside(…) 입니다.
( 그리고 재미있는것은 inside 함수가 이전에 제가 적은 IsPointInsidePolygon 와 거의 똑같군요 허허허 )
아무래도 조금더 간편한것이 좋다보니 ofPolyline을 이용해서 코드를 수정 하여 보겠습니다. 물론 예제와 똑같이 작동 합니다.

vector<ofPoint> points;
ofPolyline polyLine;
//--------------------------------------------------------------
void ofApp::draw(){

	ofClear(ofColor::white);

	ofPushStyle();
	
	//points 에 점이 적어도 3개 는 있어야 면이 생기겠죠?
	if (points.size() > 2)
	{
		polyLine.clear();

		////참고 : 벡터를 포인터로 바꾸기 points -> &points[0]
		polyLine.addVertices(&points[0], (int)points.size());
		
		////마우스 좌표로 인하여 만들어진 점 in , out 을 실시간으로 판정함 
		ofPoint targetPoint(mouseX, mouseY);
		bool isIn = polyLine.inside(targetPoint);

		////isIn으로 인하여 면의 색상을 바꾸어 봅니다.
		if (isIn == true)
		{
			ofSetColor(ofColor::magenta);
		}
		else {
			ofSetColor(ofColor::gray);
		}

		////다각형을 그려 봅니다.
		ofBeginShape();
		for (int i = 0; i < points.size(); i++)
		{
			ofVertex(points[i]);
		}
		ofEndShape();
	}


	//점을 화면에 찍어 봅니다.
	ofSetColor(ofColor::red);
	for (int i = 0; i < points.size(); i++)
	{
		ofCircle(points[i].x, points[i].y, 4);
	}

	ofPopStyle();
}



//--------------------------------------------------------------
void ofApp::mousePressed(int x, int y, int button) {

	if (button == 0)
	{
		//왼쪽 클릭으로 점들을 추가 해 봅니다.
		points.push_back(ofPoint(x, y));
	}
	else if (button == 2)
	{
		//오른쪽 클릭으로 점들을 지워 봅니다.
		if (points.size() > 0)
			points.pop_back();

	}
}

만약 구지 ofPolyline을 사용하지 않겠다 하시는 분들은 원문을 보시면 됩니다.
ofPolyline에 유용한 기능들이 많이 있군요, 나중에 번역이라도 해보면서 익혀 나가야 겠습니다.

역시 이렇게 무언가 더 좋은 방법이 나오는것을 보니 포럼의 필요성을 느낌니다. 앞으로도 많은 분들이 포럼에 참여하여 주셨으면 좋겠습니다.

.
.
.

========[원문]========
안녕하세요.

작업하다가 OF 기본 API에 왜 없을까 하는것이 있었는데, 바로 HitTest 입니다.
(이미 있는데 제가 발견을 못한것일 수도 ㅋㅋㅋ )

물론 ofRectangle 의 Intersects(…) 가 있고, circle의 경우 간단하게 중심점에서 반지름의 길이로 점과 모양의 충돌을 체크 할 수 있습니다.

물론 BOX2D나 기타 물리엔진을 불러와 Collider를 추가하면 됩니다만,
자칫 벼룩잡으려고 포크레인 쓰는 상황이 될 수 있지요.

여기에 간단히 2D 다각형과 1차원 점의 충돌을 체크 할 수 있는 메소드가 있습니다.

코드

vector<ofPoint> points;

//점 배열에서 
//from ofxTriangle (https://github.com/obviousjim/ofxTriangle)
bool IsPointInsidePolygon(ofPoint* points, int pointLength, ofPoint p)
{
	int counter = 0;
	int i;
	double xinters;
	ofPoint p1, p2;

	p1 = points[0];

	for (i = 1; i <= pointLength; i++)
	{
		p2 = points[i % pointLength];
		if (p.y > MIN(p1.y, p2.y)) {
			if (p.y <= MAX(p1.y, p2.y)) {
				if (p.x <= MAX(p1.x, p2.x)) {
					if (p1.y != p2.y) {
						xinters = (p.y - p1.y)*(p2.x - p1.x) / (p2.y - p1.y) + p1.x;
						if (p1.x == p2.x || p.x <= xinters) {
							counter++;
						}
					}
				}
			}
		}
		p1 = p2;
	}

	return counter % 2 != 0;
}



//--------------------------------------------------------------
void ofApp::draw(){
	ofClear(ofColor::white);

	ofPushStyle();
	
	//points 에 점이 적어도 3개 는 있어야 면이 생기겠죠?
	if (points.size() > 2)
	{
		//여기 입니다. 여러분!
		//마우스 좌표로 인하여 만들어진 점 in , out 을 실시간으로 판정함 
		//참고 : 벡터를 포인터로 바꾸기 points -> &points[0]
		ofPoint targetPoint(mouseX, mouseY);
		bool isIn = IsPointInsidePolygon(&points[0], (int)points.size(), targetPoint);

		//isIn으로 인하여 면의 색상을 바꾸어 봅니다.
		if (isIn == true)
		{
			ofSetColor(ofColor::magenta);
		}
		else {
			ofSetColor(ofColor::gray);
		}

		//다각형을 그려 봅니다.
		ofBeginShape();
		for (int i = 0; i < points.size(); i++)
		{
			ofVertex(points[i]);
		}
		ofEndShape();
	}


	//점을 화면에 찍어 봅니다.
	ofSetColor(ofColor::red);
	for (int i = 0; i < points.size(); i++)
	{
		ofCircle(points[i].x, points[i].y, 4);
	}

	ofPopStyle();
}



//--------------------------------------------------------------
void ofApp::mousePressed(int x, int y, int button) {

	if (button == 0)
	{
		//왼쪽 클릭으로 점들을 추가 해 봅니다.
		points.push_back(ofPoint(x, y));
	}
	else if (button == 2)
	{
		//오른쪽 클릭으로 점들을 지워 봅니다.
		if (points.size() > 0)
			points.pop_back();
	}
}

예전에 다른거 할때는 즐겨 쓰던 기능이라…
다른거에는 있는데 OF 왜 없지 하면서 만들들어 보다가, 각 정점을 삼각형으로 나누는 코드가 너무 길어져 고민하다가 ofxTriangle에서 발견 했습니다.

  • 이거 처음 만든사람 천재…- :thumbsup::thumbsup: 인정…

여러분 작업 하시는데 작은 도움이 되기를…


#2

ofPolyline에 inside()메소드가 있습니다^^;


#3

헉 저런 간단한 메소드가 제공되고 있었다니!


#4

아하… ㅋ 그렇군요 기본메소드들만 보다보니 ㅋ


#5

저도 처음 알게 되었네요 ㅋㅋ


#6

저거 응용해서 그거 만들면되겠네요~ㅎㅎㅎㅎ


#7

아…예전엔 저도 직접 만들어 썻는데 이런게 있을 줄이야…지금 하고 있는 안건에 곧바로 사용해야 겠네요. 포럼이 생겨 참 좋네요. :grinning: