Deep Learning

외부 CAD Data로 SketchGraphs 데이터셋 생성 with python (1)

ju_young 2023. 6. 4. 08:55
728x90

SketchGraphs 논문, github 코드에는 Autoconstrain을 위한 모델이 존재한다. 그리고 constraint 정보를 포함한 데이터를 사용하여 Discovering Design Concepts for CAD Sketches 에서의 AutoCompletion을 수행할 수 있다. 그리고 이 모든 것은 Onshape 이라는 CAD 프로그램을 기준으로 만들어졌다. 따라서 다른 CAD 프로그램, 오픈소스 CAD를 사용하여 SketchGraphs 데이터셋을 만드는 것을 시작해보고자 한다.


AutoCAD

우선 AutoCAD를 살펴보면 다음과 같이 constraint를 지정해줄 수 있다. 그리고 SketchGraphs에 Autoconstrain 모델이 따로 있는데 AutoCAD나 다른 CAD 프로그램에서는 이미 10년 또는 그 이전부터 Autoconstrain이라는 기능을 가지고 있다.

AutoCAD 2012

테스트를 위해서 간단하게 삼각형을 (0, 0), (10, 10), (10, 0) 좌표로 그려놓았다. 위 사진에서는 직각, 수평에 대한 constraint 밖에 안보이겠지만 실제로는 삼각형의 각 꼭짓점에는 일치 constraint가 적용되어있다. 따라서 총 5개의 constraint가 존재한다.

 

AutoCAD의 dwg 파일 포맷과 같은 경우에는 python API 지원이 안된다. 따라서 dxf 파일로 저장한 후 ezdxf 라이브러리를 사용하여 데이터를 파싱해줘야한다.

 

ezdxf를 사용하더라도 기본적으로 constraint의 정보를 가져오는 메소드가 안보여서 삽질을 많이했다.

 

저장한 dxf의 constraint 부분만 파싱해보면 대충 다음과 같이 나온다.

0 ACDBASSOC2DCONSTRAINTGROUP
5 2F8 # handle
330 2F5 # Soft-pointer ID
100 AcDbAssocAction # Subclass marker
90         1 # Associativity flag
90         0
330 2F5
360 0 # Hard-owner ID/handle to owner dictionary
90         1

...

1 AcPointCurveConstraint # This class represents a PointCurve (coincident) constraint node
330 2F8
90         8

...

1 AcPointCoincidenceConstraint
330 2F8
90        16

...

 

AcPointCurveConstraint (Coincidence를 수행하는 Point)도 보이고 AcPointCoincidenceConstraint(일치 Constraint)도 보이는데 가장 중요한 "적용될 객체"에 대한 정보가 빠져있다. 나름 관련 reference documentation도 살펴보고 했지만 모든 값들을 이해할 수가 없었다.

 

그리고 ezdxf github에 이슈로 help를 요청했는데 지원이 안된다는 답변을 받았다....

No, ezdxf does not support "constraints" in any kind.

FreeCAD

다음으로는 오픈소스 CAD 중 가장 자주 보이는 FreeCAD를 사용해보았다. FreeCAD는 python api를 사용하기위한 설치부터가 난관이었다.

 

FreeCAD Installation 를 보고 OS에 맞게 설치하면 된다. (설치 과정은 생략)

 

FreeCAD에서는 간단하게 rectangle을 그리고 data를 확인해보았다. 여기서도 역시 autoconstraints 기능을 제공한다.

doc = App.newDocument()

rectangle = Draft.make_rectangle(2000, 1000)
doc.recompute()

sketch_from_draft = Draft.make_sketch([rectangle], autoconstraints=True, delete=False, radiusPrecision=0)
doc.recompute()

for constraint in sketch_from_draft.Constraints:
    print(get_attr(constraint))
print(sketch_from_draft.Geometry)

