기본 콘텐츠로 건너뛰기

라벨이 S3D인 게시물 표시

평면 상의 점 구하기

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$ 을 구할 수 있습니다.

[S3D] Grid Line 생성하기

파이프 랙을 생성하기 위해서 먼저 Grid Line을 생성한 후에 Grid Line의 교차점에 칼럼을 생성하고 칼럼 간에는 빔을 생성합니다. 하지만 이번에는 이미 모델링한 파이프 랙의 Grid Line을 생성해달라는 요구를 받았습니다. 다음과 같은 파이프 랙의 경우에는 3개의 Grid Line System이 필요합니다. 그럼 주어진 파이프 랙에서 생성할 Grid Line System을 구분해야 합니다. 이 부분은 칼럼과 빔의 물리적 연결로 구분할 수 있습니다. 직관적입니다. Grid Line을 생성하기 위해서는 Grid Line System을 구성하는 축과 해당 축에 놓인 칼럼의 위치 정보가 필요합니다. 축을 구하기 위해서는 아래/좌측 칼럼(Y값이 가장 작은 칼럼들 중에서 가장 왼쪽에 있는 칼럼)을 구합니다. 아래/좌측 칼럼에서 가장 가까운 칼럼을 선택하여 축 하나를 생성합니다. 그리고 나머지 칼럼들 중에서 생성한 축과 직교하는 축을 이루는 칼럼을 선택하여 나머지 축을 생성합니다. 이렇게 Grid Line System을 구성하는 축들을 생성하였습니다. Global E 축과 구한 축과의 사이 각을 구하여 생성할 Grid Line System의 속성에 넣어주면 됩니다. 이제는 칼럼들을 축으로 매핑하여 축에 대한 위치를 구하면 됩니다. 해당 축과 아래/좌측 칼럼과 임의의 칼럼 간의 벡터의 내적을 이용하면 축에 대한 위치를 구할 수 있습니다. 이렇게 모든 칼럼들에 대해서 축 상의 위치를 구하면 부동 소수점 연산으로 인해 위치가 조금씩 맞지 않는 경우가 발생할 수 있습니다. 이때 Round 함수등을 이용하여 위치 변이를 보정할 수 있습니다. Grid Line System을 구분하는 부분은 직관적이고 파이프 랙 모델링 품질에 따라 결과가 바뀌게 됩니다. 만족하지 못하지만 그런대로 괜찮은것 같습니다. Grid Line System의 축과 칼럼 위치 정보를 구하는 부분은 명료하고 군더더기가 없어 만족합니다. 코...

[Cable Auto Routing] 맵 생성하기

 Cable AutoRouting을 하기 위해서는 Cable이 지나는 모든 CableTray에 대한 맵을 구성해야 합니다. 맵을 구성하기 위해 먼저 각 CableTray에 대해서 Node와 Edge를 구성합니다. 프로젝트 수행을 위해 고객사에서 보여준 제안서의 CableTray는 끊어진 Feature 없이 매끄럽게 연결되어 있었습니다. 하지만 막상 실제 프로젝트 수행이 끝난 3D Model을 받아 보니 군데군데 이빠지듯 Feature가 빠진 CableTray도 다수 있고 CableTray의 Feature 순서도 뒤죽박죽이었습니다. 우리가 생각한것보다 모델링의 품질이 좋지 않았습니다. CableTray1과 CableTray2가 하나의 CableTray로 구성될거라 생각했었는데 다른 CableTray로 만들어져 있습니다. [CableTray의 Feature가 서로 떨어져 있는 경우] CableTray는 여러 Feature들로 구성되어 있습니다. 그리고 Feature는 Part를 가지고 있습니다. Feature의 타입에는 Straight, Branch, End, Turn, AlongLegFeature등이 있습니다. Part가 있는 Feature만 노드를 생성합니다. End, Branch Feature등 물리적 형상의 나타내는 Part를 가지고 있지 않는 Feature에 대해서는 노드를 생성하지 않습니다. 노드를 생성한 Feature의 OrientedRangeBox의 Intersects 함수를 이용하여 Feature와 Feature간의 에지를 생성합니다. class CableTray: def __init__ ( ) : self ._nodes = [ ]   def build_network ( ) : for feature in self ._features: if feature. has_part : self ._nodes. append ( new Node ( feature ) )   for i...

