기본 콘텐츠로 건너뛰기

12월, 2020의 게시물 표시

Bspline Knot의 수정

앞에서 B- spline곡선은 여러 개의 부분 곡선들로 이루어져 있고, 각 부분 곡선들은 매듭 구간에서 정의되고 있다고 했습니다. 그래서 부분 곡선들이 정의되어 있는 이 매듭 구간을 수정을 하면 곡선의 형태도 바뀌게 됩니다. 이 매듭 구간을 결정하는 knot을 수정함으로써 곡선의 형태를 변형시킬 수 있습니다. 하지만 knot을 수정해서 곡선의 형태를 바꾸는 것은 그다지 바람직한 방법이 아닌 것 같습니다. knot을 수정해서 변형되는 곡선의 형태를 미리 예측하기가 힘들기 때문입니다. knot의 추가 knot의 추가는  기존의 곡선의 형태를 변형시키지 않고  새로운 knot을 매듭 벡터에 추가시키는 것입니다. knot이 하나 추가되면 m이 증가되므로 $m=n+p+1$의 식에서 n이나 p가 증가되어야 합니다. p가 증가되면 하나의 부분 곡선을 이루는데 필요한 basis function의 개수가 증가되므로 p가 증가되기 전보다 곡선의 부분적인 편집 기능이 떨어지게 됩니다. 그래서 이것은 고려하지 않고 n을 증가시킵니다. 즉 새로운 제어점을 추가시킨다는 말입니다. 다시 정리하면 n+1개의 제어점 $P_0,P_1,...,P_{n-1},P_n$와 그것과 연관된 양의 값인 $W_i$, $m+1$개의 매듭을 가진 매듭 벡터 $U=\{u_0,u_1,...,u_{m-1},u_m\}$, 차수 p를 가진 B-spline 곡선에 곡선의 형태는 변형시키지 않고 새로운 매듭을 추가시키는 것입니다. 추가시킬 새로운 매듭  u 가 매듭 구간 $[u_k,u_{k-1})$에 속한다고 가정하면, 이 매듭 구간에서 정의되는 곡선은 제어점 $P_{k-p},P_{k-p+1},...,P_{k-1},P_k$에 의해서 형성됩니다. 우리는 새로운 제어점을 찾아야 하기 때문에 $P_{k-p},P_{k-p+1}$상의 $Q_{k-p+1}, P_{k-p+1},P_{k-p+2}$상의 $Q_{k-p+2},…,P_{k-1},P_k$상의 $Q_k$을 찾아야 합니다. 그리고 나서 기존의 $P_{k-p},

Cloud 마크 그리기 개선

하나의 다각형에 대한 Cloud 마크를 그리는 것에 대해 알아봤습니다. 연결된 여러개의 다각형이 있을 경우 각각 개별적으로 다각형을 생성하는 것은 자칫 지저분해 보일 수 있으므로 연결된 다각형을 묶어 Cloud 마크를 생성하는 것에 대해 알아보도록 하겠습니다. 가운데 3개의 다각형(B,C,D)이 겹쳐져 있습니다. 먼저 겹쳐진 다각형을 찾아야 합니다. 다각형의 Bounding Box를 이용하여 서로 겹쳐지는지 여부를 확인할 수 있습니다. # A, B is Bounding Box if A.MinX > B.MaxX or A.MinY > B.MaxY or A.MaxX < B.MinX or A.MaxY < B.MaxY: return false else: return true 따라서 아래와 같이 색깔별로 묶을 수 있습니다. 여러개의 다각형을 Cloud 마크를 그리기위해 하나의 다각형으로 만들어줘야 합니다. (저희들은 하나의 다각형에 대해서 Cloud 마크를 그리는 로직을 가지고 있습니다.) 일단 다각형을 구성하는 정점들을 구합니다. 첫번째 방법 : 정점들을 포함하는 Bounding Box를 구해 다각형을 생성합니다. 두번째 방법 : 정점들을 포함하는 ConvexHull을 구해 다각형을 생성합니다.

컨테이너 박스에 최대로 배관 스풀 적재하기