# Output:
# [('Type', 'Coincident'), ('First', 0), ('FirstPos', 2), ('Second', 1), ('SecondPos', 1), ('Third', -2000), ('ThirdPos', 0), ('Value', 0.0), ('Name', ''), ('Driving', True), ('InVirtualSpace', False), ('IsActive', True)]
# [('Type', 'Horizontal'), ('First', 0), ('FirstPos', 0), ('Second', -2000), ('SecondPos', 0), ('Third', -2000), ('ThirdPos', 0), ('Value', 0.0), ('Name', ''), ('Driving', True), ('InVirtualSpace', False), ('IsActive', True)]
# [('Type', 'Coincident'), ('First', 1), ('FirstPos', 2), ('Second', 2), ('SecondPos', 1), ('Third', -2000), ('ThirdPos', 0), ('Value', 0.0), ('Name', ''), ('Driving', True), ('InVirtualSpace', False), ('IsActive', True)]
# [('Type', 'Vertical'), ('First', 1), ('FirstPos', 0), ('Second', -2000), ('SecondPos', 0), ('Third', -2000), ('ThirdPos', 0), ('Value', 0.0), ('Name', ''), ('Driving', True), ('InVirtualSpace', False), ('IsActive', True)]
# [('Type', 'Coincident'), ('First', 2), ('FirstPos', 2), ('Second', 3), ('SecondPos', 1), ('Third', -2000), ('ThirdPos', 0), ('Value', 0.0), ('Name', ''), ('Driving', True), ('InVirtualSpace', False), ('IsActive', True)]
# [('Type', 'Horizontal'), ('First', 2), ('FirstPos', 0), ('Second', -2000), ('SecondPos', 0), ('Third', -2000), ('ThirdPos', 0), ('Value', 0.0), ('Name', ''), ('Driving', True), ('InVirtualSpace', False), ('IsActive', True)]
# [('Type', 'Coincident'), ('First', 3), ('FirstPos', 2), ('Second', 0), ('SecondPos', 1), ('Third', -2000), ('ThirdPos', 0), ('Value', 0.0), ('Name', ''), ('Driving', True), ('InVirtualSpace', False), ('IsActive', True)]
# [<Line segment (0,0,0) (2000,0,0) >, <Line segment (2000,0,0) (2000,1000,0) >, <Line segment (2000,1000,0) (0,1000,0) >, <Line segment (0,1000,0) (0,0,0) >]

 

Coincident Constraint 값만 표로 정리해보면 다음과 같다. (Name, Value, Driving, InVirtualSpace, IsActive는 불필요)

Type First FirstPos Second SecondPos Third ThirdPos
Coincident 0 2 1 1 -2000 0
Coincident 1 2 2 1 -2000 0
Coincident 2 2 3 1 -2000 0
Coincident 3 2 0 1 -2000 0

우선 각 Column의 의미는 다음과 같다.

  • First: 첫 번째 객체의 index
  • FirstPos: 첫 번째 객체의 position
  • Second: 두 번째 객체의 index
  • SecondPos: 두 번째 객체의 position
  • Third: 세 번째 객체의 index
  • ThirdPos: 세 번째 객체의 position

그런데 Coincident는 두 개의 Point가 일치하는 Constraint라서 세 번째(Third)에 대한 정보가 필요없는데 -2000 값이 들어가있다. -2000이 들어간 이유는 단순히 초기값이라서 그렇다. 따라서 ThirdPos의 0 값도 초기값이다.

 

그리고 FirstPos, SecondPos도 position에 대한 정보면 좌표값을 가져야할 것 같은데 각각 2, 1 값을 가지고 있다. 이 값에 의미는 각각 다음과 같다.

  • 0 = none
  • 1 = start
  • 2 = end
  • 3 = mid

First, Second index는 Geometry를 출력한 리스트 순서대로 보면 된다.

 

dxf 파일을 open하는 것 또한 지원이 되기때문에 다음과 같이 가능하다.

python api를 사용한 open은 현재 에러가 발생해서 해결 후 데이터셋을 만드는 것을 진행해볼 예정이다.

 

요약

  • AutoCAD의 Constraint 정보를 저장할 수 없음
  • FreeCAD에도 autoconstraint 기능이 있고 dxf를 지원하여 import 한 후 적용 가능
728x90