[S3D] 칼럼(Column)간의 최소 거리 구하기

 아래와 같이 두 칼럼과 연결하는 빔이 있을때 두 칼럼간의 최소 거리를 구하는 방법입니다. 두 칼럼의 Origin Point로 거리를 구하게 되면 Cardinal Point에 따라 거리가 달라지게 됩니다. Cardinal Point에 대해서는 이전 글 을 참조하시면 됩니다. 그래서 여기서는 칼럼의 4개의 면을 이용하여 거리를 구하는 방법에 대해 생각해봅시다. 칼럼도 CableWay와 유사하게 8개의 코너 점을 가지고 있습니다. 이 코너 점을 이용하여 4개의 면을 만들 수 있습니다. $(P_0, P_1, P_5, P_4), (P_1, P_2, P_6, P_5), (P_2, P_3, P_7, P_6), (P_3, P_0, P_4, P_7)$ 이 점들로 각각 면들을 구성할 수 있습니다. 면의 방정식은 $ax+by+cz+d=0$입니다. $<a,b,c>$는 면의 법선 벡터로써 면에 존재하는 점들의 벡터 외적으로 구할 수 있습니다. 예를들어 첫번째 면의 법선 벡터는 $\overrightarrow{P_1-P_0}\times\overrightarrow{P_4-P_0}$입니다. 면들을 생성하였으면 빔의 라인과의 법선이 평행한 면들과의 교점 을 구할 수 있습니다.  라인과 법선의 평행 여부는 라인의 단위 벡터와 법선의 단위 벡터를 더하여 그 길이가 0 혹은 2에 근접하는지 여부로써 판별할 수 있습니다. 아마 위 예제에서는 2개의 평행한 면이 있어 2개의 교점을 구할 수 있습니다. S3D에서는 API를 통하여 평면과 곡선의 교점을 구할 수 있습니다. oColCurves1의 Position이 교점이 됩니다. 물론 S3D API를 이용하지 않고 직접 교점을 구할 수 있습니다. 이전 글 을 참조하시면 평면과 직선의 교점을 구할 수 있습니다. 반대편 칼럼에 대해서도 위와 같이 2개의 교점을 구합니다. 이렇게 구한 4개의 교점들에서 가장 짧은 거리를 구할 수 있습니다. 이 거리가 두 칼럼의 최소 거리가 됩니다. min_dist , line = None , ...

[S3D] 프로젝트 복원(Project Restore)

 아래는 MSSQL을 이용하여 S3D 프로젝트를 복원하는 절차입니다. Database Wizard를 실행합니다. Restore a site from a backup set 옵션을 선택합니다. 프로젝트 관련 정보를 입력합니다. Next 버튼을 눌러 복원을 시작합니다. 복원 진행 Finish 버튼을 눌러 종료합니다.

[S3D] OrientedRangeBox Intersects 함수 오류

 S3D에서 두 객체가 연결되어 있는지 여부를 확인하기 위해 객체의 OrientedRangeBox를 구한 뒤 Intersects 함수를 사용하였습니다. S3D API에서 제공하는 Intersects 함수의 설명은 아래와 같습니다. // // 요약: // Determines whether two oriented boxes intersect or not. // // 매개 변수: // oRangeBox2: // OrientedRangeBox object. // // 반환 값: // RangeBoxIntersectionType = 0: inside, 1: outside, 2: overlapping. // // 예외: // T:System.ArgumentNullException: // oRangeBox2 cannot be null. public RangeBoxIntersectionType Intersects ( OrientedRangeBox oRangeBox2 ) ; 대상인 OrientedRangeBox가 내부(0), 외부(1) 그리고 겹쳐지는지(2) 리턴합니다. 작업을 끝마친 뒤 결과를 확인하는데 결과가 이상한 부분을 확인하였습니다. Intersects 함수에서 사선으로 기다란 볼륨에 붉게 마크친 부분의 영역이 Outside라고 리턴하는 것이었습니다. ISO 뷰 실제 코드는 아래와 같습니다. OrientedRangeBox source = new OrientedRangeBox ( new Position ( 1487.1449000000002 , 1333.987 , 18.389 ) , new Vector ( 0 , 10.021999999999952 , 0 ) , new Vector ( 198.35219999999984 , 0 , 0 ) , new Vector ( 0 , 0 , 5.2151600000000045 ) ) ;   OrientedRangeBox...

