기본 콘텐츠로 건너뛰기

라벨이 GEOMETRY인 게시물 표시

Ellipse의 Start, End Point 구하기

포맷마다 프리미티브를 정의하는 것이 달라 데이터 교환을 위해서 프리미티브 변환을 해줘야 합니다. Ellipse는 아래와 같이 정의할 수 있습니다.($\alpha$=시작 각도, $\beta$=회전 각도) 위 그림에서 Ellipse상의 점 $A$는 아래 식으로 구할 수 있습니다. $x^\prime = a*cos(\theta)\\y^\prime = b*sin(\theta)$ 위 식은 2D일때의 식이고 그럼 3D일때는 어떻게 식을 구해야 할까요? $a, b$ 는 각각  $\vec{U}$축, $\vec{V}$축상의 거리이기 때문에 위 식은 아래 식으로 변환할 수 있습니다. $x^\prime = a*\vec{U}*cos(\theta)\\y^\prime = b*\vec{V}*sin(\theta)$ 위 식이 Ellipse의 일반식이 됩니다. $\vec{U}, \vec{V}$에 축의 벡터를 입력하면 원하는 좌표를 구할 수 있습니다. 예를 들어 $\vec{U}$에 $\vec{X}([1, 0, 0])$을 $\vec{V}$에 $\vec{Y}([0,1,0])$을 대입하면 아래와 같습니다. $$x^\prime = a*[1_x,0_y,0_z]*cos(\theta)\\y^\prime = b*[0_x,1_y,0_z]*sin(\theta)$$ $\vec{X}$축의 $y,z$ 요소는 0이고, $\vec{Y}$축의 $x,z$ 요소는 0이기 때문에 이것을 풀어보면 첫번째 식과 같게 됩니다. $\vec{U}$, $\vec{V}$축이 임의의 3D 축이라고 가정해보면 $$x^\prime = a*[u_x,u_y,u_z]*cos(\theta)\\y^\prime = b*[v_x,v_y,v_z]*sin(\theta)$$ 월드 좌표 $(x,y,z)$는 아래 식으로 구할 수 있습니다. $$x = a*u_x*cos(\theta)+b*v_x*sin(\theta)\\y = a*u_y*cos(\theta)+b*v_y*sin(\theta)\\z = a*u_z*cos(\theta)+b*v_z*sin(\theta)$$...

평면 상의 점 구하기

S3D는 민감한것 같습니다. 조그마한 오차도 허용하지 않고 형상을 만들지 못하겠다고 튕겨버립니다. 그림에서와 같이 사선 방향으로 Extrude하는 형상을 만들때 단면을 이루는 점들이 하나의 평면상에 있지 않으면 형상을 만들지 못합니다.(’범위를 벗어났다’나 뭐 그런 오류가 발생합니다.) 단면을 이루는 점들을 평면 상의 점들로 변환해줘야 S3D에서 오류 없이 형상을 만들 수 있습니다. 먼저 평면의 방정식은 아래와 같습니다. $$ a*x + b*y + c*z + d = 0 $$ 여기서 $<a,b,c>$는 평면의 법선 벡터입니다. 일반적으로 평면의 법선 벡터는 알고 있기 때문에 $d$ 값은 아래 식으로 구할 수 있습니다.(x,y,z에 단면을 이루는 점 하나를 대입) $$ d = -(a*x + b*y + c*z) $$ 이제 평면의 방정식을 구했기 때문에 나머지 다른 점($x_1,y_1,z_1$)들을 평면 상의 점들로 변환해주면 됩니다. $$ \begin{aligned} h &= a*x_1+b*y_1+c*z_1+d\\ pt^\prime &= pt - <a,b,c>*h \end{aligned} $$ 이렇게 평면 상의 점 $pt^\prime$ 을 구할 수 있습니다.

White Space 검색