앞선 글에 이어지는 글입니다. 컨테이너 박스에 최대로 들어갈 수 있는 스풀을 제작했다면 이제는 스풀들을 최대로 많이 컨테이너 박스에 쌓는 문제입니다. 문제를 풀기에 앞서 스풀은 아래와 같이 생겼습니다. 사람이 직접한다면 경험으로 잘 싣을 수 있겠지만 컴퓨를 이용해 문제를 푸는 입장에서는 복잡합니다. 넣을 공간을 찾는 것도 문제지만 넣는 순간도 중요합니다. 안쪽에 빈 공간이 있다고 해도 미리 쌓은 스풀이 장애물이 된다면 안쪽에 넣을 수가 없습니다. 이러한 문제를 좀더 간단히 하기 위해 스풀 패키지 단위로 컨테이너에 적재하는 것으로 문제를 축소하겠습니다. 그럼 하나의 패키지에 최대한 많은 스풀을 배치(X,Y)하면 됩니다. 패키지에는 층으로 스풀을 쌓지 않습니다. 컨테이너 밖에서 패키지에 최대한 스풀을 많이 배치하고 패키지를 컨테이너 박스에 쌓으면 됩니다.(패키지의 폭과 깊이는 컨테이너와 동일) 이제 패키지에 최대로 스풀을 많이 쌓는 방법에 대해서 고민하면 됩니다. 이러한 유사한 문제를 푸는 NESTING 알고리즘이라는게 있습니다. 정확히는 2D NESTING NESTING 알고리즘은 쉽게 말해 주어진 영역에 다각형을 최대한 많이 넣을 수 있도록 배치하는 알고리즘입니다. 스풀은 3D이므로 NESTING 알고리즘을 이용하기 위해 스풀을 2D(다각형)로 변환시킵니다. 이제 NESTING 알고리즘을 이용하여 2D 다각형을 최대한 많이 배치하도록 합니다. 거~의 끝났습니다.(아직 끝난게 아닙다.) 2D NESTING을 이용하여 배치했기 때문에 높이(Z) 방향으로 빈 공간이 생길 수 있습니다. 높이 방향으로 존재하는 빈 공간을 찾기 위해 Cell Decomposition을 이용하도록 하겠습니다. 패키지를 Cell로 구축합니다. Cell에서 스풀이 차지하는 공간을 제거합니다. 스풀이 차지하는 공간 제거 남은 Cell들이 빈 공간이므로 스풀의 Bounding Box를 이용하여 스풀이 들어갈 수 있는지 확인

[AutoCAD.NET] 주어진 폴리곤을 이용하여 Cloud 마크 그리기

아래와 같이 폴리곤이 주어졌을때 폴리곤 외곽선을 따라 Cloud 마크를 그리는 방안입니다. 폴리곤의 외곽선을 따라 아래와 같이 Cloud 마크를 그릴수 있습니다. AutoCAD.NET API를 이용하면 손쉽게 Cloud 마크를 생성할 수 있습니다. 폴리곤을 이루는 Vertex에 bulge값을 주면 arc가 생성됩니다. Polyline polyline = new Polylin(); polyline.AddVertexAt(index, pt, bulge, 0, 0); $(P0,P1,P2)$로 이루어지는 폴리곤에 Cloud 마크를 그리기 위해 정점$(P0,P1,P2)$ 사이에 임시 정점을 arc length만큼 띄워서 추가합니다. arc length는 상황에 맞게 설정해주면 됩니다. (사용자 옵션 혹은 폴리곤을 이루는 가장 작은 선분의 길이에 비례한 값) double dArcLength = 0.1; List<Point2d> lstPoint = new List<Point2d>(); Point2d[] corners = new Point2d[] { P0, P1, P2 }; for(int i = 0; i < corners.Length;++i) { double l = corners[(i + 1) % corners.Length].GetDistanceTo(corners[i]); int count = Convert.ToInt32(l / dArcLength); Vector2d vec = corners[(i + 1) % corners.Length] - corners[i]; Vector2d normal = vec.GetNormal(); for(int j = 0; j < count;++j) { Point2d pt = corners[i] + normal * j * dArcLength; lstPoint.Add(pt); } } 여기서 주의할 것은 폴리

컨테이너 박스에 들어갈 스풀 최대 길이 구하기