[S3D] Structure 부재의 OrientedRangeBox 구하기

 앞서 CableWay, CableTray의 OrientedRangeBox를 구했습니다. 이번에는 Structure 부재의 OrientedRangeBox를 구하도록 하겠습니다. Structure 부재에는 Column, Beam, Girder, Brace가 있습니다. 선택한 부재의 BussinessObject의 CutLength 속성은 부재의 길이, $Origin$은 부재의 시작점을 의미합니다. 그리고 XAxis, YAxis, ZAxis는 부재가 놓인 방향을 의미합니니다. XAxis는 길이 방향, YAxis는 너비 방향, ZAxis는 깊이 방향을 의미합니다. BussinessObject가 가지고 있는 CrossSection 속성에는 부재 단면의 정보가 있습니다. CrossSection은 다시 부재의 Width, Depth와 Cardinal Point 정보를 가지고 있습니다. Cardinal Point는 아래와 같이 정의됩니다. Cardinal Point가 지정하는 위치가 $Origin$의 위치가 됩니다. OrientedRangeBox를 정의하기 위해서는 $Origin\prime,\text{ }\overrightarrow{Width},\text{  }\overrightarrow{Depth},\text{ }\overrightarrow{Direction}$ 정보가 필요합니다. $$\begin{eqnarray} \overrightarrow{Direction} &=&\overrightarrow{XAxis}*CutLength \\ \overrightarrow{Width}&=&\overrightarrow{YAxis}*Width \\ \overrightarrow{Depth}&=&\overrightarrow{ZAxis}*Depth \end{eqnarray}$$ 이 됩니다. 방향 벡터는 모두 정해졌으니 $Origin\prime$만 구하면 됩니다. OrientedRangeBox의 $Origin\prime$은 부재의 $Ori...