아래와 같이 주어진 도면에 Label을 도면 상의 다른 객체들과 겹쳐지지 않게 배치하고자 할때 White Space 검색이 필요합니다. 먼저 도면의 모든 객체들을 포함하는 Bounding Box를 구합니다. 이 Bounding Box 안에 Label을 배치한다고 가정하겠습니다. 도면 상의 객체의 Bounding Box를 구해 도면의 Bounding Box안에 배치시킵니다. 그리고 배치하려는 Label의 Bounding Box를 구한 다음 Label을 배치할 위치를 찾을 Search Bounding Box를 설정합니다. 일반적으로 Label을 가지는 객체의 Bounding Box의 비율로 Search Bounding Box를 구합니다.(물론 도면 전체 Bounding Box가 될 수도 있습니다.) 라인 넘버의 경우 Search Bounding Box를 파이프 길이 방향으로 길게 생성하면 될것 같습니다. Search Bounding Box안에서 Label을 X,Y로 조금씩 이동(δt)하면서 Score를 구합니다. Score = distance * distance factor + overlap area ∗ overlap area factor distance = 밸브의 원점과 Label 위치와의 거리 distance factor = distance가 score에 미치는 영향 overlap area = label의 bounding box가 도면 상의 객체와 겹치는 영역 overlap area factor = overlap area가 score에 미치는 영향 $\delta t$의 크기가 작을 수록 Label을 배치할 위치의 정밀도가 높아지지만 위치를 찾는데 걸리는 시간을 길어집니다. overlap area는 사각형들이(Label과 여러 객체들이 동시에 겹쳐질수 있음) 겹쳐지는 영역을 구하면 됩니다. Label을 회전할 필요가 있으면 회전한 Bounding Box를 구하여 Search Bounding ...

[2D]두 직선의 교점 구하기

  2D상의 A,B를 지나는 직선과 C,D를 지나는 직선의 교점을 구하는 방정식을 구해보도록 합시다. $$\begin{eqnarray} l_1&=A+(B-A)\times t_1 \\ l_2&=C+(D-C)\times t_2 \\ A+(B-A)\times t_1 &= C+(D-C)\times t_2\end{eqnarray}$$ 두 직선은 교점은 위의 방정식을 통하여 구할 수 있습니다. 이 방정식을 풀어보도록 합시다. 위 방정식은 2개의 변수를 가지고 있으므로 2개의 식이 있어야만 방정식을 풀수 있습니다. 따라서 이 방정식을 매개변수 $x,y$에 대해서 풀어보면, $$\begin{eqnarray} A_x+(B_x-A_x)\times t_1 &= C_x+(D_x-C_x)\times t_2 \\ A_y+(B_y-A_y)\times t_1 &= C_y+(D_y-C_y)\times t_2\end{eqnarray}$$ (4)번 식에서 $t_2$를 구해 (5)번 식에 대입하면, $$\begin{eqnarray} A_y+(B_y-A_y)\times t_1 &=& C_y+(D_y-C_y)\times \frac{(A_x-C_x)+(B_x-A_x)\times t_1}{(D_x-C_x)} \\ (A_y-C_y)*(D_x-C_x) &=& (D_y-C_y)*(A_x-C_x)+((B_x-A_x)*(D_y-C_y)-(B_y-A_y)*(D_x-C_x))\times t_1 \\ t_1 &=& \frac{(A_y-C_y)*(D_x-C_x)-(A_x-C_x)*(D_y-C_y)}{(B_x-A_x)*(D_y-C_y)-(B_y-A_y)*(D_x-C_x)}\end{eqnarray}$$ 이렇게 해서 $t_1$를 구했습니다. 만일 분모가 0이 되면 $t_1$을 구할 수가 없게 되고 따라서 교차점도 구할 수 없습니다. (두 직선이 평행할 경우) $$(B_x-A_x)*(D_y-C_y)-(B_y-A_y)*(D_x-C_x)=0$$...

선분의 중점 구하기

 두 점 $P_1,P_2$으로 이루어진 선분의 중점은 $(P_1+P_2)/2$입니다. 어 이게 맞나? 생각할지도 모르겠습니다. 맞는지 한번 확인해 보도록 하겠습니다. $P_1,P_2$로 이루어진 선분은 다음과 같이 표현이 가능합니다. 식으로는 아래와 같이 표현할 수 있습니다. $$L = P_1 + (\overrightarrow{P_2 - P_1})\times t, (0<=t<=1)$$ 여기서 선분의 중점은 두 점의 가운데이기 때문에 t=0.5로 두면 됩니다. ($t=0$일 경우는 시작점, $t=1$일 경우는 끝점) $t$에 0.5넣어 풀어보면, $$\begin{array} \\M&=P_1+\overrightarrow{(P_2-P_1)}\times 0.5 \\ &=P_1 + P_2\times 0.5 - P_1\times 0.5 \\ &=P_1\times 0.5 + P_2\times 0.5 \\ &=(P_1+P_2)\times 0.5 \end{array}$$ $P_1, P_2$가 이루는 선분의 중점은 $(P_1+P_2)/2$ 가 되는 것을 확인할 수 있습니다. 이제부터는 두 점 $P_1, P_2$의 중점을 구할때 두 점의 합을 2로 나눈 값을 사용하시면 됩니다.

3차원에서 임의의 벡터에 수직인 벡터 구하기

