Data
https://github.com/PrincetonLIPS/SketchGraphs
Demo
seq_data = flat_array.load_dictionary_flat('./data/sg_all.npy')
seq_data['sequences']
# FlatArray(len=15020918, mem=13.3 GB)
seq = seq_data['sequences'][1320]
print(*seq, sep='\n')
"""
NodeOp(label=<EntityType.External: 7>, parameters={})
NodeOp(label=<EntityType.Line: 1>, parameters={'isConstruction': False, 'dirX': 0.0, 'dirY': -1.0, 'pntX': -0.015875, 'pntY': 0.0, 'startParam': -0.038735000000000006, 'endParam': 0.038735000000000006})
EdgeOp(label=<ConstraintType.Projected: 1>, references=(1, 0), parameters={})
NodeOp(label=<SubnodeType.SN_Start: 101>, parameters={})
EdgeOp(label=<ConstraintType.Subnode: 101>, references=(2, 1), parameters={})
EdgeOp(label=<ConstraintType.Projected: 1>, references=(2, 0, 0), parameters={})
NodeOp(label=<SubnodeType.SN_End: 102>, parameters={})
EdgeOp(label=<ConstraintType.Subnode: 101>, references=(3, 1), parameters={})
EdgeOp(label=<ConstraintType.Projected: 1>, references=(3, 0, 0), parameters={})
NodeOp(label=<EntityType.Arc: 6>, parameters={'isConstruction': False, 'clockwise': False, 'xCenter': -0.013335, 'yCenter': 0.038735000000000006, 'xDir': 1.0, 'yDir': 0.0, 'radius': 0.0025400000000000006, 'startParam': 1.5707963267948966, 'endParam': 3.141592653589793})
EdgeOp(label=<ConstraintType.Projected: 1>, references=(4, 0), parameters={})
NodeOp(label=<SubnodeType.SN_Center: 103>, parameters={})
EdgeOp(label=<ConstraintType.Subnode: 101>, references=(5, 4), parameters={})
NodeOp(label=<SubnodeType.SN_Start: 101>, parameters={})
EdgeOp(label=<ConstraintType.Subnode: 101>, references=(6, 4), parameters={})
EdgeOp(label=<ConstraintType.Projected: 1>, references=(6, 0, 0), parameters={})
NodeOp(label=<SubnodeType.SN_End: 102>, parameters={})
EdgeOp(label=<ConstraintType.Subnode: 101>, references=(7, 4), parameters={})
EdgeOp(label=<ConstraintType.Coincident: 0>, references=(7, 2), parameters={})
NodeOp(label=<EntityType.Line: 1>, parameters={'isConstruction': False, 'dirX': 1.0, 'dirY': 0.0, 'pntX': 5.204170427930421e-18, 'pntY': 0.041275000000000006, 'startParam': -0.013335000000000005, 'endParam': 0.013335000000000008})
EdgeOp(label=<ConstraintType.Projected: 1>, references=(8, 0), parameters={})
NodeOp(label=<SubnodeType.SN_Start: 101>, parameters={})
EdgeOp(label=<ConstraintType.Subnode: 101>, references=(9, 8), parameters={})
EdgeOp(label=<ConstraintType.Coincident: 0>, references=(9, 6), parameters={})
NodeOp(label=<SubnodeType.SN_End: 102>, parameters={})
...
NodeOp(label=<SubnodeType.SN_End: 102>, parameters={})
EdgeOp(label=<ConstraintType.Subnode: 101>, references=(28, 26), parameters={})
EdgeOp(label=<ConstraintType.Coincident: 0>, references=(28, 20), parameters={})
NodeOp(label=<EntityType.Stop: 8>, parameters={})
"""
SN_End, Sn_Start는 끝점, 시작점을 의미하고 SN_Center는 중심점을 의미한다. 따라서 Line은 SN_End, Sn_Start을 가지고 Arc는 SN_End, Sn_Start, SN_Center를 가지는 것을 확인할 수 있다.
sketch = datalib.sketch_from_sequence(seq)
datalib.render_sketch(sketch)
datalib.render_sketch(sketch, hand_drawn=True)
G = datalib.pgvgraph_from_sequence(seq)
datalib.render_graph(G, './graph.png')
img = plt.imread('./graph.png')
fig = plt.figure(dpi=500)
plt.imshow(img)
plt.axis('off')
Onshape
education으로 가입하여 실습을 진행해보았다.
API methods과 참고는 다음 documentation에서 할 수 있었다.
https://onshape-public.github.io/docs/featureaccess/#api-methods
# 현재 document의 모든 feature들을 가져옴
onshape_call.get_features(url)
"""
{'features': [{'type': 151,
'typeName': 'BTMSketch',
'message': {'entities': [{'type': 155,
'typeName': 'BTMSketchCurveSegment',
'message': {'startPointId': '1.start',
'endPointId': '1.end',
'startParam': -0.038735000000000006,
'endParam': 0.038735000000000006,
'geometry': {'type': 117,
'typeName': 'BTCurveGeometryLine',
'message': {'pntX': -0.015875,
'pntY': 0.0,
'dirX': 0.0,
'dirY': -1.0}},
'centerId': '',
'internalIds': [],
'isConstruction': False,
'parameters': [],
'isFromSplineHandle': False,
'isFromEndpointSplineHandle': False,
'isFromSplineControlPolygon': False,
'entityId': '1',
'namespace': '',
'hasUserCode': False,
'nodeId': 'MhyvymBuSvG+175Eo'}},
...
'serializationVersion': '1.2.0',
'sourceMicroversion': 'e62e13cc54bc6bfba667522b',
'rejectMicroversionSkew': False,
'microversionSkew': False,
'libraryVersion': 2022}
"""
onshape의 part studio에서는 위와 같이 Front, Top, Right plane이 있는데 기본적으로 sketch를 api를 사용해서 추가하면 right plane에 추가된다. 따라서 다른 plane을 지정하려면 먼저 다음과 같이 geometryId를 확인해야한다.
def add_featurescript(url, script, logging=False):
# Get doc ids and create Client
docid, wid, eid = _parse_url(url)
client = _create_client(logging)
# Send to Onshape
client.add_featurescript(docid, wid, eid, payload=script)
def add_featurescript(self, did, wid, eid, payload):
return self._api.request('post', '/api/partstudios/d/' + did + '/w/' + wid + '/e/' + eid + '/featurescript', body=payload)
script = {
"script" :
"function(context is Context, queries){return transientQueriesToStrings(evaluateQuery(context, qCreatedBy(makeId(\"Top\"), EntityType.FACE)));}",
"queries" : []
}
onshape_call.add_featurescript(url, script, logging=True)
"""
details: {
"console" : "",
"notices" : [ ],
"result" : {
"type" : 1499,
"typeName" : "BTFSValueArray",
"message" : {
"value" : [ {
"type" : 1422,
"typeName" : "BTFSValueString",
"message" : {
"value" : "JDC",
"typeTag" : ""
}
} ],
"typeTag" : ""
}
},
"serializationVersion" : "1.2.0",
...
"rejectMicroversionSkew" : false,
"microversionSkew" : false,
"libraryVersion" : 2022
}
"""
message의 가장 안쪽에 value "JDC"를 Top plane의 geometryId로 사용한다. 그리고 add_feature를 할때 parameters 부분을 다음과 같이 수정해주면 된다.
"parameters": [
{
"type": 148,
"typeName": "BTMParameterQueryList",
"message": {
"queries": [
{
"type": 138,
"typeName": "BTMIndividualQuery",
"message": {
"geometryIds": [
"JDC"
],
"hasUserCode": false
}
}
],
"parameterId": "sketchPlane",
"hasUserCode": false
}
}
],
constraint를 없애고 sketch를 추가한 것과 없애지않고 추가한 것의 차이를 확인해보겠다.
# remove constraints
no_constraint_sketch = deepcopy(sketch)
no_constraint_sketch.constraints.clear()
# with constraints
with_constraints_sketch = deepcopy(unsolved_sketch)
remove constraints | with constraints |
|
추가한 sketch를 다시 불러오기위해서는 다음과 같이 get_info(api endpoint: sketches)로 가져오고 constraint를 다시 적용하기위해서는 간단하게 sketch의 constraints에 넣어주면 된다.
# get info
unsolved_sketch_info = onshape_call.get_info(url, 'No_Constraints_Sketch')
unsolved_sketch = datalib.Sketch.from_info(unsolved_sketch_info['geomEntities'])
# apply constraints
unsolved_sketch.constraints = sketch.constraints
Autoconstrain Model
위 github에 autoconstrain을 위한 model이 있어서 논문을 살펴보았는데 message passing networks(MPNs)를 기반으로한 auto-regressive model이라고 한다.
- input representation component: primitives와 constraints의 feature embedding
- message-passing component: graph structure를 사용한 feature 변환
- readout component: 변환된 feature에 따른 확률값 출력
- Train / Eval
논문에서는 150epoch을 돌렸다고 나와있는데 epoch당 3시간이 걸려서 3epoch까지 돌려보았다. (eval은 약 1시간 30분)
train data는 약 5억5천만개(batch_size: 1248), evaluation에 사용한 test data(batch_size: 512)는 1억 6천만개이다.
epoch | recall | precision |
1 | 0.54 | 0.51 |
3 | 0.58 | 0.59 |
'Deep Learning' 카테고리의 다른 글
외부 CAD Data로 SketchGraphs 데이터셋 생성 with python (1) (0) | 2023.06.04 |
---|---|
Autoconstrain Model (0) | 2023.05.24 |
[Paper] Discovering Design Concepts for CAD Sketches (4) (0) | 2023.05.18 |
[Paper] Discovering Design Concepts for CAD Sketches (3) (0) | 2023.05.14 |
Library Induction Problem (0) | 2023.05.06 |