[S3D] CableWay, CableTray의 OrientedRangeBox 구하기

 S3D의 객체에는 RangeBox라는 객체의 크기를 가지는 속성이 있습니다. RangeBox는 글로벌 좌표계에서 Min, Max 좌표를 가지고 있습니다. 객체가 $X$축,$Y$축 또는 $Z$축에 놓여있을 때는 RangeBox와 실제 크기가 일치하겠지만, 그 외의 경우에는 RangeBox의 크기가 실제 크기보다 큽니다. 따라서 모든 경우에 객체 크기에 정확히 일치하는 크기를 구할때 RangeBox는 부적합합니다. 심지어 $X$축,$Y$축 또는 $Z$축에 놓여있을 때에도 RangeBox가 실제 크기보다 조금 더 큽니다. 모든 경우에 객체의 실제 크기와 같은 RangeBox를 구하기 위해서는 OrientedRangeBox를 구해야 합니다. 왜 S3D에서 객체의 속성으로 OrientedRangeBox를 제공하지 않는지 모르겠습니다. OrientedRangeBox는 아래와 같은 구조를 가지고 있습니다. Cable Way/Cable Tray 객체는 Start, End, 코너의 8개점, Length, Width, Depth 정보를 가지있습니다. 8개의 코너 점은 실제 형상보다 큰 지점을 가리키고 있고 Start, End는 실제 형상의 단면의 중점입니다. 코너의 8개의 점들은 객체를 이루는 두 단면의 4개씩의 점들로 이루어진다고 생각합니다. 제가 디자인했다면 이렇게 했을겁니다. 아무도 뒤죽박죽 점들의 순서를 정하지 않았을겁니다. 그렇지 않다면 제 손에 장을 지지겠습니다. 이제 이 8개의 점들로 객체의 Width, Depth 벡터를 구하면 OrientedRangeBox의 3 벡터를 결정할 수 있습니다.  $\overrightarrow{P_1-P_0}$과 $\overrightarrow{P_3-P_0}$ 중에서 객체의 $\overrightarrow{Width},\overrightarrow{Depth}$를 선택해야 합니다. 객체의 Width ,Depth 크기를 알고 있으니 $\overrightarrow{P_1-P_0}$와 $\overrightarrow{P_3-P_...

[S3D] 프로젝트 분투기

 발등에 불이 떨어졌습니다. 현재 진행 중인 2월 중간 보고에 고객사 부사장님이 참석한다고 합니다. 이미 2개의 프로젝트가 절뚝거리며 진행하고 있기 때문에 지금 프로젝트는 제대로 해야합니다. 네트워크 망 구성과 최단 거리 찾기(Dijkstra 기반) 알고리즘에 대한 코드를 정리한 후에 김** 차장과 결과를 확인하기로 했습니다. 이렇게 From, To Cable Way를 선택한 후에 버튼을 눌러 결과가 나오기를 기다렸습니다. 1분가량의 시간이 흘렀습니다. 드디어 프로그램에서 From에서 To로 가는 4,128개의 경로를 찾았습니다. 우리가 생각하지도 못한 길을 찾다니 하고 감탄하고 있을때가 아닙니다. 무려 4,128개의 경로라니요, 눈으로 보기에는 고작 대여섯개의 경로만 보이는데 말입니다. 우리의 예측과 실제 결과가 다를때에는 그 원인을 찾아야 합니다. 고단하고 손가락 아프고 눈이 시린 디버깅의 시작입니다. 반드시 4,128개 경로들의 차이점을 찾아야 합니다. 어... Cable Way를 구성하는 Feature의 RangeBox가 실제 형상보다 크게 잡히는 것을 확인했습니다. 실제 형상과 동일한 RangeBox를 예상하고 있었는데 우리의 예상이 빗나갔습니다. RangeBox 우리의 잘못이 아닙니다. 지랄맞은 S3D입니다. Insulation, Maintenance, Operation Aspect 때문일까봐 켜보고 다시 확인해봤지만 결과는 변함이 없습니다. 밤은 늦었지만 어쩔수 없이 김** 차장에게 전화해 물어봤지만 뾰족한 방안은 없습니다. 모든 주어진 데이타와 대학교 1학년때까지 쌓은 수학적 지식을 총동원하여(사실 중학교때까지의 지식만으로도 충분했습니다.) 형상에 딱 맞는 RangeBox(실제는 OrientedRangeBox)를 구했습니다. Cable Way Feature 형상에 딱 맞는 OrientedRangeBox 구하는 방법은 다음 글에서 이야기하도록 하겠습니다. 밤 9시가 넘어가고 있습니다. 집중력이 떨어지고 있습니다. 나이들어 야근은 무리라는 걸...

[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의 경우에 사용자 방향성을 정해 줄수 있다는 것이고 그렇게 된다면 위에서 말한 골치 아픈 계산을 하지 않고 프로그램에서 사용자가 입력한 각도만 사용하면 됩니다. 사용자 편의를 위해(각도를 입력하는 노력을 줄이는) 계산을 수행하는 것과 사용자를 잘 설득해 각도를 입력하라고 유...

[S3D] Flaver 없애기

SP3D에서 Flaver라고 Caching된 데이타를 이용해서 모델링 속도를 빠르게 하는데, 이게 개발하는 입장에서는 엄청 귀찮은 존재입니다. 한번 그려지고 나서 코드를 수정해도 수정된 코드로 형상이 그려지는것이 아니라 Flaver가 그려지게 됩니다. 엄청 짜증나는 일입니다. Flaver를 사용하지 않을 수는 없고 제거하는 방법을 알아보겠습니다. 1. Project Management에서 제거 Project Management 선택     옵션 선택 후 Analyze 클릭 2. Code에서 제거    아래 코드를 사용해서 Caching을 하지 않도록 합니다.(그러나 제대로 되지 않는것 같습니다)    'No Caching    pSymbolDefinition.CacheOption = igSYMBOL_CACHE_OPTION_NOT_SHARED

.NET Automation

.NET Automation /// SP3D CommonMiddle Registry /// 13.12.12 static FormMain() { AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(MyResolveEventHandler); } /// /// SP3D CommonMiddle Registry /// /// 13.12.12 public static Assembly MyResolveEventHandler(object sender, ResolveEventArgs args) { //This handler is called only when the common language runtime tries to bind to the assembly and fails. //Retrieve the list of referenced assemblies in an array of AssemblyName. //Loop through the array of referenced assemblies. foreach (AssemblyName strAssmbName in Assembly.GetExecutingAssembly().GetReferencedAssemblies()) { //Look for the assembly names that have raised the "AssemblyResolve" event. if (((strAssmbName.Name.EndsWith("CommonMiddle")) /*&& (strAssmbName.FullName.Substring(0, strAssmbName.FullName.IndexOf(",")) == args.Name.Substring(0, args.Name.IndexOf(",")))) ? 1 : 0) != 0*/)) { //We only hav...

SmartSketch Application 구하기

C# 프로젝트에서 SmartSketch.tlb 파일을 참조합니다. = 샘플 코드 = const string progID = "SmartSketch.Application"; private void GetSmartSketchApp() { try { mApp = (SmartSketch.Application)Marshal.GetActiveObject(progID); mApp.Visible = true; } catch { try { Type acType = Type.GetTypeFromProgID(progID); mApp = (SmartSketch.Application)Activator.CreateInstance(acType, true); mApp.Visible = true; } catch { MessageBox.Show( "Cannot create object of type \"" + progID + "\"" ); } } }