3차원에서 주어진 벡터 $<a, b, c>$가 있을때  벡터에 수직인 임의의 벡터를 구하는 것은 의외로 쉽지가 않습니다. 정답이 없어 찾기가 어렵다기 보다는 무한의 값에서 하나를 선택하는 것이 어려운 문제입니다. 즉  $<a, b, c>$에 수직인 벡터의 수는 무한입니다.

How do you detect where two line segments intersect?

There’s a nice approach to this problem that uses vector cross products. Define the 2-dimensional vector cross product  v  ×  w  to be  v x w y  −  v y w x  (this is the magnitude of the 3-dimensional cross product). Suppose the two line segments run from  p  to  p  +  r  and from  q  to  q  +  s . Then any point on the first line is representable as  p  +  t   r  (for a scalar parameter  t ) and any point on the second line as  q  +  u   s  (for a scalar parameter  u ). The two lines intersect if we can find  t  and  u  such that: p  +  t   r  =  q  +  u   s Cross both sides with  s , getting ( p  +  t   r ) ×  s  = ( q  +  u   s ) ×  s And since  s  ×  s  =  0 , this means ...

선분과 직선과의 거리

선분(S-E)와 점 P와의 거리를 구해보도록 합시다. 우선 두개의 벡터를 구할수 있습니다. $$ \begin{aligned} V_1 &= \overrightarrow{P-S} \\ V_2 &= \overrightarrow{E-S} \\ \vec{V_1}\cdot\vec{V_2} &= |\vec{V_2}||\vec{V_1}|cos(\theta) =|\vec{V_2}||\vec{V_2}|U \\ U &= \frac{\vec{V_1}\cdot\vec{V_2}}{|\vec{V_2}||\vec{V_2}|} \end{aligned} $$ 위 식을 통해서 U값을 구할수 있습니다. 일단 U를 구했으면, U를 통하여 $V_2$와 수직을 이루는 벡터 $\overrightarrow{P-C}$의 C 값을 구할 수 있습니다. $$ C = S + U*\overrightarrow{E-S} $$ 마지막으로 C를 구했으니 $C-P$간의 거리가 선분과 점의 거리가 됩니다. double CIsLine2d::DistanceTo(const CIsPoint2d &pt) const { const double mag = Length(); if(0.f != mag) { double u = ((pt.x() - m_start.x())*(m_end.x() - m_start.x()) + (pt.y() - m_start.y())*(m_end.y() - m_start.y())) / (mag*mag); double xp= m_start.x() + u*(m_end.x() - m_start.x()); double yp= m_start.y() + u*(m_end.y() - m_start.y()); const double dx = xp - pt.x(); const double dy = yp - pt.y(); return sqr...

3D 평면 상의 점들을 2D로 변환

3D 평면상의 점들을 2D로 변환하는 방법에 대해서 알아보도록 하자. 지금 개발하고 있는 2D상의 점들을 삼각화 시키는 루틴이 있는데 이 루틴을 3D 평면상의 점들에 대해서 적용시키기 위해서 3D 평면상의 점들을 2D로 변환시키는 방법이 필요하다. 고찰 1) 3D 평면을 X-Y 평면으로 맞추는 것이다. 3D 평면의 법선 벡터(n)를 Z축과 일치시키기 위해서 X,Y 축 방향으로 회전시키는 방법이다. 이 방법에 대해서는 이전 글 을 참조 하면 될것 같다. 고찰 2) 이 글에서 주로 생각해 볼것은 실제로 평면을 회전시키지 않고 2D 상으로 변환시키는 방법이다. 앞서 이야기 했듯이 이미 평면의 법선 벡터(n)를 알고 있으므로, 평면상의 임의의 점(P)을 하나 선택하고 그리고 다른 또 하나의 점을 선택한다. 그럼 하나의 벡터(u)를 구할 수 있고 이 벡터와 평면의 법선 벡터와의 외적을 통해 구한 벡터와 평면상에서 수직인 또 다른 벡터(v)를 구할 수 있다. 여기서 구한 평면상의 두 벡터(u,v)를 축으로 하여 평면상의 모든 점들을 u,v축에 대한 값으로 표현할 수 있다. 이렇게 해서 $t_2$의 값을 구할 수 있고, 마찬가지로 $t_1$의 값을 구할 수 있다. 결론적으로 모든 점들에 대하여 u,v 축에 대한 값을 구할수 있으므로 2D로 변환한 것이 된다. 고찰 2)가 고찰 1)보다 나은 점은 고찰 1)에서는 실제적으로 몇 단계의 계산을 거쳐 2D 상의 점으로 변환시킨다는 것이다. 이때 아무래도 시간과 floating point연산으로 인한 데이터 변형이 일어날수 있다는 것이다. 이에 비해 고찰 2)는 변화 루틴이 간단하다.