배관 자재를 운반하기 위한 컨테이너 박스에 운송비를 줄이기 위해 최대로 많은 배관 자재를 넣기 위한 방안입니다. 컨테이너 박스는 아시다시피 직육면체로 보시면 되고 배관 자재는 분기(TEE)가 없는 선형적인 구조라고 가정하겠습니다.(직관, ELBOW, REDUER, FLANGE로만 구성) 컨테이너 박스 배관 라인 쉽게 생각해보면 "컨테이너 박스에 차례로 배관 자재를 들어갈때 까지 넣으면 될것 같습니다." 이게 끝일까요? 이렇게만 하고 코딩을 시작하면 될까요? 가슴 한 구석에서 "이렇게만 하면 안될 것 같은데..." 라고 이야기하는 것 같습니다. 여튼 시작해보겠습니다. 일반적으로 컨테이너 박스는 차량에 실려 운반되기 때문에 한쪽이 긴 직육면체입니다. 다행히 직관이 컨테이너의 길이 방향으로 놓여있다면 쉬울것 같은데 그렇지 않다면 문제가 됩니다. 그래서 직관을 컨테이너 길이 방향(각도 0)으로 회전시켜서 넣습니다. 코딩을 해봅시다. if angle == 0: pass elif angle == 90: 직관을 -90도로 회전 elif angle == 270: 직관을 -270도로 회전 else: pass 여러분들이 이런 코드를 보면 위험하다는 느낌을 가져야 합니다. 평면(360)을 4분면으로 나누어 처리했는데 일반 배관 라인은 직교하여 생성하기 때문에 큰 무리가 없어 보입니다만 사선으로 이동하는 배관 라인의 경우에 우리가 원하는 결과를 만족시킬수 없습니다. 그럼 45도를 코드에 넣어서 처리하면 되지 않을까 생각하시겠지만 if angle == 0: pass elif angle == 45: 직관을 -45도로 회전 elif angle == 90: 직관을 -90도로 회전 elif angle == 270: 직관을 -270도로 회전 else: pass 그렇게 생각하면 안됩니다. 위 코드는 특정 상황에만 제대로 동작하고 예외

[S3D] Cable Tray의 Open 방향 벡터 구하기

현재 수행하고 있는 과제 중에서 기존에 그려진 Cable Way를 이용하여 Cable Way를 지나가는 Cable Tray를 자동으로 그려주는 기능이 있습니다. Cable Way가 X-Y 평면에 놓여 있을 경우에는 문제없이 잘 그려지지만 수직 방향으로 시작하는 경우에는 Cable Tray의 Open 방향이 잘못 선택되는 문제가 있습니다. 그래서 이 경우에 어떻게 Cable Tray의 Open 방향 벡터를 구하는 방법에 대해 알아보도록 하겠습니다. 제시 1) Cable Way가 시작하는 지점에서 Cable Tray의 기본 Open 방향은 아래와 같습니다. 예를 들어 Vertical Cable Way의 경우는 이렇게 생겼습니다. 우선 Vec1과 Vec2의 Cross Product를 수행하여 벡터 O를 구합니다. 그리고 Vec1과 벡터 O의 Cross Product로 벡터 X를 구합니다. 이제 벡터 X방향으로 Cable Tray의 Open 방향을 맞추면 됩니다. 벡터 O와 벡터 X의 사이 각을 구해 구한 각 만큼 Cable Tray의 단면을 회전시켜 Cable Tray를 생성하면 됩니다. 이렇게해서 Vertical일 경우 Angle을 구해 Open 방향을 찾을 수 있습니다. 단 평면을 구성할 수 있어야 하기 때문에 3점 이상이 필요합니다. 2개의 점으로 구성된 Cable Way에서 Cable Tray의 Open 방향을 맞출 수 없으므로(Open 방향을 구할 수는 있지만 맞는 방향인지는 확인할 수 없음) 사용자가 방향을 정해줘야 합니다. S3D에서는 그것이 가능합니다.!!! 확장해서 Vertical Cable Tray의 경우에 사용자 방향성을 정해 줄수 있다는 것이고 그렇게 된다면 위에서 말한 골치 아픈 계산을 하지 않고 프로그램에서 사용자가 입력한 각도만 사용하면 됩니다. 사용자 편의를 위해(각도를 입력하는 노력을 줄이는) 계산을 수행하는 것과 사용자를 잘 설득해 각도를 입력하라고 유