3D 모델링 상의 한 점과 2D 도면(뷰)과의 상호 변환

 우선 3D 모델링 상의 한 점에서 2D 도면(뷰)으로의 변환을 살펴봅시다.  일반적으로 3D 모델링을 바라보는 방향에 따라서 TOP , BOTTOM , LEFT , RIGHT , FRONT , BACK 이렇게 6개의 뷰를 생성할 수 있습니다. 아래는 각각의 뷰 변환행렬입니다. $$\begin{eqnarray}\text{Bottom View} &=&  \begin{bmatrix}1&0&0\\0&-1&0\\0&0&1\end{bmatrix} \\ \text{Top View} &=&  \begin{bmatrix}1&0&0\\0&1&0\\0&0&1\end{bmatrix} \\ \text{Right View} &=&  \begin{bmatrix}1&0&0\\0&0&1\\1&0&0\end{bmatrix} \\ \text{Left View} &=&  \begin{bmatrix}0&-1&0\\0&0&1\\-1&0&0\end{bmatrix} \end{eqnarray}$$ 그리고 3D 모델링에 스케일과 회전을 적용한 후에 3D 모델의 중점을 도면의 중점에 맞추면 도면으로의 변환이 완성됩니다. 변환할 점에서 모델의 중점을 뺀다.(모델의 중점을 (0 , 0 , 0)좌표로 두는 효과) $tmp=pt-\text{model center pt}$ 뷰 변환 행렬을 통해 2D로 변환시킨다. $tmp^\text{'}= \begin{bmatrix}a_{11}&a_{12}&a_{13}\\a_{21}&a_{22}&a_{23}\\a_{31}&a_{32}&a_{33}\end{bmatrix}*tmp$ 변환된 2D 좌표를 뷰 회전 각도로 회전시킨...

임의의 축에 대한 회전 #2

임의의 축에 대한 회전에 대한 2번째입니다. 첫번째 보다 간단합니다. 그림에서처럼 임의의 축 $\vec{n}$에 대해서 $\vec{r}$이 가리키는 점을 $\theta$만큼 회전을 시키는 경우를 생각해봅시다. $\vec{r}$은 $\vec{n}$ 수직인 성분($\vec{r_+}$)과 평행한 성분($\vec{r_{//}}$)으로 나눌 수 있습니다. 평행한 성분은 $\vec{r}$에 대해서 회전을 한 뒤에도 그 값이 변하지 않습니다. $$ r_{//} = \big( \vec{n}\cdot\vec{r} \big) \vec{n} \\ r_+ = \vec{r} - \big( \vec{r}\cdot\vec{n} \big) \vec{n} $$ $\vec{r_+}$에 수직이고 또한 $\vec{r_{//}}$에 수직인 벡터를 $\vec{V}$라 두고, $\vec{r_+}$의 $\vec{n}$에 대한 회전은, $$ \vec{V} = \vec{n}\times\vec{r_+} = \vec{n}\times\vec{r} \\ R_{r_+} = cos(\theta)r_+ + sin(\theta)\vec{V} $$ 이 됩니다. ($r_+$를 X축, $\vec{V}$를 Y축으로 생각하시면 됩니다.) 이제 $\vec{r}$의 $\vec{n}$에 대한 회전은, $$ \begin{aligned} R_{r_+} &= R_{r_{//}} + R_{r_+} \\ &= (\vec{n}\cdot\vec{r})\vec{n} + cos(\theta)r_+ + sin(\theta)\vec{V} \\ &= cos(\theta)\vec{r} + \big( 1 - cos(\theta)\big) \vec{n}(\vec{n}\cdot\vec{r}) + sin(\theta)\vec{n}\times\vec{r} \end{aligned}$$ 이 됩니다. 단, 여기서 $\vec{n}$은 단위 벡터입니다.

[Geometry] 평면과 직선의 교점 구하기

[고찰 1] S와 E는 서로 평면의 반대편에 있어야 교점이 존재하게 됩니다. 교점 C는 직선의 방정식인 $S + t*(E - S)$로 표현됩니다. 또한 C는 평면 상의 점이 되므로 $\vec{N}*C + d = 0$을 만족합니다. 첫번째 식을 두번째 식에 대입하면,$\begin{eqnarray} \vec{N}*S + t*\vec{N}*(E-S) + d = 0 \\ t = -(\vec{N}*S + d)/(\vec{N}*(E-S)) \end{eqnarray}$이 됩니다. 이렇게 해서 $t$를 구할 수 있습니다. $t$를 구한 다음 당연히 교점 C를 구할 수 있습니다.