Support importing another Dust3D document as a part
- Add example model: Backpacker To demonstrate the importing function - Add menu: Reverse Reverse selected edges. The direction of edge decide the base normal of generated mesh. - Refactor stroke mesh builder Remove recursive calls, more consistant generated result - Add menu: Importmaster
parent
cb192bdaa6
commit
63cbfa83a5
|
@ -4,6 +4,10 @@ Changes between 1.0.0-rc.3 and 1.0.0-rc.4:
|
||||||
- Add menu: Export as Image
|
- Add menu: Export as Image
|
||||||
- Add auto saving
|
- Add auto saving
|
||||||
- Change to single instance with multiple windows
|
- Change to single instance with multiple windows
|
||||||
|
- Refactor stroke mesh builder
|
||||||
|
- Add menu: Import
|
||||||
|
- Show edge direction on canvas
|
||||||
|
- Add example model: Backpacker
|
||||||
|
|
||||||
Changes between 1.0.0-rc.1 and 1.0.0-rc.3:
|
Changes between 1.0.0-rc.1 and 1.0.0-rc.3:
|
||||||
--------------------------------------------------
|
--------------------------------------------------
|
||||||
|
|
17
dust3d.pro
17
dust3d.pro
|
@ -4,9 +4,9 @@ DEFINES += NDEBUG
|
||||||
DEFINES += QT_MESSAGELOGCONTEXT
|
DEFINES += QT_MESSAGELOGCONTEXT
|
||||||
RESOURCES += resources.qrc
|
RESOURCES += resources.qrc
|
||||||
|
|
||||||
LANGUAGES = zh_CN\
|
LANGUAGES = zh_CN \
|
||||||
es_AR\
|
es_AR \
|
||||||
it_IT
|
it_IT
|
||||||
|
|
||||||
OBJECTS_DIR=obj
|
OBJECTS_DIR=obj
|
||||||
MOC_DIR=moc
|
MOC_DIR=moc
|
||||||
|
@ -135,6 +135,9 @@ include(thirdparty/qtsingleapplication/src/qtsingleapplication.pri)
|
||||||
|
|
||||||
INCLUDEPATH += src
|
INCLUDEPATH += src
|
||||||
|
|
||||||
|
SOURCES += src/meshstroketifier.cpp
|
||||||
|
HEADERS += src/meshstroketifier.h
|
||||||
|
|
||||||
SOURCES += src/autosaver.cpp
|
SOURCES += src/autosaver.cpp
|
||||||
HEADERS += src/autosaver.h
|
HEADERS += src/autosaver.h
|
||||||
|
|
||||||
|
@ -144,8 +147,8 @@ HEADERS += src/documentsaver.h
|
||||||
SOURCES += src/normalanddepthmapsgenerator.cpp
|
SOURCES += src/normalanddepthmapsgenerator.cpp
|
||||||
HEADERS += src/normalanddepthmapsgenerator.h
|
HEADERS += src/normalanddepthmapsgenerator.h
|
||||||
|
|
||||||
SOURCES += src/modelofflinerender.cpp
|
SOURCES += src/modeloffscreenrender.cpp
|
||||||
HEADERS += src/modelofflinerender.h
|
HEADERS += src/modeloffscreenrender.h
|
||||||
|
|
||||||
SOURCES += src/modelshaderprogram.cpp
|
SOURCES += src/modelshaderprogram.cpp
|
||||||
HEADERS += src/modelshaderprogram.h
|
HEADERS += src/modelshaderprogram.h
|
||||||
|
@ -198,8 +201,8 @@ HEADERS += src/glbfile.h
|
||||||
SOURCES += src/theme.cpp
|
SOURCES += src/theme.cpp
|
||||||
HEADERS += src/theme.h
|
HEADERS += src/theme.h
|
||||||
|
|
||||||
SOURCES += src/meshloader.cpp
|
SOURCES += src/model.cpp
|
||||||
HEADERS += src/meshloader.h
|
HEADERS += src/model.h
|
||||||
|
|
||||||
SOURCES += src/texturegenerator.cpp
|
SOURCES += src/texturegenerator.cpp
|
||||||
HEADERS += src/texturegenerator.h
|
HEADERS += src/texturegenerator.h
|
||||||
|
|
|
@ -399,6 +399,14 @@ Consejos:
|
||||||
<source>Image (*.png)</source>
|
<source>Image (*.png)</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Import...</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Reverse</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>ExportPreviewWidget</name>
|
<name>ExportPreviewWidget</name>
|
||||||
|
@ -1288,6 +1296,10 @@ Consejos:
|
||||||
<source>Unselect All</source>
|
<source>Unselect All</source>
|
||||||
<translation>Deseleccionar Todo</translation>
|
<translation>Deseleccionar Todo</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Reverse</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>UpdatesCheckWidget</name>
|
<name>UpdatesCheckWidget</name>
|
||||||
|
|
|
@ -406,6 +406,14 @@ Suggerimenti:
|
||||||
<source>Image (*.png)</source>
|
<source>Image (*.png)</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Import...</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Reverse</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>ExportPreviewWidget</name>
|
<name>ExportPreviewWidget</name>
|
||||||
|
@ -1295,6 +1303,10 @@ Suggerimenti:
|
||||||
<source>Unselect All</source>
|
<source>Unselect All</source>
|
||||||
<translation type="unfinished">De-Seleziona tutto</translation>
|
<translation type="unfinished">De-Seleziona tutto</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Reverse</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>UpdatesCheckWidget</name>
|
<name>UpdatesCheckWidget</name>
|
||||||
|
|
|
@ -399,6 +399,14 @@ Tips:
|
||||||
<source>Image (*.png)</source>
|
<source>Image (*.png)</source>
|
||||||
<translation>图片 (*.png)</translation>
|
<translation>图片 (*.png)</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Import...</source>
|
||||||
|
<translation>导入...</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Reverse</source>
|
||||||
|
<translation>反向</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>ExportPreviewWidget</name>
|
<name>ExportPreviewWidget</name>
|
||||||
|
@ -1288,6 +1296,10 @@ Tips:
|
||||||
<source>Colorize</source>
|
<source>Colorize</source>
|
||||||
<translation>着色</translation>
|
<translation>着色</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Reverse</source>
|
||||||
|
<translation>反向</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>UpdatesCheckWidget</name>
|
<name>UpdatesCheckWidget</name>
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
<file>resources/tree-vline.png</file>
|
<file>resources/tree-vline.png</file>
|
||||||
<file>resources/material-demo-model.ds3</file>
|
<file>resources/material-demo-model.ds3</file>
|
||||||
<file>resources/model-addax.ds3</file>
|
<file>resources/model-addax.ds3</file>
|
||||||
|
<file>resources/model-backpacker.ds3</file>
|
||||||
<file>resources/model-bicycle.ds3</file>
|
<file>resources/model-bicycle.ds3</file>
|
||||||
<file>resources/model-dog.ds3</file>
|
<file>resources/model-dog.ds3</file>
|
||||||
<file>resources/model-cat.ds3</file>
|
<file>resources/model-cat.ds3</file>
|
||||||
|
|
|
@ -1,231 +1,231 @@
|
||||||
DUST3D 1.0 xml 0000000193
|
DUST3D 1.0 xml 0000000193
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<ds3>
|
<ds3>
|
||||||
<model name="model.xml" offset="0" size="38946"/>
|
<model name="model.xml" offset="0" size="38956"/>
|
||||||
<asset name="canvas.png" offset="38946" size="292117"/>
|
<asset name="canvas.png" offset="38956" size="292117"/>
|
||||||
</ds3>
|
</ds3>
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<canvas originX="0.330693" originY="0.520792" originZ="1.5297" rigType="None">
|
<canvas originX="0.330693" originY="0.520792" originZ="1.5297" rigType="None">
|
||||||
<nodes>
|
<nodes>
|
||||||
<node id="{021f7f20-d1c4-4b79-94ef-25ecf621ee0c}" partId="{0df76de9-fa79-477d-9771-b85378446b3c}" radius="0.0950495" x="0.330693" y="0.308911" z="0.958416"/>
|
<node id="{021f7f20-d1c4-4b79-94ef-25ecf621ee0c}" partId="{449d0e15-066f-4780-918a-55978d46ed9d}" radius="0.0950495" x="0.330693" y="0.308911" z="0.958416"/>
|
||||||
<node id="{03ff6913-45f1-4508-a39f-3842694cb9f7}" partId="{c722bb89-16f8-4866-b115-74c321caf271}" radius="0.0594059" x="0.425658" y="0.457426" z="1.25445"/>
|
<node id="{03ff6913-45f1-4508-a39f-3842694cb9f7}" partId="{37860592-2626-4c6d-8069-349954bda284}" radius="0.0594059" x="0.425658" y="0.457426" z="1.24508"/>
|
||||||
<node id="{05a4fc6a-8e6f-4c0d-a6ca-023ef4bd8d14}" partId="{e84c3063-265f-4850-9e19-465b84e41118}" radius="0.00990099" x="0.388119" y="0.260972" z="0.906007"/>
|
<node id="{05a4fc6a-8e6f-4c0d-a6ca-023ef4bd8d14}" partId="{8689ab0b-3a56-4f01-b72a-0eee032928d4}" radius="0.00990099" x="0.388119" y="0.260972" z="0.906007"/>
|
||||||
<node id="{06b524b3-b2e5-4e12-993f-497c57aee71e}" partId="{0df76de9-fa79-477d-9771-b85378446b3c}" radius="0.118812" x="0.330693" y="0.368317" z="1.05347"/>
|
<node id="{06b524b3-b2e5-4e12-993f-497c57aee71e}" partId="{449d0e15-066f-4780-918a-55978d46ed9d}" radius="0.118812" x="0.330693" y="0.368317" z="1.05347"/>
|
||||||
<node id="{0da7cc8e-dd93-4b86-a305-fe14ae189790}" partId="{c722bb89-16f8-4866-b115-74c321caf271}" radius="0.0277228" x="0.409901" y="0.653465" z="1.20792"/>
|
<node id="{0da7cc8e-dd93-4b86-a305-fe14ae189790}" partId="{37860592-2626-4c6d-8069-349954bda284}" radius="0.0277228" x="0.409901" y="0.653465" z="1.19855"/>
|
||||||
<node id="{180bd087-9aa6-487a-8b50-5f2231539863}" partId="{92839eb7-0da2-4905-ae58-a1bb3903f444}" radius="0.0316832" x="0.269025" y="0.628687" z="1.83698"/>
|
<node id="{180bd087-9aa6-487a-8b50-5f2231539863}" partId="{0a233c0a-8ce5-42d3-b720-fb97b63d0e58}" radius="0.0316832" x="0.269025" y="0.628687" z="1.83698"/>
|
||||||
<node id="{1a732d47-0948-439d-a173-d0129af7644d}" partId="{a8703d0e-1581-495a-99e0-4507178bf1fa}" radius="0.0158416" x="0.330693" y="0.320792" z="1.75347"/>
|
<node id="{1a732d47-0948-439d-a173-d0129af7644d}" partId="{3719b667-4110-499d-b78b-4f2ec4e66213}" radius="0.0158416" x="0.330693" y="0.320792" z="1.75347"/>
|
||||||
<node id="{1ccfc908-f650-44bc-b072-6d100315b927}" partId="{92839eb7-0da2-4905-ae58-a1bb3903f444}" radius="0.0831683" x="0.288827" y="0.441353" z="1.73794"/>
|
<node id="{1ccfc908-f650-44bc-b072-6d100315b927}" partId="{0a233c0a-8ce5-42d3-b720-fb97b63d0e58}" radius="0.0831683" x="0.288827" y="0.441353" z="1.73794"/>
|
||||||
<node id="{1e3e9eb9-ab4c-4b64-97ad-4342d24b02f9}" partId="{c5bd1431-d740-4266-825d-217513f1a1f5}" radius="0.0118812" x="0.302688" y="0.875247" z="1.33465"/>
|
<node id="{1e3e9eb9-ab4c-4b64-97ad-4342d24b02f9}" partId="{20fce58c-660f-4e93-b97a-a316d0753042}" radius="0.0118812" x="0.302688" y="0.875247" z="1.33465"/>
|
||||||
<node id="{22f090e3-7748-4a48-841a-925de92cce58}" partId="{47d784c2-d5dc-402d-9848-e80e1c03416e}" radius="0.00990099" x="0.437119" y="0.163294" z="1.08515"/>
|
<node id="{22f090e3-7748-4a48-841a-925de92cce58}" partId="{76e8af23-9880-458a-8218-ebf61c0ba341}" radius="0.00990099" x="0.437119" y="0.163294" z="1.08515"/>
|
||||||
<node id="{2498311b-1a9b-4768-bd9c-e108e4f7a1c8}" partId="{a8703d0e-1581-495a-99e0-4507178bf1fa}" radius="0.00792079" x="0.330693" y="0.625743" z="1.93861"/>
|
<node id="{2498311b-1a9b-4768-bd9c-e108e4f7a1c8}" partId="{3719b667-4110-499d-b78b-4f2ec4e66213}" radius="0.00792079" x="0.330693" y="0.625743" z="1.93861"/>
|
||||||
<node id="{259237a6-bac4-4a79-aa57-a74d357feff2}" partId="{c722bb89-16f8-4866-b115-74c321caf271}" radius="0.0217822" x="0.384159" y="0.811881" z="1.34257"/>
|
<node id="{259237a6-bac4-4a79-aa57-a74d357feff2}" partId="{37860592-2626-4c6d-8069-349954bda284}" radius="0.0217822" x="0.384159" y="0.811881" z="1.3332"/>
|
||||||
<node id="{25b71535-a196-49b7-a019-ae08cc75dd60}" partId="{c722bb89-16f8-4866-b115-74c321caf271}" radius="0.0316832" x="0.419802" y="0.629703" z="1.23762"/>
|
<node id="{25b71535-a196-49b7-a019-ae08cc75dd60}" partId="{37860592-2626-4c6d-8069-349954bda284}" radius="0.0316832" x="0.419802" y="0.629703" z="1.22825"/>
|
||||||
<node id="{2bcb3563-c4d3-40bb-8e49-3afe61da902f}" partId="{a8703d0e-1581-495a-99e0-4507178bf1fa}" radius="0.0158416" x="0.330693" y="0.330693" z="1.80198"/>
|
<node id="{2bcb3563-c4d3-40bb-8e49-3afe61da902f}" partId="{3719b667-4110-499d-b78b-4f2ec4e66213}" radius="0.0158416" x="0.330693" y="0.330693" z="1.80198"/>
|
||||||
<node id="{2dd69178-ccf9-4026-9319-9aebbd4155df}" partId="{0df76de9-fa79-477d-9771-b85378446b3c}" radius="0.0356436" x="0.330693" y="0.330693" z="0.786139"/>
|
<node id="{2dd69178-ccf9-4026-9319-9aebbd4155df}" partId="{449d0e15-066f-4780-918a-55978d46ed9d}" radius="0.0356436" x="0.330693" y="0.330693" z="0.786139"/>
|
||||||
<node id="{2e02275f-8aa2-46f3-ad34-579a63890b17}" partId="{e6fced12-025d-471f-b260-6d7854280682}" radius="0.019802" x="0.358982" y="0.942157" z="1.62797"/>
|
<node id="{2e02275f-8aa2-46f3-ad34-579a63890b17}" partId="{57a41558-46e2-48ce-9f6b-54ada6b2d083}" radius="0.019802" x="0.358982" y="0.942157" z="1.62797"/>
|
||||||
<node id="{2ea7a440-8ff5-4143-ab72-ebe178087607}" partId="{92839eb7-0da2-4905-ae58-a1bb3903f444}" radius="0.029703" x="0.302688" y="0.986613" z="1.94599"/>
|
<node id="{2ea7a440-8ff5-4143-ab72-ebe178087607}" partId="{0a233c0a-8ce5-42d3-b720-fb97b63d0e58}" radius="0.029703" x="0.302688" y="0.986613" z="1.94599"/>
|
||||||
<node id="{31ccee3b-ba23-4294-ae81-6f6b34f1ed5d}" partId="{6df97180-d57c-46b3-8f96-4173b69abbc5}" radius="0.019802" x="0.409901" y="0.170784" z="0.957782"/>
|
<node id="{31ccee3b-ba23-4294-ae81-6f6b34f1ed5d}" partId="{0b0f5c6e-94d4-4c8e-9997-052a70fa3720}" radius="0.019802" x="0.409901" y="0.170784" z="0.957782"/>
|
||||||
<node id="{350d2902-c60e-4cba-a10c-d000ecba47ad}" partId="{c5bd1431-d740-4266-825d-217513f1a1f5}" radius="0.0118812" x="0.304668" y="0.950495" z="1.32277"/>
|
<node id="{350d2902-c60e-4cba-a10c-d000ecba47ad}" partId="{20fce58c-660f-4e93-b97a-a316d0753042}" radius="0.0118812" x="0.304668" y="0.950495" z="1.32277"/>
|
||||||
<node id="{355833f3-bd2d-4508-9293-dbf33c65222b}" partId="{a8703d0e-1581-495a-99e0-4507178bf1fa}" radius="0.0158416" x="0.330693" y="0.59604" z="1.92079"/>
|
<node id="{355833f3-bd2d-4508-9293-dbf33c65222b}" partId="{3719b667-4110-499d-b78b-4f2ec4e66213}" radius="0.0158416" x="0.330693" y="0.59604" z="1.92079"/>
|
||||||
<node id="{37dc112b-cfb9-4a87-9b82-90a27c9d1518}" partId="{0df76de9-fa79-477d-9771-b85378446b3c}" radius="0.122772" x="0.330693" y="0.39604" z="1.10693"/>
|
<node id="{37dc112b-cfb9-4a87-9b82-90a27c9d1518}" partId="{449d0e15-066f-4780-918a-55978d46ed9d}" radius="0.122772" x="0.330693" y="0.39604" z="1.10693"/>
|
||||||
<node id="{3e13f116-1dd9-4024-8b1b-764c176a7835}" partId="{a8703d0e-1581-495a-99e0-4507178bf1fa}" radius="0.00792079" x="0.330693" y="0.439604" z="1.90297"/>
|
<node id="{3e13f116-1dd9-4024-8b1b-764c176a7835}" partId="{3719b667-4110-499d-b78b-4f2ec4e66213}" radius="0.00792079" x="0.330693" y="0.439604" z="1.90297"/>
|
||||||
<node id="{40529c5a-bafd-4bc1-84c3-daae168d5da8}" partId="{e6fced12-025d-471f-b260-6d7854280682}" radius="0.0158416" x="0.368883" y="0.779908" z="1.69841"/>
|
<node id="{40529c5a-bafd-4bc1-84c3-daae168d5da8}" partId="{57a41558-46e2-48ce-9f6b-54ada6b2d083}" radius="0.0158416" x="0.368883" y="0.779908" z="1.69841"/>
|
||||||
<node id="{4123d281-63d6-44a5-bdfd-62261ab8dad9}" partId="{c722bb89-16f8-4866-b115-74c321caf271}" radius="0.0158416" x="0.384159" y="0.780198" z="1.26931"/>
|
<node id="{4123d281-63d6-44a5-bdfd-62261ab8dad9}" partId="{37860592-2626-4c6d-8069-349954bda284}" radius="0.0158416" x="0.384159" y="0.780198" z="1.25994"/>
|
||||||
<node id="{4ab72941-0a5e-442f-919f-aff60341427b}" partId="{c5bd1431-d740-4266-825d-217513f1a1f5}" radius="0.019802" x="0.306648" y="0.930692" z="1.34059"/>
|
<node id="{4ab72941-0a5e-442f-919f-aff60341427b}" partId="{20fce58c-660f-4e93-b97a-a316d0753042}" radius="0.019802" x="0.306648" y="0.930692" z="1.34059"/>
|
||||||
<node id="{4c9ba403-391c-4903-a8ba-0ff250713286}" partId="{c5bd1431-d740-4266-825d-217513f1a1f5}" radius="0.039604" x="0.255163" y="0.611881" z="1.29505"/>
|
<node id="{4c9ba403-391c-4903-a8ba-0ff250713286}" partId="{20fce58c-660f-4e93-b97a-a316d0753042}" radius="0.039604" x="0.255163" y="0.611881" z="1.29505"/>
|
||||||
<node id="{4d605b53-37e2-4622-a9df-b457e4b1ae89}" partId="{e6fced12-025d-471f-b260-6d7854280682}" radius="0.0831683" x="0.376803" y="0.428676" z="1.7314"/>
|
<node id="{4d605b53-37e2-4622-a9df-b457e4b1ae89}" partId="{57a41558-46e2-48ce-9f6b-54ada6b2d083}" radius="0.0831683" x="0.376803" y="0.428676" z="1.7314"/>
|
||||||
<node id="{4ff2a8f5-aade-4320-98c5-f78abbf31df0}" partId="{0df76de9-fa79-477d-9771-b85378446b3c}" radius="0.154455" x="0.330693" y="0.441584" z="1.45941"/>
|
<node id="{4ff2a8f5-aade-4320-98c5-f78abbf31df0}" partId="{449d0e15-066f-4780-918a-55978d46ed9d}" radius="0.154455" x="0.330693" y="0.441584" z="1.45941"/>
|
||||||
<node id="{54127252-0ecb-4a08-84b8-489ce894aebe}" partId="{92839eb7-0da2-4905-ae58-a1bb3903f444}" radius="0.0792079" x="0.259123" y="0.500455" z="1.76833"/>
|
<node id="{54127252-0ecb-4a08-84b8-489ce894aebe}" partId="{0a233c0a-8ce5-42d3-b720-fb97b63d0e58}" radius="0.0792079" x="0.259123" y="0.500455" z="1.76833"/>
|
||||||
<node id="{5526b16b-07a8-44ae-a2a1-23edd995a34e}" partId="{c5bd1431-d740-4266-825d-217513f1a1f5}" radius="0.0158416" x="0.304668" y="0.90495" z="1.33862"/>
|
<node id="{5526b16b-07a8-44ae-a2a1-23edd995a34e}" partId="{20fce58c-660f-4e93-b97a-a316d0753042}" radius="0.0158416" x="0.304668" y="0.90495" z="1.33862"/>
|
||||||
<node id="{59c85ebe-b47b-4d4b-b40a-9bb0ed434914}" partId="{c722bb89-16f8-4866-b115-74c321caf271}" radius="0.0594059" x="0.443023" y="0.568858" z="1.2982"/>
|
<node id="{59c85ebe-b47b-4d4b-b40a-9bb0ed434914}" partId="{37860592-2626-4c6d-8069-349954bda284}" radius="0.0594059" x="0.443023" y="0.568858" z="1.28883"/>
|
||||||
<node id="{5b25a3a7-ed5a-42ef-a277-6fd8406649f2}" partId="{6df97180-d57c-46b3-8f96-4173b69abbc5}" radius="0.0237624" x="0.352476" y="0.235317" z="0.906707"/>
|
<node id="{5b25a3a7-ed5a-42ef-a277-6fd8406649f2}" partId="{0b0f5c6e-94d4-4c8e-9997-052a70fa3720}" radius="0.0237624" x="0.352476" y="0.235317" z="0.906707"/>
|
||||||
<node id="{5f73c8dd-e8c1-484c-af35-5b2789c0582c}" partId="{a8703d0e-1581-495a-99e0-4507178bf1fa}" radius="0.005" x="0.330693" y="0.635644" z="1.95644"/>
|
<node id="{5f73c8dd-e8c1-484c-af35-5b2789c0582c}" partId="{3719b667-4110-499d-b78b-4f2ec4e66213}" radius="0.005" x="0.330693" y="0.635644" z="1.95644"/>
|
||||||
<node id="{6183e755-7d06-4e96-aee0-2e4a5df4c83f}" partId="{e84c3063-265f-4850-9e19-465b84e41118}" radius="0.00594059" x="0.40198" y="0.25849" z="0.918282"/>
|
<node id="{6183e755-7d06-4e96-aee0-2e4a5df4c83f}" partId="{8689ab0b-3a56-4f01-b72a-0eee032928d4}" radius="0.00594059" x="0.40198" y="0.25849" z="0.918282"/>
|
||||||
<node id="{6281b6cb-d0ae-43b2-b124-26fcedacf472}" partId="{c5bd1431-d740-4266-825d-217513f1a1f5}" radius="0.0633663" x="0.245262" y="0.520792" z="1.27921"/>
|
<node id="{6281b6cb-d0ae-43b2-b124-26fcedacf472}" partId="{20fce58c-660f-4e93-b97a-a316d0753042}" radius="0.0633663" x="0.245262" y="0.520792" z="1.27921"/>
|
||||||
<node id="{67afd8c7-012e-4db6-8de5-b2cb35cfbc50}" partId="{0df76de9-fa79-477d-9771-b85378446b3c}" radius="0.0752475" x="0.330693" y="0.386139" z="1.76832"/>
|
<node id="{67afd8c7-012e-4db6-8de5-b2cb35cfbc50}" partId="{449d0e15-066f-4780-918a-55978d46ed9d}" radius="0.0752475" x="0.330693" y="0.386139" z="1.76832"/>
|
||||||
<node id="{68fee6f0-597d-4079-a61b-4def65e1c8f9}" partId="{6df97180-d57c-46b3-8f96-4173b69abbc5}" radius="0.019802" x="0.437624" y="0.149406" z="0.992491"/>
|
<node id="{68fee6f0-597d-4079-a61b-4def65e1c8f9}" partId="{0b0f5c6e-94d4-4c8e-9997-052a70fa3720}" radius="0.019802" x="0.437624" y="0.149406" z="0.992491"/>
|
||||||
<node id="{6b0da1e9-337b-4cf4-9d08-c2ab19b18c80}" partId="{47d784c2-d5dc-402d-9848-e80e1c03416e}" radius="0.0257426" x="0.37864" y="0.224511" z="0.978218"/>
|
<node id="{6b0da1e9-337b-4cf4-9d08-c2ab19b18c80}" partId="{76e8af23-9880-458a-8218-ebf61c0ba341}" radius="0.0257426" x="0.37864" y="0.224511" z="0.978218"/>
|
||||||
<node id="{6b2b333d-2abf-4d6e-8957-7a848c46e651}" partId="{a8703d0e-1581-495a-99e0-4507178bf1fa}" radius="0.0118812" x="0.330693" y="0.475248" z="1.91683"/>
|
<node id="{6b2b333d-2abf-4d6e-8957-7a848c46e651}" partId="{3719b667-4110-499d-b78b-4f2ec4e66213}" radius="0.0118812" x="0.330693" y="0.475248" z="1.91683"/>
|
||||||
<node id="{6c08eb60-5120-4ae2-9854-df02e5ebf9c8}" partId="{a8703d0e-1581-495a-99e0-4507178bf1fa}" radius="0.0118812" x="0.330693" y="0.378218" z="1.86337"/>
|
<node id="{6c08eb60-5120-4ae2-9854-df02e5ebf9c8}" partId="{3719b667-4110-499d-b78b-4f2ec4e66213}" radius="0.0118812" x="0.330693" y="0.378218" z="1.86337"/>
|
||||||
<node id="{71ea7967-b59e-4507-bf55-225882ecbba5}" partId="{c5bd1431-d740-4266-825d-217513f1a1f5}" radius="0.0594059" x="0.245263" y="0.576237" z="1.29109"/>
|
<node id="{71ea7967-b59e-4507-bf55-225882ecbba5}" partId="{20fce58c-660f-4e93-b97a-a316d0753042}" radius="0.0594059" x="0.245263" y="0.576237" z="1.29109"/>
|
||||||
<node id="{72a946b4-b2a0-426a-884b-5cf5176f9ece}" partId="{47d784c2-d5dc-402d-9848-e80e1c03416e}" radius="0.0257426" x="0.409418" y="0.199587" z="1.03762"/>
|
<node id="{72a946b4-b2a0-426a-884b-5cf5176f9ece}" partId="{76e8af23-9880-458a-8218-ebf61c0ba341}" radius="0.0257426" x="0.409418" y="0.199587" z="1.03762"/>
|
||||||
<node id="{734b73e6-9175-42d8-8ffe-057b933bc666}" partId="{c722bb89-16f8-4866-b115-74c321caf271}" radius="0.029703" x="0.386139" y="0.805941" z="1.36634"/>
|
<node id="{734b73e6-9175-42d8-8ffe-057b933bc666}" partId="{37860592-2626-4c6d-8069-349954bda284}" radius="0.029703" x="0.386139" y="0.805941" z="1.35697"/>
|
||||||
<node id="{74399604-82fe-4cc0-a61f-0de6f297f80b}" partId="{e6fced12-025d-471f-b260-6d7854280682}" radius="0.0277228" x="0.374823" y="0.725738" z="1.71259"/>
|
<node id="{74399604-82fe-4cc0-a61f-0de6f297f80b}" partId="{57a41558-46e2-48ce-9f6b-54ada6b2d083}" radius="0.0277228" x="0.374823" y="0.725738" z="1.71259"/>
|
||||||
<node id="{7615ca8a-d9d4-4987-84b1-7c5578ac55f0}" partId="{c722bb89-16f8-4866-b115-74c321caf271}" radius="0.0158416" x="0.39208" y="0.716832" z="1.20198"/>
|
<node id="{7615ca8a-d9d4-4987-84b1-7c5578ac55f0}" partId="{37860592-2626-4c6d-8069-349954bda284}" radius="0.0158416" x="0.39208" y="0.716832" z="1.19261"/>
|
||||||
<node id="{797ac170-8b69-423e-8ca5-acb7217188be}" partId="{6df97180-d57c-46b3-8f96-4173b69abbc5}" radius="0.005" x="0.431683" y="0.0075189" z="1.3375"/>
|
<node id="{797ac170-8b69-423e-8ca5-acb7217188be}" partId="{0b0f5c6e-94d4-4c8e-9997-052a70fa3720}" radius="0.005" x="0.431683" y="0.0075189" z="1.3375"/>
|
||||||
<node id="{7af1da13-55ff-4ce7-9fcd-ab9825098cb8}" partId="{0df76de9-fa79-477d-9771-b85378446b3c}" radius="0.0435644" x="0.330693" y="0.314851" z="0.829703"/>
|
<node id="{7af1da13-55ff-4ce7-9fcd-ab9825098cb8}" partId="{449d0e15-066f-4780-918a-55978d46ed9d}" radius="0.0435644" x="0.330693" y="0.314851" z="0.829703"/>
|
||||||
<node id="{7cfbf2a4-3d92-4357-8644-4e195dfac673}" partId="{a8703d0e-1581-495a-99e0-4507178bf1fa}" radius="0.0158416" x="0.330693" y="0.518812" z="1.92079"/>
|
<node id="{7cfbf2a4-3d92-4357-8644-4e195dfac673}" partId="{3719b667-4110-499d-b78b-4f2ec4e66213}" radius="0.0158416" x="0.330693" y="0.518812" z="1.92079"/>
|
||||||
<node id="{7d3f47b9-2de0-46e2-9691-3c7de959777f}" partId="{c5bd1431-d740-4266-825d-217513f1a1f5}" radius="0.0158416" x="0.296747" y="0.817822" z="1.32871"/>
|
<node id="{7d3f47b9-2de0-46e2-9691-3c7de959777f}" partId="{20fce58c-660f-4e93-b97a-a316d0753042}" radius="0.0158416" x="0.296747" y="0.817822" z="1.32871"/>
|
||||||
<node id="{7f6a90b8-57d3-4319-8bd3-c7c1733f52f5}" partId="{0df76de9-fa79-477d-9771-b85378446b3c}" radius="0.130693" x="0.330693" y="0.415842" z="1.70891"/>
|
<node id="{7f6a90b8-57d3-4319-8bd3-c7c1733f52f5}" partId="{449d0e15-066f-4780-918a-55978d46ed9d}" radius="0.130693" x="0.330693" y="0.415842" z="1.70891"/>
|
||||||
<node id="{7fd2060f-8360-4fb2-a9c9-ba773bcb4fc6}" partId="{e6fced12-025d-471f-b260-6d7854280682}" radius="0.0217822" x="0.360962" y="0.963494" z="1.58918"/>
|
<node id="{7fd2060f-8360-4fb2-a9c9-ba773bcb4fc6}" partId="{57a41558-46e2-48ce-9f6b-54ada6b2d083}" radius="0.0217822" x="0.360962" y="0.963494" z="1.58918"/>
|
||||||
<node id="{84c39fc7-a579-453f-b2d2-3872af219174}" partId="{6df97180-d57c-46b3-8f96-4173b69abbc5}" radius="0.019802" x="0.407921" y="0.126117" z="1.05069"/>
|
<node id="{84c39fc7-a579-453f-b2d2-3872af219174}" partId="{0b0f5c6e-94d4-4c8e-9997-052a70fa3720}" radius="0.019802" x="0.407921" y="0.126117" z="1.05069"/>
|
||||||
<node id="{883859a6-0102-4a26-8596-3c47bcaf1970}" partId="{a8703d0e-1581-495a-99e0-4507178bf1fa}" radius="0.019802" x="0.330693" y="0.558416" z="1.91683"/>
|
<node id="{883859a6-0102-4a26-8596-3c47bcaf1970}" partId="{3719b667-4110-499d-b78b-4f2ec4e66213}" radius="0.019802" x="0.330693" y="0.558416" z="1.91683"/>
|
||||||
<node id="{89836264-59bd-420a-84d1-dae0a7d98f27}" partId="{0df76de9-fa79-477d-9771-b85378446b3c}" radius="0.154455" x="0.330693" y="0.419802" z="1.24752"/>
|
<node id="{89836264-59bd-420a-84d1-dae0a7d98f27}" partId="{449d0e15-066f-4780-918a-55978d46ed9d}" radius="0.154455" x="0.330693" y="0.419802" z="1.24752"/>
|
||||||
<node id="{8a9ec61d-2d9c-46f1-a0da-d04b5ee65085}" partId="{92839eb7-0da2-4905-ae58-a1bb3903f444}" radius="0.019802" x="0.306648" y="0.913681" z="1.96436"/>
|
<node id="{8a9ec61d-2d9c-46f1-a0da-d04b5ee65085}" partId="{0a233c0a-8ce5-42d3-b720-fb97b63d0e58}" radius="0.019802" x="0.306648" y="0.913681" z="1.96436"/>
|
||||||
<node id="{8ae179bd-6309-4cfa-b892-5a040d1b75df}" partId="{c722bb89-16f8-4866-b115-74c321caf271}" radius="0.0118812" x="0.384159" y="0.807921" z="1.31881"/>
|
<node id="{8ae179bd-6309-4cfa-b892-5a040d1b75df}" partId="{37860592-2626-4c6d-8069-349954bda284}" radius="0.0118812" x="0.384159" y="0.807921" z="1.30944"/>
|
||||||
<node id="{8da76f01-7c78-4227-a64e-af317cb591d5}" partId="{92839eb7-0da2-4905-ae58-a1bb3903f444}" radius="0.0158416" x="0.296747" y="0.741714" z="1.92297"/>
|
<node id="{8da76f01-7c78-4227-a64e-af317cb591d5}" partId="{0a233c0a-8ce5-42d3-b720-fb97b63d0e58}" radius="0.0158416" x="0.296747" y="0.741714" z="1.92297"/>
|
||||||
<node id="{913b6427-0ac2-4ace-ae9d-10434c1b5bdf}" partId="{0df76de9-fa79-477d-9771-b85378446b3c}" radius="0.0277228" x="0.330693" y="0.350495" z="0.763367"/>
|
<node id="{913b6427-0ac2-4ace-ae9d-10434c1b5bdf}" partId="{449d0e15-066f-4780-918a-55978d46ed9d}" radius="0.0277228" x="0.330693" y="0.350495" z="0.763367"/>
|
||||||
<node id="{936ea324-7ae0-4fe3-be1c-bc3f43bbcd7b}" partId="{92839eb7-0da2-4905-ae58-a1bb3903f444}" radius="0.0594059" x="0.257144" y="0.55998" z="1.78688"/>
|
<node id="{936ea324-7ae0-4fe3-be1c-bc3f43bbcd7b}" partId="{0a233c0a-8ce5-42d3-b720-fb97b63d0e58}" radius="0.0594059" x="0.257144" y="0.55998" z="1.78688"/>
|
||||||
<node id="{9ba73d77-9c23-40eb-97c3-b6d6c8ebd6d9}" partId="{0df76de9-fa79-477d-9771-b85378446b3c}" radius="0.150495" x="0.330693" y="0.439604" z="1.5802"/>
|
<node id="{9ba73d77-9c23-40eb-97c3-b6d6c8ebd6d9}" partId="{449d0e15-066f-4780-918a-55978d46ed9d}" radius="0.150495" x="0.330693" y="0.439604" z="1.5802"/>
|
||||||
<node id="{a2b78111-e6f4-4389-b7ed-4ba0a55599e8}" partId="{92839eb7-0da2-4905-ae58-a1bb3903f444}" radius="0.0118812" x="0.304668" y="0.933528" z="1.95106"/>
|
<node id="{a2b78111-e6f4-4389-b7ed-4ba0a55599e8}" partId="{0a233c0a-8ce5-42d3-b720-fb97b63d0e58}" radius="0.0118812" x="0.304668" y="0.933528" z="1.95106"/>
|
||||||
<node id="{a30b2cb5-7893-4db3-8fe8-269d30bca548}" partId="{c5bd1431-d740-4266-825d-217513f1a1f5}" radius="0.029703" x="0.302688" y="0.988119" z="1.29109"/>
|
<node id="{a30b2cb5-7893-4db3-8fe8-269d30bca548}" partId="{20fce58c-660f-4e93-b97a-a316d0753042}" radius="0.029703" x="0.302688" y="0.988119" z="1.29109"/>
|
||||||
<node id="{a459f13d-414a-454f-8739-97ddba88d0ad}" partId="{6df97180-d57c-46b3-8f96-4173b69abbc5}" radius="0.0118812" x="0.419802" y="0.038863" z="1.24557"/>
|
<node id="{a459f13d-414a-454f-8739-97ddba88d0ad}" partId="{0b0f5c6e-94d4-4c8e-9997-052a70fa3720}" radius="0.0118812" x="0.419802" y="0.038863" z="1.24557"/>
|
||||||
<node id="{ab7d093a-d8de-4328-97fa-d9ed37aec364}" partId="{c722bb89-16f8-4866-b115-74c321caf271}" radius="0.019802" x="0.382179" y="0.794059" z="1.29901"/>
|
<node id="{ab7d093a-d8de-4328-97fa-d9ed37aec364}" partId="{37860592-2626-4c6d-8069-349954bda284}" radius="0.019802" x="0.382179" y="0.794059" z="1.28964"/>
|
||||||
<node id="{b0e81284-8fbc-4757-a52e-c485fe57d92c}" partId="{92839eb7-0da2-4905-ae58-a1bb3903f444}" radius="0.0277228" x="0.290807" y="0.689913" z="1.9017"/>
|
<node id="{b0e81284-8fbc-4757-a52e-c485fe57d92c}" partId="{0a233c0a-8ce5-42d3-b720-fb97b63d0e58}" radius="0.0277228" x="0.290807" y="0.689913" z="1.9017"/>
|
||||||
<node id="{b10279cc-27c0-470f-8614-72a45ad74fb2}" partId="{c722bb89-16f8-4866-b115-74c321caf271}" radius="0.0118812" x="0.386139" y="0.750495" z="1.23564"/>
|
<node id="{b10279cc-27c0-470f-8614-72a45ad74fb2}" partId="{37860592-2626-4c6d-8069-349954bda284}" radius="0.0118812" x="0.386139" y="0.750495" z="1.22627"/>
|
||||||
<node id="{b6d23fe7-3bd6-4a4f-9601-0661304b1c94}" partId="{47d784c2-d5dc-402d-9848-e80e1c03416e}" radius="0.0178218" x="0.36479" y="0.235726" z="0.953465"/>
|
<node id="{b6d23fe7-3bd6-4a4f-9601-0661304b1c94}" partId="{76e8af23-9880-458a-8218-ebf61c0ba341}" radius="0.0178218" x="0.36479" y="0.235726" z="0.953465"/>
|
||||||
<node id="{b7527147-9500-4627-8704-5e363c3a2779}" partId="{92839eb7-0da2-4905-ae58-a1bb3903f444}" radius="0.039604" x="0.255163" y="0.586955" z="1.8011"/>
|
<node id="{b7527147-9500-4627-8704-5e363c3a2779}" partId="{0a233c0a-8ce5-42d3-b720-fb97b63d0e58}" radius="0.039604" x="0.255163" y="0.586955" z="1.8011"/>
|
||||||
<node id="{b7c80ca9-246f-4b6f-84cb-c3642691cf76}" partId="{c722bb89-16f8-4866-b115-74c321caf271}" radius="0.0633663" x="0.446984" y="0.515123" z="1.28317"/>
|
<node id="{b7c80ca9-246f-4b6f-84cb-c3642691cf76}" partId="{37860592-2626-4c6d-8069-349954bda284}" radius="0.0633663" x="0.446984" y="0.515123" z="1.2738"/>
|
||||||
<node id="{b88113fa-d829-40e0-95ef-0462032ce7b9}" partId="{e6fced12-025d-471f-b260-6d7854280682}" radius="0.0316832" x="0.396605" y="0.637891" z="1.69775"/>
|
<node id="{b88113fa-d829-40e0-95ef-0462032ce7b9}" partId="{57a41558-46e2-48ce-9f6b-54ada6b2d083}" radius="0.0316832" x="0.396605" y="0.637891" z="1.69775"/>
|
||||||
<node id="{baae591e-9437-454a-ba87-ea28bbde87c9}" partId="{e6fced12-025d-471f-b260-6d7854280682}" radius="0.029703" x="0.362942" y="0.989347" z="1.56941"/>
|
<node id="{baae591e-9437-454a-ba87-ea28bbde87c9}" partId="{57a41558-46e2-48ce-9f6b-54ada6b2d083}" radius="0.029703" x="0.362942" y="0.989347" z="1.56941"/>
|
||||||
<node id="{bba5b320-733b-44a4-a701-27f12003dde9}" partId="{c722bb89-16f8-4866-b115-74c321caf271}" radius="0.0316832" x="0.39802" y="0.683168" z="1.1802"/>
|
<node id="{bba5b320-733b-44a4-a701-27f12003dde9}" partId="{37860592-2626-4c6d-8069-349954bda284}" radius="0.0316832" x="0.39802" y="0.683168" z="1.17083"/>
|
||||||
<node id="{bcb2d6a7-7a55-424a-84a9-ef7ba7e42731}" partId="{6df97180-d57c-46b3-8f96-4173b69abbc5}" radius="0.0158416" x="0.392079" y="0.112624" z="1.12511"/>
|
<node id="{bcb2d6a7-7a55-424a-84a9-ef7ba7e42731}" partId="{0b0f5c6e-94d4-4c8e-9997-052a70fa3720}" radius="0.0158416" x="0.392079" y="0.112624" z="1.12511"/>
|
||||||
<node id="{bff67e53-359b-4e50-bafb-dcc9dd84f4ec}" partId="{92839eb7-0da2-4905-ae58-a1bb3903f444}" radius="0.0277228" x="0.278926" y="0.655904" z="1.85913"/>
|
<node id="{bff67e53-359b-4e50-bafb-dcc9dd84f4ec}" partId="{0a233c0a-8ce5-42d3-b720-fb97b63d0e58}" radius="0.0277228" x="0.278926" y="0.655904" z="1.85913"/>
|
||||||
<node id="{c0000c88-edd1-46ca-b57b-9dc6874f72eb}" partId="{6df97180-d57c-46b3-8f96-4173b69abbc5}" radius="0.0158416" x="0.405941" y="0.0482526" z="1.19816"/>
|
<node id="{c0000c88-edd1-46ca-b57b-9dc6874f72eb}" partId="{0b0f5c6e-94d4-4c8e-9997-052a70fa3720}" radius="0.0158416" x="0.405941" y="0.0482526" z="1.19816"/>
|
||||||
<node id="{c03f9808-ad09-4e34-8683-225be168d659}" partId="{c5bd1431-d740-4266-825d-217513f1a1f5}" radius="0.0237624" x="0.290807" y="0.756436" z="1.31881"/>
|
<node id="{c03f9808-ad09-4e34-8683-225be168d659}" partId="{20fce58c-660f-4e93-b97a-a316d0753042}" radius="0.0237624" x="0.290807" y="0.756436" z="1.31881"/>
|
||||||
<node id="{c41b7308-14bf-4950-b2ba-2775199a92e0}" partId="{c5bd1431-d740-4266-825d-217513f1a1f5}" radius="0.0316832" x="0.269025" y="0.663366" z="1.30693"/>
|
<node id="{c41b7308-14bf-4950-b2ba-2775199a92e0}" partId="{20fce58c-660f-4e93-b97a-a316d0753042}" radius="0.0316832" x="0.269025" y="0.663366" z="1.30693"/>
|
||||||
<node id="{c6050850-281f-41f3-b736-c734179996c3}" partId="{6df97180-d57c-46b3-8f96-4173b69abbc5}" radius="0.0118812" x="0.431683" y="0.0294736" z="1.27119"/>
|
<node id="{c6050850-281f-41f3-b736-c734179996c3}" partId="{0b0f5c6e-94d4-4c8e-9997-052a70fa3720}" radius="0.0118812" x="0.431683" y="0.0294736" z="1.27119"/>
|
||||||
<node id="{c6ab722d-0df4-46df-a666-c08534fa785e}" partId="{e6fced12-025d-471f-b260-6d7854280682}" radius="0.0158416" x="0.360962" y="0.886031" z="1.65148"/>
|
<node id="{c6ab722d-0df4-46df-a666-c08534fa785e}" partId="{57a41558-46e2-48ce-9f6b-54ada6b2d083}" radius="0.0158416" x="0.360962" y="0.886031" z="1.65148"/>
|
||||||
<node id="{ca57c536-2786-4b36-a3d9-9590b9658843}" partId="{c5bd1431-d740-4266-825d-217513f1a1f5}" radius="0.0277228" x="0.278926" y="0.69901" z="1.30891"/>
|
<node id="{ca57c536-2786-4b36-a3d9-9590b9658843}" partId="{20fce58c-660f-4e93-b97a-a316d0753042}" radius="0.0277228" x="0.278926" y="0.69901" z="1.30891"/>
|
||||||
<node id="{cda8ff54-1879-450f-8af9-a118ff6bfd7f}" partId="{0df76de9-fa79-477d-9771-b85378446b3c}" radius="0.162376" x="0.330693" y="0.411881" z="1.33663"/>
|
<node id="{cda8ff54-1879-450f-8af9-a118ff6bfd7f}" partId="{449d0e15-066f-4780-918a-55978d46ed9d}" radius="0.162376" x="0.330693" y="0.411881" z="1.33663"/>
|
||||||
<node id="{d32e752f-fdd0-4ccc-8558-f341ceef5f91}" partId="{6df97180-d57c-46b3-8f96-4173b69abbc5}" radius="0.00792079" x="0.433663" y="0.0193337" z="1.30536"/>
|
<node id="{d32e752f-fdd0-4ccc-8558-f341ceef5f91}" partId="{0b0f5c6e-94d4-4c8e-9997-052a70fa3720}" radius="0.00792079" x="0.433663" y="0.0193337" z="1.30536"/>
|
||||||
<node id="{d46924c8-54d7-4f2b-8376-b5e12a7b535c}" partId="{92839eb7-0da2-4905-ae58-a1bb3903f444}" radius="0.0118812" x="0.302688" y="0.799967" z="1.93784"/>
|
<node id="{d46924c8-54d7-4f2b-8376-b5e12a7b535c}" partId="{0a233c0a-8ce5-42d3-b720-fb97b63d0e58}" radius="0.0118812" x="0.302688" y="0.799967" z="1.93784"/>
|
||||||
<node id="{d6fd2f1a-7c90-4c62-82be-1eeb781c5847}" partId="{6df97180-d57c-46b3-8f96-4173b69abbc5}" radius="0.0158416" x="0.39604" y="0.0777943" z="1.16925"/>
|
<node id="{d6fd2f1a-7c90-4c62-82be-1eeb781c5847}" partId="{0b0f5c6e-94d4-4c8e-9997-052a70fa3720}" radius="0.0158416" x="0.39604" y="0.0777943" z="1.16925"/>
|
||||||
<node id="{d71693ae-f238-4bd3-881e-bcdee119c22c}" partId="{c5bd1431-d740-4266-825d-217513f1a1f5}" radius="0.0217822" x="0.304668" y="0.974257" z="1.29901"/>
|
<node id="{d71693ae-f238-4bd3-881e-bcdee119c22c}" partId="{20fce58c-660f-4e93-b97a-a316d0753042}" radius="0.0217822" x="0.304668" y="0.974257" z="1.29901"/>
|
||||||
<node id="{d884eda9-29ca-41ab-8a45-3995c8058549}" partId="{e6fced12-025d-471f-b260-6d7854280682}" radius="0.039604" x="0.410467" y="0.582969" z="1.69421"/>
|
<node id="{d884eda9-29ca-41ab-8a45-3995c8058549}" partId="{57a41558-46e2-48ce-9f6b-54ada6b2d083}" radius="0.039604" x="0.410467" y="0.582969" z="1.69421"/>
|
||||||
<node id="{dd3e9c97-c506-4faf-9a47-d0003c62cf33}" partId="{47d784c2-d5dc-402d-9848-e80e1c03416e}" radius="0.0178218" x="0.423268" y="0.184411" z="1.06535"/>
|
<node id="{dd3e9c97-c506-4faf-9a47-d0003c62cf33}" partId="{76e8af23-9880-458a-8218-ebf61c0ba341}" radius="0.0178218" x="0.423268" y="0.184411" z="1.06535"/>
|
||||||
<node id="{dd48d6f8-0172-4886-a11a-6c9f36444be5}" partId="{c5bd1431-d740-4266-825d-217513f1a1f5}" radius="0.0594059" x="0.251203" y="0.457426" z="1.26435"/>
|
<node id="{dd48d6f8-0172-4886-a11a-6c9f36444be5}" partId="{20fce58c-660f-4e93-b97a-a316d0753042}" radius="0.0594059" x="0.251203" y="0.457426" z="1.26435"/>
|
||||||
<node id="{ded04835-2d99-46a0-8763-7869526dd8be}" partId="{92839eb7-0da2-4905-ae58-a1bb3903f444}" radius="0.0158416" x="0.304668" y="0.854708" z="1.94936"/>
|
<node id="{ded04835-2d99-46a0-8763-7869526dd8be}" partId="{0a233c0a-8ce5-42d3-b720-fb97b63d0e58}" radius="0.0158416" x="0.304668" y="0.854708" z="1.94936"/>
|
||||||
<node id="{e274e844-fbf1-47fb-bbec-0504785f3c11}" partId="{a8703d0e-1581-495a-99e0-4507178bf1fa}" radius="0.0158416" x="0.330693" y="0.350495" z="1.8396"/>
|
<node id="{e274e844-fbf1-47fb-bbec-0504785f3c11}" partId="{3719b667-4110-499d-b78b-4f2ec4e66213}" radius="0.0158416" x="0.330693" y="0.350495" z="1.8396"/>
|
||||||
<node id="{e3deddc7-edcd-4bdf-b0bd-f2d46e8bef63}" partId="{47d784c2-d5dc-402d-9848-e80e1c03416e}" radius="0.0217822" x="0.398646" y="0.20831" z="1.00792"/>
|
<node id="{e3deddc7-edcd-4bdf-b0bd-f2d46e8bef63}" partId="{76e8af23-9880-458a-8218-ebf61c0ba341}" radius="0.0217822" x="0.398646" y="0.20831" z="1.00792"/>
|
||||||
<node id="{e40576eb-3d06-4c53-8f29-98683f2d7aab}" partId="{e6fced12-025d-471f-b260-6d7854280682}" radius="0.0594059" x="0.408486" y="0.552868" z="1.69909"/>
|
<node id="{e40576eb-3d06-4c53-8f29-98683f2d7aab}" partId="{57a41558-46e2-48ce-9f6b-54ada6b2d083}" radius="0.0594059" x="0.408486" y="0.552868" z="1.69909"/>
|
||||||
<node id="{e5361db3-58e4-41af-a955-55010430d3a7}" partId="{e6fced12-025d-471f-b260-6d7854280682}" radius="0.0277228" x="0.386704" y="0.672958" z="1.69906"/>
|
<node id="{e5361db3-58e4-41af-a955-55010430d3a7}" partId="{57a41558-46e2-48ce-9f6b-54ada6b2d083}" radius="0.0277228" x="0.386704" y="0.672958" z="1.69906"/>
|
||||||
<node id="{e5d65034-602c-4336-a919-b4a8ff8fc68f}" partId="{0df76de9-fa79-477d-9771-b85378446b3c}" radius="0.0752475" x="0.330693" y="0.29505" z="0.893069"/>
|
<node id="{e5d65034-602c-4336-a919-b4a8ff8fc68f}" partId="{449d0e15-066f-4780-918a-55978d46ed9d}" radius="0.0752475" x="0.330693" y="0.29505" z="0.893069"/>
|
||||||
<node id="{e97e7112-dae7-4465-8cb2-d1d66fc81dee}" partId="{c722bb89-16f8-4866-b115-74c321caf271}" radius="0.039604" x="0.433664" y="0.59802" z="1.26931"/>
|
<node id="{e97e7112-dae7-4465-8cb2-d1d66fc81dee}" partId="{37860592-2626-4c6d-8069-349954bda284}" radius="0.039604" x="0.433664" y="0.59802" z="1.25994"/>
|
||||||
<node id="{e9fd4236-5ce0-4d2e-8868-d894967fb749}" partId="{e6fced12-025d-471f-b260-6d7854280682}" radius="0.0118812" x="0.360962" y="0.950003" z="1.6054"/>
|
<node id="{e9fd4236-5ce0-4d2e-8868-d894967fb749}" partId="{57a41558-46e2-48ce-9f6b-54ada6b2d083}" radius="0.0118812" x="0.360962" y="0.950003" z="1.6054"/>
|
||||||
<node id="{eb75e8d6-9b28-4ec5-afa6-59b006152425}" partId="{92839eb7-0da2-4905-ae58-a1bb3903f444}" radius="0.0217822" x="0.304668" y="0.954068" z="1.94622"/>
|
<node id="{eb75e8d6-9b28-4ec5-afa6-59b006152425}" partId="{0a233c0a-8ce5-42d3-b720-fb97b63d0e58}" radius="0.0217822" x="0.304668" y="0.954068" z="1.94622"/>
|
||||||
<node id="{ec7fe0a0-42da-486a-a46e-6721de480bd4}" partId="{e6fced12-025d-471f-b260-6d7854280682}" radius="0.0792079" x="0.406507" y="0.494165" z="1.7201"/>
|
<node id="{ec7fe0a0-42da-486a-a46e-6721de480bd4}" partId="{57a41558-46e2-48ce-9f6b-54ada6b2d083}" radius="0.0792079" x="0.406507" y="0.494165" z="1.7201"/>
|
||||||
<node id="{fc6e43f7-ba5d-4aec-8307-c2cba3b60d25}" partId="{a8703d0e-1581-495a-99e0-4507178bf1fa}" radius="0.0118812" x="0.330693" y="0.407921" z="1.88119"/>
|
<node id="{fc6e43f7-ba5d-4aec-8307-c2cba3b60d25}" partId="{3719b667-4110-499d-b78b-4f2ec4e66213}" radius="0.0118812" x="0.330693" y="0.407921" z="1.88119"/>
|
||||||
<node id="{fc9412df-c285-4fca-bd36-75e6b5fa9a10}" partId="{e6fced12-025d-471f-b260-6d7854280682}" radius="0.0118812" x="0.362942" y="0.83538" z="1.67522"/>
|
<node id="{fc9412df-c285-4fca-bd36-75e6b5fa9a10}" partId="{57a41558-46e2-48ce-9f6b-54ada6b2d083}" radius="0.0118812" x="0.362942" y="0.83538" z="1.67522"/>
|
||||||
<node id="{fce1e549-0427-4875-800c-6177d0c6d0c1}" partId="{e84c3063-265f-4850-9e19-465b84e41118}" radius="0.00594059" x="0.390099" y="0.264697" z="0.887594"/>
|
<node id="{fce1e549-0427-4875-800c-6177d0c6d0c1}" partId="{8689ab0b-3a56-4f01-b72a-0eee032928d4}" radius="0.00594059" x="0.390099" y="0.264697" z="0.887594"/>
|
||||||
<node id="{fe1bb602-5c84-4e9f-89e6-2fc993fc3263}" partId="{6df97180-d57c-46b3-8f96-4173b69abbc5}" radius="0.019802" x="0.380198" y="0.188474" z="0.940183"/>
|
<node id="{fe1bb602-5c84-4e9f-89e6-2fc993fc3263}" partId="{0b0f5c6e-94d4-4c8e-9997-052a70fa3720}" radius="0.019802" x="0.380198" y="0.188474" z="0.940183"/>
|
||||||
</nodes>
|
</nodes>
|
||||||
<edges>
|
<edges>
|
||||||
<edge from="{355833f3-bd2d-4508-9293-dbf33c65222b}" id="{0571dd67-b846-4ecc-9011-5eedaaff0865}" partId="{a8703d0e-1581-495a-99e0-4507178bf1fa}" to="{2498311b-1a9b-4768-bd9c-e108e4f7a1c8}"/>
|
<edge from="{355833f3-bd2d-4508-9293-dbf33c65222b}" id="{0571dd67-b846-4ecc-9011-5eedaaff0865}" partId="{3719b667-4110-499d-b78b-4f2ec4e66213}" to="{2498311b-1a9b-4768-bd9c-e108e4f7a1c8}"/>
|
||||||
<edge from="{c03f9808-ad09-4e34-8683-225be168d659}" id="{0b5bdca7-b1f3-4ca1-810f-9304ade0c583}" partId="{c5bd1431-d740-4266-825d-217513f1a1f5}" to="{7d3f47b9-2de0-46e2-9691-3c7de959777f}"/>
|
<edge from="{c03f9808-ad09-4e34-8683-225be168d659}" id="{0b5bdca7-b1f3-4ca1-810f-9304ade0c583}" partId="{20fce58c-660f-4e93-b97a-a316d0753042}" to="{7d3f47b9-2de0-46e2-9691-3c7de959777f}"/>
|
||||||
<edge from="{72a946b4-b2a0-426a-884b-5cf5176f9ece}" id="{0ccf11ec-8354-47a0-b907-528675c72b35}" partId="{47d784c2-d5dc-402d-9848-e80e1c03416e}" to="{dd3e9c97-c506-4faf-9a47-d0003c62cf33}"/>
|
<edge from="{72a946b4-b2a0-426a-884b-5cf5176f9ece}" id="{0ccf11ec-8354-47a0-b907-528675c72b35}" partId="{76e8af23-9880-458a-8218-ebf61c0ba341}" to="{dd3e9c97-c506-4faf-9a47-d0003c62cf33}"/>
|
||||||
<edge from="{4123d281-63d6-44a5-bdfd-62261ab8dad9}" id="{0d024d6e-4265-4168-8e70-b10effd903c0}" partId="{c722bb89-16f8-4866-b115-74c321caf271}" to="{ab7d093a-d8de-4328-97fa-d9ed37aec364}"/>
|
<edge from="{4123d281-63d6-44a5-bdfd-62261ab8dad9}" id="{0d024d6e-4265-4168-8e70-b10effd903c0}" partId="{37860592-2626-4c6d-8069-349954bda284}" to="{ab7d093a-d8de-4328-97fa-d9ed37aec364}"/>
|
||||||
<edge from="{dd3e9c97-c506-4faf-9a47-d0003c62cf33}" id="{0d6cd4aa-7f87-4b3b-906c-d2292662143e}" partId="{47d784c2-d5dc-402d-9848-e80e1c03416e}" to="{22f090e3-7748-4a48-841a-925de92cce58}"/>
|
<edge from="{dd3e9c97-c506-4faf-9a47-d0003c62cf33}" id="{0d6cd4aa-7f87-4b3b-906c-d2292662143e}" partId="{76e8af23-9880-458a-8218-ebf61c0ba341}" to="{22f090e3-7748-4a48-841a-925de92cce58}"/>
|
||||||
<edge from="{74399604-82fe-4cc0-a61f-0de6f297f80b}" id="{0e138337-1ae6-4b93-8321-31d1351a396f}" partId="{e6fced12-025d-471f-b260-6d7854280682}" to="{40529c5a-bafd-4bc1-84c3-daae168d5da8}"/>
|
<edge from="{74399604-82fe-4cc0-a61f-0de6f297f80b}" id="{0e138337-1ae6-4b93-8321-31d1351a396f}" partId="{57a41558-46e2-48ce-9f6b-54ada6b2d083}" to="{40529c5a-bafd-4bc1-84c3-daae168d5da8}"/>
|
||||||
<edge from="{c6ab722d-0df4-46df-a666-c08534fa785e}" id="{0e31bac7-c1a3-4aba-88f0-9a269091a488}" partId="{e6fced12-025d-471f-b260-6d7854280682}" to="{2e02275f-8aa2-46f3-ad34-579a63890b17}"/>
|
<edge from="{c6ab722d-0df4-46df-a666-c08534fa785e}" id="{0e31bac7-c1a3-4aba-88f0-9a269091a488}" partId="{57a41558-46e2-48ce-9f6b-54ada6b2d083}" to="{2e02275f-8aa2-46f3-ad34-579a63890b17}"/>
|
||||||
<edge from="{31ccee3b-ba23-4294-ae81-6f6b34f1ed5d}" id="{10bec875-0bb4-4840-bc88-9c48b7f6c3d6}" partId="{6df97180-d57c-46b3-8f96-4173b69abbc5}" to="{68fee6f0-597d-4079-a61b-4def65e1c8f9}"/>
|
<edge from="{31ccee3b-ba23-4294-ae81-6f6b34f1ed5d}" id="{10bec875-0bb4-4840-bc88-9c48b7f6c3d6}" partId="{0b0f5c6e-94d4-4c8e-9997-052a70fa3720}" to="{68fee6f0-597d-4079-a61b-4def65e1c8f9}"/>
|
||||||
<edge from="{b6d23fe7-3bd6-4a4f-9601-0661304b1c94}" id="{1304817d-5b36-454c-9006-6c295ac5a4fc}" partId="{47d784c2-d5dc-402d-9848-e80e1c03416e}" to="{6b0da1e9-337b-4cf4-9d08-c2ab19b18c80}"/>
|
<edge from="{b6d23fe7-3bd6-4a4f-9601-0661304b1c94}" id="{1304817d-5b36-454c-9006-6c295ac5a4fc}" partId="{76e8af23-9880-458a-8218-ebf61c0ba341}" to="{6b0da1e9-337b-4cf4-9d08-c2ab19b18c80}"/>
|
||||||
<edge from="{68fee6f0-597d-4079-a61b-4def65e1c8f9}" id="{14a673b6-75ca-4d94-aebb-d34dc05b6b40}" partId="{6df97180-d57c-46b3-8f96-4173b69abbc5}" to="{84c39fc7-a579-453f-b2d2-3872af219174}"/>
|
<edge from="{68fee6f0-597d-4079-a61b-4def65e1c8f9}" id="{14a673b6-75ca-4d94-aebb-d34dc05b6b40}" partId="{0b0f5c6e-94d4-4c8e-9997-052a70fa3720}" to="{84c39fc7-a579-453f-b2d2-3872af219174}"/>
|
||||||
<edge from="{37dc112b-cfb9-4a87-9b82-90a27c9d1518}" id="{165d9cb1-a82d-4bbc-8884-f45fc723503b}" partId="{0df76de9-fa79-477d-9771-b85378446b3c}" to="{89836264-59bd-420a-84d1-dae0a7d98f27}"/>
|
<edge from="{37dc112b-cfb9-4a87-9b82-90a27c9d1518}" id="{165d9cb1-a82d-4bbc-8884-f45fc723503b}" partId="{449d0e15-066f-4780-918a-55978d46ed9d}" to="{89836264-59bd-420a-84d1-dae0a7d98f27}"/>
|
||||||
<edge from="{8ae179bd-6309-4cfa-b892-5a040d1b75df}" id="{17dcd894-c09e-4946-8191-45e100ec4e45}" partId="{c722bb89-16f8-4866-b115-74c321caf271}" to="{259237a6-bac4-4a79-aa57-a74d357feff2}"/>
|
<edge from="{8ae179bd-6309-4cfa-b892-5a040d1b75df}" id="{17dcd894-c09e-4946-8191-45e100ec4e45}" partId="{37860592-2626-4c6d-8069-349954bda284}" to="{259237a6-bac4-4a79-aa57-a74d357feff2}"/>
|
||||||
<edge from="{5b25a3a7-ed5a-42ef-a277-6fd8406649f2}" id="{18c55d57-cc36-4f4c-9fa9-b45cf7b288df}" partId="{6df97180-d57c-46b3-8f96-4173b69abbc5}" to="{fe1bb602-5c84-4e9f-89e6-2fc993fc3263}"/>
|
<edge from="{5b25a3a7-ed5a-42ef-a277-6fd8406649f2}" id="{18c55d57-cc36-4f4c-9fa9-b45cf7b288df}" partId="{0b0f5c6e-94d4-4c8e-9997-052a70fa3720}" to="{fe1bb602-5c84-4e9f-89e6-2fc993fc3263}"/>
|
||||||
<edge from="{e5361db3-58e4-41af-a955-55010430d3a7}" id="{1e0ba45a-bb1b-4383-a8d0-704920602cc6}" partId="{e6fced12-025d-471f-b260-6d7854280682}" to="{74399604-82fe-4cc0-a61f-0de6f297f80b}"/>
|
<edge from="{e5361db3-58e4-41af-a955-55010430d3a7}" id="{1e0ba45a-bb1b-4383-a8d0-704920602cc6}" partId="{57a41558-46e2-48ce-9f6b-54ada6b2d083}" to="{74399604-82fe-4cc0-a61f-0de6f297f80b}"/>
|
||||||
<edge from="{3e13f116-1dd9-4024-8b1b-764c176a7835}" id="{26479dee-1e07-4917-ba2a-9b9fc3ec2f71}" partId="{a8703d0e-1581-495a-99e0-4507178bf1fa}" to="{6b2b333d-2abf-4d6e-8957-7a848c46e651}"/>
|
<edge from="{3e13f116-1dd9-4024-8b1b-764c176a7835}" id="{26479dee-1e07-4917-ba2a-9b9fc3ec2f71}" partId="{3719b667-4110-499d-b78b-4f2ec4e66213}" to="{6b2b333d-2abf-4d6e-8957-7a848c46e651}"/>
|
||||||
<edge from="{d71693ae-f238-4bd3-881e-bcdee119c22c}" id="{2c88fbbd-5dfd-435f-a88f-b9a8b0d9d803}" partId="{c5bd1431-d740-4266-825d-217513f1a1f5}" to="{a30b2cb5-7893-4db3-8fe8-269d30bca548}"/>
|
<edge from="{d71693ae-f238-4bd3-881e-bcdee119c22c}" id="{2c88fbbd-5dfd-435f-a88f-b9a8b0d9d803}" partId="{20fce58c-660f-4e93-b97a-a316d0753042}" to="{a30b2cb5-7893-4db3-8fe8-269d30bca548}"/>
|
||||||
<edge from="{89836264-59bd-420a-84d1-dae0a7d98f27}" id="{3235421c-0321-4505-bc89-7ef5fb1884ed}" partId="{0df76de9-fa79-477d-9771-b85378446b3c}" to="{cda8ff54-1879-450f-8af9-a118ff6bfd7f}"/>
|
<edge from="{89836264-59bd-420a-84d1-dae0a7d98f27}" id="{3235421c-0321-4505-bc89-7ef5fb1884ed}" partId="{449d0e15-066f-4780-918a-55978d46ed9d}" to="{cda8ff54-1879-450f-8af9-a118ff6bfd7f}"/>
|
||||||
<edge from="{40529c5a-bafd-4bc1-84c3-daae168d5da8}" id="{34e70dac-c738-4d1a-b259-bf01b26c913b}" partId="{e6fced12-025d-471f-b260-6d7854280682}" to="{fc9412df-c285-4fca-bd36-75e6b5fa9a10}"/>
|
<edge from="{40529c5a-bafd-4bc1-84c3-daae168d5da8}" id="{34e70dac-c738-4d1a-b259-bf01b26c913b}" partId="{57a41558-46e2-48ce-9f6b-54ada6b2d083}" to="{fc9412df-c285-4fca-bd36-75e6b5fa9a10}"/>
|
||||||
<edge from="{ded04835-2d99-46a0-8763-7869526dd8be}" id="{38f2e48b-4df7-45b0-bdc9-231ea61d6ec3}" partId="{92839eb7-0da2-4905-ae58-a1bb3903f444}" to="{8a9ec61d-2d9c-46f1-a0da-d04b5ee65085}"/>
|
<edge from="{ded04835-2d99-46a0-8763-7869526dd8be}" id="{38f2e48b-4df7-45b0-bdc9-231ea61d6ec3}" partId="{0a233c0a-8ce5-42d3-b720-fb97b63d0e58}" to="{8a9ec61d-2d9c-46f1-a0da-d04b5ee65085}"/>
|
||||||
<edge from="{e5d65034-602c-4336-a919-b4a8ff8fc68f}" id="{406ac7e5-450d-4162-8eb7-70e4d86bc14b}" partId="{0df76de9-fa79-477d-9771-b85378446b3c}" to="{021f7f20-d1c4-4b79-94ef-25ecf621ee0c}"/>
|
<edge from="{e5d65034-602c-4336-a919-b4a8ff8fc68f}" id="{406ac7e5-450d-4162-8eb7-70e4d86bc14b}" partId="{449d0e15-066f-4780-918a-55978d46ed9d}" to="{021f7f20-d1c4-4b79-94ef-25ecf621ee0c}"/>
|
||||||
<edge from="{fc6e43f7-ba5d-4aec-8307-c2cba3b60d25}" id="{4211f57d-43d9-405c-872f-f184f701b2f6}" partId="{a8703d0e-1581-495a-99e0-4507178bf1fa}" to="{3e13f116-1dd9-4024-8b1b-764c176a7835}"/>
|
<edge from="{fc6e43f7-ba5d-4aec-8307-c2cba3b60d25}" id="{4211f57d-43d9-405c-872f-f184f701b2f6}" partId="{3719b667-4110-499d-b78b-4f2ec4e66213}" to="{3e13f116-1dd9-4024-8b1b-764c176a7835}"/>
|
||||||
<edge from="{4c9ba403-391c-4903-a8ba-0ff250713286}" id="{4b984aed-5a41-4d31-ad6e-d8000f5aa5dc}" partId="{c5bd1431-d740-4266-825d-217513f1a1f5}" to="{c41b7308-14bf-4950-b2ba-2775199a92e0}"/>
|
<edge from="{4c9ba403-391c-4903-a8ba-0ff250713286}" id="{4b984aed-5a41-4d31-ad6e-d8000f5aa5dc}" partId="{20fce58c-660f-4e93-b97a-a316d0753042}" to="{c41b7308-14bf-4950-b2ba-2775199a92e0}"/>
|
||||||
<edge from="{bcb2d6a7-7a55-424a-84a9-ef7ba7e42731}" id="{511eab57-7312-425c-96c1-c48e4aea3f1d}" partId="{6df97180-d57c-46b3-8f96-4173b69abbc5}" to="{d6fd2f1a-7c90-4c62-82be-1eeb781c5847}"/>
|
<edge from="{bcb2d6a7-7a55-424a-84a9-ef7ba7e42731}" id="{511eab57-7312-425c-96c1-c48e4aea3f1d}" partId="{0b0f5c6e-94d4-4c8e-9997-052a70fa3720}" to="{d6fd2f1a-7c90-4c62-82be-1eeb781c5847}"/>
|
||||||
<edge from="{c0000c88-edd1-46ca-b57b-9dc6874f72eb}" id="{53999bf4-3333-47d0-9288-0a1d2854ddbb}" partId="{6df97180-d57c-46b3-8f96-4173b69abbc5}" to="{a459f13d-414a-454f-8739-97ddba88d0ad}"/>
|
<edge from="{c0000c88-edd1-46ca-b57b-9dc6874f72eb}" id="{53999bf4-3333-47d0-9288-0a1d2854ddbb}" partId="{0b0f5c6e-94d4-4c8e-9997-052a70fa3720}" to="{a459f13d-414a-454f-8739-97ddba88d0ad}"/>
|
||||||
<edge from="{b10279cc-27c0-470f-8614-72a45ad74fb2}" id="{547bfc25-9d06-43af-bb18-87bf486ab0c6}" partId="{c722bb89-16f8-4866-b115-74c321caf271}" to="{4123d281-63d6-44a5-bdfd-62261ab8dad9}"/>
|
<edge from="{b10279cc-27c0-470f-8614-72a45ad74fb2}" id="{547bfc25-9d06-43af-bb18-87bf486ab0c6}" partId="{37860592-2626-4c6d-8069-349954bda284}" to="{4123d281-63d6-44a5-bdfd-62261ab8dad9}"/>
|
||||||
<edge from="{1ccfc908-f650-44bc-b072-6d100315b927}" id="{58c2ae11-7c73-4660-8c72-09a124c8d299}" partId="{92839eb7-0da2-4905-ae58-a1bb3903f444}" to="{54127252-0ecb-4a08-84b8-489ce894aebe}"/>
|
<edge from="{1ccfc908-f650-44bc-b072-6d100315b927}" id="{58c2ae11-7c73-4660-8c72-09a124c8d299}" partId="{0a233c0a-8ce5-42d3-b720-fb97b63d0e58}" to="{54127252-0ecb-4a08-84b8-489ce894aebe}"/>
|
||||||
<edge from="{ab7d093a-d8de-4328-97fa-d9ed37aec364}" id="{6795486b-b073-4971-81a4-3e370af49840}" partId="{c722bb89-16f8-4866-b115-74c321caf271}" to="{8ae179bd-6309-4cfa-b892-5a040d1b75df}"/>
|
<edge from="{ab7d093a-d8de-4328-97fa-d9ed37aec364}" id="{6795486b-b073-4971-81a4-3e370af49840}" partId="{37860592-2626-4c6d-8069-349954bda284}" to="{8ae179bd-6309-4cfa-b892-5a040d1b75df}"/>
|
||||||
<edge from="{fc9412df-c285-4fca-bd36-75e6b5fa9a10}" id="{67e435e7-126a-44d2-a882-82793a9144f8}" partId="{e6fced12-025d-471f-b260-6d7854280682}" to="{c6ab722d-0df4-46df-a666-c08534fa785e}"/>
|
<edge from="{fc9412df-c285-4fca-bd36-75e6b5fa9a10}" id="{67e435e7-126a-44d2-a882-82793a9144f8}" partId="{57a41558-46e2-48ce-9f6b-54ada6b2d083}" to="{c6ab722d-0df4-46df-a666-c08534fa785e}"/>
|
||||||
<edge from="{05a4fc6a-8e6f-4c0d-a6ca-023ef4bd8d14}" id="{6f2e6906-ac73-4767-9148-1d426c1223c6}" partId="{e84c3063-265f-4850-9e19-465b84e41118}" to="{6183e755-7d06-4e96-aee0-2e4a5df4c83f}"/>
|
<edge from="{05a4fc6a-8e6f-4c0d-a6ca-023ef4bd8d14}" id="{6f2e6906-ac73-4767-9148-1d426c1223c6}" partId="{8689ab0b-3a56-4f01-b72a-0eee032928d4}" to="{6183e755-7d06-4e96-aee0-2e4a5df4c83f}"/>
|
||||||
<edge from="{2bcb3563-c4d3-40bb-8e49-3afe61da902f}" id="{70e4682b-c179-4c34-a6d9-1c3f5bcbb34d}" partId="{a8703d0e-1581-495a-99e0-4507178bf1fa}" to="{e274e844-fbf1-47fb-bbec-0504785f3c11}"/>
|
<edge from="{2bcb3563-c4d3-40bb-8e49-3afe61da902f}" id="{70e4682b-c179-4c34-a6d9-1c3f5bcbb34d}" partId="{3719b667-4110-499d-b78b-4f2ec4e66213}" to="{e274e844-fbf1-47fb-bbec-0504785f3c11}"/>
|
||||||
<edge from="{8a9ec61d-2d9c-46f1-a0da-d04b5ee65085}" id="{762ee8d5-5fe7-40a4-aa79-e6a53566e747}" partId="{92839eb7-0da2-4905-ae58-a1bb3903f444}" to="{a2b78111-e6f4-4389-b7ed-4ba0a55599e8}"/>
|
<edge from="{8a9ec61d-2d9c-46f1-a0da-d04b5ee65085}" id="{762ee8d5-5fe7-40a4-aa79-e6a53566e747}" partId="{0a233c0a-8ce5-42d3-b720-fb97b63d0e58}" to="{a2b78111-e6f4-4389-b7ed-4ba0a55599e8}"/>
|
||||||
<edge from="{913b6427-0ac2-4ace-ae9d-10434c1b5bdf}" id="{789cc205-b308-472a-9dd4-f5014f302812}" partId="{0df76de9-fa79-477d-9771-b85378446b3c}" to="{2dd69178-ccf9-4026-9319-9aebbd4155df}"/>
|
<edge from="{913b6427-0ac2-4ace-ae9d-10434c1b5bdf}" id="{789cc205-b308-472a-9dd4-f5014f302812}" partId="{449d0e15-066f-4780-918a-55978d46ed9d}" to="{2dd69178-ccf9-4026-9319-9aebbd4155df}"/>
|
||||||
<edge from="{b7c80ca9-246f-4b6f-84cb-c3642691cf76}" id="{79b9c36d-cdcb-4052-a970-2bad1dd1eee2}" partId="{c722bb89-16f8-4866-b115-74c321caf271}" to="{59c85ebe-b47b-4d4b-b40a-9bb0ed434914}"/>
|
<edge from="{b7c80ca9-246f-4b6f-84cb-c3642691cf76}" id="{79b9c36d-cdcb-4052-a970-2bad1dd1eee2}" partId="{37860592-2626-4c6d-8069-349954bda284}" to="{59c85ebe-b47b-4d4b-b40a-9bb0ed434914}"/>
|
||||||
<edge from="{bba5b320-733b-44a4-a701-27f12003dde9}" id="{7bf2b03e-1f3f-4578-a7be-7ffc9faeea78}" partId="{c722bb89-16f8-4866-b115-74c321caf271}" to="{7615ca8a-d9d4-4987-84b1-7c5578ac55f0}"/>
|
<edge from="{bba5b320-733b-44a4-a701-27f12003dde9}" id="{7bf2b03e-1f3f-4578-a7be-7ffc9faeea78}" partId="{37860592-2626-4c6d-8069-349954bda284}" to="{7615ca8a-d9d4-4987-84b1-7c5578ac55f0}"/>
|
||||||
<edge from="{e9fd4236-5ce0-4d2e-8868-d894967fb749}" id="{7cbde8f1-cf0e-4b9e-9e96-ee7a95bb90b7}" partId="{e6fced12-025d-471f-b260-6d7854280682}" to="{7fd2060f-8360-4fb2-a9c9-ba773bcb4fc6}"/>
|
<edge from="{e9fd4236-5ce0-4d2e-8868-d894967fb749}" id="{7cbde8f1-cf0e-4b9e-9e96-ee7a95bb90b7}" partId="{57a41558-46e2-48ce-9f6b-54ada6b2d083}" to="{7fd2060f-8360-4fb2-a9c9-ba773bcb4fc6}"/>
|
||||||
<edge from="{e3deddc7-edcd-4bdf-b0bd-f2d46e8bef63}" id="{7ee05d80-10eb-4057-9899-e80d52ce50d6}" partId="{47d784c2-d5dc-402d-9848-e80e1c03416e}" to="{72a946b4-b2a0-426a-884b-5cf5176f9ece}"/>
|
<edge from="{e3deddc7-edcd-4bdf-b0bd-f2d46e8bef63}" id="{7ee05d80-10eb-4057-9899-e80d52ce50d6}" partId="{76e8af23-9880-458a-8218-ebf61c0ba341}" to="{72a946b4-b2a0-426a-884b-5cf5176f9ece}"/>
|
||||||
<edge from="{e97e7112-dae7-4465-8cb2-d1d66fc81dee}" id="{7fb90996-7133-4748-b958-ecd9b5314179}" partId="{c722bb89-16f8-4866-b115-74c321caf271}" to="{25b71535-a196-49b7-a019-ae08cc75dd60}"/>
|
<edge from="{e97e7112-dae7-4465-8cb2-d1d66fc81dee}" id="{7fb90996-7133-4748-b958-ecd9b5314179}" partId="{37860592-2626-4c6d-8069-349954bda284}" to="{25b71535-a196-49b7-a019-ae08cc75dd60}"/>
|
||||||
<edge from="{1e3e9eb9-ab4c-4b64-97ad-4342d24b02f9}" id="{80ef73f7-7dfa-4bde-808c-b18b4219cf0d}" partId="{c5bd1431-d740-4266-825d-217513f1a1f5}" to="{5526b16b-07a8-44ae-a2a1-23edd995a34e}"/>
|
<edge from="{1e3e9eb9-ab4c-4b64-97ad-4342d24b02f9}" id="{80ef73f7-7dfa-4bde-808c-b18b4219cf0d}" partId="{20fce58c-660f-4e93-b97a-a316d0753042}" to="{5526b16b-07a8-44ae-a2a1-23edd995a34e}"/>
|
||||||
<edge from="{0da7cc8e-dd93-4b86-a305-fe14ae189790}" id="{818c8cca-41c6-4305-90d1-1afa2e52b509}" partId="{c722bb89-16f8-4866-b115-74c321caf271}" to="{bba5b320-733b-44a4-a701-27f12003dde9}"/>
|
<edge from="{0da7cc8e-dd93-4b86-a305-fe14ae189790}" id="{818c8cca-41c6-4305-90d1-1afa2e52b509}" partId="{37860592-2626-4c6d-8069-349954bda284}" to="{bba5b320-733b-44a4-a701-27f12003dde9}"/>
|
||||||
<edge from="{1a732d47-0948-439d-a173-d0129af7644d}" id="{81e64481-ea3f-4ef6-b235-179cc699cfd1}" partId="{a8703d0e-1581-495a-99e0-4507178bf1fa}" to="{2bcb3563-c4d3-40bb-8e49-3afe61da902f}"/>
|
<edge from="{1a732d47-0948-439d-a173-d0129af7644d}" id="{81e64481-ea3f-4ef6-b235-179cc699cfd1}" partId="{3719b667-4110-499d-b78b-4f2ec4e66213}" to="{2bcb3563-c4d3-40bb-8e49-3afe61da902f}"/>
|
||||||
<edge from="{b88113fa-d829-40e0-95ef-0462032ce7b9}" id="{825aa883-9f21-4f59-a825-5e6d1b85c360}" partId="{e6fced12-025d-471f-b260-6d7854280682}" to="{e5361db3-58e4-41af-a955-55010430d3a7}"/>
|
<edge from="{b88113fa-d829-40e0-95ef-0462032ce7b9}" id="{825aa883-9f21-4f59-a825-5e6d1b85c360}" partId="{57a41558-46e2-48ce-9f6b-54ada6b2d083}" to="{e5361db3-58e4-41af-a955-55010430d3a7}"/>
|
||||||
<edge from="{4ff2a8f5-aade-4320-98c5-f78abbf31df0}" id="{8271cc73-9e77-4b65-9192-d025f8db480a}" partId="{0df76de9-fa79-477d-9771-b85378446b3c}" to="{9ba73d77-9c23-40eb-97c3-b6d6c8ebd6d9}"/>
|
<edge from="{4ff2a8f5-aade-4320-98c5-f78abbf31df0}" id="{8271cc73-9e77-4b65-9192-d025f8db480a}" partId="{449d0e15-066f-4780-918a-55978d46ed9d}" to="{9ba73d77-9c23-40eb-97c3-b6d6c8ebd6d9}"/>
|
||||||
<edge from="{7fd2060f-8360-4fb2-a9c9-ba773bcb4fc6}" id="{8357f57c-1e39-4641-92cf-715097acd4d2}" partId="{e6fced12-025d-471f-b260-6d7854280682}" to="{baae591e-9437-454a-ba87-ea28bbde87c9}"/>
|
<edge from="{7fd2060f-8360-4fb2-a9c9-ba773bcb4fc6}" id="{8357f57c-1e39-4641-92cf-715097acd4d2}" partId="{57a41558-46e2-48ce-9f6b-54ada6b2d083}" to="{baae591e-9437-454a-ba87-ea28bbde87c9}"/>
|
||||||
<edge from="{883859a6-0102-4a26-8596-3c47bcaf1970}" id="{83ab6636-39af-445e-a558-8524daa3457e}" partId="{a8703d0e-1581-495a-99e0-4507178bf1fa}" to="{355833f3-bd2d-4508-9293-dbf33c65222b}"/>
|
<edge from="{883859a6-0102-4a26-8596-3c47bcaf1970}" id="{83ab6636-39af-445e-a558-8524daa3457e}" partId="{3719b667-4110-499d-b78b-4f2ec4e66213}" to="{355833f3-bd2d-4508-9293-dbf33c65222b}"/>
|
||||||
<edge from="{06b524b3-b2e5-4e12-993f-497c57aee71e}" id="{8c355a03-2920-42a1-8aeb-3ac4518a14d7}" partId="{0df76de9-fa79-477d-9771-b85378446b3c}" to="{37dc112b-cfb9-4a87-9b82-90a27c9d1518}"/>
|
<edge from="{06b524b3-b2e5-4e12-993f-497c57aee71e}" id="{8c355a03-2920-42a1-8aeb-3ac4518a14d7}" partId="{449d0e15-066f-4780-918a-55978d46ed9d}" to="{37dc112b-cfb9-4a87-9b82-90a27c9d1518}"/>
|
||||||
<edge from="{54127252-0ecb-4a08-84b8-489ce894aebe}" id="{8eee20ef-8b62-468c-891a-48b0da139bda}" partId="{92839eb7-0da2-4905-ae58-a1bb3903f444}" to="{936ea324-7ae0-4fe3-be1c-bc3f43bbcd7b}"/>
|
<edge from="{54127252-0ecb-4a08-84b8-489ce894aebe}" id="{8eee20ef-8b62-468c-891a-48b0da139bda}" partId="{0a233c0a-8ce5-42d3-b720-fb97b63d0e58}" to="{936ea324-7ae0-4fe3-be1c-bc3f43bbcd7b}"/>
|
||||||
<edge from="{7d3f47b9-2de0-46e2-9691-3c7de959777f}" id="{92b04bef-2f8a-4ef0-bba0-52ca298b5515}" partId="{c5bd1431-d740-4266-825d-217513f1a1f5}" to="{1e3e9eb9-ab4c-4b64-97ad-4342d24b02f9}"/>
|
<edge from="{7d3f47b9-2de0-46e2-9691-3c7de959777f}" id="{92b04bef-2f8a-4ef0-bba0-52ca298b5515}" partId="{20fce58c-660f-4e93-b97a-a316d0753042}" to="{1e3e9eb9-ab4c-4b64-97ad-4342d24b02f9}"/>
|
||||||
<edge from="{d46924c8-54d7-4f2b-8376-b5e12a7b535c}" id="{9a89b123-3117-4abd-bf09-556ca6ed70e1}" partId="{92839eb7-0da2-4905-ae58-a1bb3903f444}" to="{ded04835-2d99-46a0-8763-7869526dd8be}"/>
|
<edge from="{d46924c8-54d7-4f2b-8376-b5e12a7b535c}" id="{9a89b123-3117-4abd-bf09-556ca6ed70e1}" partId="{0a233c0a-8ce5-42d3-b720-fb97b63d0e58}" to="{ded04835-2d99-46a0-8763-7869526dd8be}"/>
|
||||||
<edge from="{7f6a90b8-57d3-4319-8bd3-c7c1733f52f5}" id="{9b481d72-e16b-4561-8a61-0c9eedd4195c}" partId="{0df76de9-fa79-477d-9771-b85378446b3c}" to="{67afd8c7-012e-4db6-8de5-b2cb35cfbc50}"/>
|
<edge from="{7f6a90b8-57d3-4319-8bd3-c7c1733f52f5}" id="{9b481d72-e16b-4561-8a61-0c9eedd4195c}" partId="{449d0e15-066f-4780-918a-55978d46ed9d}" to="{67afd8c7-012e-4db6-8de5-b2cb35cfbc50}"/>
|
||||||
<edge from="{2498311b-1a9b-4768-bd9c-e108e4f7a1c8}" id="{9b9f6939-d9c5-495e-832b-6c05563d15c6}" partId="{a8703d0e-1581-495a-99e0-4507178bf1fa}" to="{5f73c8dd-e8c1-484c-af35-5b2789c0582c}"/>
|
<edge from="{2498311b-1a9b-4768-bd9c-e108e4f7a1c8}" id="{9b9f6939-d9c5-495e-832b-6c05563d15c6}" partId="{3719b667-4110-499d-b78b-4f2ec4e66213}" to="{5f73c8dd-e8c1-484c-af35-5b2789c0582c}"/>
|
||||||
<edge from="{2e02275f-8aa2-46f3-ad34-579a63890b17}" id="{9f6e8cb5-6ca9-43cc-90a1-8777c6bc3f4d}" partId="{e6fced12-025d-471f-b260-6d7854280682}" to="{e9fd4236-5ce0-4d2e-8868-d894967fb749}"/>
|
<edge from="{2e02275f-8aa2-46f3-ad34-579a63890b17}" id="{9f6e8cb5-6ca9-43cc-90a1-8777c6bc3f4d}" partId="{57a41558-46e2-48ce-9f6b-54ada6b2d083}" to="{e9fd4236-5ce0-4d2e-8868-d894967fb749}"/>
|
||||||
<edge from="{b0e81284-8fbc-4757-a52e-c485fe57d92c}" id="{a0d3799c-5771-40ea-a082-16eb44484097}" partId="{92839eb7-0da2-4905-ae58-a1bb3903f444}" to="{8da76f01-7c78-4227-a64e-af317cb591d5}"/>
|
<edge from="{b0e81284-8fbc-4757-a52e-c485fe57d92c}" id="{a0d3799c-5771-40ea-a082-16eb44484097}" partId="{0a233c0a-8ce5-42d3-b720-fb97b63d0e58}" to="{8da76f01-7c78-4227-a64e-af317cb591d5}"/>
|
||||||
<edge from="{ec7fe0a0-42da-486a-a46e-6721de480bd4}" id="{a414e67e-32aa-469a-aa0b-6bc9c017914f}" partId="{e6fced12-025d-471f-b260-6d7854280682}" to="{e40576eb-3d06-4c53-8f29-98683f2d7aab}"/>
|
<edge from="{ec7fe0a0-42da-486a-a46e-6721de480bd4}" id="{a414e67e-32aa-469a-aa0b-6bc9c017914f}" partId="{57a41558-46e2-48ce-9f6b-54ada6b2d083}" to="{e40576eb-3d06-4c53-8f29-98683f2d7aab}"/>
|
||||||
<edge from="{6b0da1e9-337b-4cf4-9d08-c2ab19b18c80}" id="{a6bdf02e-8a58-412b-b966-4d7ab5a75c4c}" partId="{47d784c2-d5dc-402d-9848-e80e1c03416e}" to="{e3deddc7-edcd-4bdf-b0bd-f2d46e8bef63}"/>
|
<edge from="{6b0da1e9-337b-4cf4-9d08-c2ab19b18c80}" id="{a6bdf02e-8a58-412b-b966-4d7ab5a75c4c}" partId="{76e8af23-9880-458a-8218-ebf61c0ba341}" to="{e3deddc7-edcd-4bdf-b0bd-f2d46e8bef63}"/>
|
||||||
<edge from="{2dd69178-ccf9-4026-9319-9aebbd4155df}" id="{a8ec6007-46c5-469e-a2a7-8f9e07600769}" partId="{0df76de9-fa79-477d-9771-b85378446b3c}" to="{7af1da13-55ff-4ce7-9fcd-ab9825098cb8}"/>
|
<edge from="{2dd69178-ccf9-4026-9319-9aebbd4155df}" id="{a8ec6007-46c5-469e-a2a7-8f9e07600769}" partId="{449d0e15-066f-4780-918a-55978d46ed9d}" to="{7af1da13-55ff-4ce7-9fcd-ab9825098cb8}"/>
|
||||||
<edge from="{eb75e8d6-9b28-4ec5-afa6-59b006152425}" id="{abeca8a9-6bd4-4b0a-8251-e96bf407048b}" partId="{92839eb7-0da2-4905-ae58-a1bb3903f444}" to="{2ea7a440-8ff5-4143-ab72-ebe178087607}"/>
|
<edge from="{eb75e8d6-9b28-4ec5-afa6-59b006152425}" id="{abeca8a9-6bd4-4b0a-8251-e96bf407048b}" partId="{0a233c0a-8ce5-42d3-b720-fb97b63d0e58}" to="{2ea7a440-8ff5-4143-ab72-ebe178087607}"/>
|
||||||
<edge from="{936ea324-7ae0-4fe3-be1c-bc3f43bbcd7b}" id="{ac022191-87c3-4c7a-a438-116cbbdda637}" partId="{92839eb7-0da2-4905-ae58-a1bb3903f444}" to="{b7527147-9500-4627-8704-5e363c3a2779}"/>
|
<edge from="{936ea324-7ae0-4fe3-be1c-bc3f43bbcd7b}" id="{ac022191-87c3-4c7a-a438-116cbbdda637}" partId="{0a233c0a-8ce5-42d3-b720-fb97b63d0e58}" to="{b7527147-9500-4627-8704-5e363c3a2779}"/>
|
||||||
<edge from="{e274e844-fbf1-47fb-bbec-0504785f3c11}" id="{acf93680-3ad2-401b-b262-c62f7e474f67}" partId="{a8703d0e-1581-495a-99e0-4507178bf1fa}" to="{6c08eb60-5120-4ae2-9854-df02e5ebf9c8}"/>
|
<edge from="{e274e844-fbf1-47fb-bbec-0504785f3c11}" id="{acf93680-3ad2-401b-b262-c62f7e474f67}" partId="{3719b667-4110-499d-b78b-4f2ec4e66213}" to="{6c08eb60-5120-4ae2-9854-df02e5ebf9c8}"/>
|
||||||
<edge from="{4d605b53-37e2-4622-a9df-b457e4b1ae89}" id="{ae82ab35-71da-41c1-8910-04e89d1eb5e9}" partId="{e6fced12-025d-471f-b260-6d7854280682}" to="{ec7fe0a0-42da-486a-a46e-6721de480bd4}"/>
|
<edge from="{4d605b53-37e2-4622-a9df-b457e4b1ae89}" id="{ae82ab35-71da-41c1-8910-04e89d1eb5e9}" partId="{57a41558-46e2-48ce-9f6b-54ada6b2d083}" to="{ec7fe0a0-42da-486a-a46e-6721de480bd4}"/>
|
||||||
<edge from="{05a4fc6a-8e6f-4c0d-a6ca-023ef4bd8d14}" id="{aeb759e3-fa06-494a-8750-51bbf9cd4686}" partId="{e84c3063-265f-4850-9e19-465b84e41118}" to="{fce1e549-0427-4875-800c-6177d0c6d0c1}"/>
|
<edge from="{05a4fc6a-8e6f-4c0d-a6ca-023ef4bd8d14}" id="{aeb759e3-fa06-494a-8750-51bbf9cd4686}" partId="{8689ab0b-3a56-4f01-b72a-0eee032928d4}" to="{fce1e549-0427-4875-800c-6177d0c6d0c1}"/>
|
||||||
<edge from="{180bd087-9aa6-487a-8b50-5f2231539863}" id="{b27a7b36-cd01-4c1d-8498-86160dfc104e}" partId="{92839eb7-0da2-4905-ae58-a1bb3903f444}" to="{bff67e53-359b-4e50-bafb-dcc9dd84f4ec}"/>
|
<edge from="{180bd087-9aa6-487a-8b50-5f2231539863}" id="{b27a7b36-cd01-4c1d-8498-86160dfc104e}" partId="{0a233c0a-8ce5-42d3-b720-fb97b63d0e58}" to="{bff67e53-359b-4e50-bafb-dcc9dd84f4ec}"/>
|
||||||
<edge from="{d884eda9-29ca-41ab-8a45-3995c8058549}" id="{b28f37c3-86c7-41cc-bf50-1abfdd047230}" partId="{e6fced12-025d-471f-b260-6d7854280682}" to="{b88113fa-d829-40e0-95ef-0462032ce7b9}"/>
|
<edge from="{d884eda9-29ca-41ab-8a45-3995c8058549}" id="{b28f37c3-86c7-41cc-bf50-1abfdd047230}" partId="{57a41558-46e2-48ce-9f6b-54ada6b2d083}" to="{b88113fa-d829-40e0-95ef-0462032ce7b9}"/>
|
||||||
<edge from="{fe1bb602-5c84-4e9f-89e6-2fc993fc3263}" id="{b571a73e-6106-4568-aac8-89a04bfd56d0}" partId="{6df97180-d57c-46b3-8f96-4173b69abbc5}" to="{31ccee3b-ba23-4294-ae81-6f6b34f1ed5d}"/>
|
<edge from="{fe1bb602-5c84-4e9f-89e6-2fc993fc3263}" id="{b571a73e-6106-4568-aac8-89a04bfd56d0}" partId="{0b0f5c6e-94d4-4c8e-9997-052a70fa3720}" to="{31ccee3b-ba23-4294-ae81-6f6b34f1ed5d}"/>
|
||||||
<edge from="{350d2902-c60e-4cba-a10c-d000ecba47ad}" id="{b75865bf-917f-4555-9089-3337cb56a5a4}" partId="{c5bd1431-d740-4266-825d-217513f1a1f5}" to="{d71693ae-f238-4bd3-881e-bcdee119c22c}"/>
|
<edge from="{350d2902-c60e-4cba-a10c-d000ecba47ad}" id="{b75865bf-917f-4555-9089-3337cb56a5a4}" partId="{20fce58c-660f-4e93-b97a-a316d0753042}" to="{d71693ae-f238-4bd3-881e-bcdee119c22c}"/>
|
||||||
<edge from="{6b2b333d-2abf-4d6e-8957-7a848c46e651}" id="{b8b4db97-0620-4f9e-ad9b-febcd68bc3a2}" partId="{a8703d0e-1581-495a-99e0-4507178bf1fa}" to="{7cfbf2a4-3d92-4357-8644-4e195dfac673}"/>
|
<edge from="{6b2b333d-2abf-4d6e-8957-7a848c46e651}" id="{b8b4db97-0620-4f9e-ad9b-febcd68bc3a2}" partId="{3719b667-4110-499d-b78b-4f2ec4e66213}" to="{7cfbf2a4-3d92-4357-8644-4e195dfac673}"/>
|
||||||
<edge from="{8da76f01-7c78-4227-a64e-af317cb591d5}" id="{ba3022d3-0ac2-4b38-bac2-40d43337ade9}" partId="{92839eb7-0da2-4905-ae58-a1bb3903f444}" to="{d46924c8-54d7-4f2b-8376-b5e12a7b535c}"/>
|
<edge from="{8da76f01-7c78-4227-a64e-af317cb591d5}" id="{ba3022d3-0ac2-4b38-bac2-40d43337ade9}" partId="{0a233c0a-8ce5-42d3-b720-fb97b63d0e58}" to="{d46924c8-54d7-4f2b-8376-b5e12a7b535c}"/>
|
||||||
<edge from="{e40576eb-3d06-4c53-8f29-98683f2d7aab}" id="{bc36eb75-79af-4854-90a8-40cf4ce00ef2}" partId="{e6fced12-025d-471f-b260-6d7854280682}" to="{d884eda9-29ca-41ab-8a45-3995c8058549}"/>
|
<edge from="{e40576eb-3d06-4c53-8f29-98683f2d7aab}" id="{bc36eb75-79af-4854-90a8-40cf4ce00ef2}" partId="{57a41558-46e2-48ce-9f6b-54ada6b2d083}" to="{d884eda9-29ca-41ab-8a45-3995c8058549}"/>
|
||||||
<edge from="{d6fd2f1a-7c90-4c62-82be-1eeb781c5847}" id="{be5ad665-f8a3-4759-a292-5c7ce7c36379}" partId="{6df97180-d57c-46b3-8f96-4173b69abbc5}" to="{c0000c88-edd1-46ca-b57b-9dc6874f72eb}"/>
|
<edge from="{d6fd2f1a-7c90-4c62-82be-1eeb781c5847}" id="{be5ad665-f8a3-4759-a292-5c7ce7c36379}" partId="{0b0f5c6e-94d4-4c8e-9997-052a70fa3720}" to="{c0000c88-edd1-46ca-b57b-9dc6874f72eb}"/>
|
||||||
<edge from="{6c08eb60-5120-4ae2-9854-df02e5ebf9c8}" id="{c0dcff73-1887-4b09-b84b-8c2d73f7ba88}" partId="{a8703d0e-1581-495a-99e0-4507178bf1fa}" to="{fc6e43f7-ba5d-4aec-8307-c2cba3b60d25}"/>
|
<edge from="{6c08eb60-5120-4ae2-9854-df02e5ebf9c8}" id="{c0dcff73-1887-4b09-b84b-8c2d73f7ba88}" partId="{3719b667-4110-499d-b78b-4f2ec4e66213}" to="{fc6e43f7-ba5d-4aec-8307-c2cba3b60d25}"/>
|
||||||
<edge from="{b7527147-9500-4627-8704-5e363c3a2779}" id="{c3d0ce6d-956a-4400-b24b-aae9864b13fb}" partId="{92839eb7-0da2-4905-ae58-a1bb3903f444}" to="{180bd087-9aa6-487a-8b50-5f2231539863}"/>
|
<edge from="{b7527147-9500-4627-8704-5e363c3a2779}" id="{c3d0ce6d-956a-4400-b24b-aae9864b13fb}" partId="{0a233c0a-8ce5-42d3-b720-fb97b63d0e58}" to="{180bd087-9aa6-487a-8b50-5f2231539863}"/>
|
||||||
<edge from="{cda8ff54-1879-450f-8af9-a118ff6bfd7f}" id="{c6f54f48-0c1b-4ced-96c2-0643d36f751d}" partId="{0df76de9-fa79-477d-9771-b85378446b3c}" to="{4ff2a8f5-aade-4320-98c5-f78abbf31df0}"/>
|
<edge from="{cda8ff54-1879-450f-8af9-a118ff6bfd7f}" id="{c6f54f48-0c1b-4ced-96c2-0643d36f751d}" partId="{449d0e15-066f-4780-918a-55978d46ed9d}" to="{4ff2a8f5-aade-4320-98c5-f78abbf31df0}"/>
|
||||||
<edge from="{59c85ebe-b47b-4d4b-b40a-9bb0ed434914}" id="{c9bec503-da68-4899-b137-05802372eb5d}" partId="{c722bb89-16f8-4866-b115-74c321caf271}" to="{e97e7112-dae7-4465-8cb2-d1d66fc81dee}"/>
|
<edge from="{59c85ebe-b47b-4d4b-b40a-9bb0ed434914}" id="{c9bec503-da68-4899-b137-05802372eb5d}" partId="{37860592-2626-4c6d-8069-349954bda284}" to="{e97e7112-dae7-4465-8cb2-d1d66fc81dee}"/>
|
||||||
<edge from="{a2b78111-e6f4-4389-b7ed-4ba0a55599e8}" id="{c9c18f11-be89-4d07-bd5d-bc61b240f6e3}" partId="{92839eb7-0da2-4905-ae58-a1bb3903f444}" to="{eb75e8d6-9b28-4ec5-afa6-59b006152425}"/>
|
<edge from="{a2b78111-e6f4-4389-b7ed-4ba0a55599e8}" id="{c9c18f11-be89-4d07-bd5d-bc61b240f6e3}" partId="{0a233c0a-8ce5-42d3-b720-fb97b63d0e58}" to="{eb75e8d6-9b28-4ec5-afa6-59b006152425}"/>
|
||||||
<edge from="{5526b16b-07a8-44ae-a2a1-23edd995a34e}" id="{cffc683c-b686-456e-8256-9715cc3af11c}" partId="{c5bd1431-d740-4266-825d-217513f1a1f5}" to="{4ab72941-0a5e-442f-919f-aff60341427b}"/>
|
<edge from="{5526b16b-07a8-44ae-a2a1-23edd995a34e}" id="{cffc683c-b686-456e-8256-9715cc3af11c}" partId="{20fce58c-660f-4e93-b97a-a316d0753042}" to="{4ab72941-0a5e-442f-919f-aff60341427b}"/>
|
||||||
<edge from="{ca57c536-2786-4b36-a3d9-9590b9658843}" id="{d2d11141-a91c-4c23-a406-b2702e56aa2e}" partId="{c5bd1431-d740-4266-825d-217513f1a1f5}" to="{c03f9808-ad09-4e34-8683-225be168d659}"/>
|
<edge from="{ca57c536-2786-4b36-a3d9-9590b9658843}" id="{d2d11141-a91c-4c23-a406-b2702e56aa2e}" partId="{20fce58c-660f-4e93-b97a-a316d0753042}" to="{c03f9808-ad09-4e34-8683-225be168d659}"/>
|
||||||
<edge from="{c41b7308-14bf-4950-b2ba-2775199a92e0}" id="{d3cbd72b-29d6-4e5a-990e-60308c700dcb}" partId="{c5bd1431-d740-4266-825d-217513f1a1f5}" to="{ca57c536-2786-4b36-a3d9-9590b9658843}"/>
|
<edge from="{c41b7308-14bf-4950-b2ba-2775199a92e0}" id="{d3cbd72b-29d6-4e5a-990e-60308c700dcb}" partId="{20fce58c-660f-4e93-b97a-a316d0753042}" to="{ca57c536-2786-4b36-a3d9-9590b9658843}"/>
|
||||||
<edge from="{03ff6913-45f1-4508-a39f-3842694cb9f7}" id="{d8cea11e-3a2f-4665-aba1-c2f735fafe4f}" partId="{c722bb89-16f8-4866-b115-74c321caf271}" to="{b7c80ca9-246f-4b6f-84cb-c3642691cf76}"/>
|
<edge from="{03ff6913-45f1-4508-a39f-3842694cb9f7}" id="{d8cea11e-3a2f-4665-aba1-c2f735fafe4f}" partId="{37860592-2626-4c6d-8069-349954bda284}" to="{b7c80ca9-246f-4b6f-84cb-c3642691cf76}"/>
|
||||||
<edge from="{021f7f20-d1c4-4b79-94ef-25ecf621ee0c}" id="{e1295617-c398-44dd-9f3e-3642bd5b4fd0}" partId="{0df76de9-fa79-477d-9771-b85378446b3c}" to="{06b524b3-b2e5-4e12-993f-497c57aee71e}"/>
|
<edge from="{021f7f20-d1c4-4b79-94ef-25ecf621ee0c}" id="{e1295617-c398-44dd-9f3e-3642bd5b4fd0}" partId="{449d0e15-066f-4780-918a-55978d46ed9d}" to="{06b524b3-b2e5-4e12-993f-497c57aee71e}"/>
|
||||||
<edge from="{bff67e53-359b-4e50-bafb-dcc9dd84f4ec}" id="{e909cd44-983d-48f6-84be-b72a9da90e23}" partId="{92839eb7-0da2-4905-ae58-a1bb3903f444}" to="{b0e81284-8fbc-4757-a52e-c485fe57d92c}"/>
|
<edge from="{bff67e53-359b-4e50-bafb-dcc9dd84f4ec}" id="{e909cd44-983d-48f6-84be-b72a9da90e23}" partId="{0a233c0a-8ce5-42d3-b720-fb97b63d0e58}" to="{b0e81284-8fbc-4757-a52e-c485fe57d92c}"/>
|
||||||
<edge from="{6281b6cb-d0ae-43b2-b124-26fcedacf472}" id="{ea5ff8b9-9072-4597-a0be-590bda826036}" partId="{c5bd1431-d740-4266-825d-217513f1a1f5}" to="{71ea7967-b59e-4507-bf55-225882ecbba5}"/>
|
<edge from="{6281b6cb-d0ae-43b2-b124-26fcedacf472}" id="{ea5ff8b9-9072-4597-a0be-590bda826036}" partId="{20fce58c-660f-4e93-b97a-a316d0753042}" to="{71ea7967-b59e-4507-bf55-225882ecbba5}"/>
|
||||||
<edge from="{7af1da13-55ff-4ce7-9fcd-ab9825098cb8}" id="{ed5751b8-c5c9-45fb-9d36-59bf1acd46ba}" partId="{0df76de9-fa79-477d-9771-b85378446b3c}" to="{e5d65034-602c-4336-a919-b4a8ff8fc68f}"/>
|
<edge from="{7af1da13-55ff-4ce7-9fcd-ab9825098cb8}" id="{ed5751b8-c5c9-45fb-9d36-59bf1acd46ba}" partId="{449d0e15-066f-4780-918a-55978d46ed9d}" to="{e5d65034-602c-4336-a919-b4a8ff8fc68f}"/>
|
||||||
<edge from="{d32e752f-fdd0-4ccc-8558-f341ceef5f91}" id="{ed7f4d40-55fb-4905-8e21-e1926963be4a}" partId="{6df97180-d57c-46b3-8f96-4173b69abbc5}" to="{797ac170-8b69-423e-8ca5-acb7217188be}"/>
|
<edge from="{d32e752f-fdd0-4ccc-8558-f341ceef5f91}" id="{ed7f4d40-55fb-4905-8e21-e1926963be4a}" partId="{0b0f5c6e-94d4-4c8e-9997-052a70fa3720}" to="{797ac170-8b69-423e-8ca5-acb7217188be}"/>
|
||||||
<edge from="{9ba73d77-9c23-40eb-97c3-b6d6c8ebd6d9}" id="{ee60e02e-74aa-4225-a2ce-e5c7640810b8}" partId="{0df76de9-fa79-477d-9771-b85378446b3c}" to="{7f6a90b8-57d3-4319-8bd3-c7c1733f52f5}"/>
|
<edge from="{9ba73d77-9c23-40eb-97c3-b6d6c8ebd6d9}" id="{ee60e02e-74aa-4225-a2ce-e5c7640810b8}" partId="{449d0e15-066f-4780-918a-55978d46ed9d}" to="{7f6a90b8-57d3-4319-8bd3-c7c1733f52f5}"/>
|
||||||
<edge from="{c6050850-281f-41f3-b736-c734179996c3}" id="{ef205344-30a5-4074-be1d-c84101ed974d}" partId="{6df97180-d57c-46b3-8f96-4173b69abbc5}" to="{d32e752f-fdd0-4ccc-8558-f341ceef5f91}"/>
|
<edge from="{c6050850-281f-41f3-b736-c734179996c3}" id="{ef205344-30a5-4074-be1d-c84101ed974d}" partId="{0b0f5c6e-94d4-4c8e-9997-052a70fa3720}" to="{d32e752f-fdd0-4ccc-8558-f341ceef5f91}"/>
|
||||||
<edge from="{71ea7967-b59e-4507-bf55-225882ecbba5}" id="{f345a9c6-b8cf-47b6-85fb-b8e2453e4ba2}" partId="{c5bd1431-d740-4266-825d-217513f1a1f5}" to="{4c9ba403-391c-4903-a8ba-0ff250713286}"/>
|
<edge from="{71ea7967-b59e-4507-bf55-225882ecbba5}" id="{f345a9c6-b8cf-47b6-85fb-b8e2453e4ba2}" partId="{20fce58c-660f-4e93-b97a-a316d0753042}" to="{4c9ba403-391c-4903-a8ba-0ff250713286}"/>
|
||||||
<edge from="{84c39fc7-a579-453f-b2d2-3872af219174}" id="{f66a4dd5-23ae-4b98-94ac-516c55097579}" partId="{6df97180-d57c-46b3-8f96-4173b69abbc5}" to="{bcb2d6a7-7a55-424a-84a9-ef7ba7e42731}"/>
|
<edge from="{84c39fc7-a579-453f-b2d2-3872af219174}" id="{f66a4dd5-23ae-4b98-94ac-516c55097579}" partId="{0b0f5c6e-94d4-4c8e-9997-052a70fa3720}" to="{bcb2d6a7-7a55-424a-84a9-ef7ba7e42731}"/>
|
||||||
<edge from="{7615ca8a-d9d4-4987-84b1-7c5578ac55f0}" id="{f6792241-1cb0-4dca-83f5-196104a5e084}" partId="{c722bb89-16f8-4866-b115-74c321caf271}" to="{b10279cc-27c0-470f-8614-72a45ad74fb2}"/>
|
<edge from="{7615ca8a-d9d4-4987-84b1-7c5578ac55f0}" id="{f6792241-1cb0-4dca-83f5-196104a5e084}" partId="{37860592-2626-4c6d-8069-349954bda284}" to="{b10279cc-27c0-470f-8614-72a45ad74fb2}"/>
|
||||||
<edge from="{7cfbf2a4-3d92-4357-8644-4e195dfac673}" id="{f94b58a6-5da2-41cc-9d4b-fd636f830ac3}" partId="{a8703d0e-1581-495a-99e0-4507178bf1fa}" to="{883859a6-0102-4a26-8596-3c47bcaf1970}"/>
|
<edge from="{7cfbf2a4-3d92-4357-8644-4e195dfac673}" id="{f94b58a6-5da2-41cc-9d4b-fd636f830ac3}" partId="{3719b667-4110-499d-b78b-4f2ec4e66213}" to="{883859a6-0102-4a26-8596-3c47bcaf1970}"/>
|
||||||
<edge from="{4ab72941-0a5e-442f-919f-aff60341427b}" id="{fa298da1-3ba9-4a3c-9b10-48592e3adecf}" partId="{c5bd1431-d740-4266-825d-217513f1a1f5}" to="{350d2902-c60e-4cba-a10c-d000ecba47ad}"/>
|
<edge from="{4ab72941-0a5e-442f-919f-aff60341427b}" id="{fa298da1-3ba9-4a3c-9b10-48592e3adecf}" partId="{20fce58c-660f-4e93-b97a-a316d0753042}" to="{350d2902-c60e-4cba-a10c-d000ecba47ad}"/>
|
||||||
<edge from="{25b71535-a196-49b7-a019-ae08cc75dd60}" id="{fc3465c1-148c-4933-b1d3-fd3779f5a79c}" partId="{c722bb89-16f8-4866-b115-74c321caf271}" to="{0da7cc8e-dd93-4b86-a305-fe14ae189790}"/>
|
<edge from="{25b71535-a196-49b7-a019-ae08cc75dd60}" id="{fc3465c1-148c-4933-b1d3-fd3779f5a79c}" partId="{37860592-2626-4c6d-8069-349954bda284}" to="{0da7cc8e-dd93-4b86-a305-fe14ae189790}"/>
|
||||||
<edge from="{259237a6-bac4-4a79-aa57-a74d357feff2}" id="{fc8d90fd-2e16-44e5-9aef-95836cb57abe}" partId="{c722bb89-16f8-4866-b115-74c321caf271}" to="{734b73e6-9175-42d8-8ffe-057b933bc666}"/>
|
<edge from="{259237a6-bac4-4a79-aa57-a74d357feff2}" id="{fc8d90fd-2e16-44e5-9aef-95836cb57abe}" partId="{37860592-2626-4c6d-8069-349954bda284}" to="{734b73e6-9175-42d8-8ffe-057b933bc666}"/>
|
||||||
<edge from="{dd48d6f8-0172-4886-a11a-6c9f36444be5}" id="{fd138d2f-058c-44af-950d-6c8d8ff02597}" partId="{c5bd1431-d740-4266-825d-217513f1a1f5}" to="{6281b6cb-d0ae-43b2-b124-26fcedacf472}"/>
|
<edge from="{dd48d6f8-0172-4886-a11a-6c9f36444be5}" id="{fd138d2f-058c-44af-950d-6c8d8ff02597}" partId="{20fce58c-660f-4e93-b97a-a316d0753042}" to="{6281b6cb-d0ae-43b2-b124-26fcedacf472}"/>
|
||||||
<edge from="{a459f13d-414a-454f-8739-97ddba88d0ad}" id="{fdebed2f-479c-46eb-90a3-9c450383dba6}" partId="{6df97180-d57c-46b3-8f96-4173b69abbc5}" to="{c6050850-281f-41f3-b736-c734179996c3}"/>
|
<edge from="{a459f13d-414a-454f-8739-97ddba88d0ad}" id="{fdebed2f-479c-46eb-90a3-9c450383dba6}" partId="{0b0f5c6e-94d4-4c8e-9997-052a70fa3720}" to="{c6050850-281f-41f3-b736-c734179996c3}"/>
|
||||||
</edges>
|
</edges>
|
||||||
<parts>
|
<parts>
|
||||||
<part chamfered="false" color="#ffe0d6cc" countershaded="true" deformThickness="0.9" disabled="false" id="{0df76de9-fa79-477d-9771-b85378446b3c}" locked="false" rounded="true" subdived="true" visible="true" xMirrored="false"/>
|
<part chamfered="false" color="#ffe0d6cc" deformWidth="0.84" disabled="false" id="{0a233c0a-8ce5-42d3-b720-fb97b63d0e58}" locked="false" rounded="true" subdived="true" visible="true" xMirrored="false"/>
|
||||||
<part chamfered="false" color="#ffe0d6cc" disabled="false" id="{47d784c2-d5dc-402d-9848-e80e1c03416e}" locked="false" rounded="false" subdived="false" visible="true" xMirrored="true"/>
|
<part chamfered="false" color="#ffa19274" deformWidth="0.78" disabled="false" id="{0b0f5c6e-94d4-4c8e-9997-052a70fa3720}" locked="false" rounded="true" subdived="false" visible="true" xMirrored="true"/>
|
||||||
<part chamfered="false" color="#ffa19274" deformWidth="0.78" disabled="false" id="{6df97180-d57c-46b3-8f96-4173b69abbc5}" locked="false" rounded="true" subdived="false" visible="true" xMirrored="true"/>
|
<part chamfered="false" color="#ffe0d6cc" deformWidth="0.78" disabled="false" id="{20fce58c-660f-4e93-b97a-a316d0753042}" locked="false" rounded="true" subdived="true" visible="true" xMirrored="false"/>
|
||||||
<part chamfered="false" color="#ffe0d6cc" deformWidth="0.84" disabled="false" id="{92839eb7-0da2-4905-ae58-a1bb3903f444}" locked="false" rounded="true" subdived="true" visible="true" xMirrored="false"/>
|
<part chamfered="false" color="#ffe0d6cc" disabled="false" id="{3719b667-4110-499d-b78b-4f2ec4e66213}" locked="false" rounded="true" subdived="false" visible="true" xMirrored="false"/>
|
||||||
<part chamfered="false" color="#ffe0d6cc" disabled="false" id="{a8703d0e-1581-495a-99e0-4507178bf1fa}" locked="false" rounded="true" subdived="false" visible="true" xMirrored="false"/>
|
<part base="YZ" chamfered="false" color="#ffe0d6cc" deformThickness="0.67" disabled="false" id="{37860592-2626-4c6d-8069-349954bda284}" locked="false" rounded="true" subdived="true" visible="true" xMirrored="false"/>
|
||||||
<part chamfered="false" color="#ffe0d6cc" deformWidth="0.78" disabled="false" id="{c5bd1431-d740-4266-825d-217513f1a1f5}" locked="false" rounded="true" subdived="true" visible="true" xMirrored="false"/>
|
<part chamfered="false" color="#ffe0d6cc" countershaded="true" deformThickness="0.9" disabled="false" id="{449d0e15-066f-4780-918a-55978d46ed9d}" locked="false" rounded="true" subdived="true" visible="true" xMirrored="false"/>
|
||||||
<part chamfered="false" color="#ffe0d6cc" deformThickness="0.67" disabled="false" id="{c722bb89-16f8-4866-b115-74c321caf271}" locked="false" rounded="true" subdived="true" visible="true" xMirrored="false"/>
|
<part chamfered="false" color="#ffe0d6cc" deformWidth="0.84" disabled="false" id="{57a41558-46e2-48ce-9f6b-54ada6b2d083}" locked="false" rounded="true" subdived="true" visible="true" xMirrored="false"/>
|
||||||
<part chamfered="false" color="#ffe0d6cc" deformWidth="0.84" disabled="false" id="{e6fced12-025d-471f-b260-6d7854280682}" locked="false" rounded="true" subdived="true" visible="true" xMirrored="false"/>
|
<part chamfered="false" color="#ffe0d6cc" disabled="false" id="{76e8af23-9880-458a-8218-ebf61c0ba341}" locked="false" rounded="false" subdived="false" visible="true" xMirrored="true"/>
|
||||||
<part chamfered="false" color="#ff675e4c" disabled="false" id="{e84c3063-265f-4850-9e19-465b84e41118}" locked="false" rounded="false" subdived="false" visible="true" xMirrored="true"/>
|
<part chamfered="false" color="#ff675e4c" disabled="false" id="{8689ab0b-3a56-4f01-b72a-0eee032928d4}" locked="false" rounded="false" subdived="false" visible="true" xMirrored="true"/>
|
||||||
</parts>
|
</parts>
|
||||||
<components>
|
<components>
|
||||||
<component combineMode="Normal" expanded="false" id="{ff328100-3815-472c-80ba-0aeed815ba5f}" linkData="{0df76de9-fa79-477d-9771-b85378446b3c}" linkDataType="partId"/>
|
<component combineMode="Normal" expanded="false" id="{19e6614b-a56f-49fa-9387-8b3d49379d95}" linkData="{449d0e15-066f-4780-918a-55978d46ed9d}" linkDataType="partId"/>
|
||||||
<component combineMode="Normal" expanded="false" id="{b5bf0500-8c5a-4033-990c-4fe46ba37210}" linkData="{6df97180-d57c-46b3-8f96-4173b69abbc5}" linkDataType="partId"/>
|
<component combineMode="Normal" expanded="false" id="{6093e8bc-9a95-4f30-ac61-b6b84a117a61}" linkData="{0b0f5c6e-94d4-4c8e-9997-052a70fa3720}" linkDataType="partId"/>
|
||||||
<component combineMode="Normal" expanded="false" id="{9bca00cb-3f47-4675-a94f-23b243ba31f8}" linkData="{a8703d0e-1581-495a-99e0-4507178bf1fa}" linkDataType="partId"/>
|
<component combineMode="Normal" expanded="false" id="{33a056aa-596d-49a0-b9b0-168b3245c3bd}" linkData="{3719b667-4110-499d-b78b-4f2ec4e66213}" linkDataType="partId"/>
|
||||||
<component combineMode="Normal" expanded="false" id="{5f6bab49-2b71-4216-ab35-6b4354b00d01}" linkData="{c722bb89-16f8-4866-b115-74c321caf271}" linkDataType="partId"/>
|
<component combineMode="Normal" expanded="false" id="{1d8b664b-651f-49b3-8210-db55dc5021be}" linkData="{37860592-2626-4c6d-8069-349954bda284}" linkDataType="partId"/>
|
||||||
<component combineMode="Normal" expanded="false" id="{b1737790-b19e-4165-bcf4-faa061a6e7ba}" linkData="{c5bd1431-d740-4266-825d-217513f1a1f5}" linkDataType="partId"/>
|
<component combineMode="Normal" expanded="false" id="{070e4698-1cdf-454e-91d9-c8ffcf775e80}" linkData="{20fce58c-660f-4e93-b97a-a316d0753042}" linkDataType="partId"/>
|
||||||
<component combineMode="Normal" expanded="false" id="{ef2e2f92-6443-4836-9b87-4a812814a68f}" linkData="{47d784c2-d5dc-402d-9848-e80e1c03416e}" linkDataType="partId"/>
|
<component combineMode="Normal" expanded="false" id="{6b029d28-9104-406c-a737-a5c554de71b1}" linkData="{76e8af23-9880-458a-8218-ebf61c0ba341}" linkDataType="partId"/>
|
||||||
<component combineMode="Normal" expanded="false" id="{4f104e42-4d09-4efb-ab6b-61739b831588}" linkData="{92839eb7-0da2-4905-ae58-a1bb3903f444}" linkDataType="partId"/>
|
<component combineMode="Normal" expanded="false" id="{cc087c8e-ef7d-454f-806b-3e1c35099274}" linkData="{0a233c0a-8ce5-42d3-b720-fb97b63d0e58}" linkDataType="partId"/>
|
||||||
<component combineMode="Normal" expanded="false" id="{1c8d6af8-a290-452e-9e87-cd401f0d8e81}" linkData="{e6fced12-025d-471f-b260-6d7854280682}" linkDataType="partId"/>
|
<component combineMode="Normal" expanded="false" id="{0d66852f-0a5b-4a53-8b20-ff0d46829e51}" linkData="{57a41558-46e2-48ce-9f6b-54ada6b2d083}" linkDataType="partId"/>
|
||||||
<component combineMode="Inversion" expanded="false" id="{29da2789-fc49-4eb9-93df-f92b395394e3}" linkData="{e84c3063-265f-4850-9e19-465b84e41118}" linkDataType="partId"/>
|
<component combineMode="Inversion" expanded="false" id="{a5aa1b28-5d78-404e-b8b9-2d115a9859ee}" linkData="{8689ab0b-3a56-4f01-b72a-0eee032928d4}" linkDataType="partId"/>
|
||||||
</components>
|
</components>
|
||||||
<materials/>
|
<materials/>
|
||||||
<poses/>
|
<poses/>
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -7,234 +7,234 @@ DUST3D 1.0 xml 0000000193
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<canvas originX="0.293069" originY="0.623762" originZ="1.20693" polyCount="TremendouslyHighPoly" rigType="Animal">
|
<canvas originX="0.293069" originY="0.623762" originZ="1.20693" polyCount="TremendouslyHighPoly" rigType="Animal">
|
||||||
<nodes>
|
<nodes>
|
||||||
<node id="{00da2bf5-53b1-495b-8f56-aaf78e74e9c2}" partId="{57622c57-5929-4a6a-b4ac-17dc909f002a}" radius="0.019802" x="0.293069" y="0.849505" z="1.45743"/>
|
<node id="{00da2bf5-53b1-495b-8f56-aaf78e74e9c2}" partId="{0a57548e-12d8-4488-9ce4-8fe3b64db253}" radius="0.019802" x="0.293069" y="0.849505" z="1.45743"/>
|
||||||
<node id="{0369aab4-b9b7-4d53-bc43-118f226dadc9}" partId="{019249f8-0f48-4f9e-87e3-6d2e821e87ac}" radius="0.00594061" x="0.10792" y="0.940163" z="1.2098"/>
|
<node id="{0369aab4-b9b7-4d53-bc43-118f226dadc9}" partId="{65aa6ccd-94db-47cf-aa84-dce3c2b3fa65}" radius="0.00594061" x="0.10792" y="0.940163" z="1.2098"/>
|
||||||
<node id="{05872b14-1e9a-4ba9-bbf8-0111c9100527}" partId="{dd604661-6acc-4ef1-83fc-36a374c54734}" radius="0.0118812" x="0.368776" y="0.121915" z="1.19315"/>
|
<node id="{05872b14-1e9a-4ba9-bbf8-0111c9100527}" partId="{ff29229a-564e-4e50-af37-0ae6c25b78ae}" radius="0.0118812" x="0.368776" y="0.121915" z="1.19315"/>
|
||||||
<node id="{0891b311-79de-4ed7-8410-b3e43e675a9b}" partId="{ad2259a2-362c-499e-9123-d6f8ac0a1966}" radius="0.0910891" x="0.29505" y="0.382178" z="1.17822"/>
|
<node id="{0891b311-79de-4ed7-8410-b3e43e675a9b}" partId="{422ad92f-8ad5-402a-9629-2348eb14e103}" radius="0.0910891" x="0.29505" y="0.382178" z="1.17822"/>
|
||||||
<node boneMark="Limb" id="{08f7ae7b-869a-4f40-87a4-a575d78c2a60}" partId="{b27111c8-625f-405d-88a9-55df58d51de0}" radius="0.0594059" x="0.427115" y="0.655402" z="1.22574"/>
|
<node boneMark="Limb" id="{08f7ae7b-869a-4f40-87a4-a575d78c2a60}" partId="{5f080e1f-48f5-4aa7-aa0c-d175f9045341}" radius="0.0594059" x="0.427115" y="0.655402" z="1.22574"/>
|
||||||
<node id="{0cecd379-b9d6-4568-9d5b-82720916a6e4}" partId="{0b8f8da9-d461-48c4-bbfd-343f0b648235}" radius="0.0118812" x="0.459895" y="0.514042" z="1.06634"/>
|
<node id="{0cecd379-b9d6-4568-9d5b-82720916a6e4}" partId="{0048f320-55a9-4777-914e-95944cb34b46}" radius="0.0118812" x="0.459895" y="0.514042" z="1.06634"/>
|
||||||
<node boneMark="Joint" id="{13bc43e1-b35e-4645-8fd5-e9e8b16d5fc8}" partId="{881a0adc-3b0d-4575-b7d7-d6df8907e3f3}" radius="0.0594059" x="0.128121" y="0.759157" z="1.18614"/>
|
<node boneMark="Joint" id="{13bc43e1-b35e-4645-8fd5-e9e8b16d5fc8}" partId="{79289522-791a-488f-bd2d-15db6c8f2f84}" radius="0.0594059" x="0.128121" y="0.759157" z="1.18614"/>
|
||||||
<node id="{13d47f89-649c-4830-ba6d-fbf7f132793e}" partId="{9fae01c2-855a-472b-8181-02a1b76fcab1}" radius="0.0079208" x="0.13613" y="0.495533" z="1.0901"/>
|
<node id="{13d47f89-649c-4830-ba6d-fbf7f132793e}" partId="{b6e20100-8c2b-4550-aee8-806aa713c90c}" radius="0.0079208" x="0.13613" y="0.495533" z="1.0901"/>
|
||||||
<node id="{1e7e802c-3711-40c8-9dd6-bcded439cffe}" partId="{a5ad3f64-2091-4cea-8085-e17881f0573d}" radius="0.0079208" x="0.468977" y="0.966347" z="1.19721"/>
|
<node id="{1e7e802c-3711-40c8-9dd6-bcded439cffe}" partId="{cef2d5ce-ed55-4030-a415-e39a20d3ff86}" radius="0.0079208" x="0.468977" y="0.966347" z="1.19721"/>
|
||||||
<node id="{2073cdb1-77ef-4c51-8ca0-4ad4e0908d6c}" partId="{b27111c8-625f-405d-88a9-55df58d51de0}" radius="0.019802" x="0.454833" y="0.953807" z="1.2099"/>
|
<node id="{2073cdb1-77ef-4c51-8ca0-4ad4e0908d6c}" partId="{5f080e1f-48f5-4aa7-aa0c-d175f9045341}" radius="0.019802" x="0.454833" y="0.953807" z="1.2099"/>
|
||||||
<node boneMark="Limb" id="{22f4fc91-c657-497f-aef8-87d38a42e23f}" partId="{d5ccb7d6-3357-473c-a26a-12ce5713d92e}" radius="0.0316832" x="0.165992" y="0.30808" z="1.19516"/>
|
<node boneMark="Limb" id="{22f4fc91-c657-497f-aef8-87d38a42e23f}" partId="{9c9383da-b1ad-4fed-ac7d-e65d9334882f}" radius="0.0316832" x="0.165992" y="0.30808" z="1.19516"/>
|
||||||
<node boneMark="Joint" id="{25b52681-7ee3-458e-8db2-bf784e1c101d}" partId="{b27111c8-625f-405d-88a9-55df58d51de0}" radius="0.019802" x="0.398712" y="0.903059" z="1.23366"/>
|
<node boneMark="Joint" id="{25b52681-7ee3-458e-8db2-bf784e1c101d}" partId="{5f080e1f-48f5-4aa7-aa0c-d175f9045341}" radius="0.019802" x="0.398712" y="0.903059" z="1.23366"/>
|
||||||
<node id="{25e5be7a-dbb8-4d8f-a0b7-441eef6c694f}" partId="{d5ccb7d6-3357-473c-a26a-12ce5713d92e}" radius="0.039604" x="0.259919" y="0.25653" z="1.19061"/>
|
<node id="{25e5be7a-dbb8-4d8f-a0b7-441eef6c694f}" partId="{9c9383da-b1ad-4fed-ac7d-e65d9334882f}" radius="0.039604" x="0.259919" y="0.25653" z="1.19061"/>
|
||||||
<node id="{273c09b7-d466-496f-9d06-ef7fa267c9a7}" partId="{c9c2c2b9-571b-4067-8b01-b59725670dd4}" radius="0.0079208" x="0.473093" y="0.513442" z="1.06634"/>
|
<node id="{273c09b7-d466-496f-9d06-ef7fa267c9a7}" partId="{c569a92e-6b1b-4d8b-9284-76fef9c124f0}" radius="0.0079208" x="0.473093" y="0.513442" z="1.06634"/>
|
||||||
<node id="{274f069c-1c6b-4837-8892-853ca652c07e}" partId="{471dfce0-6e13-4146-b261-2090e30f407b}" radius="0.0079208" x="0.468977" y="0.963426" z="1.1784"/>
|
<node id="{274f069c-1c6b-4837-8892-853ca652c07e}" partId="{aceff516-7672-4ab0-8de4-10fb8c7a0681}" radius="0.0079208" x="0.468977" y="0.963426" z="1.1784"/>
|
||||||
<node id="{27721191-b625-44bd-9253-cfc7df7b094b}" partId="{dd604661-6acc-4ef1-83fc-36a374c54734}" radius="0.0158416" x="0.378718" y="0.105351" z="1.20042"/>
|
<node id="{27721191-b625-44bd-9253-cfc7df7b094b}" partId="{ff29229a-564e-4e50-af37-0ae6c25b78ae}" radius="0.0158416" x="0.378718" y="0.105351" z="1.20042"/>
|
||||||
<node id="{27fb4823-e857-4e61-a454-a12d30ecfb17}" partId="{a5ad3f64-2091-4cea-8085-e17881f0573d}" radius="0.005" x="0.474917" y="0.981778" z="1.19311"/>
|
<node id="{27fb4823-e857-4e61-a454-a12d30ecfb17}" partId="{cef2d5ce-ed55-4030-a415-e39a20d3ff86}" radius="0.005" x="0.474917" y="0.981778" z="1.19311"/>
|
||||||
<node id="{286523f2-bf39-4f2c-aae7-dcf7223140e4}" partId="{442a221d-5a04-4d09-9cfd-bdd138320c26}" radius="0.005" x="0.0801996" y="0.968697" z="1.17343"/>
|
<node id="{286523f2-bf39-4f2c-aae7-dcf7223140e4}" partId="{de6790b2-a8be-42ea-9f96-75c8ac21c6da}" radius="0.005" x="0.0801996" y="0.968697" z="1.17343"/>
|
||||||
<node id="{2b5dae5c-17e3-4632-ab54-36e21859fbca}" partId="{ad2259a2-362c-499e-9123-d6f8ac0a1966}" radius="0.0871287" x="0.29505" y="0.287129" z="1.17624"/>
|
<node id="{2b5dae5c-17e3-4632-ab54-36e21859fbca}" partId="{422ad92f-8ad5-402a-9629-2348eb14e103}" radius="0.0871287" x="0.29505" y="0.287129" z="1.17624"/>
|
||||||
<node id="{2bec4749-11de-442a-862f-8d04d0c590ef}" partId="{ad2259a2-362c-499e-9123-d6f8ac0a1966}" radius="0.0831683" x="0.29505" y="0.766337" z="1.23564"/>
|
<node id="{2bec4749-11de-442a-862f-8d04d0c590ef}" partId="{422ad92f-8ad5-402a-9629-2348eb14e103}" radius="0.0831683" x="0.29505" y="0.766337" z="1.23564"/>
|
||||||
<node boneMark="Joint" id="{2e54f33b-c879-4e40-83cc-75eeefaccdc3}" partId="{b27111c8-625f-405d-88a9-55df58d51de0}" radius="0.0594059" x="0.438783" y="0.770349" z="1.18812"/>
|
<node boneMark="Joint" id="{2e54f33b-c879-4e40-83cc-75eeefaccdc3}" partId="{5f080e1f-48f5-4aa7-aa0c-d175f9045341}" radius="0.0594059" x="0.438783" y="0.770349" z="1.18812"/>
|
||||||
<node id="{37ad0424-3633-48a9-a2ea-bac83d140ec8}" partId="{b27111c8-625f-405d-88a9-55df58d51de0}" radius="0.0316832" x="0.428869" y="0.838801" z="1.22178"/>
|
<node id="{37ad0424-3633-48a9-a2ea-bac83d140ec8}" partId="{5f080e1f-48f5-4aa7-aa0c-d175f9045341}" radius="0.0316832" x="0.428869" y="0.838801" z="1.22178"/>
|
||||||
<node id="{3c4fd98e-c829-43f2-9ae5-c3c1c064a0a8}" partId="{2dacf558-7216-4577-8631-16769f860e18}" radius="0.005" x="0.149958" y="0.521944" z="1.09604"/>
|
<node id="{3c4fd98e-c829-43f2-9ae5-c3c1c064a0a8}" partId="{828c4638-7c11-4aeb-8f23-773dbeea8440}" radius="0.005" x="0.149958" y="0.521944" z="1.09604"/>
|
||||||
<node id="{3d6b06a7-af07-48e4-849b-204cb9af6a69}" partId="{881a0adc-3b0d-4575-b7d7-d6df8907e3f3}" radius="0.039604" x="0.254276" y="0.568263" z="1.20099"/>
|
<node id="{3d6b06a7-af07-48e4-849b-204cb9af6a69}" partId="{79289522-791a-488f-bd2d-15db6c8f2f84}" radius="0.039604" x="0.254276" y="0.568263" z="1.20099"/>
|
||||||
<node boneMark="Limb" id="{3e59449e-b487-4708-8b3e-31242cb50d19}" partId="{881a0adc-3b0d-4575-b7d7-d6df8907e3f3}" radius="0.0594059" x="0.145463" y="0.652011" z="1.22575"/>
|
<node boneMark="Limb" id="{3e59449e-b487-4708-8b3e-31242cb50d19}" partId="{79289522-791a-488f-bd2d-15db6c8f2f84}" radius="0.0594059" x="0.145463" y="0.652011" z="1.22575"/>
|
||||||
<node id="{419c8aca-4bb8-4bab-84e1-214b23a17a27}" partId="{a5ad3f64-2091-4cea-8085-e17881f0573d}" radius="0.0059406" x="0.447197" y="0.951167" z="1.20163"/>
|
<node id="{419c8aca-4bb8-4bab-84e1-214b23a17a27}" partId="{cef2d5ce-ed55-4030-a415-e39a20d3ff86}" radius="0.0059406" x="0.447197" y="0.951167" z="1.20163"/>
|
||||||
<node id="{457564d3-ccd0-465a-8d0b-b57c379666fd}" partId="{57622c57-5929-4a6a-b4ac-17dc909f002a}" radius="0.019802" x="0.293069" y="0.873267" z="1.35842"/>
|
<node id="{457564d3-ccd0-465a-8d0b-b57c379666fd}" partId="{0a57548e-12d8-4488-9ce4-8fe3b64db253}" radius="0.019802" x="0.293069" y="0.873267" z="1.35842"/>
|
||||||
<node id="{4946f825-7960-4653-9148-8d21e269c74e}" partId="{d5ccb7d6-3357-473c-a26a-12ce5713d92e}" radius="0.0277228" x="0.143884" y="0.352036" z="1.17367"/>
|
<node id="{4946f825-7960-4653-9148-8d21e269c74e}" partId="{9c9383da-b1ad-4fed-ac7d-e65d9334882f}" radius="0.0277228" x="0.143884" y="0.352036" z="1.17367"/>
|
||||||
<node id="{4b8f93a6-db8f-47c8-8d37-777db444914c}" partId="{dd604661-6acc-4ef1-83fc-36a374c54734}" radius="0.0158416" x="0.358132" y="0.0672427" z="1.20202"/>
|
<node id="{4b8f93a6-db8f-47c8-8d37-777db444914c}" partId="{ff29229a-564e-4e50-af37-0ae6c25b78ae}" radius="0.0158416" x="0.358132" y="0.0672427" z="1.20202"/>
|
||||||
<node id="{4c1029e5-c16d-442c-bc48-bdeed5d4706a}" partId="{881a0adc-3b0d-4575-b7d7-d6df8907e3f3}" radius="0.019802" x="0.109793" y="0.942925" z="1.20991"/>
|
<node id="{4c1029e5-c16d-442c-bc48-bdeed5d4706a}" partId="{79289522-791a-488f-bd2d-15db6c8f2f84}" radius="0.019802" x="0.109793" y="0.942925" z="1.20991"/>
|
||||||
<node boneMark="Joint" id="{50c1e61f-d968-4d2f-b4c2-9839326f49da}" partId="{d5ccb7d6-3357-473c-a26a-12ce5713d92e}" radius="0.0277228" x="0.155635" y="0.394941" z="1.12743"/>
|
<node boneMark="Joint" id="{50c1e61f-d968-4d2f-b4c2-9839326f49da}" partId="{9c9383da-b1ad-4fed-ac7d-e65d9334882f}" radius="0.0277228" x="0.155635" y="0.394941" z="1.12743"/>
|
||||||
<node id="{52a3dfd0-0bb7-4869-91b2-85c729e289b0}" partId="{9fae01c2-855a-472b-8181-02a1b76fcab1}" radius="0.0118812" x="0.151192" y="0.467655" z="1.10792"/>
|
<node id="{52a3dfd0-0bb7-4869-91b2-85c729e289b0}" partId="{b6e20100-8c2b-4550-aee8-806aa713c90c}" radius="0.0118812" x="0.151192" y="0.467655" z="1.10792"/>
|
||||||
<node id="{5492a461-1b28-47c8-811c-2542022eff84}" partId="{2dacf558-7216-4577-8631-16769f860e18}" radius="0.005" x="0.148921" y="0.541719" z="1.10198"/>
|
<node id="{5492a461-1b28-47c8-811c-2542022eff84}" partId="{828c4638-7c11-4aeb-8f23-773dbeea8440}" radius="0.005" x="0.148921" y="0.541719" z="1.10198"/>
|
||||||
<node id="{5bad0bb7-9015-44cc-a57f-4200b20a84f0}" partId="{9fae01c2-855a-472b-8181-02a1b76fcab1}" radius="0.005" x="0.129207" y="0.528428" z="1.09604"/>
|
<node id="{5bad0bb7-9015-44cc-a57f-4200b20a84f0}" partId="{b6e20100-8c2b-4550-aee8-806aa713c90c}" radius="0.005" x="0.129207" y="0.528428" z="1.09604"/>
|
||||||
<node id="{5d85b12a-fdd1-42c7-83d4-027d77716fc8}" partId="{c9c2c2b9-571b-4067-8b01-b59725670dd4}" radius="0.0118812" x="0.458031" y="0.485563" z="1.08416"/>
|
<node id="{5d85b12a-fdd1-42c7-83d4-027d77716fc8}" partId="{c569a92e-6b1b-4d8b-9284-76fef9c124f0}" radius="0.0118812" x="0.458031" y="0.485563" z="1.08416"/>
|
||||||
<node id="{5eb58123-c8a7-4899-a34e-1c63df33e759}" partId="{442a221d-5a04-4d09-9cfd-bdd138320c26}" radius="0.0079208" x="0.0861396" y="0.953524" z="1.1784"/>
|
<node id="{5eb58123-c8a7-4899-a34e-1c63df33e759}" partId="{de6790b2-a8be-42ea-9f96-75c8ac21c6da}" radius="0.0079208" x="0.0861396" y="0.953524" z="1.1784"/>
|
||||||
<node id="{5ff7a560-b046-4ddd-b26e-7dfbcc1083b3}" partId="{983cf6ce-44d9-41e8-8489-289b423a423a}" radius="0.0118812" x="0.44012" y="0.515079" z="1.06634"/>
|
<node id="{5ff7a560-b046-4ddd-b26e-7dfbcc1083b3}" partId="{1f878838-6686-4bcc-bc82-d9c5583d05e8}" radius="0.0118812" x="0.44012" y="0.515079" z="1.06634"/>
|
||||||
<node boneMark="Tail" id="{6186ebb3-84a4-4f2c-9992-b39a3831dea3}" partId="{57622c57-5929-4a6a-b4ac-17dc909f002a}" radius="0.0277228" x="0.293069" y="0.823762" z="1.31089"/>
|
<node boneMark="Tail" id="{6186ebb3-84a4-4f2c-9992-b39a3831dea3}" partId="{0a57548e-12d8-4488-9ce4-8fe3b64db253}" radius="0.0277228" x="0.293069" y="0.823762" z="1.31089"/>
|
||||||
<node id="{653c799b-da4a-4d0a-9be5-84bbe3ae7551}" partId="{0b8f8da9-d461-48c4-bbfd-343f0b648235}" radius="0.0118812" x="0.458444" y="0.486357" z="1.08416"/>
|
<node id="{653c799b-da4a-4d0a-9be5-84bbe3ae7551}" partId="{0048f320-55a9-4777-914e-95944cb34b46}" radius="0.0118812" x="0.458444" y="0.486357" z="1.08416"/>
|
||||||
<node boneMark="Joint" id="{6954e176-c739-40d8-b1ef-8ce38884bba2}" partId="{881a0adc-3b0d-4575-b7d7-d6df8907e3f3}" radius="0.019802" x="0.170124" y="0.897261" z="1.23367"/>
|
<node boneMark="Joint" id="{6954e176-c739-40d8-b1ef-8ce38884bba2}" partId="{79289522-791a-488f-bd2d-15db6c8f2f84}" radius="0.019802" x="0.170124" y="0.897261" z="1.23367"/>
|
||||||
<node id="{69d7c60a-eaa7-4d64-a09b-755fb3b4c9ae}" partId="{d2be1f6f-2053-491c-962b-f27e1a809848}" radius="0.0237624" x="0.452707" y="0.453717" z="1.09675"/>
|
<node id="{69d7c60a-eaa7-4d64-a09b-755fb3b4c9ae}" partId="{93d5b991-f821-4974-96bd-17c46090ffa9}" radius="0.0237624" x="0.452707" y="0.453717" z="1.09675"/>
|
||||||
<node id="{6b2d17cd-4fbe-4fd3-8f80-6c467d3811fd}" partId="{471dfce0-6e13-4146-b261-2090e30f407b}" radius="0.0079208" x="0.447197" y="0.952032" z="1.2028"/>
|
<node id="{6b2d17cd-4fbe-4fd3-8f80-6c467d3811fd}" partId="{aceff516-7672-4ab0-8de4-10fb8c7a0681}" radius="0.0079208" x="0.447197" y="0.952032" z="1.2028"/>
|
||||||
<node id="{6e90e23a-c67b-4dc7-af76-2145793a9c3b}" partId="{471dfce0-6e13-4146-b261-2090e30f407b}" radius="0.005" x="0.474917" y="0.978599" z="1.17343"/>
|
<node id="{6e90e23a-c67b-4dc7-af76-2145793a9c3b}" partId="{aceff516-7672-4ab0-8de4-10fb8c7a0681}" radius="0.005" x="0.474917" y="0.978599" z="1.17343"/>
|
||||||
<node id="{723a0584-b3a1-41a9-a9dc-96b21e733f1f}" partId="{ad2259a2-362c-499e-9123-d6f8ac0a1966}" radius="0.0712871" x="0.293069" y="0.174257" z="1.20099"/>
|
<node id="{723a0584-b3a1-41a9-a9dc-96b21e733f1f}" partId="{422ad92f-8ad5-402a-9629-2348eb14e103}" radius="0.0712871" x="0.293069" y="0.174257" z="1.20099"/>
|
||||||
<node id="{7305f345-84d5-44b5-af37-c48bf3925ca4}" partId="{ad2259a2-362c-499e-9123-d6f8ac0a1966}" radius="0.0950495" x="0.29505" y="0.508911" z="1.19406"/>
|
<node id="{7305f345-84d5-44b5-af37-c48bf3925ca4}" partId="{422ad92f-8ad5-402a-9629-2348eb14e103}" radius="0.0950495" x="0.29505" y="0.508911" z="1.19406"/>
|
||||||
<node boneMark="Neck" id="{78d00d69-b1b9-4fad-b0cc-87f9b6f1539f}" partId="{fe5e25e8-58cb-43d5-ba72-c64e2cf44d6d}" radius="0.0554455" x="0.293069" y="0.172277" z="1.20792"/>
|
<node boneMark="Neck" id="{78d00d69-b1b9-4fad-b0cc-87f9b6f1539f}" partId="{6ff1a4e8-b864-4c5e-8a8e-2d28edd2c55a}" radius="0.0554455" x="0.293069" y="0.172277" z="1.20792"/>
|
||||||
<node id="{78f63ac5-8fc8-40dd-80e4-b316b3b4b409}" partId="{dd604661-6acc-4ef1-83fc-36a374c54734}" radius="0.0237624" x="0.371603" y="0.0817292" z="1.20441"/>
|
<node id="{78f63ac5-8fc8-40dd-80e4-b316b3b4b409}" partId="{ff29229a-564e-4e50-af37-0ae6c25b78ae}" radius="0.0237624" x="0.371603" y="0.0817292" z="1.20441"/>
|
||||||
<node id="{79b757ee-5f39-4a71-8019-5e447daa9860}" partId="{d4c0d323-791a-4a2a-ad1b-8e8fb93bf42d}" radius="0.0059406" x="0.10792" y="0.941265" z="1.20163"/>
|
<node id="{79b757ee-5f39-4a71-8019-5e447daa9860}" partId="{8d55eb65-52a8-47da-9b5b-7d6d914943cc}" radius="0.0059406" x="0.10792" y="0.941265" z="1.20163"/>
|
||||||
<node id="{83e2e87a-2fd0-4df4-8278-28dd30482f67}" partId="{983cf6ce-44d9-41e8-8489-289b423a423a}" radius="0.005" x="0.437409" y="0.539015" z="1.07228"/>
|
<node id="{83e2e87a-2fd0-4df4-8278-28dd30482f67}" partId="{1f878838-6686-4bcc-bc82-d9c5583d05e8}" radius="0.005" x="0.437409" y="0.539015" z="1.07228"/>
|
||||||
<node boneMark="Joint" id="{8642cce7-c158-4559-99af-bf2caa121348}" partId="{d2be1f6f-2053-491c-962b-f27e1a809848}" radius="0.0277228" x="0.456934" y="0.413582" z="1.10575"/>
|
<node boneMark="Joint" id="{8642cce7-c158-4559-99af-bf2caa121348}" partId="{93d5b991-f821-4974-96bd-17c46090ffa9}" radius="0.0277228" x="0.456934" y="0.413582" z="1.10575"/>
|
||||||
<node id="{8b71e1a2-e0bc-435d-9bd2-c096f60c7f23}" partId="{546efa0c-392d-47c5-80c1-4138b07cf0a4}" radius="0.005" x="0.170777" y="0.540882" z="1.10198"/>
|
<node id="{8b71e1a2-e0bc-435d-9bd2-c096f60c7f23}" partId="{2162fa67-7e23-4e5f-9a9d-4175b10c44c9}" radius="0.005" x="0.170777" y="0.540882" z="1.10198"/>
|
||||||
<node id="{8c4b6bea-3045-4b62-ba65-442c7c5548b9}" partId="{d2be1f6f-2053-491c-962b-f27e1a809848}" radius="0.0277228" x="0.471089" y="0.374671" z="1.15476"/>
|
<node id="{8c4b6bea-3045-4b62-ba65-442c7c5548b9}" partId="{93d5b991-f821-4974-96bd-17c46090ffa9}" radius="0.0277228" x="0.471089" y="0.374671" z="1.15476"/>
|
||||||
<node id="{8f14d451-9613-48ef-8670-124223236475}" partId="{91850869-d0e1-4e42-a452-d1259dbd5643}" radius="0.00792081" x="0.10792" y="0.940742" z="1.20846"/>
|
<node id="{8f14d451-9613-48ef-8670-124223236475}" partId="{c2b415b2-4419-408e-be54-1b6b2521441a}" radius="0.00792081" x="0.10792" y="0.940742" z="1.20846"/>
|
||||||
<node id="{90b31f2b-f532-4402-b648-4d7717ce6853}" partId="{80e078b3-ad1d-4a0f-b695-e63bff35af45}" radius="0.00990099" x="0.364357" y="0.0435644" z="1.13564"/>
|
<node id="{90b31f2b-f532-4402-b648-4d7717ce6853}" partId="{62dc13e0-9173-4223-9c39-c682f30a2338}" radius="0.00990099" x="0.364357" y="0.0435644" z="1.13564"/>
|
||||||
<node id="{944c7657-e978-4bb6-94ad-b03dbafae824}" partId="{d5ccb7d6-3357-473c-a26a-12ce5713d92e}" radius="0.0237624" x="0.1577" y="0.43577" z="1.12124"/>
|
<node id="{944c7657-e978-4bb6-94ad-b03dbafae824}" partId="{9c9383da-b1ad-4fed-ac7d-e65d9334882f}" radius="0.0237624" x="0.1577" y="0.43577" z="1.12124"/>
|
||||||
<node id="{94c6dd69-3b99-4b25-b6dd-e8d80b579a7e}" partId="{2c899cf6-d358-454e-ad79-5a5bddaf0bff}" radius="0.0158416" x="0.348515" y="0.0534653" z="1.16238"/>
|
<node id="{94c6dd69-3b99-4b25-b6dd-e8d80b579a7e}" partId="{3145e23e-d0bf-4f3f-8609-92f40c348fa5}" radius="0.0158416" x="0.348515" y="0.0534653" z="1.16238"/>
|
||||||
<node id="{98e623f4-0c83-4da8-9ba8-c4d470f0c5f0}" partId="{6c3c3e49-1701-4f8c-9490-32d51f52fe9f}" radius="0.0079208" x="0.468977" y="0.967235" z="1.22968"/>
|
<node id="{98e623f4-0c83-4da8-9ba8-c4d470f0c5f0}" partId="{b049bb5c-a4e5-402e-88db-a5cccbee3851}" radius="0.0079208" x="0.468977" y="0.967235" z="1.22968"/>
|
||||||
<node id="{9ad35b2b-3998-4822-9ecf-ff2425531106}" partId="{b27111c8-625f-405d-88a9-55df58d51de0}" radius="0.019802" x="0.426945" y="0.930406" z="1.22376"/>
|
<node id="{9ad35b2b-3998-4822-9ecf-ff2425531106}" partId="{5f080e1f-48f5-4aa7-aa0c-d175f9045341}" radius="0.019802" x="0.426945" y="0.930406" z="1.22376"/>
|
||||||
<node id="{9bc24536-52b6-42c4-801e-6994069ae93b}" partId="{91850869-d0e1-4e42-a452-d1259dbd5643}" radius="0.0079208" x="0.0861396" y="0.957333" z="1.22968"/>
|
<node id="{9bc24536-52b6-42c4-801e-6994069ae93b}" partId="{c2b415b2-4419-408e-be54-1b6b2521441a}" radius="0.0079208" x="0.0861396" y="0.957333" z="1.22968"/>
|
||||||
<node id="{9d2b664d-a090-4c9c-b8a3-6a07d8d0eb08}" partId="{fe5e25e8-58cb-43d5-ba72-c64e2cf44d6d}" radius="0.0158416" x="0.293069" y="0.0613861" z="1.01287"/>
|
<node id="{9d2b664d-a090-4c9c-b8a3-6a07d8d0eb08}" partId="{6ff1a4e8-b864-4c5e-8a8e-2d28edd2c55a}" radius="0.0158416" x="0.293069" y="0.0613861" z="1.01287"/>
|
||||||
<node id="{a003f447-592d-45db-ac31-50e1b0dacb02}" partId="{c9c2c2b9-571b-4067-8b01-b59725670dd4}" radius="0.005" x="0.480016" y="0.546337" z="1.07228"/>
|
<node id="{a003f447-592d-45db-ac31-50e1b0dacb02}" partId="{c569a92e-6b1b-4d8b-9284-76fef9c124f0}" radius="0.005" x="0.480016" y="0.546337" z="1.07228"/>
|
||||||
<node id="{a019b2a5-f245-4139-b1a2-6b9462326c51}" partId="{983cf6ce-44d9-41e8-8489-289b423a423a}" radius="0.0118812" x="0.450534" y="0.486772" z="1.08416"/>
|
<node id="{a019b2a5-f245-4139-b1a2-6b9462326c51}" partId="{1f878838-6686-4bcc-bc82-d9c5583d05e8}" radius="0.0118812" x="0.450534" y="0.486772" z="1.08416"/>
|
||||||
<node id="{a43e38c8-aa79-4a6f-860b-65055bafcf62}" partId="{91850869-d0e1-4e42-a452-d1259dbd5643}" radius="0.005" x="0.0801996" y="0.973235" z="1.2311"/>
|
<node id="{a43e38c8-aa79-4a6f-860b-65055bafcf62}" partId="{c2b415b2-4419-408e-be54-1b6b2521441a}" radius="0.005" x="0.0801996" y="0.973235" z="1.2311"/>
|
||||||
<node id="{a4935618-a165-4f84-aabf-c6d317c7a714}" partId="{0b8f8da9-d461-48c4-bbfd-343f0b648235}" radius="0.005" x="0.459265" y="0.539853" z="1.07228"/>
|
<node id="{a4935618-a165-4f84-aabf-c6d317c7a714}" partId="{0048f320-55a9-4777-914e-95944cb34b46}" radius="0.005" x="0.459265" y="0.539853" z="1.07228"/>
|
||||||
<node id="{a6567353-5b7a-4de0-8d0f-b916fd8a7287}" partId="{d4c0d323-791a-4a2a-ad1b-8e8fb93bf42d}" radius="0.005" x="0.0801996" y="0.971876" z="1.19311"/>
|
<node id="{a6567353-5b7a-4de0-8d0f-b916fd8a7287}" partId="{8d55eb65-52a8-47da-9b5b-7d6d914943cc}" radius="0.005" x="0.0801996" y="0.971876" z="1.19311"/>
|
||||||
<node id="{b078b7da-3fce-44fb-9dd0-9812f579991e}" partId="{019249f8-0f48-4f9e-87e3-6d2e821e87ac}" radius="0.005" x="0.0801996" y="0.971906" z="1.21121"/>
|
<node id="{b078b7da-3fce-44fb-9dd0-9812f579991e}" partId="{65aa6ccd-94db-47cf-aa84-dce3c2b3fa65}" radius="0.005" x="0.0801996" y="0.971906" z="1.21121"/>
|
||||||
<node id="{b1a0502c-3215-461f-b003-4edd9a13562b}" partId="{983cf6ce-44d9-41e8-8489-289b423a423a}" radius="0.005" x="0.438446" y="0.55879" z="1.07822"/>
|
<node id="{b1a0502c-3215-461f-b003-4edd9a13562b}" partId="{1f878838-6686-4bcc-bc82-d9c5583d05e8}" radius="0.005" x="0.438446" y="0.55879" z="1.07822"/>
|
||||||
<node boneMark="Limb" id="{b1aec088-f56d-4b96-b34b-4602276b67f4}" partId="{d2be1f6f-2053-491c-962b-f27e1a809848}" radius="0.0316832" x="0.428503" y="0.310597" z="1.17886"/>
|
<node boneMark="Limb" id="{b1aec088-f56d-4b96-b34b-4602276b67f4}" partId="{93d5b991-f821-4974-96bd-17c46090ffa9}" radius="0.0316832" x="0.428503" y="0.310597" z="1.17886"/>
|
||||||
<node id="{b5c30ec3-4045-4502-911b-bc29b8a93496}" partId="{d4c0d323-791a-4a2a-ad1b-8e8fb93bf42d}" radius="0.0079208" x="0.0861396" y="0.956445" z="1.19721"/>
|
<node id="{b5c30ec3-4045-4502-911b-bc29b8a93496}" partId="{8d55eb65-52a8-47da-9b5b-7d6d914943cc}" radius="0.0079208" x="0.0861396" y="0.956445" z="1.19721"/>
|
||||||
<node id="{b5f2d7c5-24dd-41e3-9dce-47e8db05ca86}" partId="{ad2259a2-362c-499e-9123-d6f8ac0a1966}" radius="0.110891" x="0.29505" y="0.59604" z="1.2198"/>
|
<node id="{b5f2d7c5-24dd-41e3-9dce-47e8db05ca86}" partId="{422ad92f-8ad5-402a-9629-2348eb14e103}" radius="0.110891" x="0.29505" y="0.59604" z="1.2198"/>
|
||||||
<node id="{b7f18151-9b31-4e34-ad41-3d7a0358b1cd}" partId="{15325291-8856-42d7-9bc0-eb9ea53eadc1}" radius="0.00594061" x="0.447197" y="0.950065" z="1.2098"/>
|
<node id="{b7f18151-9b31-4e34-ad41-3d7a0358b1cd}" partId="{3d3ba42b-7be6-4174-96c3-500daab0dc7f}" radius="0.00594061" x="0.447197" y="0.950065" z="1.2098"/>
|
||||||
<node boneMark="Joint" id="{bb1434c7-51ad-4226-a6e0-2e0ee5c626d7}" partId="{d5ccb7d6-3357-473c-a26a-12ce5713d92e}" radius="0.019802" x="0.154596" y="0.464592" z="1.11268"/>
|
<node boneMark="Joint" id="{bb1434c7-51ad-4226-a6e0-2e0ee5c626d7}" partId="{9c9383da-b1ad-4fed-ac7d-e65d9334882f}" radius="0.019802" x="0.154596" y="0.464592" z="1.11268"/>
|
||||||
<node id="{bcb62c53-e5db-48ac-bbac-38159a42dfe3}" partId="{57622c57-5929-4a6a-b4ac-17dc909f002a}" radius="0.019802" x="0.293069" y="0.875248" z="1.42178"/>
|
<node id="{bcb62c53-e5db-48ac-bbac-38159a42dfe3}" partId="{0a57548e-12d8-4488-9ce4-8fe3b64db253}" radius="0.019802" x="0.293069" y="0.875248" z="1.42178"/>
|
||||||
<node id="{bfb08a33-feee-4741-9855-64add2915ec4}" partId="{546efa0c-392d-47c5-80c1-4138b07cf0a4}" radius="0.005" x="0.171813" y="0.521107" z="1.09604"/>
|
<node id="{bfb08a33-feee-4741-9855-64add2915ec4}" partId="{2162fa67-7e23-4e5f-9a9d-4175b10c44c9}" radius="0.005" x="0.171813" y="0.521107" z="1.09604"/>
|
||||||
<node id="{c03d7db7-dcba-4926-b22d-04bd37ed3b65}" partId="{6c3c3e49-1701-4f8c-9490-32d51f52fe9f}" radius="0.00792081" x="0.447197" y="0.950644" z="1.20846"/>
|
<node id="{c03d7db7-dcba-4926-b22d-04bd37ed3b65}" partId="{b049bb5c-a4e5-402e-88db-a5cccbee3851}" radius="0.00792081" x="0.447197" y="0.950644" z="1.20846"/>
|
||||||
<node id="{c0535c22-dc84-4a77-84fc-d04b2d839575}" partId="{019249f8-0f48-4f9e-87e3-6d2e821e87ac}" radius="0.0079208" x="0.0861396" y="0.955949" z="1.21069"/>
|
<node id="{c0535c22-dc84-4a77-84fc-d04b2d839575}" partId="{65aa6ccd-94db-47cf-aa84-dce3c2b3fa65}" radius="0.0079208" x="0.0861396" y="0.955949" z="1.21069"/>
|
||||||
<node id="{c0cb6b06-3876-4550-9c05-29110ae1f2d9}" partId="{6c3c3e49-1701-4f8c-9490-32d51f52fe9f}" radius="0.005" x="0.474917" y="0.983137" z="1.2311"/>
|
<node id="{c0cb6b06-3876-4550-9c05-29110ae1f2d9}" partId="{b049bb5c-a4e5-402e-88db-a5cccbee3851}" radius="0.005" x="0.474917" y="0.983137" z="1.2311"/>
|
||||||
<node id="{c578f2fb-079d-43a6-873d-6e094e7df09a}" partId="{57622c57-5929-4a6a-b4ac-17dc909f002a}" radius="0.00792079" x="0.293069" y="0.845545" z="1.48713"/>
|
<node id="{c578f2fb-079d-43a6-873d-6e094e7df09a}" partId="{0a57548e-12d8-4488-9ce4-8fe3b64db253}" radius="0.00792079" x="0.293069" y="0.845545" z="1.48713"/>
|
||||||
<node id="{ca7d354f-4221-4301-ba44-4ee63ac652de}" partId="{546efa0c-392d-47c5-80c1-4138b07cf0a4}" radius="0.0118812" x="0.158689" y="0.468864" z="1.10792"/>
|
<node id="{ca7d354f-4221-4301-ba44-4ee63ac652de}" partId="{2162fa67-7e23-4e5f-9a9d-4175b10c44c9}" radius="0.0118812" x="0.158689" y="0.468864" z="1.10792"/>
|
||||||
<node id="{cb6c4607-f520-4a2e-b282-e54e2cb8165a}" partId="{fe5e25e8-58cb-43d5-ba72-c64e2cf44d6d}" radius="0.0673267" x="0.293069" y="0.0772277" z="1.17228"/>
|
<node id="{cb6c4607-f520-4a2e-b282-e54e2cb8165a}" partId="{6ff1a4e8-b864-4c5e-8a8e-2d28edd2c55a}" radius="0.0673267" x="0.293069" y="0.0772277" z="1.17228"/>
|
||||||
<node id="{d00956a4-1164-40c6-b6f8-b601e504b7fd}" partId="{2c899cf6-d358-454e-ad79-5a5bddaf0bff}" radius="0.0178218" x="0.330693" y="0.0495049" z="1.10792"/>
|
<node id="{d00956a4-1164-40c6-b6f8-b601e504b7fd}" partId="{3145e23e-d0bf-4f3f-8609-92f40c348fa5}" radius="0.0178218" x="0.330693" y="0.0495049" z="1.10792"/>
|
||||||
<node id="{d0250089-5e1a-43f7-b5f8-363642c7ae79}" partId="{881a0adc-3b0d-4575-b7d7-d6df8907e3f3}" radius="0.019802" x="0.139614" y="0.922043" z="1.22377"/>
|
<node id="{d0250089-5e1a-43f7-b5f8-363642c7ae79}" partId="{79289522-791a-488f-bd2d-15db6c8f2f84}" radius="0.019802" x="0.139614" y="0.922043" z="1.22377"/>
|
||||||
<node id="{d2f082e0-13c8-4bc5-8c05-06cea9d46463}" partId="{fe5e25e8-58cb-43d5-ba72-c64e2cf44d6d}" radius="0.0514851" x="0.293069" y="0.0594059" z="1.10693"/>
|
<node id="{d2f082e0-13c8-4bc5-8c05-06cea9d46463}" partId="{6ff1a4e8-b864-4c5e-8a8e-2d28edd2c55a}" radius="0.0514851" x="0.293069" y="0.0594059" z="1.10693"/>
|
||||||
<node id="{d7dd0c55-e568-413d-99f0-cf91bcc4c534}" partId="{2dacf558-7216-4577-8631-16769f860e18}" radius="0.0118812" x="0.149328" y="0.496134" z="1.0901"/>
|
<node id="{d7dd0c55-e568-413d-99f0-cf91bcc4c534}" partId="{828c4638-7c11-4aeb-8f23-773dbeea8440}" radius="0.0118812" x="0.149328" y="0.496134" z="1.0901"/>
|
||||||
<node boneMark="Joint" id="{da8b7964-8659-41c2-aeee-aa3a1bf7d39c}" partId="{d2be1f6f-2053-491c-962b-f27e1a809848}" radius="0.019802" x="0.454264" y="0.481995" z="1.08619"/>
|
<node boneMark="Joint" id="{da8b7964-8659-41c2-aeee-aa3a1bf7d39c}" partId="{93d5b991-f821-4974-96bd-17c46090ffa9}" radius="0.019802" x="0.454264" y="0.481995" z="1.08619"/>
|
||||||
<node id="{df5207c8-afdb-4305-b322-33de580b7379}" partId="{ad2259a2-362c-499e-9123-d6f8ac0a1966}" radius="0.0990099" x="0.29505" y="0.69901" z="1.22772"/>
|
<node id="{df5207c8-afdb-4305-b322-33de580b7379}" partId="{422ad92f-8ad5-402a-9629-2348eb14e103}" radius="0.0990099" x="0.29505" y="0.69901" z="1.22772"/>
|
||||||
<node id="{e73bbdbf-3ba8-4a70-99e0-bde3f7f1e5cd}" partId="{546efa0c-392d-47c5-80c1-4138b07cf0a4}" radius="0.0118812" x="0.169102" y="0.49717" z="1.0901"/>
|
<node id="{e73bbdbf-3ba8-4a70-99e0-bde3f7f1e5cd}" partId="{2162fa67-7e23-4e5f-9a9d-4175b10c44c9}" radius="0.0118812" x="0.169102" y="0.49717" z="1.0901"/>
|
||||||
<node id="{e767a69a-e29d-4fbc-8e1d-615a443f40f5}" partId="{2c899cf6-d358-454e-ad79-5a5bddaf0bff}" radius="0.0237624" x="0.348515" y="0.0475248" z="1.13366"/>
|
<node id="{e767a69a-e29d-4fbc-8e1d-615a443f40f5}" partId="{3145e23e-d0bf-4f3f-8609-92f40c348fa5}" radius="0.0237624" x="0.348515" y="0.0475248" z="1.13366"/>
|
||||||
<node id="{ef8ef04c-4d5b-4663-a607-d1fa25995a0e}" partId="{d2be1f6f-2053-491c-962b-f27e1a809848}" radius="0.039604" x="0.327654" y="0.256375" z="1.18956"/>
|
<node id="{ef8ef04c-4d5b-4663-a607-d1fa25995a0e}" partId="{93d5b991-f821-4974-96bd-17c46090ffa9}" radius="0.039604" x="0.327654" y="0.256375" z="1.18956"/>
|
||||||
<node id="{f06c29c3-080f-48d0-8ed5-e6fd3fabd51d}" partId="{fe5e25e8-58cb-43d5-ba72-c64e2cf44d6d}" radius="0.0237624" x="0.293069" y="0.0653465" z="1.05149"/>
|
<node id="{f06c29c3-080f-48d0-8ed5-e6fd3fabd51d}" partId="{6ff1a4e8-b864-4c5e-8a8e-2d28edd2c55a}" radius="0.0237624" x="0.293069" y="0.0653465" z="1.05149"/>
|
||||||
<node boneMark="Joint" id="{f28a9edd-92c5-4e9e-9b69-e63ec9fd7f4f}" partId="{57622c57-5929-4a6a-b4ac-17dc909f002a}" radius="0.0158416" x="0.293069" y="0.889109" z="1.39406"/>
|
<node boneMark="Joint" id="{f28a9edd-92c5-4e9e-9b69-e63ec9fd7f4f}" partId="{0a57548e-12d8-4488-9ce4-8fe3b64db253}" radius="0.0158416" x="0.293069" y="0.889109" z="1.39406"/>
|
||||||
<node id="{f467cb17-e94e-43f1-822c-c95dcb59c4a1}" partId="{15325291-8856-42d7-9bc0-eb9ea53eadc1}" radius="0.005" x="0.474917" y="0.981808" z="1.21121"/>
|
<node id="{f467cb17-e94e-43f1-822c-c95dcb59c4a1}" partId="{3d3ba42b-7be6-4174-96c3-500daab0dc7f}" radius="0.005" x="0.474917" y="0.981808" z="1.21121"/>
|
||||||
<node id="{f53d85ae-0a06-47aa-8402-b5e0124cff66}" partId="{881a0adc-3b0d-4575-b7d7-d6df8907e3f3}" radius="0.0316832" x="0.145682" y="0.830619" z="1.22179"/>
|
<node id="{f53d85ae-0a06-47aa-8402-b5e0124cff66}" partId="{79289522-791a-488f-bd2d-15db6c8f2f84}" radius="0.0316832" x="0.145682" y="0.830619" z="1.22179"/>
|
||||||
<node id="{f700b2e2-8fa0-4ea7-87e7-9a668edc7749}" partId="{442a221d-5a04-4d09-9cfd-bdd138320c26}" radius="0.0079208" x="0.10792" y="0.94213" z="1.2028"/>
|
<node id="{f700b2e2-8fa0-4ea7-87e7-9a668edc7749}" partId="{de6790b2-a8be-42ea-9f96-75c8ac21c6da}" radius="0.0079208" x="0.10792" y="0.94213" z="1.2028"/>
|
||||||
<node id="{f89eea85-45e0-47d7-a009-96e2086d58fc}" partId="{57622c57-5929-4a6a-b4ac-17dc909f002a}" radius="0.0475248" x="0.293069" y="0.746535" z="1.2604"/>
|
<node id="{f89eea85-45e0-47d7-a009-96e2086d58fc}" partId="{0a57548e-12d8-4488-9ce4-8fe3b64db253}" radius="0.0475248" x="0.293069" y="0.746535" z="1.2604"/>
|
||||||
<node id="{f94eabec-5f95-49f4-98ef-dd639838aaf0}" partId="{0b8f8da9-d461-48c4-bbfd-343f0b648235}" radius="0.005" x="0.460301" y="0.559628" z="1.07822"/>
|
<node id="{f94eabec-5f95-49f4-98ef-dd639838aaf0}" partId="{0048f320-55a9-4777-914e-95944cb34b46}" radius="0.005" x="0.460301" y="0.559628" z="1.07822"/>
|
||||||
<node id="{fa3fc46e-827d-47b3-b266-5ad5728d9247}" partId="{2dacf558-7216-4577-8631-16769f860e18}" radius="0.0118812" x="0.150778" y="0.468449" z="1.10792"/>
|
<node id="{fa3fc46e-827d-47b3-b266-5ad5728d9247}" partId="{828c4638-7c11-4aeb-8f23-773dbeea8440}" radius="0.0118812" x="0.150778" y="0.468449" z="1.10792"/>
|
||||||
<node id="{fa9f59c1-5451-4e3f-839a-39ae13615edf}" partId="{15325291-8856-42d7-9bc0-eb9ea53eadc1}" radius="0.0079208" x="0.468977" y="0.965851" z="1.21069"/>
|
<node id="{fa9f59c1-5451-4e3f-839a-39ae13615edf}" partId="{3d3ba42b-7be6-4174-96c3-500daab0dc7f}" radius="0.0079208" x="0.468977" y="0.965851" z="1.21069"/>
|
||||||
<node id="{feacc347-69c3-4789-b565-9ac8156fca41}" partId="{b27111c8-625f-405d-88a9-55df58d51de0}" radius="0.039604" x="0.343555" y="0.567979" z="1.20099"/>
|
<node id="{feacc347-69c3-4789-b565-9ac8156fca41}" partId="{5f080e1f-48f5-4aa7-aa0c-d175f9045341}" radius="0.039604" x="0.343555" y="0.567979" z="1.20099"/>
|
||||||
</nodes>
|
</nodes>
|
||||||
<edges>
|
<edges>
|
||||||
<edge from="{b1aec088-f56d-4b96-b34b-4602276b67f4}" id="{03559a5e-eca9-4b9b-a085-1badd686158a}" partId="{d2be1f6f-2053-491c-962b-f27e1a809848}" to="{8c4b6bea-3045-4b62-ba65-442c7c5548b9}"/>
|
<edge from="{b1aec088-f56d-4b96-b34b-4602276b67f4}" id="{03559a5e-eca9-4b9b-a085-1badd686158a}" partId="{93d5b991-f821-4974-96bd-17c46090ffa9}" to="{8c4b6bea-3045-4b62-ba65-442c7c5548b9}"/>
|
||||||
<edge from="{d00956a4-1164-40c6-b6f8-b601e504b7fd}" id="{0bc68793-fa92-4765-bf48-8479bc222295}" partId="{2c899cf6-d358-454e-ad79-5a5bddaf0bff}" to="{e767a69a-e29d-4fbc-8e1d-615a443f40f5}"/>
|
<edge from="{d00956a4-1164-40c6-b6f8-b601e504b7fd}" id="{0bc68793-fa92-4765-bf48-8479bc222295}" partId="{3145e23e-d0bf-4f3f-8609-92f40c348fa5}" to="{e767a69a-e29d-4fbc-8e1d-615a443f40f5}"/>
|
||||||
<edge from="{e73bbdbf-3ba8-4a70-99e0-bde3f7f1e5cd}" id="{0c191a67-6941-4607-bbb6-2cfabf551aac}" partId="{546efa0c-392d-47c5-80c1-4138b07cf0a4}" to="{bfb08a33-feee-4741-9855-64add2915ec4}"/>
|
<edge from="{e73bbdbf-3ba8-4a70-99e0-bde3f7f1e5cd}" id="{0c191a67-6941-4607-bbb6-2cfabf551aac}" partId="{2162fa67-7e23-4e5f-9a9d-4175b10c44c9}" to="{bfb08a33-feee-4741-9855-64add2915ec4}"/>
|
||||||
<edge from="{0369aab4-b9b7-4d53-bc43-118f226dadc9}" id="{0c59cfdd-95a6-46f4-ab18-e088ed966657}" partId="{019249f8-0f48-4f9e-87e3-6d2e821e87ac}" to="{c0535c22-dc84-4a77-84fc-d04b2d839575}"/>
|
<edge from="{0369aab4-b9b7-4d53-bc43-118f226dadc9}" id="{0c59cfdd-95a6-46f4-ab18-e088ed966657}" partId="{65aa6ccd-94db-47cf-aa84-dce3c2b3fa65}" to="{c0535c22-dc84-4a77-84fc-d04b2d839575}"/>
|
||||||
<edge from="{8f14d451-9613-48ef-8670-124223236475}" id="{0fb2cf45-efab-48dd-baa6-1ae968ac7dca}" partId="{91850869-d0e1-4e42-a452-d1259dbd5643}" to="{9bc24536-52b6-42c4-801e-6994069ae93b}"/>
|
<edge from="{8f14d451-9613-48ef-8670-124223236475}" id="{0fb2cf45-efab-48dd-baa6-1ae968ac7dca}" partId="{c2b415b2-4419-408e-be54-1b6b2521441a}" to="{9bc24536-52b6-42c4-801e-6994069ae93b}"/>
|
||||||
<edge from="{a4935618-a165-4f84-aabf-c6d317c7a714}" id="{1df5cc4c-288a-4d34-bd8e-1f0eb01cba30}" partId="{0b8f8da9-d461-48c4-bbfd-343f0b648235}" to="{f94eabec-5f95-49f4-98ef-dd639838aaf0}"/>
|
<edge from="{a4935618-a165-4f84-aabf-c6d317c7a714}" id="{1df5cc4c-288a-4d34-bd8e-1f0eb01cba30}" partId="{0048f320-55a9-4777-914e-95944cb34b46}" to="{f94eabec-5f95-49f4-98ef-dd639838aaf0}"/>
|
||||||
<edge from="{b7f18151-9b31-4e34-ad41-3d7a0358b1cd}" id="{1fdac3a3-9ff7-4375-aa4c-aee852e9cba6}" partId="{15325291-8856-42d7-9bc0-eb9ea53eadc1}" to="{fa9f59c1-5451-4e3f-839a-39ae13615edf}"/>
|
<edge from="{b7f18151-9b31-4e34-ad41-3d7a0358b1cd}" id="{1fdac3a3-9ff7-4375-aa4c-aee852e9cba6}" partId="{3d3ba42b-7be6-4174-96c3-500daab0dc7f}" to="{fa9f59c1-5451-4e3f-839a-39ae13615edf}"/>
|
||||||
<edge from="{653c799b-da4a-4d0a-9be5-84bbe3ae7551}" id="{23fea5bb-2593-477e-8518-756ac0ab113f}" partId="{0b8f8da9-d461-48c4-bbfd-343f0b648235}" to="{0cecd379-b9d6-4568-9d5b-82720916a6e4}"/>
|
<edge from="{653c799b-da4a-4d0a-9be5-84bbe3ae7551}" id="{23fea5bb-2593-477e-8518-756ac0ab113f}" partId="{0048f320-55a9-4777-914e-95944cb34b46}" to="{0cecd379-b9d6-4568-9d5b-82720916a6e4}"/>
|
||||||
<edge from="{f28a9edd-92c5-4e9e-9b69-e63ec9fd7f4f}" id="{2662a435-be76-40be-84b0-1632ffcf151a}" partId="{57622c57-5929-4a6a-b4ac-17dc909f002a}" to="{bcb62c53-e5db-48ac-bbac-38159a42dfe3}"/>
|
<edge from="{f28a9edd-92c5-4e9e-9b69-e63ec9fd7f4f}" id="{2662a435-be76-40be-84b0-1632ffcf151a}" partId="{0a57548e-12d8-4488-9ce4-8fe3b64db253}" to="{bcb62c53-e5db-48ac-bbac-38159a42dfe3}"/>
|
||||||
<edge from="{d0250089-5e1a-43f7-b5f8-363642c7ae79}" id="{27cad29d-2627-4b05-84d2-2750c54e60b5}" partId="{881a0adc-3b0d-4575-b7d7-d6df8907e3f3}" to="{4c1029e5-c16d-442c-bc48-bdeed5d4706a}"/>
|
<edge from="{d0250089-5e1a-43f7-b5f8-363642c7ae79}" id="{27cad29d-2627-4b05-84d2-2750c54e60b5}" partId="{79289522-791a-488f-bd2d-15db6c8f2f84}" to="{4c1029e5-c16d-442c-bc48-bdeed5d4706a}"/>
|
||||||
<edge from="{5ff7a560-b046-4ddd-b26e-7dfbcc1083b3}" id="{29ef255d-fb26-46af-8acb-0731e1e182f3}" partId="{983cf6ce-44d9-41e8-8489-289b423a423a}" to="{83e2e87a-2fd0-4df4-8278-28dd30482f67}"/>
|
<edge from="{5ff7a560-b046-4ddd-b26e-7dfbcc1083b3}" id="{29ef255d-fb26-46af-8acb-0731e1e182f3}" partId="{1f878838-6686-4bcc-bc82-d9c5583d05e8}" to="{83e2e87a-2fd0-4df4-8278-28dd30482f67}"/>
|
||||||
<edge from="{9d2b664d-a090-4c9c-b8a3-6a07d8d0eb08}" id="{339d89cb-a895-456a-8efe-9c80c47fa0fc}" partId="{fe5e25e8-58cb-43d5-ba72-c64e2cf44d6d}" to="{f06c29c3-080f-48d0-8ed5-e6fd3fabd51d}"/>
|
<edge from="{9d2b664d-a090-4c9c-b8a3-6a07d8d0eb08}" id="{339d89cb-a895-456a-8efe-9c80c47fa0fc}" partId="{6ff1a4e8-b864-4c5e-8a8e-2d28edd2c55a}" to="{f06c29c3-080f-48d0-8ed5-e6fd3fabd51d}"/>
|
||||||
<edge from="{d7dd0c55-e568-413d-99f0-cf91bcc4c534}" id="{39358088-3f7b-400e-886b-01576860291d}" partId="{2dacf558-7216-4577-8631-16769f860e18}" to="{3c4fd98e-c829-43f2-9ae5-c3c1c064a0a8}"/>
|
<edge from="{d7dd0c55-e568-413d-99f0-cf91bcc4c534}" id="{39358088-3f7b-400e-886b-01576860291d}" partId="{828c4638-7c11-4aeb-8f23-773dbeea8440}" to="{3c4fd98e-c829-43f2-9ae5-c3c1c064a0a8}"/>
|
||||||
<edge from="{98e623f4-0c83-4da8-9ba8-c4d470f0c5f0}" id="{3e3290b7-49b3-47a2-9bed-325b13b8f13f}" partId="{6c3c3e49-1701-4f8c-9490-32d51f52fe9f}" to="{c0cb6b06-3876-4550-9c05-29110ae1f2d9}"/>
|
<edge from="{98e623f4-0c83-4da8-9ba8-c4d470f0c5f0}" id="{3e3290b7-49b3-47a2-9bed-325b13b8f13f}" partId="{b049bb5c-a4e5-402e-88db-a5cccbee3851}" to="{c0cb6b06-3876-4550-9c05-29110ae1f2d9}"/>
|
||||||
<edge from="{cb6c4607-f520-4a2e-b282-e54e2cb8165a}" id="{457abb0d-0c84-4d74-9e94-bf366c3c341b}" partId="{fe5e25e8-58cb-43d5-ba72-c64e2cf44d6d}" to="{78d00d69-b1b9-4fad-b0cc-87f9b6f1539f}"/>
|
<edge from="{cb6c4607-f520-4a2e-b282-e54e2cb8165a}" id="{457abb0d-0c84-4d74-9e94-bf366c3c341b}" partId="{6ff1a4e8-b864-4c5e-8a8e-2d28edd2c55a}" to="{78d00d69-b1b9-4fad-b0cc-87f9b6f1539f}"/>
|
||||||
<edge from="{0cecd379-b9d6-4568-9d5b-82720916a6e4}" id="{47a88fde-5580-411f-afef-edb3742e6b5d}" partId="{0b8f8da9-d461-48c4-bbfd-343f0b648235}" to="{a4935618-a165-4f84-aabf-c6d317c7a714}"/>
|
<edge from="{0cecd379-b9d6-4568-9d5b-82720916a6e4}" id="{47a88fde-5580-411f-afef-edb3742e6b5d}" partId="{0048f320-55a9-4777-914e-95944cb34b46}" to="{a4935618-a165-4f84-aabf-c6d317c7a714}"/>
|
||||||
<edge from="{4946f825-7960-4653-9148-8d21e269c74e}" id="{4ee5c0b3-ac1e-4918-92ea-957b4f996fcc}" partId="{d5ccb7d6-3357-473c-a26a-12ce5713d92e}" to="{50c1e61f-d968-4d2f-b4c2-9839326f49da}"/>
|
<edge from="{4946f825-7960-4653-9148-8d21e269c74e}" id="{4ee5c0b3-ac1e-4918-92ea-957b4f996fcc}" partId="{9c9383da-b1ad-4fed-ac7d-e65d9334882f}" to="{50c1e61f-d968-4d2f-b4c2-9839326f49da}"/>
|
||||||
<edge from="{3e59449e-b487-4708-8b3e-31242cb50d19}" id="{5480ad4e-1ec3-496c-8841-517dee20eff1}" partId="{881a0adc-3b0d-4575-b7d7-d6df8907e3f3}" to="{13bc43e1-b35e-4645-8fd5-e9e8b16d5fc8}"/>
|
<edge from="{3e59449e-b487-4708-8b3e-31242cb50d19}" id="{5480ad4e-1ec3-496c-8841-517dee20eff1}" partId="{79289522-791a-488f-bd2d-15db6c8f2f84}" to="{13bc43e1-b35e-4645-8fd5-e9e8b16d5fc8}"/>
|
||||||
<edge from="{8642cce7-c158-4559-99af-bf2caa121348}" id="{57eeedc3-4844-42f5-90d3-176d8b9a0ded}" partId="{d2be1f6f-2053-491c-962b-f27e1a809848}" to="{69d7c60a-eaa7-4d64-a09b-755fb3b4c9ae}"/>
|
<edge from="{8642cce7-c158-4559-99af-bf2caa121348}" id="{57eeedc3-4844-42f5-90d3-176d8b9a0ded}" partId="{93d5b991-f821-4974-96bd-17c46090ffa9}" to="{69d7c60a-eaa7-4d64-a09b-755fb3b4c9ae}"/>
|
||||||
<edge from="{69d7c60a-eaa7-4d64-a09b-755fb3b4c9ae}" id="{5bdecde8-59e6-4c52-bf16-775df40f8207}" partId="{d2be1f6f-2053-491c-962b-f27e1a809848}" to="{da8b7964-8659-41c2-aeee-aa3a1bf7d39c}"/>
|
<edge from="{69d7c60a-eaa7-4d64-a09b-755fb3b4c9ae}" id="{5bdecde8-59e6-4c52-bf16-775df40f8207}" partId="{93d5b991-f821-4974-96bd-17c46090ffa9}" to="{da8b7964-8659-41c2-aeee-aa3a1bf7d39c}"/>
|
||||||
<edge from="{27721191-b625-44bd-9253-cfc7df7b094b}" id="{5de6c308-5fa9-48a8-b3c4-173fbeb3c4d7}" partId="{dd604661-6acc-4ef1-83fc-36a374c54734}" to="{05872b14-1e9a-4ba9-bbf8-0111c9100527}"/>
|
<edge from="{27721191-b625-44bd-9253-cfc7df7b094b}" id="{5de6c308-5fa9-48a8-b3c4-173fbeb3c4d7}" partId="{ff29229a-564e-4e50-af37-0ae6c25b78ae}" to="{05872b14-1e9a-4ba9-bbf8-0111c9100527}"/>
|
||||||
<edge from="{a019b2a5-f245-4139-b1a2-6b9462326c51}" id="{604937ca-7961-439f-87a0-2979b2bba504}" partId="{983cf6ce-44d9-41e8-8489-289b423a423a}" to="{5ff7a560-b046-4ddd-b26e-7dfbcc1083b3}"/>
|
<edge from="{a019b2a5-f245-4139-b1a2-6b9462326c51}" id="{604937ca-7961-439f-87a0-2979b2bba504}" partId="{1f878838-6686-4bcc-bc82-d9c5583d05e8}" to="{5ff7a560-b046-4ddd-b26e-7dfbcc1083b3}"/>
|
||||||
<edge from="{6954e176-c739-40d8-b1ef-8ce38884bba2}" id="{67791486-597e-407f-b7fa-fcdd952976d5}" partId="{881a0adc-3b0d-4575-b7d7-d6df8907e3f3}" to="{d0250089-5e1a-43f7-b5f8-363642c7ae79}"/>
|
<edge from="{6954e176-c739-40d8-b1ef-8ce38884bba2}" id="{67791486-597e-407f-b7fa-fcdd952976d5}" partId="{79289522-791a-488f-bd2d-15db6c8f2f84}" to="{d0250089-5e1a-43f7-b5f8-363642c7ae79}"/>
|
||||||
<edge from="{79b757ee-5f39-4a71-8019-5e447daa9860}" id="{691fca9b-c174-480d-910a-084130308108}" partId="{d4c0d323-791a-4a2a-ad1b-8e8fb93bf42d}" to="{b5c30ec3-4045-4502-911b-bc29b8a93496}"/>
|
<edge from="{79b757ee-5f39-4a71-8019-5e447daa9860}" id="{691fca9b-c174-480d-910a-084130308108}" partId="{8d55eb65-52a8-47da-9b5b-7d6d914943cc}" to="{b5c30ec3-4045-4502-911b-bc29b8a93496}"/>
|
||||||
<edge from="{5d85b12a-fdd1-42c7-83d4-027d77716fc8}" id="{69cf3563-054e-4b4e-88b3-9077aba0309c}" partId="{c9c2c2b9-571b-4067-8b01-b59725670dd4}" to="{273c09b7-d466-496f-9d06-ef7fa267c9a7}"/>
|
<edge from="{5d85b12a-fdd1-42c7-83d4-027d77716fc8}" id="{69cf3563-054e-4b4e-88b3-9077aba0309c}" partId="{c569a92e-6b1b-4d8b-9284-76fef9c124f0}" to="{273c09b7-d466-496f-9d06-ef7fa267c9a7}"/>
|
||||||
<edge from="{78f63ac5-8fc8-40dd-80e4-b316b3b4b409}" id="{69dd2419-2eae-4dad-9e0b-857099719a24}" partId="{dd604661-6acc-4ef1-83fc-36a374c54734}" to="{27721191-b625-44bd-9253-cfc7df7b094b}"/>
|
<edge from="{78f63ac5-8fc8-40dd-80e4-b316b3b4b409}" id="{69dd2419-2eae-4dad-9e0b-857099719a24}" partId="{ff29229a-564e-4e50-af37-0ae6c25b78ae}" to="{27721191-b625-44bd-9253-cfc7df7b094b}"/>
|
||||||
<edge from="{ca7d354f-4221-4301-ba44-4ee63ac652de}" id="{71893b64-d141-4d64-a360-066f34d22cfe}" partId="{546efa0c-392d-47c5-80c1-4138b07cf0a4}" to="{e73bbdbf-3ba8-4a70-99e0-bde3f7f1e5cd}"/>
|
<edge from="{ca7d354f-4221-4301-ba44-4ee63ac652de}" id="{71893b64-d141-4d64-a360-066f34d22cfe}" partId="{2162fa67-7e23-4e5f-9a9d-4175b10c44c9}" to="{e73bbdbf-3ba8-4a70-99e0-bde3f7f1e5cd}"/>
|
||||||
<edge from="{fa9f59c1-5451-4e3f-839a-39ae13615edf}" id="{727a73c2-d792-449a-ad3d-2a2ea5807f3d}" partId="{15325291-8856-42d7-9bc0-eb9ea53eadc1}" to="{f467cb17-e94e-43f1-822c-c95dcb59c4a1}"/>
|
<edge from="{fa9f59c1-5451-4e3f-839a-39ae13615edf}" id="{727a73c2-d792-449a-ad3d-2a2ea5807f3d}" partId="{3d3ba42b-7be6-4174-96c3-500daab0dc7f}" to="{f467cb17-e94e-43f1-822c-c95dcb59c4a1}"/>
|
||||||
<edge from="{b5f2d7c5-24dd-41e3-9dce-47e8db05ca86}" id="{781b9387-2b6e-4aa2-b944-69b41906b89e}" partId="{ad2259a2-362c-499e-9123-d6f8ac0a1966}" to="{df5207c8-afdb-4305-b322-33de580b7379}"/>
|
<edge from="{b5f2d7c5-24dd-41e3-9dce-47e8db05ca86}" id="{781b9387-2b6e-4aa2-b944-69b41906b89e}" partId="{422ad92f-8ad5-402a-9629-2348eb14e103}" to="{df5207c8-afdb-4305-b322-33de580b7379}"/>
|
||||||
<edge from="{fa3fc46e-827d-47b3-b266-5ad5728d9247}" id="{783f01bb-a97c-4601-b1c0-5f6e17aa4e3a}" partId="{2dacf558-7216-4577-8631-16769f860e18}" to="{d7dd0c55-e568-413d-99f0-cf91bcc4c534}"/>
|
<edge from="{fa3fc46e-827d-47b3-b266-5ad5728d9247}" id="{783f01bb-a97c-4601-b1c0-5f6e17aa4e3a}" partId="{828c4638-7c11-4aeb-8f23-773dbeea8440}" to="{d7dd0c55-e568-413d-99f0-cf91bcc4c534}"/>
|
||||||
<edge from="{6186ebb3-84a4-4f2c-9992-b39a3831dea3}" id="{7846da51-81d8-434f-b461-08c0e56aeb40}" partId="{57622c57-5929-4a6a-b4ac-17dc909f002a}" to="{457564d3-ccd0-465a-8d0b-b57c379666fd}"/>
|
<edge from="{6186ebb3-84a4-4f2c-9992-b39a3831dea3}" id="{7846da51-81d8-434f-b461-08c0e56aeb40}" partId="{0a57548e-12d8-4488-9ce4-8fe3b64db253}" to="{457564d3-ccd0-465a-8d0b-b57c379666fd}"/>
|
||||||
<edge from="{13bc43e1-b35e-4645-8fd5-e9e8b16d5fc8}" id="{7cc566fa-0f48-421c-bfa8-fe802bcf7837}" partId="{881a0adc-3b0d-4575-b7d7-d6df8907e3f3}" to="{f53d85ae-0a06-47aa-8402-b5e0124cff66}"/>
|
<edge from="{13bc43e1-b35e-4645-8fd5-e9e8b16d5fc8}" id="{7cc566fa-0f48-421c-bfa8-fe802bcf7837}" partId="{79289522-791a-488f-bd2d-15db6c8f2f84}" to="{f53d85ae-0a06-47aa-8402-b5e0124cff66}"/>
|
||||||
<edge from="{13d47f89-649c-4830-ba6d-fbf7f132793e}" id="{7cd31182-1d8a-4a5a-a860-8a57a92d780f}" partId="{9fae01c2-855a-472b-8181-02a1b76fcab1}" to="{5bad0bb7-9015-44cc-a57f-4200b20a84f0}"/>
|
<edge from="{13d47f89-649c-4830-ba6d-fbf7f132793e}" id="{7cd31182-1d8a-4a5a-a860-8a57a92d780f}" partId="{b6e20100-8c2b-4550-aee8-806aa713c90c}" to="{5bad0bb7-9015-44cc-a57f-4200b20a84f0}"/>
|
||||||
<edge from="{feacc347-69c3-4789-b565-9ac8156fca41}" id="{7eab925b-db9e-4fe9-ae08-f953009c0cb2}" partId="{b27111c8-625f-405d-88a9-55df58d51de0}" to="{08f7ae7b-869a-4f40-87a4-a575d78c2a60}"/>
|
<edge from="{feacc347-69c3-4789-b565-9ac8156fca41}" id="{7eab925b-db9e-4fe9-ae08-f953009c0cb2}" partId="{5f080e1f-48f5-4aa7-aa0c-d175f9045341}" to="{08f7ae7b-869a-4f40-87a4-a575d78c2a60}"/>
|
||||||
<edge from="{f700b2e2-8fa0-4ea7-87e7-9a668edc7749}" id="{80408bef-00bd-4a51-95a6-1960595f17ba}" partId="{442a221d-5a04-4d09-9cfd-bdd138320c26}" to="{5eb58123-c8a7-4899-a34e-1c63df33e759}"/>
|
<edge from="{f700b2e2-8fa0-4ea7-87e7-9a668edc7749}" id="{80408bef-00bd-4a51-95a6-1960595f17ba}" partId="{de6790b2-a8be-42ea-9f96-75c8ac21c6da}" to="{5eb58123-c8a7-4899-a34e-1c63df33e759}"/>
|
||||||
<edge from="{944c7657-e978-4bb6-94ad-b03dbafae824}" id="{80e8f33c-7074-4a24-85c0-47c2508c6349}" partId="{d5ccb7d6-3357-473c-a26a-12ce5713d92e}" to="{bb1434c7-51ad-4226-a6e0-2e0ee5c626d7}"/>
|
<edge from="{944c7657-e978-4bb6-94ad-b03dbafae824}" id="{80e8f33c-7074-4a24-85c0-47c2508c6349}" partId="{9c9383da-b1ad-4fed-ac7d-e65d9334882f}" to="{bb1434c7-51ad-4226-a6e0-2e0ee5c626d7}"/>
|
||||||
<edge from="{22f4fc91-c657-497f-aef8-87d38a42e23f}" id="{83113970-b08c-4f44-ad8f-f3ec8260fd73}" partId="{d5ccb7d6-3357-473c-a26a-12ce5713d92e}" to="{4946f825-7960-4653-9148-8d21e269c74e}"/>
|
<edge from="{22f4fc91-c657-497f-aef8-87d38a42e23f}" id="{83113970-b08c-4f44-ad8f-f3ec8260fd73}" partId="{9c9383da-b1ad-4fed-ac7d-e65d9334882f}" to="{4946f825-7960-4653-9148-8d21e269c74e}"/>
|
||||||
<edge from="{83e2e87a-2fd0-4df4-8278-28dd30482f67}" id="{83308095-fe21-419b-8409-31ba40d9bb4f}" partId="{983cf6ce-44d9-41e8-8489-289b423a423a}" to="{b1a0502c-3215-461f-b003-4edd9a13562b}"/>
|
<edge from="{83e2e87a-2fd0-4df4-8278-28dd30482f67}" id="{83308095-fe21-419b-8409-31ba40d9bb4f}" partId="{1f878838-6686-4bcc-bc82-d9c5583d05e8}" to="{b1a0502c-3215-461f-b003-4edd9a13562b}"/>
|
||||||
<edge from="{274f069c-1c6b-4837-8892-853ca652c07e}" id="{855fc650-6623-4dcf-a1cd-04fabd1ab5d3}" partId="{471dfce0-6e13-4146-b261-2090e30f407b}" to="{6e90e23a-c67b-4dc7-af76-2145793a9c3b}"/>
|
<edge from="{274f069c-1c6b-4837-8892-853ca652c07e}" id="{855fc650-6623-4dcf-a1cd-04fabd1ab5d3}" partId="{aceff516-7672-4ab0-8de4-10fb8c7a0681}" to="{6e90e23a-c67b-4dc7-af76-2145793a9c3b}"/>
|
||||||
<edge from="{6b2d17cd-4fbe-4fd3-8f80-6c467d3811fd}" id="{884e4588-1fd9-4a4a-8ded-7c571f02606a}" partId="{471dfce0-6e13-4146-b261-2090e30f407b}" to="{274f069c-1c6b-4837-8892-853ca652c07e}"/>
|
<edge from="{6b2d17cd-4fbe-4fd3-8f80-6c467d3811fd}" id="{884e4588-1fd9-4a4a-8ded-7c571f02606a}" partId="{aceff516-7672-4ab0-8de4-10fb8c7a0681}" to="{274f069c-1c6b-4837-8892-853ca652c07e}"/>
|
||||||
<edge from="{f06c29c3-080f-48d0-8ed5-e6fd3fabd51d}" id="{8906f231-ed91-47ce-8959-3ea190eb7381}" partId="{fe5e25e8-58cb-43d5-ba72-c64e2cf44d6d}" to="{d2f082e0-13c8-4bc5-8c05-06cea9d46463}"/>
|
<edge from="{f06c29c3-080f-48d0-8ed5-e6fd3fabd51d}" id="{8906f231-ed91-47ce-8959-3ea190eb7381}" partId="{6ff1a4e8-b864-4c5e-8a8e-2d28edd2c55a}" to="{d2f082e0-13c8-4bc5-8c05-06cea9d46463}"/>
|
||||||
<edge from="{c0535c22-dc84-4a77-84fc-d04b2d839575}" id="{91257c7b-4fc7-4dbf-baf7-d42b475856d4}" partId="{019249f8-0f48-4f9e-87e3-6d2e821e87ac}" to="{b078b7da-3fce-44fb-9dd0-9812f579991e}"/>
|
<edge from="{c0535c22-dc84-4a77-84fc-d04b2d839575}" id="{91257c7b-4fc7-4dbf-baf7-d42b475856d4}" partId="{65aa6ccd-94db-47cf-aa84-dce3c2b3fa65}" to="{b078b7da-3fce-44fb-9dd0-9812f579991e}"/>
|
||||||
<edge from="{9bc24536-52b6-42c4-801e-6994069ae93b}" id="{94792102-b5f4-4986-9b3f-7ceed3d3f78a}" partId="{91850869-d0e1-4e42-a452-d1259dbd5643}" to="{a43e38c8-aa79-4a6f-860b-65055bafcf62}"/>
|
<edge from="{9bc24536-52b6-42c4-801e-6994069ae93b}" id="{94792102-b5f4-4986-9b3f-7ceed3d3f78a}" partId="{c2b415b2-4419-408e-be54-1b6b2521441a}" to="{a43e38c8-aa79-4a6f-860b-65055bafcf62}"/>
|
||||||
<edge from="{00da2bf5-53b1-495b-8f56-aaf78e74e9c2}" id="{97adbdb0-987f-46d3-815b-bb9c50f494d1}" partId="{57622c57-5929-4a6a-b4ac-17dc909f002a}" to="{c578f2fb-079d-43a6-873d-6e094e7df09a}"/>
|
<edge from="{00da2bf5-53b1-495b-8f56-aaf78e74e9c2}" id="{97adbdb0-987f-46d3-815b-bb9c50f494d1}" partId="{0a57548e-12d8-4488-9ce4-8fe3b64db253}" to="{c578f2fb-079d-43a6-873d-6e094e7df09a}"/>
|
||||||
<edge from="{bfb08a33-feee-4741-9855-64add2915ec4}" id="{98e36f0b-f0b7-4d76-b0ac-284d0c945aaa}" partId="{546efa0c-392d-47c5-80c1-4138b07cf0a4}" to="{8b71e1a2-e0bc-435d-9bd2-c096f60c7f23}"/>
|
<edge from="{bfb08a33-feee-4741-9855-64add2915ec4}" id="{98e36f0b-f0b7-4d76-b0ac-284d0c945aaa}" partId="{2162fa67-7e23-4e5f-9a9d-4175b10c44c9}" to="{8b71e1a2-e0bc-435d-9bd2-c096f60c7f23}"/>
|
||||||
<edge from="{50c1e61f-d968-4d2f-b4c2-9839326f49da}" id="{9973a3e5-fc86-485c-84ac-c9bdddcef463}" partId="{d5ccb7d6-3357-473c-a26a-12ce5713d92e}" to="{944c7657-e978-4bb6-94ad-b03dbafae824}"/>
|
<edge from="{50c1e61f-d968-4d2f-b4c2-9839326f49da}" id="{9973a3e5-fc86-485c-84ac-c9bdddcef463}" partId="{9c9383da-b1ad-4fed-ac7d-e65d9334882f}" to="{944c7657-e978-4bb6-94ad-b03dbafae824}"/>
|
||||||
<edge from="{0891b311-79de-4ed7-8410-b3e43e675a9b}" id="{9baf5410-751e-44e2-a8dd-28f81d6b834b}" partId="{ad2259a2-362c-499e-9123-d6f8ac0a1966}" to="{7305f345-84d5-44b5-af37-c48bf3925ca4}"/>
|
<edge from="{0891b311-79de-4ed7-8410-b3e43e675a9b}" id="{9baf5410-751e-44e2-a8dd-28f81d6b834b}" partId="{422ad92f-8ad5-402a-9629-2348eb14e103}" to="{7305f345-84d5-44b5-af37-c48bf3925ca4}"/>
|
||||||
<edge from="{c03d7db7-dcba-4926-b22d-04bd37ed3b65}" id="{aa2acb4a-8151-44e4-83d9-af6588273f03}" partId="{6c3c3e49-1701-4f8c-9490-32d51f52fe9f}" to="{98e623f4-0c83-4da8-9ba8-c4d470f0c5f0}"/>
|
<edge from="{c03d7db7-dcba-4926-b22d-04bd37ed3b65}" id="{aa2acb4a-8151-44e4-83d9-af6588273f03}" partId="{b049bb5c-a4e5-402e-88db-a5cccbee3851}" to="{98e623f4-0c83-4da8-9ba8-c4d470f0c5f0}"/>
|
||||||
<edge from="{bcb62c53-e5db-48ac-bbac-38159a42dfe3}" id="{aae25104-da55-41df-a259-6124f8394c67}" partId="{57622c57-5929-4a6a-b4ac-17dc909f002a}" to="{00da2bf5-53b1-495b-8f56-aaf78e74e9c2}"/>
|
<edge from="{bcb62c53-e5db-48ac-bbac-38159a42dfe3}" id="{aae25104-da55-41df-a259-6124f8394c67}" partId="{0a57548e-12d8-4488-9ce4-8fe3b64db253}" to="{00da2bf5-53b1-495b-8f56-aaf78e74e9c2}"/>
|
||||||
<edge from="{3d6b06a7-af07-48e4-849b-204cb9af6a69}" id="{b4182212-1b23-4672-b18f-99059a6e86e6}" partId="{881a0adc-3b0d-4575-b7d7-d6df8907e3f3}" to="{3e59449e-b487-4708-8b3e-31242cb50d19}"/>
|
<edge from="{3d6b06a7-af07-48e4-849b-204cb9af6a69}" id="{b4182212-1b23-4672-b18f-99059a6e86e6}" partId="{79289522-791a-488f-bd2d-15db6c8f2f84}" to="{3e59449e-b487-4708-8b3e-31242cb50d19}"/>
|
||||||
<edge from="{25b52681-7ee3-458e-8db2-bf784e1c101d}" id="{b5b4b7f9-66bc-4312-b962-2e9b17431841}" partId="{b27111c8-625f-405d-88a9-55df58d51de0}" to="{9ad35b2b-3998-4822-9ecf-ff2425531106}"/>
|
<edge from="{25b52681-7ee3-458e-8db2-bf784e1c101d}" id="{b5b4b7f9-66bc-4312-b962-2e9b17431841}" partId="{5f080e1f-48f5-4aa7-aa0c-d175f9045341}" to="{9ad35b2b-3998-4822-9ecf-ff2425531106}"/>
|
||||||
<edge from="{08f7ae7b-869a-4f40-87a4-a575d78c2a60}" id="{b5d52537-0126-473f-b846-e9776e763d6f}" partId="{b27111c8-625f-405d-88a9-55df58d51de0}" to="{2e54f33b-c879-4e40-83cc-75eeefaccdc3}"/>
|
<edge from="{08f7ae7b-869a-4f40-87a4-a575d78c2a60}" id="{b5d52537-0126-473f-b846-e9776e763d6f}" partId="{5f080e1f-48f5-4aa7-aa0c-d175f9045341}" to="{2e54f33b-c879-4e40-83cc-75eeefaccdc3}"/>
|
||||||
<edge from="{9ad35b2b-3998-4822-9ecf-ff2425531106}" id="{b5fcb83f-4aee-4d3d-a105-e22272e7556f}" partId="{b27111c8-625f-405d-88a9-55df58d51de0}" to="{2073cdb1-77ef-4c51-8ca0-4ad4e0908d6c}"/>
|
<edge from="{9ad35b2b-3998-4822-9ecf-ff2425531106}" id="{b5fcb83f-4aee-4d3d-a105-e22272e7556f}" partId="{5f080e1f-48f5-4aa7-aa0c-d175f9045341}" to="{2073cdb1-77ef-4c51-8ca0-4ad4e0908d6c}"/>
|
||||||
<edge from="{5eb58123-c8a7-4899-a34e-1c63df33e759}" id="{b84ac82e-48bb-4adb-bf52-d3fe98dc7fc3}" partId="{442a221d-5a04-4d09-9cfd-bdd138320c26}" to="{286523f2-bf39-4f2c-aae7-dcf7223140e4}"/>
|
<edge from="{5eb58123-c8a7-4899-a34e-1c63df33e759}" id="{b84ac82e-48bb-4adb-bf52-d3fe98dc7fc3}" partId="{de6790b2-a8be-42ea-9f96-75c8ac21c6da}" to="{286523f2-bf39-4f2c-aae7-dcf7223140e4}"/>
|
||||||
<edge from="{273c09b7-d466-496f-9d06-ef7fa267c9a7}" id="{b8aa3f35-e0e1-4490-98c3-d3edcc4234d7}" partId="{c9c2c2b9-571b-4067-8b01-b59725670dd4}" to="{a003f447-592d-45db-ac31-50e1b0dacb02}"/>
|
<edge from="{273c09b7-d466-496f-9d06-ef7fa267c9a7}" id="{b8aa3f35-e0e1-4490-98c3-d3edcc4234d7}" partId="{c569a92e-6b1b-4d8b-9284-76fef9c124f0}" to="{a003f447-592d-45db-ac31-50e1b0dacb02}"/>
|
||||||
<edge from="{2b5dae5c-17e3-4632-ab54-36e21859fbca}" id="{bbe18ec3-0537-4d8f-8cdb-3bff15339b18}" partId="{ad2259a2-362c-499e-9123-d6f8ac0a1966}" to="{0891b311-79de-4ed7-8410-b3e43e675a9b}"/>
|
<edge from="{2b5dae5c-17e3-4632-ab54-36e21859fbca}" id="{bbe18ec3-0537-4d8f-8cdb-3bff15339b18}" partId="{422ad92f-8ad5-402a-9629-2348eb14e103}" to="{0891b311-79de-4ed7-8410-b3e43e675a9b}"/>
|
||||||
<edge from="{25e5be7a-dbb8-4d8f-a0b7-441eef6c694f}" id="{bdb3e1c9-df23-4482-9acb-2ef1aaf4da86}" partId="{d5ccb7d6-3357-473c-a26a-12ce5713d92e}" to="{22f4fc91-c657-497f-aef8-87d38a42e23f}"/>
|
<edge from="{25e5be7a-dbb8-4d8f-a0b7-441eef6c694f}" id="{bdb3e1c9-df23-4482-9acb-2ef1aaf4da86}" partId="{9c9383da-b1ad-4fed-ac7d-e65d9334882f}" to="{22f4fc91-c657-497f-aef8-87d38a42e23f}"/>
|
||||||
<edge from="{7305f345-84d5-44b5-af37-c48bf3925ca4}" id="{be288181-dd71-413e-a459-fbc568ebeacf}" partId="{ad2259a2-362c-499e-9123-d6f8ac0a1966}" to="{b5f2d7c5-24dd-41e3-9dce-47e8db05ca86}"/>
|
<edge from="{7305f345-84d5-44b5-af37-c48bf3925ca4}" id="{be288181-dd71-413e-a459-fbc568ebeacf}" partId="{422ad92f-8ad5-402a-9629-2348eb14e103}" to="{b5f2d7c5-24dd-41e3-9dce-47e8db05ca86}"/>
|
||||||
<edge from="{ef8ef04c-4d5b-4663-a607-d1fa25995a0e}" id="{c174d83a-8896-4fc8-8263-7d3d45624d2f}" partId="{d2be1f6f-2053-491c-962b-f27e1a809848}" to="{b1aec088-f56d-4b96-b34b-4602276b67f4}"/>
|
<edge from="{ef8ef04c-4d5b-4663-a607-d1fa25995a0e}" id="{c174d83a-8896-4fc8-8263-7d3d45624d2f}" partId="{93d5b991-f821-4974-96bd-17c46090ffa9}" to="{b1aec088-f56d-4b96-b34b-4602276b67f4}"/>
|
||||||
<edge from="{b5c30ec3-4045-4502-911b-bc29b8a93496}" id="{c6dbe094-8524-4ddc-b4ee-50d4972c0d32}" partId="{d4c0d323-791a-4a2a-ad1b-8e8fb93bf42d}" to="{a6567353-5b7a-4de0-8d0f-b916fd8a7287}"/>
|
<edge from="{b5c30ec3-4045-4502-911b-bc29b8a93496}" id="{c6dbe094-8524-4ddc-b4ee-50d4972c0d32}" partId="{8d55eb65-52a8-47da-9b5b-7d6d914943cc}" to="{a6567353-5b7a-4de0-8d0f-b916fd8a7287}"/>
|
||||||
<edge from="{78f63ac5-8fc8-40dd-80e4-b316b3b4b409}" id="{c9b8937c-b107-4b7d-bbca-ed9ff44511e6}" partId="{dd604661-6acc-4ef1-83fc-36a374c54734}" to="{4b8f93a6-db8f-47c8-8d37-777db444914c}"/>
|
<edge from="{78f63ac5-8fc8-40dd-80e4-b316b3b4b409}" id="{c9b8937c-b107-4b7d-bbca-ed9ff44511e6}" partId="{ff29229a-564e-4e50-af37-0ae6c25b78ae}" to="{4b8f93a6-db8f-47c8-8d37-777db444914c}"/>
|
||||||
<edge from="{37ad0424-3633-48a9-a2ea-bac83d140ec8}" id="{cbc0c4f2-b380-4c9d-a558-ce0b8dc27df7}" partId="{b27111c8-625f-405d-88a9-55df58d51de0}" to="{25b52681-7ee3-458e-8db2-bf784e1c101d}"/>
|
<edge from="{37ad0424-3633-48a9-a2ea-bac83d140ec8}" id="{cbc0c4f2-b380-4c9d-a558-ce0b8dc27df7}" partId="{5f080e1f-48f5-4aa7-aa0c-d175f9045341}" to="{25b52681-7ee3-458e-8db2-bf784e1c101d}"/>
|
||||||
<edge from="{3c4fd98e-c829-43f2-9ae5-c3c1c064a0a8}" id="{cc8fba76-684e-4dd1-bf89-4f7804bcd2b9}" partId="{2dacf558-7216-4577-8631-16769f860e18}" to="{5492a461-1b28-47c8-811c-2542022eff84}"/>
|
<edge from="{3c4fd98e-c829-43f2-9ae5-c3c1c064a0a8}" id="{cc8fba76-684e-4dd1-bf89-4f7804bcd2b9}" partId="{828c4638-7c11-4aeb-8f23-773dbeea8440}" to="{5492a461-1b28-47c8-811c-2542022eff84}"/>
|
||||||
<edge from="{1e7e802c-3711-40c8-9dd6-bcded439cffe}" id="{cd25b802-82bf-4920-afa6-3f4e53b91467}" partId="{a5ad3f64-2091-4cea-8085-e17881f0573d}" to="{27fb4823-e857-4e61-a454-a12d30ecfb17}"/>
|
<edge from="{1e7e802c-3711-40c8-9dd6-bcded439cffe}" id="{cd25b802-82bf-4920-afa6-3f4e53b91467}" partId="{cef2d5ce-ed55-4030-a415-e39a20d3ff86}" to="{27fb4823-e857-4e61-a454-a12d30ecfb17}"/>
|
||||||
<edge from="{8c4b6bea-3045-4b62-ba65-442c7c5548b9}" id="{d72ba288-db29-4126-a786-af95ba91ddc2}" partId="{d2be1f6f-2053-491c-962b-f27e1a809848}" to="{8642cce7-c158-4559-99af-bf2caa121348}"/>
|
<edge from="{8c4b6bea-3045-4b62-ba65-442c7c5548b9}" id="{d72ba288-db29-4126-a786-af95ba91ddc2}" partId="{93d5b991-f821-4974-96bd-17c46090ffa9}" to="{8642cce7-c158-4559-99af-bf2caa121348}"/>
|
||||||
<edge from="{f89eea85-45e0-47d7-a009-96e2086d58fc}" id="{de46426b-2eae-4d54-96de-edcd7d78c3b5}" partId="{57622c57-5929-4a6a-b4ac-17dc909f002a}" to="{6186ebb3-84a4-4f2c-9992-b39a3831dea3}"/>
|
<edge from="{f89eea85-45e0-47d7-a009-96e2086d58fc}" id="{de46426b-2eae-4d54-96de-edcd7d78c3b5}" partId="{0a57548e-12d8-4488-9ce4-8fe3b64db253}" to="{6186ebb3-84a4-4f2c-9992-b39a3831dea3}"/>
|
||||||
<edge from="{df5207c8-afdb-4305-b322-33de580b7379}" id="{de74f905-1595-47cc-bc6f-fe10ce731622}" partId="{ad2259a2-362c-499e-9123-d6f8ac0a1966}" to="{2bec4749-11de-442a-862f-8d04d0c590ef}"/>
|
<edge from="{df5207c8-afdb-4305-b322-33de580b7379}" id="{de74f905-1595-47cc-bc6f-fe10ce731622}" partId="{422ad92f-8ad5-402a-9629-2348eb14e103}" to="{2bec4749-11de-442a-862f-8d04d0c590ef}"/>
|
||||||
<edge from="{457564d3-ccd0-465a-8d0b-b57c379666fd}" id="{e277cc73-c658-4704-896e-25ec0bd28d3d}" partId="{57622c57-5929-4a6a-b4ac-17dc909f002a}" to="{f28a9edd-92c5-4e9e-9b69-e63ec9fd7f4f}"/>
|
<edge from="{457564d3-ccd0-465a-8d0b-b57c379666fd}" id="{e277cc73-c658-4704-896e-25ec0bd28d3d}" partId="{0a57548e-12d8-4488-9ce4-8fe3b64db253}" to="{f28a9edd-92c5-4e9e-9b69-e63ec9fd7f4f}"/>
|
||||||
<edge from="{52a3dfd0-0bb7-4869-91b2-85c729e289b0}" id="{e68abb76-b443-44cc-8673-a54dba1a53ee}" partId="{9fae01c2-855a-472b-8181-02a1b76fcab1}" to="{13d47f89-649c-4830-ba6d-fbf7f132793e}"/>
|
<edge from="{52a3dfd0-0bb7-4869-91b2-85c729e289b0}" id="{e68abb76-b443-44cc-8673-a54dba1a53ee}" partId="{b6e20100-8c2b-4550-aee8-806aa713c90c}" to="{13d47f89-649c-4830-ba6d-fbf7f132793e}"/>
|
||||||
<edge from="{e767a69a-e29d-4fbc-8e1d-615a443f40f5}" id="{e81d6458-fb42-4372-b45f-821f4e7869e3}" partId="{2c899cf6-d358-454e-ad79-5a5bddaf0bff}" to="{94c6dd69-3b99-4b25-b6dd-e8d80b579a7e}"/>
|
<edge from="{e767a69a-e29d-4fbc-8e1d-615a443f40f5}" id="{e81d6458-fb42-4372-b45f-821f4e7869e3}" partId="{3145e23e-d0bf-4f3f-8609-92f40c348fa5}" to="{94c6dd69-3b99-4b25-b6dd-e8d80b579a7e}"/>
|
||||||
<edge from="{419c8aca-4bb8-4bab-84e1-214b23a17a27}" id="{ede7f2e3-638d-4e9e-92ad-be7873d93dd4}" partId="{a5ad3f64-2091-4cea-8085-e17881f0573d}" to="{1e7e802c-3711-40c8-9dd6-bcded439cffe}"/>
|
<edge from="{419c8aca-4bb8-4bab-84e1-214b23a17a27}" id="{ede7f2e3-638d-4e9e-92ad-be7873d93dd4}" partId="{cef2d5ce-ed55-4030-a415-e39a20d3ff86}" to="{1e7e802c-3711-40c8-9dd6-bcded439cffe}"/>
|
||||||
<edge from="{2e54f33b-c879-4e40-83cc-75eeefaccdc3}" id="{efe6dea3-8a74-4cb8-8185-b3f81abec92a}" partId="{b27111c8-625f-405d-88a9-55df58d51de0}" to="{37ad0424-3633-48a9-a2ea-bac83d140ec8}"/>
|
<edge from="{2e54f33b-c879-4e40-83cc-75eeefaccdc3}" id="{efe6dea3-8a74-4cb8-8185-b3f81abec92a}" partId="{5f080e1f-48f5-4aa7-aa0c-d175f9045341}" to="{37ad0424-3633-48a9-a2ea-bac83d140ec8}"/>
|
||||||
<edge from="{d2f082e0-13c8-4bc5-8c05-06cea9d46463}" id="{fe31b37d-778b-49a2-8e14-7d6fa7bf62b6}" partId="{fe5e25e8-58cb-43d5-ba72-c64e2cf44d6d}" to="{cb6c4607-f520-4a2e-b282-e54e2cb8165a}"/>
|
<edge from="{d2f082e0-13c8-4bc5-8c05-06cea9d46463}" id="{fe31b37d-778b-49a2-8e14-7d6fa7bf62b6}" partId="{6ff1a4e8-b864-4c5e-8a8e-2d28edd2c55a}" to="{cb6c4607-f520-4a2e-b282-e54e2cb8165a}"/>
|
||||||
<edge from="{f53d85ae-0a06-47aa-8402-b5e0124cff66}" id="{fefb02c4-a3b4-4a66-a909-9c0a44bd56d4}" partId="{881a0adc-3b0d-4575-b7d7-d6df8907e3f3}" to="{6954e176-c739-40d8-b1ef-8ce38884bba2}"/>
|
<edge from="{f53d85ae-0a06-47aa-8402-b5e0124cff66}" id="{fefb02c4-a3b4-4a66-a909-9c0a44bd56d4}" partId="{79289522-791a-488f-bd2d-15db6c8f2f84}" to="{6954e176-c739-40d8-b1ef-8ce38884bba2}"/>
|
||||||
<edge from="{723a0584-b3a1-41a9-a9dc-96b21e733f1f}" id="{ffe15b4f-148a-4f9a-a782-7345734c42cf}" partId="{ad2259a2-362c-499e-9123-d6f8ac0a1966}" to="{2b5dae5c-17e3-4632-ab54-36e21859fbca}"/>
|
<edge from="{723a0584-b3a1-41a9-a9dc-96b21e733f1f}" id="{ffe15b4f-148a-4f9a-a782-7345734c42cf}" partId="{422ad92f-8ad5-402a-9629-2348eb14e103}" to="{2b5dae5c-17e3-4632-ab54-36e21859fbca}"/>
|
||||||
</edges>
|
</edges>
|
||||||
<parts>
|
<parts>
|
||||||
<part chamfered="false" color="#ffb6afb4" disabled="false" id="{019249f8-0f48-4f9e-87e3-6d2e821e87ac}" locked="false" rounded="false" subdived="false" visible="true" xMirrored="false"/>
|
<part chamfered="false" color="#ffb6afb4" disabled="false" id="{0048f320-55a9-4777-914e-95944cb34b46}" locked="false" rounded="false" subdived="true" visible="true" xMirrored="false"/>
|
||||||
<part chamfered="false" color="#ffb6afb4" disabled="false" id="{0b8f8da9-d461-48c4-bbfd-343f0b648235}" locked="false" rounded="false" subdived="true" visible="true" xMirrored="false"/>
|
<part chamfered="false" color="#ffb6afb4" countershaded="true" deformThickness="0.84" disabled="false" id="{0a57548e-12d8-4488-9ce4-8fe3b64db253}" locked="false" rounded="false" subdived="true" visible="true" xMirrored="false"/>
|
||||||
<part chamfered="false" color="#ffb6afb4" disabled="false" id="{15325291-8856-42d7-9bc0-eb9ea53eadc1}" locked="false" rounded="false" subdived="false" visible="true" xMirrored="false"/>
|
<part chamfered="false" color="#ffb6afb4" disabled="false" id="{1f878838-6686-4bcc-bc82-d9c5583d05e8}" locked="false" rounded="false" subdived="true" visible="true" xMirrored="false"/>
|
||||||
<part chamfered="false" color="#ff797477" disabled="false" id="{2c899cf6-d358-454e-ad79-5a5bddaf0bff}" locked="false" rounded="true" subdived="true" visible="true" xMirrored="true"/>
|
<part chamfered="false" color="#ffb6afb4" disabled="false" id="{2162fa67-7e23-4e5f-9a9d-4175b10c44c9}" locked="false" rounded="false" subdived="true" visible="true" xMirrored="false"/>
|
||||||
<part chamfered="false" color="#ffb6afb4" disabled="false" id="{2dacf558-7216-4577-8631-16769f860e18}" locked="false" rounded="false" subdived="true" visible="true" xMirrored="false"/>
|
<part chamfered="false" color="#ff797477" disabled="false" id="{3145e23e-d0bf-4f3f-8609-92f40c348fa5}" locked="false" rounded="true" subdived="true" visible="true" xMirrored="true"/>
|
||||||
<part chamfered="false" color="#ffb6afb4" disabled="false" id="{442a221d-5a04-4d09-9cfd-bdd138320c26}" locked="false" rounded="false" subdived="false" visible="true" xMirrored="false"/>
|
<part chamfered="false" color="#ffb6afb4" disabled="false" id="{3d3ba42b-7be6-4174-96c3-500daab0dc7f}" locked="false" rounded="false" subdived="false" visible="true" xMirrored="false"/>
|
||||||
<part chamfered="false" color="#ffb6afb4" disabled="false" id="{471dfce0-6e13-4146-b261-2090e30f407b}" locked="false" rounded="false" subdived="false" visible="true" xMirrored="false"/>
|
<part chamfered="false" color="#ffb6afb4" countershaded="true" deformWidth="0.82" disabled="false" id="{422ad92f-8ad5-402a-9629-2348eb14e103}" locked="false" rounded="true" subdived="true" visible="true" xMirrored="false"/>
|
||||||
<part chamfered="false" color="#ffb6afb4" disabled="false" id="{546efa0c-392d-47c5-80c1-4138b07cf0a4}" locked="false" rounded="false" subdived="true" visible="true" xMirrored="false"/>
|
<part chamfered="false" color="#ffb6afb4" deformWidth="0.84" disabled="false" id="{5f080e1f-48f5-4aa7-aa0c-d175f9045341}" locked="false" rounded="false" subdived="true" visible="true" xMirrored="false"/>
|
||||||
<part chamfered="false" color="#ffb6afb4" countershaded="true" deformThickness="0.84" disabled="false" id="{57622c57-5929-4a6a-b4ac-17dc909f002a}" locked="false" rounded="false" subdived="true" visible="true" xMirrored="false"/>
|
<part chamfered="false" color="#ff2a292a" disabled="false" id="{62dc13e0-9173-4223-9c39-c682f30a2338}" locked="false" rounded="false" subdived="true" visible="true" xMirrored="true"/>
|
||||||
<part chamfered="false" color="#ffb6afb4" disabled="false" id="{6c3c3e49-1701-4f8c-9490-32d51f52fe9f}" locked="false" rounded="false" subdived="false" visible="true" xMirrored="false"/>
|
<part chamfered="false" color="#ffb6afb4" disabled="false" id="{65aa6ccd-94db-47cf-aa84-dce3c2b3fa65}" locked="false" rounded="false" subdived="false" visible="true" xMirrored="false"/>
|
||||||
<part chamfered="false" color="#ff2a292a" disabled="false" id="{80e078b3-ad1d-4a0f-b695-e63bff35af45}" locked="false" rounded="false" subdived="true" visible="true" xMirrored="true"/>
|
<part chamfered="false" color="#ffb6afb4" countershaded="true" deformThickness="1.16" disabled="false" id="{6ff1a4e8-b864-4c5e-8a8e-2d28edd2c55a}" locked="false" rounded="true" subdived="true" visible="true" xMirrored="false"/>
|
||||||
<part chamfered="false" color="#ffb6afb4" deformWidth="0.84" disabled="false" id="{881a0adc-3b0d-4575-b7d7-d6df8907e3f3}" locked="false" rounded="false" subdived="true" visible="true" xMirrored="false"/>
|
<part chamfered="false" color="#ffb6afb4" deformWidth="0.84" disabled="false" id="{79289522-791a-488f-bd2d-15db6c8f2f84}" locked="false" rounded="false" subdived="true" visible="true" xMirrored="false"/>
|
||||||
<part chamfered="false" color="#ffb6afb4" disabled="false" id="{91850869-d0e1-4e42-a452-d1259dbd5643}" locked="false" rounded="false" subdived="false" visible="true" xMirrored="false"/>
|
<part chamfered="false" color="#ffb6afb4" disabled="false" id="{828c4638-7c11-4aeb-8f23-773dbeea8440}" locked="false" rounded="false" subdived="true" visible="true" xMirrored="false"/>
|
||||||
<part chamfered="false" color="#ffb6afb4" disabled="false" id="{983cf6ce-44d9-41e8-8489-289b423a423a}" locked="false" rounded="false" subdived="true" visible="true" xMirrored="false"/>
|
<part chamfered="false" color="#ffb6afb4" disabled="false" id="{8d55eb65-52a8-47da-9b5b-7d6d914943cc}" locked="false" rounded="false" subdived="false" visible="true" xMirrored="false"/>
|
||||||
<part chamfered="false" color="#ffb6afb4" disabled="false" id="{9fae01c2-855a-472b-8181-02a1b76fcab1}" locked="false" rounded="false" subdived="false" visible="true" xMirrored="false"/>
|
<part chamfered="false" color="#ffb6afb4" deformWidth="0.91" disabled="false" id="{93d5b991-f821-4974-96bd-17c46090ffa9}" locked="false" rounded="true" subdived="true" visible="true" xMirrored="false"/>
|
||||||
<part chamfered="false" color="#ffb6afb4" disabled="false" id="{a5ad3f64-2091-4cea-8085-e17881f0573d}" locked="false" rounded="false" subdived="false" visible="true" xMirrored="false"/>
|
<part chamfered="false" color="#ffb6afb4" deformWidth="0.91" disabled="false" id="{9c9383da-b1ad-4fed-ac7d-e65d9334882f}" locked="false" rounded="true" subdived="true" visible="true" xMirrored="false"/>
|
||||||
<part chamfered="false" color="#ffb6afb4" countershaded="true" deformWidth="0.82" disabled="false" id="{ad2259a2-362c-499e-9123-d6f8ac0a1966}" locked="false" rounded="true" subdived="true" visible="true" xMirrored="false"/>
|
<part chamfered="false" color="#ffb6afb4" disabled="false" id="{aceff516-7672-4ab0-8de4-10fb8c7a0681}" locked="false" rounded="false" subdived="false" visible="true" xMirrored="false"/>
|
||||||
<part chamfered="false" color="#ffb6afb4" deformWidth="0.84" disabled="false" id="{b27111c8-625f-405d-88a9-55df58d51de0}" locked="false" rounded="false" subdived="true" visible="true" xMirrored="false"/>
|
<part chamfered="false" color="#ffb6afb4" disabled="false" id="{b049bb5c-a4e5-402e-88db-a5cccbee3851}" locked="false" rounded="false" subdived="false" visible="true" xMirrored="false"/>
|
||||||
<part chamfered="false" color="#ffb6afb4" disabled="false" id="{c9c2c2b9-571b-4067-8b01-b59725670dd4}" locked="false" rounded="false" subdived="false" visible="true" xMirrored="false"/>
|
<part chamfered="false" color="#ffb6afb4" disabled="false" id="{b6e20100-8c2b-4550-aee8-806aa713c90c}" locked="false" rounded="false" subdived="false" visible="true" xMirrored="false"/>
|
||||||
<part chamfered="false" color="#ffb6afb4" deformWidth="0.91" disabled="false" id="{d2be1f6f-2053-491c-962b-f27e1a809848}" locked="false" rounded="true" subdived="true" visible="true" xMirrored="false"/>
|
<part chamfered="false" color="#ffb6afb4" disabled="false" id="{c2b415b2-4419-408e-be54-1b6b2521441a}" locked="false" rounded="false" subdived="false" visible="true" xMirrored="false"/>
|
||||||
<part chamfered="false" color="#ffb6afb4" disabled="false" id="{d4c0d323-791a-4a2a-ad1b-8e8fb93bf42d}" locked="false" rounded="false" subdived="false" visible="true" xMirrored="false"/>
|
<part chamfered="false" color="#ffb6afb4" disabled="false" id="{c569a92e-6b1b-4d8b-9284-76fef9c124f0}" locked="false" rounded="false" subdived="false" visible="true" xMirrored="false"/>
|
||||||
<part chamfered="false" color="#ffb6afb4" deformWidth="0.91" disabled="false" id="{d5ccb7d6-3357-473c-a26a-12ce5713d92e}" locked="false" rounded="true" subdived="true" visible="true" xMirrored="false"/>
|
<part chamfered="false" color="#ffb6afb4" disabled="false" id="{cef2d5ce-ed55-4030-a415-e39a20d3ff86}" locked="false" rounded="false" subdived="false" visible="true" xMirrored="false"/>
|
||||||
<part chamfered="false" color="#ffb6afb4" cutRotation="0.62" deformWidth="0.15" disabled="false" id="{dd604661-6acc-4ef1-83fc-36a374c54734}" locked="false" rounded="false" subdived="false" visible="true" xMirrored="true"/>
|
<part chamfered="false" color="#ffb6afb4" disabled="false" id="{de6790b2-a8be-42ea-9f96-75c8ac21c6da}" locked="false" rounded="false" subdived="false" visible="true" xMirrored="false"/>
|
||||||
<part chamfered="false" color="#ffb6afb4" countershaded="true" deformThickness="1.16" disabled="false" id="{fe5e25e8-58cb-43d5-ba72-c64e2cf44d6d}" locked="false" rounded="true" subdived="true" visible="true" xMirrored="false"/>
|
<part chamfered="false" color="#ffb6afb4" cutRotation="0.62" deformWidth="0.33" disabled="false" id="{ff29229a-564e-4e50-af37-0ae6c25b78ae}" locked="false" rounded="false" subdived="false" visible="true" xMirrored="true"/>
|
||||||
</parts>
|
</parts>
|
||||||
<components>
|
<components>
|
||||||
<component combineMode="Normal" expanded="false" id="{80825faa-d9b1-4b8d-98fa-85fb3d2b2b35}" linkData="{fe5e25e8-58cb-43d5-ba72-c64e2cf44d6d}" linkDataType="partId"/>
|
<component combineMode="Normal" expanded="false" id="{8b222323-fd8b-4617-aba3-f67f55a6ad95}" linkData="{6ff1a4e8-b864-4c5e-8a8e-2d28edd2c55a}" linkDataType="partId"/>
|
||||||
<component combineMode="Normal" expanded="false" id="{2811dd84-ce7d-46fe-becb-a6ece902a2a0}" linkData="{ad2259a2-362c-499e-9123-d6f8ac0a1966}" linkDataType="partId"/>
|
<component combineMode="Normal" expanded="false" id="{1bed0336-0b1c-409d-8f9b-79726eff5bcf}" linkData="{422ad92f-8ad5-402a-9629-2348eb14e103}" linkDataType="partId"/>
|
||||||
<component combineMode="Normal" expanded="false" id="{24052f98-6d3f-4299-808e-04a33486056b}" linkData="{57622c57-5929-4a6a-b4ac-17dc909f002a}" linkDataType="partId"/>
|
<component combineMode="Normal" expanded="false" id="{aeceba75-3e1f-4e17-93e0-6bf57a08fc6e}" linkData="{0a57548e-12d8-4488-9ce4-8fe3b64db253}" linkDataType="partId"/>
|
||||||
<component combineMode="Normal" expanded="false" id="{9a41ca60-5e2d-491b-8a89-ec55d59c8908}" linkData="{d5ccb7d6-3357-473c-a26a-12ce5713d92e}" linkDataType="partId"/>
|
<component combineMode="Normal" expanded="false" id="{21abd416-ce02-47f6-938d-6e7d35c6d8f4}" linkData="{9c9383da-b1ad-4fed-ac7d-e65d9334882f}" linkDataType="partId"/>
|
||||||
<component combineMode="Normal" expanded="false" id="{a58d9d13-6b67-42eb-870a-a1924272602a}" linkData="{d2be1f6f-2053-491c-962b-f27e1a809848}" linkDataType="partId"/>
|
<component combineMode="Normal" expanded="false" id="{51b08def-b3a4-428f-a03d-4125c76bc6ad}" linkData="{93d5b991-f821-4974-96bd-17c46090ffa9}" linkDataType="partId"/>
|
||||||
<component combineMode="Normal" expanded="false" id="{46543657-43b0-4460-8c48-c0957c0434b7}" linkData="{b27111c8-625f-405d-88a9-55df58d51de0}" linkDataType="partId"/>
|
<component combineMode="Normal" expanded="false" id="{86ff1c3a-175e-4450-8c10-0523794e0cf4}" linkData="{5f080e1f-48f5-4aa7-aa0c-d175f9045341}" linkDataType="partId"/>
|
||||||
<component combineMode="Normal" expanded="false" id="{d11f248d-dfb7-4298-af9e-dc60a9fb0011}" linkData="{881a0adc-3b0d-4575-b7d7-d6df8907e3f3}" linkDataType="partId"/>
|
<component combineMode="Normal" expanded="false" id="{162ed54e-3062-4c63-93b3-8189b0bb1028}" linkData="{79289522-791a-488f-bd2d-15db6c8f2f84}" linkDataType="partId"/>
|
||||||
<component combineMode="Normal" expanded="false" id="{8763787f-7e83-44b0-80ab-71fd10936fa9}" linkData="{983cf6ce-44d9-41e8-8489-289b423a423a}" linkDataType="partId"/>
|
<component combineMode="Normal" expanded="false" id="{50d83758-21df-40f6-a804-68b8ca1301f1}" linkData="{1f878838-6686-4bcc-bc82-d9c5583d05e8}" linkDataType="partId"/>
|
||||||
<component combineMode="Normal" expanded="false" id="{61dcbceb-6e49-47b1-ac07-209b16ef1cb1}" linkData="{0b8f8da9-d461-48c4-bbfd-343f0b648235}" linkDataType="partId"/>
|
<component combineMode="Normal" expanded="false" id="{026fdbd1-1a08-4008-82db-2ca3de67f429}" linkData="{0048f320-55a9-4777-914e-95944cb34b46}" linkDataType="partId"/>
|
||||||
<component combineMode="Normal" expanded="false" id="{bd2d596d-0477-47f8-8083-1def956cb7fd}" linkData="{c9c2c2b9-571b-4067-8b01-b59725670dd4}" linkDataType="partId"/>
|
<component combineMode="Normal" expanded="false" id="{c1dd1e40-469a-4e32-b8fe-ba90d553b3ca}" linkData="{c569a92e-6b1b-4d8b-9284-76fef9c124f0}" linkDataType="partId"/>
|
||||||
<component combineMode="Normal" expanded="false" id="{b8e478cc-e2cb-4e6a-956b-a4145355d2e2}" linkData="{546efa0c-392d-47c5-80c1-4138b07cf0a4}" linkDataType="partId"/>
|
<component combineMode="Normal" expanded="false" id="{b29dba15-f2d9-4afa-94d7-7c027bcf27dd}" linkData="{2162fa67-7e23-4e5f-9a9d-4175b10c44c9}" linkDataType="partId"/>
|
||||||
<component combineMode="Normal" expanded="false" id="{5e744fdf-98b0-4571-95b5-ba05747a30a7}" linkData="{2dacf558-7216-4577-8631-16769f860e18}" linkDataType="partId"/>
|
<component combineMode="Normal" expanded="false" id="{b2c413da-9043-4e6a-9a8e-abb9a126f54c}" linkData="{828c4638-7c11-4aeb-8f23-773dbeea8440}" linkDataType="partId"/>
|
||||||
<component combineMode="Normal" expanded="false" id="{9d280cd2-7391-405b-bb86-32f7131dc566}" linkData="{9fae01c2-855a-472b-8181-02a1b76fcab1}" linkDataType="partId"/>
|
<component combineMode="Normal" expanded="false" id="{53d42cdd-93f8-4a41-925e-0dcbe373f5e3}" linkData="{b6e20100-8c2b-4550-aee8-806aa713c90c}" linkDataType="partId"/>
|
||||||
<component combineMode="Normal" expanded="false" id="{a5b46483-8649-4973-8f2e-bc1dd66fd9bd}" linkData="{6c3c3e49-1701-4f8c-9490-32d51f52fe9f}" linkDataType="partId"/>
|
<component combineMode="Normal" expanded="false" id="{fe6fe973-2958-4cb6-b8cc-1c8c20c72b45}" linkData="{b049bb5c-a4e5-402e-88db-a5cccbee3851}" linkDataType="partId"/>
|
||||||
<component combineMode="Normal" expanded="false" id="{8a20c19b-ea41-42b5-9ffe-f465682ab8f5}" linkData="{15325291-8856-42d7-9bc0-eb9ea53eadc1}" linkDataType="partId"/>
|
<component combineMode="Normal" expanded="false" id="{145d43d4-9b5c-4791-887b-21f318b6d190}" linkData="{3d3ba42b-7be6-4174-96c3-500daab0dc7f}" linkDataType="partId"/>
|
||||||
<component combineMode="Normal" expanded="false" id="{202b5c05-5435-461e-8777-b9dff62619c1}" linkData="{471dfce0-6e13-4146-b261-2090e30f407b}" linkDataType="partId"/>
|
<component combineMode="Normal" expanded="false" id="{9e2d24be-642a-4f87-b9c7-a66bcb1baf1c}" linkData="{aceff516-7672-4ab0-8de4-10fb8c7a0681}" linkDataType="partId"/>
|
||||||
<component combineMode="Normal" expanded="false" id="{aeefae79-b1bf-477f-9f4c-54b4f973766f}" linkData="{a5ad3f64-2091-4cea-8085-e17881f0573d}" linkDataType="partId"/>
|
<component combineMode="Normal" expanded="false" id="{37d27813-02cd-479e-8de2-e6ffc6b18dbf}" linkData="{cef2d5ce-ed55-4030-a415-e39a20d3ff86}" linkDataType="partId"/>
|
||||||
<component combineMode="Normal" expanded="false" id="{dba2df2e-92ff-4221-a5e0-4af930c10a42}" linkData="{91850869-d0e1-4e42-a452-d1259dbd5643}" linkDataType="partId"/>
|
<component combineMode="Normal" expanded="false" id="{96323358-10dc-4fe9-a6f4-7aee4fe074bd}" linkData="{c2b415b2-4419-408e-be54-1b6b2521441a}" linkDataType="partId"/>
|
||||||
<component combineMode="Normal" expanded="false" id="{c8392698-b8cf-4dcd-a72c-2617bd83e920}" linkData="{019249f8-0f48-4f9e-87e3-6d2e821e87ac}" linkDataType="partId"/>
|
<component combineMode="Normal" expanded="false" id="{5b17a1e6-b837-429f-ae51-89f45874ea4f}" linkData="{65aa6ccd-94db-47cf-aa84-dce3c2b3fa65}" linkDataType="partId"/>
|
||||||
<component combineMode="Normal" expanded="false" id="{53c9e72d-a221-4ecf-9bb0-08a31625a5ec}" linkData="{442a221d-5a04-4d09-9cfd-bdd138320c26}" linkDataType="partId"/>
|
<component combineMode="Normal" expanded="false" id="{f0b7a33a-6c96-400d-9800-6d9f75edc099}" linkData="{de6790b2-a8be-42ea-9f96-75c8ac21c6da}" linkDataType="partId"/>
|
||||||
<component combineMode="Normal" expanded="false" id="{7432db30-498e-438c-b6dc-69a16f18af88}" linkData="{d4c0d323-791a-4a2a-ad1b-8e8fb93bf42d}" linkDataType="partId"/>
|
<component combineMode="Normal" expanded="false" id="{5c57715a-8616-4cf6-b2c2-3bf5ce50b53d}" linkData="{8d55eb65-52a8-47da-9b5b-7d6d914943cc}" linkDataType="partId"/>
|
||||||
<component combineMode="Normal" expanded="false" id="{734b21ee-2a7b-4f0d-a087-3c5915b3a6ef}" linkData="{2c899cf6-d358-454e-ad79-5a5bddaf0bff}" linkDataType="partId"/>
|
<component combineMode="Normal" expanded="false" id="{3ff1b8d2-c944-4578-b532-acce0683303b}" linkData="{3145e23e-d0bf-4f3f-8609-92f40c348fa5}" linkDataType="partId"/>
|
||||||
<component combineMode="Normal" expanded="false" id="{2e9234a4-ec4c-4621-aa83-8eb078c94fe0}" linkData="{dd604661-6acc-4ef1-83fc-36a374c54734}" linkDataType="partId"/>
|
<component combineMode="Normal" expanded="false" id="{dc08b366-9adb-48fd-bc0e-26b147e7e4a6}" linkData="{ff29229a-564e-4e50-af37-0ae6c25b78ae}" linkDataType="partId"/>
|
||||||
<component combineMode="Normal" expanded="false" id="{921b72f3-9d6a-4d78-b1f0-528bc4a119d5}" linkData="{80e078b3-ad1d-4a0f-b695-e63bff35af45}" linkDataType="partId"/>
|
<component combineMode="Normal" expanded="false" id="{c967697f-b119-4664-989c-3aeb6bf35f4f}" linkData="{62dc13e0-9173-4223-9c39-c682f30a2338}" linkDataType="partId"/>
|
||||||
</components>
|
</components>
|
||||||
<materials/>
|
<materials/>
|
||||||
<poses/>
|
<poses/>
|
||||||
|
|
|
@ -1,102 +1,102 @@
|
||||||
DUST3D 1.0 xml 0000000194
|
DUST3D 1.0 xml 0000000194
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<ds3>
|
<ds3>
|
||||||
<model name="model.xml" offset="0" size="18526"/>
|
<model name="model.xml" offset="0" size="18527"/>
|
||||||
<asset name="canvas.png" offset="18526" size="1461880"/>
|
<asset name="canvas.png" offset="18527" size="1461880"/>
|
||||||
</ds3>
|
</ds3>
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<canvas originX="2.30357" originY="0.250001" originZ="5.33631" polyCount="TremendouslyHighPoly" rigType="Animal">
|
<canvas originX="2.30357" originY="0.250001" originZ="5.33631" polyCount="TremendouslyHighPoly" rigType="Animal">
|
||||||
<nodes>
|
<nodes>
|
||||||
<node id="{002d2643-ad37-4b31-9427-ffa80d75cef0}" partId="{c30b83af-faa5-4697-88f4-145eccc4a141}" radius="0.130952" x="2.30952" y="0.14881" z="5.06548"/>
|
<node id="{002d2643-ad37-4b31-9427-ffa80d75cef0}" partId="{b8b3ef86-c3fb-413e-81b2-22704d2c9bde}" radius="0.149644" x="2.30952" y="0.14881" z="5.06548"/>
|
||||||
<node id="{0773edbe-d60e-4df9-ac1a-b228f69aeb9e}" partId="{af705abc-552c-43b7-9518-5c299bbbaefe}" radius="0.0178571" x="2.24242" y="0.277906" z="5.24721"/>
|
<node id="{0773edbe-d60e-4df9-ac1a-b228f69aeb9e}" partId="{1933a268-77e5-4c9d-9a0e-81adb51be9cf}" radius="0.0178571" x="2.24242" y="0.277906" z="5.24721"/>
|
||||||
<node id="{0c6e2b32-45d5-4c33-8f41-f8d259f3bfaf}" partId="{af705abc-552c-43b7-9518-5c299bbbaefe}" radius="0.00595238" x="2.24242" y="0.330289" z="5.25834"/>
|
<node id="{0c6e2b32-45d5-4c33-8f41-f8d259f3bfaf}" partId="{1933a268-77e5-4c9d-9a0e-81adb51be9cf}" radius="0.00595238" x="2.24242" y="0.330289" z="5.25834"/>
|
||||||
<node id="{105c0e26-729b-4f41-9c57-5cc6a8feb5c4}" partId="{a0fd6b1b-efc3-4211-a439-4e87d2fdb3f9}" radius="0.0892857" x="2.30357" y="0.232143" z="5.96429"/>
|
<node id="{105c0e26-729b-4f41-9c57-5cc6a8feb5c4}" partId="{ae61b00a-6fa7-4d27-9b78-43f87bac6823}" radius="0.0892857" x="2.30357" y="0.232143" z="5.96429"/>
|
||||||
<node id="{2be2d852-dc7e-4082-b3bd-fb7c7b67cd9e}" partId="{c30b83af-faa5-4697-88f4-145eccc4a141}" radius="0.142857" x="2.30952" y="0.172619" z="5.20833"/>
|
<node id="{2be2d852-dc7e-4082-b3bd-fb7c7b67cd9e}" partId="{b8b3ef86-c3fb-413e-81b2-22704d2c9bde}" radius="0.142857" x="2.30952" y="0.172619" z="5.20833"/>
|
||||||
<node boneMark="Limb" id="{2cd26254-2af2-419b-944d-7ec4d20ccb49}" partId="{78b71f39-5010-4771-8d90-aaa08f38aa7a}" radius="0.232143" x="2.22619" y="0.130952" z="5.11607"/>
|
<node boneMark="Limb" id="{2cd26254-2af2-419b-944d-7ec4d20ccb49}" partId="{f5133a44-dda9-4189-bba6-7d291eb5453e}" radius="0.232143" x="2.22619" y="0.130952" z="5.11607"/>
|
||||||
<node id="{31955658-3734-4b40-935e-5ab565b1a031}" partId="{60038150-9349-422c-96b1-cead9d97ab73}" radius="0.0119048" x="2.3671" y="0.107444" z="4.75297"/>
|
<node id="{31955658-3734-4b40-935e-5ab565b1a031}" partId="{52600dec-a5db-4d32-b175-fef8168d9f69}" radius="0.0119048" x="2.3671" y="0.107444" z="4.75297"/>
|
||||||
<node id="{33482357-a9fb-43fd-971d-13e6cba6923a}" partId="{92f4278b-354e-45fb-83ea-6464be1d3309}" radius="0.0238095" x="2.30357" y="0.154762" z="4.6994"/>
|
<node id="{33482357-a9fb-43fd-971d-13e6cba6923a}" partId="{a5feecf2-e126-4034-8cde-597ad5d0e412}" radius="0.0238095" x="2.30357" y="0.154762" z="4.6994"/>
|
||||||
<node id="{3ffe9f73-2f15-492c-9049-3ec5a11c13e5}" partId="{c30b83af-faa5-4697-88f4-145eccc4a141}" radius="0.0833333" x="2.30952" y="0.220238" z="5.57738"/>
|
<node id="{3ffe9f73-2f15-492c-9049-3ec5a11c13e5}" partId="{b8b3ef86-c3fb-413e-81b2-22704d2c9bde}" radius="0.0833333" x="2.30952" y="0.220238" z="5.57738"/>
|
||||||
<node id="{478ce079-24b3-49d2-b627-d1f930324acf}" partId="{78b71f39-5010-4771-8d90-aaa08f38aa7a}" radius="0.232143" x="1.94048" y="0.273809" z="5.15178"/>
|
<node id="{478ce079-24b3-49d2-b627-d1f930324acf}" partId="{f5133a44-dda9-4189-bba6-7d291eb5453e}" radius="0.232143" x="1.94048" y="0.273809" z="5.15178"/>
|
||||||
<node id="{55364285-9fc5-447b-980d-8a7b9c6fb20c}" partId="{a0fd6b1b-efc3-4211-a439-4e87d2fdb3f9}" radius="0.0654762" x="2.30357" y="0.214286" z="5.80952"/>
|
<node id="{55364285-9fc5-447b-980d-8a7b9c6fb20c}" partId="{ae61b00a-6fa7-4d27-9b78-43f87bac6823}" radius="0.0654762" x="2.30357" y="0.214286" z="5.80952"/>
|
||||||
<node id="{577919f7-ebd4-4d95-954a-f1e53757bf7c}" partId="{92f4278b-354e-45fb-83ea-6464be1d3309}" radius="0.005" x="2.30952" y="0.190476" z="4.57738"/>
|
<node id="{577919f7-ebd4-4d95-954a-f1e53757bf7c}" partId="{a5feecf2-e126-4034-8cde-597ad5d0e412}" radius="0.005" x="2.30952" y="0.190476" z="4.57738"/>
|
||||||
<node id="{60e0a638-397d-4ae5-ac21-bc6c932e36f6}" partId="{aee65af2-6917-4e38-a03d-08243b9d9e24}" radius="0.0357143" x="2.30357" y="0.154762" z="4.69643"/>
|
<node id="{60e0a638-397d-4ae5-ac21-bc6c932e36f6}" partId="{74ab9ba2-f9d5-4d65-abb0-d6f1ae73b253}" radius="0.0357143" x="2.30357" y="0.154762" z="4.69643"/>
|
||||||
<node id="{64fd22d8-d4e9-49f2-84d2-a7dc883aac3e}" partId="{af705abc-552c-43b7-9518-5c299bbbaefe}" radius="0.00595238" x="2.25216" y="0.396958" z="5.27251"/>
|
<node id="{64fd22d8-d4e9-49f2-84d2-a7dc883aac3e}" partId="{1933a268-77e5-4c9d-9a0e-81adb51be9cf}" radius="0.00595238" x="2.25216" y="0.396958" z="5.27251"/>
|
||||||
<node boneMark="Tail" id="{65894105-a88a-4946-9da0-dcc34c3d1201}" partId="{a0fd6b1b-efc3-4211-a439-4e87d2fdb3f9}" radius="0.0654762" x="2.30357" y="0.220238" z="5.67857"/>
|
<node boneMark="Tail" id="{65894105-a88a-4946-9da0-dcc34c3d1201}" partId="{ae61b00a-6fa7-4d27-9b78-43f87bac6823}" radius="0.0654762" x="2.30357" y="0.220238" z="5.67857"/>
|
||||||
<node id="{6a5c5722-8801-4958-98e2-a39fff2fcedb}" partId="{a0fd6b1b-efc3-4211-a439-4e87d2fdb3f9}" radius="0.0892857" x="2.30357" y="0.22619" z="5.58036"/>
|
<node id="{6a5c5722-8801-4958-98e2-a39fff2fcedb}" partId="{ae61b00a-6fa7-4d27-9b78-43f87bac6823}" radius="0.0892857" x="2.30357" y="0.22619" z="5.58036"/>
|
||||||
<node id="{72e92d06-1c01-43cb-8de3-ec6f9a74301d}" partId="{c30b83af-faa5-4697-88f4-145eccc4a141}" radius="0.107143" x="2.30952" y="0.125" z="4.91667"/>
|
<node id="{72e92d06-1c01-43cb-8de3-ec6f9a74301d}" partId="{b8b3ef86-c3fb-413e-81b2-22704d2c9bde}" radius="0.125835" x="2.30952" y="0.125" z="4.91667"/>
|
||||||
<node id="{768d8ac5-7c00-4faf-9a4f-13993f69213a}" partId="{bd1b2d09-62da-44c7-a0d0-d37f9943eaa7}" radius="0.0178571" x="2.99405" y="0.958333" z="1.59226"/>
|
<node id="{768d8ac5-7c00-4faf-9a4f-13993f69213a}" partId="{62d7ef5f-8f47-4aeb-bb39-97da75e181ea}" radius="0.0178571" x="3.04762" y="0.958333" z="1.59226"/>
|
||||||
<node id="{8486ca8d-6418-427f-b3cd-9dc4cc8b8308}" partId="{c30b83af-faa5-4697-88f4-145eccc4a141}" radius="0.107143" x="2.30952" y="0.214286" z="5.50595"/>
|
<node id="{8486ca8d-6418-427f-b3cd-9dc4cc8b8308}" partId="{b8b3ef86-c3fb-413e-81b2-22704d2c9bde}" radius="0.107143" x="2.30952" y="0.214286" z="5.50595"/>
|
||||||
<node id="{86225f61-4a1a-4675-a8a4-befd428fcdd8}" partId="{c30b83af-faa5-4697-88f4-145eccc4a141}" radius="0.0833333" x="2.30952" y="0.107143" z="4.83036"/>
|
<node id="{86225f61-4a1a-4675-a8a4-befd428fcdd8}" partId="{b8b3ef86-c3fb-413e-81b2-22704d2c9bde}" radius="0.0833333" x="2.30952" y="0.107143" z="4.83036"/>
|
||||||
<node id="{95c7520f-6d00-4b48-a2b3-7e20e58c9388}" partId="{af705abc-552c-43b7-9518-5c299bbbaefe}" radius="0.005" x="2.22728" y="0.452192" z="5.38419"/>
|
<node id="{95c7520f-6d00-4b48-a2b3-7e20e58c9388}" partId="{1933a268-77e5-4c9d-9a0e-81adb51be9cf}" radius="0.005" x="2.22728" y="0.452192" z="5.38419"/>
|
||||||
<node id="{9f38a9ee-e7e5-4e63-8d55-0623ca9ef5f2}" partId="{c30b83af-faa5-4697-88f4-145eccc4a141}" radius="0.142857" x="2.30952" y="0.214286" z="5.3631"/>
|
<node id="{9f38a9ee-e7e5-4e63-8d55-0623ca9ef5f2}" partId="{b8b3ef86-c3fb-413e-81b2-22704d2c9bde}" radius="0.142857" x="2.30952" y="0.214286" z="5.3631"/>
|
||||||
<node id="{a7c6d064-d5ad-48c7-b508-ad6f7de3a330}" partId="{bd1b2d09-62da-44c7-a0d0-d37f9943eaa7}" radius="0.0178571" x="3.00595" y="0.642857" z="1.59226"/>
|
<node id="{a7c6d064-d5ad-48c7-b508-ad6f7de3a330}" partId="{62d7ef5f-8f47-4aeb-bb39-97da75e181ea}" radius="0.0178571" x="3.03572" y="0.642857" z="1.59226"/>
|
||||||
<node id="{ad81ec2b-2ab8-41e1-b044-a992b9e670c9}" partId="{bd1b2d09-62da-44c7-a0d0-d37f9943eaa7}" radius="0.0178571" x="3.09524" y="0.541667" z="1.59226"/>
|
<node id="{ad81ec2b-2ab8-41e1-b044-a992b9e670c9}" partId="{62d7ef5f-8f47-4aeb-bb39-97da75e181ea}" radius="0.0178571" x="2.94643" y="0.541667" z="1.59226"/>
|
||||||
<node boneMark="Neck" id="{b35647e5-b5f2-431c-b928-f13b17ecce62}" partId="{aee65af2-6917-4e38-a03d-08243b9d9e24}" radius="0.0952381" x="2.30357" y="0.125" z="4.84821"/>
|
<node boneMark="Neck" id="{b35647e5-b5f2-431c-b928-f13b17ecce62}" partId="{74ab9ba2-f9d5-4d65-abb0-d6f1ae73b253}" radius="0.0952381" x="2.30357" y="0.125" z="4.84821"/>
|
||||||
<node id="{ba8340d9-94c0-4d00-924f-1c7e955e933a}" partId="{af705abc-552c-43b7-9518-5c299bbbaefe}" radius="0.0178571" x="2.24676" y="0.437208" z="5.34301"/>
|
<node id="{ba8340d9-94c0-4d00-924f-1c7e955e933a}" partId="{1933a268-77e5-4c9d-9a0e-81adb51be9cf}" radius="0.0178571" x="2.24676" y="0.437208" z="5.34301"/>
|
||||||
<node id="{c1bfe566-ede8-451c-aff5-67440421761f}" partId="{92f4278b-354e-45fb-83ea-6464be1d3309}" radius="0.0119048" x="2.30952" y="0.160714" z="4.6369"/>
|
<node id="{c1bfe566-ede8-451c-aff5-67440421761f}" partId="{a5feecf2-e126-4034-8cde-597ad5d0e412}" radius="0.0119048" x="2.30952" y="0.160714" z="4.6369"/>
|
||||||
<node id="{c1ef7958-3e56-40cb-88b2-5c3baaa8dda9}" partId="{78b71f39-5010-4771-8d90-aaa08f38aa7a}" radius="0.077381" x="1.51191" y="0.666668" z="5.32143"/>
|
<node id="{c1ef7958-3e56-40cb-88b2-5c3baaa8dda9}" partId="{f5133a44-dda9-4189-bba6-7d291eb5453e}" radius="0.077381" x="1.51191" y="0.666668" z="5.32143"/>
|
||||||
<node boneMark="Joint" id="{c95cfb16-56f5-4e55-b96f-685ef3735e33}" partId="{78b71f39-5010-4771-8d90-aaa08f38aa7a}" radius="0.0654762" x="1.39286" y="0.75" z="5.39285"/>
|
<node boneMark="Joint" id="{c95cfb16-56f5-4e55-b96f-685ef3735e33}" partId="{f5133a44-dda9-4189-bba6-7d291eb5453e}" radius="0.0654762" x="1.39286" y="0.75" z="5.39285"/>
|
||||||
<node boneMark="Joint" id="{cdaad2ba-c614-412e-a1c6-b9da2bab2162}" partId="{78b71f39-5010-4771-8d90-aaa08f38aa7a}" radius="0.232143" x="1.8631" y="0.398809" z="5.23214"/>
|
<node boneMark="Joint" id="{cdaad2ba-c614-412e-a1c6-b9da2bab2162}" partId="{f5133a44-dda9-4189-bba6-7d291eb5453e}" radius="0.232143" x="1.8631" y="0.398809" z="5.23214"/>
|
||||||
<node id="{d865109f-5575-4663-8d0b-e41776fd0c9a}" partId="{bd1b2d09-62da-44c7-a0d0-d37f9943eaa7}" radius="0.0178571" x="2.9881" y="0.815476" z="1.59226"/>
|
<node id="{d865109f-5575-4663-8d0b-e41776fd0c9a}" partId="{62d7ef5f-8f47-4aeb-bb39-97da75e181ea}" radius="0.0178571" x="3.05357" y="0.815476" z="1.59226"/>
|
||||||
<node id="{e2aa74db-2711-46ab-bf58-203cf02c7e12}" partId="{60038150-9349-422c-96b1-cead9d97ab73}" radius="0.0119048" x="2.33527" y="0.124699" z="4.71726"/>
|
<node id="{e2aa74db-2711-46ab-bf58-203cf02c7e12}" partId="{52600dec-a5db-4d32-b175-fef8168d9f69}" radius="0.0119048" x="2.33527" y="0.124699" z="4.71726"/>
|
||||||
<node id="{e4e4496a-af11-45f1-b14b-f83ccf13138d}" partId="{78b71f39-5010-4771-8d90-aaa08f38aa7a}" radius="0.14881" x="1.6131" y="0.54762" z="5.2619"/>
|
<node id="{e4e4496a-af11-45f1-b14b-f83ccf13138d}" partId="{f5133a44-dda9-4189-bba6-7d291eb5453e}" radius="0.14881" x="1.6131" y="0.54762" z="5.2619"/>
|
||||||
<node id="{ea5e8c43-8d6e-483b-b68e-1bba762c75f2}" partId="{af705abc-552c-43b7-9518-5c299bbbaefe}" radius="0.0178571" x="2.24729" y="0.420925" z="5.29829"/>
|
<node id="{ea5e8c43-8d6e-483b-b68e-1bba762c75f2}" partId="{1933a268-77e5-4c9d-9a0e-81adb51be9cf}" radius="0.0178571" x="2.24729" y="0.420925" z="5.29829"/>
|
||||||
<node id="{ec6f812c-2def-4efc-be46-f00e8ea5d53c}" partId="{a0fd6b1b-efc3-4211-a439-4e87d2fdb3f9}" radius="0.0892857" x="2.30357" y="0.214286" z="5.89881"/>
|
<node id="{ec6f812c-2def-4efc-be46-f00e8ea5d53c}" partId="{ae61b00a-6fa7-4d27-9b78-43f87bac6823}" radius="0.0892857" x="2.30357" y="0.214286" z="5.89881"/>
|
||||||
<node id="{fab13514-17e7-4196-b109-469dceca460b}" partId="{aee65af2-6917-4e38-a03d-08243b9d9e24}" radius="0.0595238" x="2.30357" y="0.136905" z="4.7619"/>
|
<node id="{fab13514-17e7-4196-b109-469dceca460b}" partId="{74ab9ba2-f9d5-4d65-abb0-d6f1ae73b253}" radius="0.0595238" x="2.30357" y="0.136905" z="4.7619"/>
|
||||||
</nodes>
|
</nodes>
|
||||||
<edges>
|
<edges>
|
||||||
<edge from="{e4e4496a-af11-45f1-b14b-f83ccf13138d}" id="{079c1f09-1fd7-4dcb-bdf0-0bfc96d74fa6}" partId="{78b71f39-5010-4771-8d90-aaa08f38aa7a}" to="{c1ef7958-3e56-40cb-88b2-5c3baaa8dda9}"/>
|
<edge from="{e4e4496a-af11-45f1-b14b-f83ccf13138d}" id="{079c1f09-1fd7-4dcb-bdf0-0bfc96d74fa6}" partId="{f5133a44-dda9-4189-bba6-7d291eb5453e}" to="{c1ef7958-3e56-40cb-88b2-5c3baaa8dda9}"/>
|
||||||
<edge from="{ad81ec2b-2ab8-41e1-b044-a992b9e670c9}" id="{1fbc1f23-79c9-4316-9f26-9097216e63dd}" partId="{bd1b2d09-62da-44c7-a0d0-d37f9943eaa7}" to="{a7c6d064-d5ad-48c7-b508-ad6f7de3a330}"/>
|
<edge from="{ad81ec2b-2ab8-41e1-b044-a992b9e670c9}" id="{1fbc1f23-79c9-4316-9f26-9097216e63dd}" partId="{62d7ef5f-8f47-4aeb-bb39-97da75e181ea}" to="{a7c6d064-d5ad-48c7-b508-ad6f7de3a330}"/>
|
||||||
<edge from="{33482357-a9fb-43fd-971d-13e6cba6923a}" id="{292931fb-346b-4453-a368-db9af68b5463}" partId="{92f4278b-354e-45fb-83ea-6464be1d3309}" to="{c1bfe566-ede8-451c-aff5-67440421761f}"/>
|
<edge from="{33482357-a9fb-43fd-971d-13e6cba6923a}" id="{292931fb-346b-4453-a368-db9af68b5463}" partId="{a5feecf2-e126-4034-8cde-597ad5d0e412}" to="{c1bfe566-ede8-451c-aff5-67440421761f}"/>
|
||||||
<edge from="{fab13514-17e7-4196-b109-469dceca460b}" id="{3528cf96-8957-4719-b1a4-404e58e0dac0}" partId="{aee65af2-6917-4e38-a03d-08243b9d9e24}" to="{60e0a638-397d-4ae5-ac21-bc6c932e36f6}"/>
|
<edge from="{fab13514-17e7-4196-b109-469dceca460b}" id="{3528cf96-8957-4719-b1a4-404e58e0dac0}" partId="{74ab9ba2-f9d5-4d65-abb0-d6f1ae73b253}" to="{60e0a638-397d-4ae5-ac21-bc6c932e36f6}"/>
|
||||||
<edge from="{0c6e2b32-45d5-4c33-8f41-f8d259f3bfaf}" id="{3dab5592-ed48-4ae3-8501-6f9925309c3e}" partId="{af705abc-552c-43b7-9518-5c299bbbaefe}" to="{64fd22d8-d4e9-49f2-84d2-a7dc883aac3e}"/>
|
<edge from="{0c6e2b32-45d5-4c33-8f41-f8d259f3bfaf}" id="{3dab5592-ed48-4ae3-8501-6f9925309c3e}" partId="{1933a268-77e5-4c9d-9a0e-81adb51be9cf}" to="{64fd22d8-d4e9-49f2-84d2-a7dc883aac3e}"/>
|
||||||
<edge from="{86225f61-4a1a-4675-a8a4-befd428fcdd8}" id="{41b5d109-26bd-49d3-b096-dec144e887c4}" partId="{c30b83af-faa5-4697-88f4-145eccc4a141}" to="{72e92d06-1c01-43cb-8de3-ec6f9a74301d}"/>
|
<edge from="{86225f61-4a1a-4675-a8a4-befd428fcdd8}" id="{41b5d109-26bd-49d3-b096-dec144e887c4}" partId="{b8b3ef86-c3fb-413e-81b2-22704d2c9bde}" to="{72e92d06-1c01-43cb-8de3-ec6f9a74301d}"/>
|
||||||
<edge from="{65894105-a88a-4946-9da0-dcc34c3d1201}" id="{47a9be10-963b-434b-a04d-4663f96dfaf8}" partId="{a0fd6b1b-efc3-4211-a439-4e87d2fdb3f9}" to="{55364285-9fc5-447b-980d-8a7b9c6fb20c}"/>
|
<edge from="{65894105-a88a-4946-9da0-dcc34c3d1201}" id="{47a9be10-963b-434b-a04d-4663f96dfaf8}" partId="{ae61b00a-6fa7-4d27-9b78-43f87bac6823}" to="{55364285-9fc5-447b-980d-8a7b9c6fb20c}"/>
|
||||||
<edge from="{cdaad2ba-c614-412e-a1c6-b9da2bab2162}" id="{543a1de2-1a71-43d7-aa3a-ea21a2d7538f}" partId="{78b71f39-5010-4771-8d90-aaa08f38aa7a}" to="{e4e4496a-af11-45f1-b14b-f83ccf13138d}"/>
|
<edge from="{cdaad2ba-c614-412e-a1c6-b9da2bab2162}" id="{543a1de2-1a71-43d7-aa3a-ea21a2d7538f}" partId="{f5133a44-dda9-4189-bba6-7d291eb5453e}" to="{e4e4496a-af11-45f1-b14b-f83ccf13138d}"/>
|
||||||
<edge from="{64fd22d8-d4e9-49f2-84d2-a7dc883aac3e}" id="{5656a96e-8bce-4bc8-83a4-bb57ce5b70ec}" partId="{af705abc-552c-43b7-9518-5c299bbbaefe}" to="{ea5e8c43-8d6e-483b-b68e-1bba762c75f2}"/>
|
<edge from="{64fd22d8-d4e9-49f2-84d2-a7dc883aac3e}" id="{5656a96e-8bce-4bc8-83a4-bb57ce5b70ec}" partId="{1933a268-77e5-4c9d-9a0e-81adb51be9cf}" to="{ea5e8c43-8d6e-483b-b68e-1bba762c75f2}"/>
|
||||||
<edge from="{e2aa74db-2711-46ab-bf58-203cf02c7e12}" id="{699740c9-d498-496d-8ca8-d022404430e3}" partId="{60038150-9349-422c-96b1-cead9d97ab73}" to="{31955658-3734-4b40-935e-5ab565b1a031}"/>
|
<edge from="{e2aa74db-2711-46ab-bf58-203cf02c7e12}" id="{699740c9-d498-496d-8ca8-d022404430e3}" partId="{52600dec-a5db-4d32-b175-fef8168d9f69}" to="{31955658-3734-4b40-935e-5ab565b1a031}"/>
|
||||||
<edge from="{6a5c5722-8801-4958-98e2-a39fff2fcedb}" id="{729ef5a4-b2ff-45d0-a59f-c7321b2408a1}" partId="{a0fd6b1b-efc3-4211-a439-4e87d2fdb3f9}" to="{65894105-a88a-4946-9da0-dcc34c3d1201}"/>
|
<edge from="{6a5c5722-8801-4958-98e2-a39fff2fcedb}" id="{729ef5a4-b2ff-45d0-a59f-c7321b2408a1}" partId="{ae61b00a-6fa7-4d27-9b78-43f87bac6823}" to="{65894105-a88a-4946-9da0-dcc34c3d1201}"/>
|
||||||
<edge from="{ea5e8c43-8d6e-483b-b68e-1bba762c75f2}" id="{7460d47d-58f1-420d-9a2d-8abcc2b77b20}" partId="{af705abc-552c-43b7-9518-5c299bbbaefe}" to="{ba8340d9-94c0-4d00-924f-1c7e955e933a}"/>
|
<edge from="{ea5e8c43-8d6e-483b-b68e-1bba762c75f2}" id="{7460d47d-58f1-420d-9a2d-8abcc2b77b20}" partId="{1933a268-77e5-4c9d-9a0e-81adb51be9cf}" to="{ba8340d9-94c0-4d00-924f-1c7e955e933a}"/>
|
||||||
<edge from="{55364285-9fc5-447b-980d-8a7b9c6fb20c}" id="{7f1d6db0-502e-48f3-9f44-ac626a48b869}" partId="{a0fd6b1b-efc3-4211-a439-4e87d2fdb3f9}" to="{ec6f812c-2def-4efc-be46-f00e8ea5d53c}"/>
|
<edge from="{55364285-9fc5-447b-980d-8a7b9c6fb20c}" id="{7f1d6db0-502e-48f3-9f44-ac626a48b869}" partId="{ae61b00a-6fa7-4d27-9b78-43f87bac6823}" to="{ec6f812c-2def-4efc-be46-f00e8ea5d53c}"/>
|
||||||
<edge from="{9f38a9ee-e7e5-4e63-8d55-0623ca9ef5f2}" id="{80b4c3cd-45b5-456f-87e6-39de48ac76e1}" partId="{c30b83af-faa5-4697-88f4-145eccc4a141}" to="{8486ca8d-6418-427f-b3cd-9dc4cc8b8308}"/>
|
<edge from="{9f38a9ee-e7e5-4e63-8d55-0623ca9ef5f2}" id="{80b4c3cd-45b5-456f-87e6-39de48ac76e1}" partId="{b8b3ef86-c3fb-413e-81b2-22704d2c9bde}" to="{8486ca8d-6418-427f-b3cd-9dc4cc8b8308}"/>
|
||||||
<edge from="{2cd26254-2af2-419b-944d-7ec4d20ccb49}" id="{8132f215-3d6d-46f6-bc4b-140341098298}" partId="{78b71f39-5010-4771-8d90-aaa08f38aa7a}" to="{478ce079-24b3-49d2-b627-d1f930324acf}"/>
|
<edge from="{2cd26254-2af2-419b-944d-7ec4d20ccb49}" id="{8132f215-3d6d-46f6-bc4b-140341098298}" partId="{f5133a44-dda9-4189-bba6-7d291eb5453e}" to="{478ce079-24b3-49d2-b627-d1f930324acf}"/>
|
||||||
<edge from="{478ce079-24b3-49d2-b627-d1f930324acf}" id="{8718b4ff-7004-4f54-9ef2-ebcb2aef2cb5}" partId="{78b71f39-5010-4771-8d90-aaa08f38aa7a}" to="{cdaad2ba-c614-412e-a1c6-b9da2bab2162}"/>
|
<edge from="{478ce079-24b3-49d2-b627-d1f930324acf}" id="{8718b4ff-7004-4f54-9ef2-ebcb2aef2cb5}" partId="{f5133a44-dda9-4189-bba6-7d291eb5453e}" to="{cdaad2ba-c614-412e-a1c6-b9da2bab2162}"/>
|
||||||
<edge from="{ba8340d9-94c0-4d00-924f-1c7e955e933a}" id="{88cff3cc-13ea-41ca-bc2c-da7871696d23}" partId="{af705abc-552c-43b7-9518-5c299bbbaefe}" to="{95c7520f-6d00-4b48-a2b3-7e20e58c9388}"/>
|
<edge from="{ba8340d9-94c0-4d00-924f-1c7e955e933a}" id="{88cff3cc-13ea-41ca-bc2c-da7871696d23}" partId="{1933a268-77e5-4c9d-9a0e-81adb51be9cf}" to="{95c7520f-6d00-4b48-a2b3-7e20e58c9388}"/>
|
||||||
<edge from="{002d2643-ad37-4b31-9427-ffa80d75cef0}" id="{88d7324c-1c6a-4282-b935-0853da418023}" partId="{c30b83af-faa5-4697-88f4-145eccc4a141}" to="{2be2d852-dc7e-4082-b3bd-fb7c7b67cd9e}"/>
|
<edge from="{002d2643-ad37-4b31-9427-ffa80d75cef0}" id="{88d7324c-1c6a-4282-b935-0853da418023}" partId="{b8b3ef86-c3fb-413e-81b2-22704d2c9bde}" to="{2be2d852-dc7e-4082-b3bd-fb7c7b67cd9e}"/>
|
||||||
<edge from="{b35647e5-b5f2-431c-b928-f13b17ecce62}" id="{8a14bac1-b29a-4c47-ae52-701c20debd3e}" partId="{aee65af2-6917-4e38-a03d-08243b9d9e24}" to="{fab13514-17e7-4196-b109-469dceca460b}"/>
|
<edge from="{b35647e5-b5f2-431c-b928-f13b17ecce62}" id="{8a14bac1-b29a-4c47-ae52-701c20debd3e}" partId="{74ab9ba2-f9d5-4d65-abb0-d6f1ae73b253}" to="{fab13514-17e7-4196-b109-469dceca460b}"/>
|
||||||
<edge from="{a7c6d064-d5ad-48c7-b508-ad6f7de3a330}" id="{9f5eff50-c80b-4aa2-b0ef-6b7c2352db74}" partId="{bd1b2d09-62da-44c7-a0d0-d37f9943eaa7}" to="{d865109f-5575-4663-8d0b-e41776fd0c9a}"/>
|
<edge from="{a7c6d064-d5ad-48c7-b508-ad6f7de3a330}" id="{9f5eff50-c80b-4aa2-b0ef-6b7c2352db74}" partId="{62d7ef5f-8f47-4aeb-bb39-97da75e181ea}" to="{d865109f-5575-4663-8d0b-e41776fd0c9a}"/>
|
||||||
<edge from="{8486ca8d-6418-427f-b3cd-9dc4cc8b8308}" id="{af8ae996-ffef-4c28-ab35-7bad88460ad0}" partId="{c30b83af-faa5-4697-88f4-145eccc4a141}" to="{3ffe9f73-2f15-492c-9049-3ec5a11c13e5}"/>
|
<edge from="{8486ca8d-6418-427f-b3cd-9dc4cc8b8308}" id="{af8ae996-ffef-4c28-ab35-7bad88460ad0}" partId="{b8b3ef86-c3fb-413e-81b2-22704d2c9bde}" to="{3ffe9f73-2f15-492c-9049-3ec5a11c13e5}"/>
|
||||||
<edge from="{d865109f-5575-4663-8d0b-e41776fd0c9a}" id="{b1572a57-b371-454a-a90a-bc875fb4ade2}" partId="{bd1b2d09-62da-44c7-a0d0-d37f9943eaa7}" to="{768d8ac5-7c00-4faf-9a4f-13993f69213a}"/>
|
<edge from="{d865109f-5575-4663-8d0b-e41776fd0c9a}" id="{b1572a57-b371-454a-a90a-bc875fb4ade2}" partId="{62d7ef5f-8f47-4aeb-bb39-97da75e181ea}" to="{768d8ac5-7c00-4faf-9a4f-13993f69213a}"/>
|
||||||
<edge from="{c1bfe566-ede8-451c-aff5-67440421761f}" id="{c33aa039-0678-43a3-94c5-b4f318c1207c}" partId="{92f4278b-354e-45fb-83ea-6464be1d3309}" to="{577919f7-ebd4-4d95-954a-f1e53757bf7c}"/>
|
<edge from="{c1bfe566-ede8-451c-aff5-67440421761f}" id="{c33aa039-0678-43a3-94c5-b4f318c1207c}" partId="{a5feecf2-e126-4034-8cde-597ad5d0e412}" to="{577919f7-ebd4-4d95-954a-f1e53757bf7c}"/>
|
||||||
<edge from="{72e92d06-1c01-43cb-8de3-ec6f9a74301d}" id="{cf52057c-e1fb-4697-bae6-97edf29d054a}" partId="{c30b83af-faa5-4697-88f4-145eccc4a141}" to="{002d2643-ad37-4b31-9427-ffa80d75cef0}"/>
|
<edge from="{72e92d06-1c01-43cb-8de3-ec6f9a74301d}" id="{cf52057c-e1fb-4697-bae6-97edf29d054a}" partId="{b8b3ef86-c3fb-413e-81b2-22704d2c9bde}" to="{002d2643-ad37-4b31-9427-ffa80d75cef0}"/>
|
||||||
<edge from="{c1ef7958-3e56-40cb-88b2-5c3baaa8dda9}" id="{d06fec43-319e-4a6c-85da-2350a49c5f1f}" partId="{78b71f39-5010-4771-8d90-aaa08f38aa7a}" to="{c95cfb16-56f5-4e55-b96f-685ef3735e33}"/>
|
<edge from="{c1ef7958-3e56-40cb-88b2-5c3baaa8dda9}" id="{d06fec43-319e-4a6c-85da-2350a49c5f1f}" partId="{f5133a44-dda9-4189-bba6-7d291eb5453e}" to="{c95cfb16-56f5-4e55-b96f-685ef3735e33}"/>
|
||||||
<edge from="{2be2d852-dc7e-4082-b3bd-fb7c7b67cd9e}" id="{ecf79230-c93d-459d-886f-b42bf0947edf}" partId="{c30b83af-faa5-4697-88f4-145eccc4a141}" to="{9f38a9ee-e7e5-4e63-8d55-0623ca9ef5f2}"/>
|
<edge from="{2be2d852-dc7e-4082-b3bd-fb7c7b67cd9e}" id="{ecf79230-c93d-459d-886f-b42bf0947edf}" partId="{b8b3ef86-c3fb-413e-81b2-22704d2c9bde}" to="{9f38a9ee-e7e5-4e63-8d55-0623ca9ef5f2}"/>
|
||||||
<edge from="{0773edbe-d60e-4df9-ac1a-b228f69aeb9e}" id="{f5924de5-ebc7-4fa3-8a0c-b48300e75d3f}" partId="{af705abc-552c-43b7-9518-5c299bbbaefe}" to="{0c6e2b32-45d5-4c33-8f41-f8d259f3bfaf}"/>
|
<edge from="{0773edbe-d60e-4df9-ac1a-b228f69aeb9e}" id="{f5924de5-ebc7-4fa3-8a0c-b48300e75d3f}" partId="{1933a268-77e5-4c9d-9a0e-81adb51be9cf}" to="{0c6e2b32-45d5-4c33-8f41-f8d259f3bfaf}"/>
|
||||||
<edge from="{ec6f812c-2def-4efc-be46-f00e8ea5d53c}" id="{f83edf96-acbd-4f4a-8355-765439eef106}" partId="{a0fd6b1b-efc3-4211-a439-4e87d2fdb3f9}" to="{105c0e26-729b-4f41-9c57-5cc6a8feb5c4}"/>
|
<edge from="{ec6f812c-2def-4efc-be46-f00e8ea5d53c}" id="{f83edf96-acbd-4f4a-8355-765439eef106}" partId="{ae61b00a-6fa7-4d27-9b78-43f87bac6823}" to="{105c0e26-729b-4f41-9c57-5cc6a8feb5c4}"/>
|
||||||
</edges>
|
</edges>
|
||||||
<parts>
|
<parts>
|
||||||
<part chamfered="false" color="#ff000008" disabled="false" id="{60038150-9349-422c-96b1-cead9d97ab73}" locked="false" rounded="true" subdived="false" visible="true" xMirrored="true"/>
|
<part chamfered="false" color="#ff100f0a" disabled="false" id="{1933a268-77e5-4c9d-9a0e-81adb51be9cf}" locked="false" rounded="false" subdived="false" visible="true" xMirrored="true"/>
|
||||||
<part base="YZ" chamfered="false" color="#ff918d8a" colorSolubility="0.02" cutFace="{bd1b2d09-62da-44c7-a0d0-d37f9943eaa7}" cutRotation="-0.62" disabled="false" id="{78b71f39-5010-4771-8d90-aaa08f38aa7a}" locked="false" rounded="false" subdived="false" visible="true" xMirrored="true"/>
|
<part chamfered="false" color="#ff000008" disabled="false" id="{52600dec-a5db-4d32-b175-fef8168d9f69}" locked="false" rounded="true" subdived="false" visible="true" xMirrored="true"/>
|
||||||
<part chamfered="false" color="#ff7a160c" disabled="false" id="{92f4278b-354e-45fb-83ea-6464be1d3309}" locked="false" rounded="true" subdived="false" visible="true" xMirrored="false"/>
|
<part chamfered="false" disabled="false" id="{62d7ef5f-8f47-4aeb-bb39-97da75e181ea}" locked="false" rounded="false" subdived="false" target="CutFace" visible="true" xMirrored="false"/>
|
||||||
<part chamfered="false" color="#ff43464a" colorSolubility="0.03" cutFace="Pentagon" deformThickness="0.67" disabled="false" id="{a0fd6b1b-efc3-4211-a439-4e87d2fdb3f9}" locked="false" rounded="false" subdived="false" visible="true" xMirrored="false"/>
|
<part chamfered="false" disabled="false" id="{74ab9ba2-f9d5-4d65-abb0-d6f1ae73b253}" locked="false" rounded="true" subdived="true" visible="true" xMirrored="false"/>
|
||||||
<part chamfered="false" disabled="false" id="{aee65af2-6917-4e38-a03d-08243b9d9e24}" locked="false" rounded="true" subdived="true" visible="true" xMirrored="false"/>
|
<part chamfered="false" color="#ff7a160c" disabled="false" id="{a5feecf2-e126-4034-8cde-597ad5d0e412}" locked="false" rounded="true" subdived="false" visible="true" xMirrored="false"/>
|
||||||
<part chamfered="false" color="#ff100f0a" disabled="false" id="{af705abc-552c-43b7-9518-5c299bbbaefe}" locked="false" rounded="false" subdived="false" visible="true" xMirrored="true"/>
|
<part chamfered="false" color="#ff43464a" colorSolubility="0.03" cutFace="Pentagon" deformThickness="0.67" disabled="false" id="{ae61b00a-6fa7-4d27-9b78-43f87bac6823}" locked="false" rounded="false" subdived="false" visible="true" xMirrored="false"/>
|
||||||
<part chamfered="false" disabled="false" id="{bd1b2d09-62da-44c7-a0d0-d37f9943eaa7}" locked="false" rounded="false" subdived="false" target="CutFace" visible="true" xMirrored="false"/>
|
<part chamfered="false" color="#ff918d8a" countershaded="true" disabled="false" id="{b8b3ef86-c3fb-413e-81b2-22704d2c9bde}" locked="false" rounded="true" subdived="true" visible="true" xMirrored="false"/>
|
||||||
<part chamfered="false" color="#ff918d8a" countershaded="true" disabled="false" id="{c30b83af-faa5-4697-88f4-145eccc4a141}" locked="false" rounded="true" subdived="true" visible="true" xMirrored="false"/>
|
<part base="XY" chamfered="false" color="#ff918d8a" colorSolubility="0.02" cutFace="{62d7ef5f-8f47-4aeb-bb39-97da75e181ea}" cutRotation="-0.93" disabled="false" id="{f5133a44-dda9-4189-bba6-7d291eb5453e}" locked="false" rounded="false" subdived="false" visible="true" xMirrored="true"/>
|
||||||
</parts>
|
</parts>
|
||||||
<components>
|
<components>
|
||||||
<component combineMode="Normal" expanded="false" id="{2b6785d0-6640-46fd-9b07-fb7d7d27013f}" linkData="{c30b83af-faa5-4697-88f4-145eccc4a141}" linkDataType="partId"/>
|
<component combineMode="Normal" expanded="false" id="{7d85ab06-a83f-4efd-92b0-3de6b0a01ad6}" linkData="{b8b3ef86-c3fb-413e-81b2-22704d2c9bde}" linkDataType="partId"/>
|
||||||
<component combineMode="Normal" expanded="false" id="{fedc5b0b-68aa-4eaa-a91f-01c4e668e169}" linkData="{aee65af2-6917-4e38-a03d-08243b9d9e24}" linkDataType="partId"/>
|
<component combineMode="Normal" expanded="false" id="{4a8ddcb5-a103-43f4-94a2-28f3ddd7d664}" linkData="{74ab9ba2-f9d5-4d65-abb0-d6f1ae73b253}" linkDataType="partId"/>
|
||||||
<component combineMode="Normal" expanded="false" id="{b2796ea6-be20-4deb-9a36-1c3fe6a20853}" linkData="{92f4278b-354e-45fb-83ea-6464be1d3309}" linkDataType="partId"/>
|
<component combineMode="Normal" expanded="false" id="{cb4a149d-27c2-4269-b2cd-043c1187dd3e}" linkData="{a5feecf2-e126-4034-8cde-597ad5d0e412}" linkDataType="partId"/>
|
||||||
<component combineMode="Normal" expanded="false" id="{384d5cf8-3408-4b27-86ee-a549c6461ba8}" linkData="{a0fd6b1b-efc3-4211-a439-4e87d2fdb3f9}" linkDataType="partId"/>
|
<component combineMode="Normal" expanded="false" id="{dce09af8-44ea-44b6-bec8-c6c35ddbb32e}" linkData="{ae61b00a-6fa7-4d27-9b78-43f87bac6823}" linkDataType="partId"/>
|
||||||
<component combineMode="Normal" expanded="false" id="{ad00c8b1-05cc-471f-b961-d9a3b62edec7}" linkData="{bd1b2d09-62da-44c7-a0d0-d37f9943eaa7}" linkDataType="partId"/>
|
<component combineMode="Normal" expanded="false" id="{7928aa06-f34a-4b07-b3ae-163653b94ecf}" linkData="{62d7ef5f-8f47-4aeb-bb39-97da75e181ea}" linkDataType="partId"/>
|
||||||
<component combineMode="Normal" expanded="false" id="{d44a51c9-001b-4b99-8dc8-c32a3206a83c}" linkData="{78b71f39-5010-4771-8d90-aaa08f38aa7a}" linkDataType="partId"/>
|
<component combineMode="Normal" expanded="false" id="{934eafe9-c13b-467c-96b8-0d85556c3ba0}" linkData="{f5133a44-dda9-4189-bba6-7d291eb5453e}" linkDataType="partId"/>
|
||||||
<component combineMode="Normal" expanded="false" id="{a8ca8ad7-1236-496f-a227-a07443f2af29}" linkData="{af705abc-552c-43b7-9518-5c299bbbaefe}" linkDataType="partId"/>
|
<component combineMode="Normal" expanded="false" id="{086e12ff-5a8f-47ea-bed1-78f211451455}" linkData="{1933a268-77e5-4c9d-9a0e-81adb51be9cf}" linkDataType="partId"/>
|
||||||
<component combineMode="Normal" expanded="false" id="{7a321445-6552-4cf0-a2aa-95295c41d313}" linkData="{60038150-9349-422c-96b1-cead9d97ab73}" linkDataType="partId"/>
|
<component combineMode="Normal" expanded="false" id="{f3048869-1026-447a-ab9f-c16e9dc62762}" linkData="{52600dec-a5db-4d32-b175-fef8168d9f69}" linkDataType="partId"/>
|
||||||
</components>
|
</components>
|
||||||
<materials/>
|
<materials/>
|
||||||
<poses>
|
<poses>
|
||||||
<pose id="{3e2fcabd-34a5-4054-8be9-f221b8282241}" name="up" yTranslationScale="0.1">
|
<pose id="{8463a15e-a207-448f-b899-86fa889d0dca}" name="up" yTranslationScale="0.1">
|
||||||
<frames>
|
<frames>
|
||||||
<frame duration="1">
|
<frame duration="1">
|
||||||
<parameters>
|
<parameters>
|
||||||
|
@ -112,7 +112,7 @@ DUST3D 1.0 xml 0000000194
|
||||||
</frame>
|
</frame>
|
||||||
</frames>
|
</frames>
|
||||||
</pose>
|
</pose>
|
||||||
<pose id="{123dce5f-9a65-4baa-b7d9-92a7417c7167}" name="down" yTranslationScale="0.1">
|
<pose id="{23e36552-3716-4765-90a6-58d28e9038e1}" name="down" yTranslationScale="0.1">
|
||||||
<frames>
|
<frames>
|
||||||
<frame duration="1">
|
<frame duration="1">
|
||||||
<parameters>
|
<parameters>
|
||||||
|
@ -130,13 +130,13 @@ DUST3D 1.0 xml 0000000194
|
||||||
</pose>
|
</pose>
|
||||||
</poses>
|
</poses>
|
||||||
<motions>
|
<motions>
|
||||||
<motion id="{e8da45ff-1bef-4458-a2b8-f5c3fcea8406}" name="fly">
|
<motion id="{32934db3-6cb9-4167-9db5-8f8953d58026}" name="fly">
|
||||||
<clips>
|
<clips>
|
||||||
<clip duration="0" linkData="{3e2fcabd-34a5-4054-8be9-f221b8282241}" linkDataType="poseId"/>
|
<clip duration="0" linkData="{8463a15e-a207-448f-b899-86fa889d0dca}" linkDataType="poseId"/>
|
||||||
<clip duration="0.3" linkData="EaseInBack" linkDataType="InterpolationType"/>
|
<clip duration="0.3" linkData="EaseInBack" linkDataType="InterpolationType"/>
|
||||||
<clip duration="0" linkData="{123dce5f-9a65-4baa-b7d9-92a7417c7167}" linkDataType="poseId"/>
|
<clip duration="0" linkData="{23e36552-3716-4765-90a6-58d28e9038e1}" linkDataType="poseId"/>
|
||||||
<clip duration="0.5" linkData="EaseInBack" linkDataType="InterpolationType"/>
|
<clip duration="0.5" linkData="EaseInBack" linkDataType="InterpolationType"/>
|
||||||
<clip duration="0" linkData="{3e2fcabd-34a5-4054-8be9-f221b8282241}" linkDataType="poseId"/>
|
<clip duration="0" linkData="{8463a15e-a207-448f-b899-86fa889d0dca}" linkDataType="poseId"/>
|
||||||
</clips>
|
</clips>
|
||||||
</motion>
|
</motion>
|
||||||
</motions>
|
</motions>
|
||||||
|
|
|
@ -10,7 +10,7 @@ void AnimationClipPlayer::setSpeedMode(SpeedMode speedMode)
|
||||||
m_speedMode = speedMode;
|
m_speedMode = speedMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimationClipPlayer::updateFrameMeshes(std::vector<std::pair<float, MeshLoader *>> &frameMeshes)
|
void AnimationClipPlayer::updateFrameMeshes(std::vector<std::pair<float, Model *>> &frameMeshes)
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
|
|
||||||
|
@ -50,26 +50,26 @@ int AnimationClipPlayer::getFrameDurationMillis(int frame)
|
||||||
return millis;
|
return millis;
|
||||||
}
|
}
|
||||||
|
|
||||||
MeshLoader *AnimationClipPlayer::takeFrameMesh()
|
Model *AnimationClipPlayer::takeFrameMesh()
|
||||||
{
|
{
|
||||||
if (m_currentPlayIndex >= (int)m_frameMeshes.size()) {
|
if (m_currentPlayIndex >= (int)m_frameMeshes.size()) {
|
||||||
if (nullptr != m_lastFrameMesh)
|
if (nullptr != m_lastFrameMesh)
|
||||||
return new MeshLoader(*m_lastFrameMesh);
|
return new Model(*m_lastFrameMesh);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
int millis = getFrameDurationMillis(m_currentPlayIndex) - m_countForFrame.elapsed();
|
int millis = getFrameDurationMillis(m_currentPlayIndex) - m_countForFrame.elapsed();
|
||||||
if (millis > 0) {
|
if (millis > 0) {
|
||||||
m_timerForFrame.singleShot(millis, this, &AnimationClipPlayer::frameReadyToShow);
|
m_timerForFrame.singleShot(millis, this, &AnimationClipPlayer::frameReadyToShow);
|
||||||
if (nullptr != m_lastFrameMesh)
|
if (nullptr != m_lastFrameMesh)
|
||||||
return new MeshLoader(*m_lastFrameMesh);
|
return new Model(*m_lastFrameMesh);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
m_currentPlayIndex = (m_currentPlayIndex + 1) % m_frameMeshes.size();
|
m_currentPlayIndex = (m_currentPlayIndex + 1) % m_frameMeshes.size();
|
||||||
m_countForFrame.restart();
|
m_countForFrame.restart();
|
||||||
|
|
||||||
MeshLoader *mesh = new MeshLoader(*m_frameMeshes[m_currentPlayIndex].second);
|
Model *mesh = new Model(*m_frameMeshes[m_currentPlayIndex].second);
|
||||||
m_timerForFrame.singleShot(getFrameDurationMillis(m_currentPlayIndex), this, &AnimationClipPlayer::frameReadyToShow);
|
m_timerForFrame.singleShot(getFrameDurationMillis(m_currentPlayIndex), this, &AnimationClipPlayer::frameReadyToShow);
|
||||||
delete m_lastFrameMesh;
|
delete m_lastFrameMesh;
|
||||||
m_lastFrameMesh = new MeshLoader(*mesh);
|
m_lastFrameMesh = new Model(*mesh);
|
||||||
return mesh;
|
return mesh;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QTime>
|
#include <QTime>
|
||||||
#include "meshloader.h"
|
#include "model.h"
|
||||||
|
|
||||||
class AnimationClipPlayer : public QObject
|
class AnimationClipPlayer : public QObject
|
||||||
{
|
{
|
||||||
|
@ -21,8 +21,8 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
~AnimationClipPlayer();
|
~AnimationClipPlayer();
|
||||||
MeshLoader *takeFrameMesh();
|
Model *takeFrameMesh();
|
||||||
void updateFrameMeshes(std::vector<std::pair<float, MeshLoader *>> &frameMeshes);
|
void updateFrameMeshes(std::vector<std::pair<float, Model *>> &frameMeshes);
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
@ -32,9 +32,9 @@ private:
|
||||||
void freeFrames();
|
void freeFrames();
|
||||||
int getFrameDurationMillis(int frame);
|
int getFrameDurationMillis(int frame);
|
||||||
|
|
||||||
MeshLoader *m_lastFrameMesh = nullptr;
|
Model *m_lastFrameMesh = nullptr;
|
||||||
int m_currentPlayIndex = 0;
|
int m_currentPlayIndex = 0;
|
||||||
std::vector<std::pair<float, MeshLoader *>> m_frameMeshes;
|
std::vector<std::pair<float, Model *>> m_frameMeshes;
|
||||||
QTime m_countForFrame;
|
QTime m_countForFrame;
|
||||||
QTimer m_timerForFrame;
|
QTimer m_timerForFrame;
|
||||||
SpeedMode m_speedMode = SpeedMode::Normal;
|
SpeedMode m_speedMode = SpeedMode::Normal;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#include <QVector2D>
|
#include <QVector2D>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "boundingboxmesh.h"
|
#include "boundingboxmesh.h"
|
||||||
#include "meshloader.h"
|
#include "model.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
ShaderVertex *buildBoundingBoxMeshEdges(const std::vector<std::tuple<QVector3D, QVector3D, float, float, QColor>> &boxes,
|
ShaderVertex *buildBoundingBoxMeshEdges(const std::vector<std::tuple<QVector3D, QVector3D, float, float, QColor>> &boxes,
|
||||||
|
@ -73,8 +73,8 @@ ShaderVertex *buildBoundingBoxMeshEdges(const std::vector<std::tuple<QVector3D,
|
||||||
currentVertex.normX = 0;
|
currentVertex.normX = 0;
|
||||||
currentVertex.normY = 1;
|
currentVertex.normY = 1;
|
||||||
currentVertex.normZ = 0;
|
currentVertex.normZ = 0;
|
||||||
currentVertex.metalness = MeshLoader::m_defaultMetalness;
|
currentVertex.metalness = Model::m_defaultMetalness;
|
||||||
currentVertex.roughness = MeshLoader::m_defaultRoughness;
|
currentVertex.roughness = Model::m_defaultRoughness;
|
||||||
currentVertex.tangentX = 0;
|
currentVertex.tangentX = 0;
|
||||||
currentVertex.tangentY = 0;
|
currentVertex.tangentY = 0;
|
||||||
currentVertex.tangentZ = 0;
|
currentVertex.tangentZ = 0;
|
||||||
|
@ -93,9 +93,9 @@ ShaderVertex *buildBoundingBoxMeshEdges(const std::vector<std::tuple<QVector3D,
|
||||||
return edgeVertices;
|
return edgeVertices;
|
||||||
}
|
}
|
||||||
|
|
||||||
MeshLoader *buildBoundingBoxMesh(const std::vector<std::tuple<QVector3D, QVector3D, float, float, QColor>> &boxes)
|
Model *buildBoundingBoxMesh(const std::vector<std::tuple<QVector3D, QVector3D, float, float, QColor>> &boxes)
|
||||||
{
|
{
|
||||||
int edgeVerticesNum = 0;
|
int edgeVerticesNum = 0;
|
||||||
ShaderVertex *edgeVertices = buildBoundingBoxMeshEdges(boxes, &edgeVerticesNum);
|
ShaderVertex *edgeVertices = buildBoundingBoxMeshEdges(boxes, &edgeVerticesNum);
|
||||||
return new MeshLoader(nullptr, 0, edgeVertices, edgeVerticesNum);
|
return new Model(nullptr, 0, edgeVertices, edgeVerticesNum);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,10 +4,10 @@
|
||||||
#include <QVector3D>
|
#include <QVector3D>
|
||||||
#include <QColor>
|
#include <QColor>
|
||||||
#include "shadervertex.h"
|
#include "shadervertex.h"
|
||||||
#include "meshloader.h"
|
#include "model.h"
|
||||||
|
|
||||||
ShaderVertex *buildBoundingBoxMeshEdges(const std::vector<std::tuple<QVector3D, QVector3D, float, float, QColor>> &boxes,
|
ShaderVertex *buildBoundingBoxMeshEdges(const std::vector<std::tuple<QVector3D, QVector3D, float, float, QColor>> &boxes,
|
||||||
int *edgeVerticesNum);
|
int *edgeVerticesNum);
|
||||||
MeshLoader *buildBoundingBoxMesh(const std::vector<std::tuple<QVector3D, QVector3D, float, float, QColor>> &boxes);
|
Model *buildBoundingBoxMesh(const std::vector<std::tuple<QVector3D, QVector3D, float, float, QColor>> &boxes);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <QUuid>
|
#include <QUuid>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <QTransform>
|
#include <QTransform>
|
||||||
|
#include <QGuiApplication>
|
||||||
#include "contourtopartconverter.h"
|
#include "contourtopartconverter.h"
|
||||||
#include "imageskeletonextractor.h"
|
#include "imageskeletonextractor.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
@ -23,6 +24,7 @@ ContourToPartConverter::ContourToPartConverter(const QPolygonF &mainProfile,
|
||||||
void ContourToPartConverter::process()
|
void ContourToPartConverter::process()
|
||||||
{
|
{
|
||||||
convert();
|
convert();
|
||||||
|
this->moveToThread(QGuiApplication::instance()->thread());
|
||||||
emit finished();
|
emit finished();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,7 @@ void CutFaceWidget::updatePreview(QUuid partId)
|
||||||
qDebug() << "Part not found:" << m_partId;
|
qDebug() << "Part not found:" << m_partId;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
MeshLoader *previewMesh = part->takePreviewMesh();
|
Model *previewMesh = part->takePreviewMesh();
|
||||||
m_previewWidget->updateMesh(previewMesh);
|
m_previewWidget->updateMesh(previewMesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
135
src/document.cpp
135
src/document.cpp
|
@ -170,6 +170,24 @@ void Document::breakEdge(QUuid edgeId)
|
||||||
addEdge(middleNodeId, secondNodeId);
|
addEdge(middleNodeId, secondNodeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Document::reverseEdge(QUuid edgeId)
|
||||||
|
{
|
||||||
|
SkeletonEdge *edge = (SkeletonEdge *)findEdge(edgeId);
|
||||||
|
if (nullptr == edge) {
|
||||||
|
qDebug() << "Find edge failed:" << edgeId;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (edge->nodeIds.size() != 2) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::swap(edge->nodeIds[0], edge->nodeIds[1]);
|
||||||
|
auto part = partMap.find(edge->partId);
|
||||||
|
if (part != partMap.end())
|
||||||
|
part->second.dirty = true;
|
||||||
|
emit edgeReversed(edgeId);
|
||||||
|
emit skeletonChanged();
|
||||||
|
}
|
||||||
|
|
||||||
void Document::removeEdge(QUuid edgeId)
|
void Document::removeEdge(QUuid edgeId)
|
||||||
{
|
{
|
||||||
const SkeletonEdge *edge = findEdge(edgeId);
|
const SkeletonEdge *edge = findEdge(edgeId);
|
||||||
|
@ -346,7 +364,7 @@ void Document::addPartByPolygons(const QPolygonF &mainProfile, const QPolygonF &
|
||||||
connect(contourToPartConverter, &ContourToPartConverter::finished, this, [=]() {
|
connect(contourToPartConverter, &ContourToPartConverter::finished, this, [=]() {
|
||||||
const auto &snapshot = contourToPartConverter->getSnapshot();
|
const auto &snapshot = contourToPartConverter->getSnapshot();
|
||||||
if (!snapshot.nodes.empty()) {
|
if (!snapshot.nodes.empty()) {
|
||||||
addFromSnapshot(snapshot, true);
|
addFromSnapshot(snapshot, SnapshotSource::Paste);
|
||||||
saveSnapshot();
|
saveSnapshot();
|
||||||
}
|
}
|
||||||
delete contourToPartConverter;
|
delete contourToPartConverter;
|
||||||
|
@ -1145,6 +1163,8 @@ void Document::toSnapshot(Snapshot *snapshot, const std::set<QUuid> &limitNodeId
|
||||||
part["cutFace"] = CutFaceToString(partIt.second.cutFace);
|
part["cutFace"] = CutFaceToString(partIt.second.cutFace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!partIt.second.fillMeshLinkedId.isNull())
|
||||||
|
part["fillMesh"] = partIt.second.fillMeshLinkedId.toString();
|
||||||
part["dirty"] = partIt.second.dirty ? "true" : "false";
|
part["dirty"] = partIt.second.dirty ? "true" : "false";
|
||||||
if (partIt.second.hasColor)
|
if (partIt.second.hasColor)
|
||||||
part["color"] = partIt.second.color.name(QColor::HexArgb);
|
part["color"] = partIt.second.color.name(QColor::HexArgb);
|
||||||
|
@ -1443,11 +1463,11 @@ void Document::createSinglePartFromEdges(const std::vector<QVector3D> &nodes,
|
||||||
emit skeletonChanged();
|
emit skeletonChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Document::addFromSnapshot(const Snapshot &snapshot, bool fromPaste)
|
void Document::addFromSnapshot(const Snapshot &snapshot, enum SnapshotSource source)
|
||||||
{
|
{
|
||||||
bool isOriginChanged = false;
|
bool isOriginChanged = false;
|
||||||
bool isRigTypeChanged = false;
|
bool isRigTypeChanged = false;
|
||||||
if (!fromPaste) {
|
if (SnapshotSource::Paste != source) {
|
||||||
this->polyCount = PolyCountFromString(valueOfKeyInMapOrEmpty(snapshot.canvas, "polyCount").toUtf8().constData());
|
this->polyCount = PolyCountFromString(valueOfKeyInMapOrEmpty(snapshot.canvas, "polyCount").toUtf8().constData());
|
||||||
const auto &originXit = snapshot.canvas.find("originX");
|
const auto &originXit = snapshot.canvas.find("originX");
|
||||||
const auto &originYit = snapshot.canvas.find("originY");
|
const auto &originYit = snapshot.canvas.find("originY");
|
||||||
|
@ -1482,38 +1502,41 @@ void Document::addFromSnapshot(const Snapshot &snapshot, bool fromPaste)
|
||||||
qDebug() << "Unsupported material type:" << materialType;
|
qDebug() << "Unsupported material type:" << materialType;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
QUuid newMaterialId = QUuid::createUuid();
|
QUuid oldMaterialId = QUuid(valueOfKeyInMapOrEmpty(materialAttributes, "id"));
|
||||||
auto &newMaterial = materialMap[newMaterialId];
|
QUuid newMaterialId = SnapshotSource::Import == source ? oldMaterialId : QUuid::createUuid();
|
||||||
newMaterial.id = newMaterialId;
|
oldNewIdMap[oldMaterialId] = newMaterialId;
|
||||||
newMaterial.name = valueOfKeyInMapOrEmpty(materialAttributes, "name");
|
if (materialMap.end() == materialMap.find(newMaterialId)) {
|
||||||
oldNewIdMap[QUuid(valueOfKeyInMapOrEmpty(materialAttributes, "id"))] = newMaterialId;
|
auto &newMaterial = materialMap[newMaterialId];
|
||||||
for (const auto &layerIt: materialIt.second) {
|
newMaterial.id = newMaterialId;
|
||||||
MaterialLayer layer;
|
newMaterial.name = valueOfKeyInMapOrEmpty(materialAttributes, "name");
|
||||||
auto findTileScale = layerIt.first.find("tileScale");
|
for (const auto &layerIt: materialIt.second) {
|
||||||
if (findTileScale != layerIt.first.end())
|
MaterialLayer layer;
|
||||||
layer.tileScale = findTileScale->second.toFloat();
|
auto findTileScale = layerIt.first.find("tileScale");
|
||||||
for (const auto &mapItem: layerIt.second) {
|
if (findTileScale != layerIt.first.end())
|
||||||
auto textureTypeString = valueOfKeyInMapOrEmpty(mapItem, "for");
|
layer.tileScale = findTileScale->second.toFloat();
|
||||||
auto textureType = TextureTypeFromString(textureTypeString.toUtf8().constData());
|
for (const auto &mapItem: layerIt.second) {
|
||||||
if (TextureType::None == textureType) {
|
auto textureTypeString = valueOfKeyInMapOrEmpty(mapItem, "for");
|
||||||
qDebug() << "Unsupported texture type:" << textureTypeString;
|
auto textureType = TextureTypeFromString(textureTypeString.toUtf8().constData());
|
||||||
continue;
|
if (TextureType::None == textureType) {
|
||||||
|
qDebug() << "Unsupported texture type:" << textureTypeString;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto linkTypeString = valueOfKeyInMapOrEmpty(mapItem, "linkDataType");
|
||||||
|
if ("imageId" != linkTypeString) {
|
||||||
|
qDebug() << "Unsupported link data type:" << linkTypeString;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto imageId = QUuid(valueOfKeyInMapOrEmpty(mapItem, "linkData"));
|
||||||
|
MaterialMap materialMap;
|
||||||
|
materialMap.imageId = imageId;
|
||||||
|
materialMap.forWhat = textureType;
|
||||||
|
layer.maps.push_back(materialMap);
|
||||||
}
|
}
|
||||||
auto linkTypeString = valueOfKeyInMapOrEmpty(mapItem, "linkDataType");
|
newMaterial.layers.push_back(layer);
|
||||||
if ("imageId" != linkTypeString) {
|
|
||||||
qDebug() << "Unsupported link data type:" << linkTypeString;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
auto imageId = QUuid(valueOfKeyInMapOrEmpty(mapItem, "linkData"));
|
|
||||||
MaterialMap materialMap;
|
|
||||||
materialMap.imageId = imageId;
|
|
||||||
materialMap.forWhat = textureType;
|
|
||||||
layer.maps.push_back(materialMap);
|
|
||||||
}
|
}
|
||||||
newMaterial.layers.push_back(layer);
|
materialIdList.push_back(newMaterialId);
|
||||||
|
emit materialAdded(newMaterialId);
|
||||||
}
|
}
|
||||||
materialIdList.push_back(newMaterialId);
|
|
||||||
emit materialAdded(newMaterialId);
|
|
||||||
}
|
}
|
||||||
std::map<QUuid, QUuid> cutFaceLinkedIdModifyMap;
|
std::map<QUuid, QUuid> cutFaceLinkedIdModifyMap;
|
||||||
for (const auto &partKv: snapshot.parts) {
|
for (const auto &partKv: snapshot.parts) {
|
||||||
|
@ -1550,6 +1573,12 @@ void Document::addFromSnapshot(const Snapshot &snapshot, bool fromPaste)
|
||||||
cutFaceLinkedIdModifyMap.insert({part.id, cutFaceLinkedId});
|
cutFaceLinkedIdModifyMap.insert({part.id, cutFaceLinkedId});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const auto &fillMeshIt = partKv.second.find("fillMesh");
|
||||||
|
if (fillMeshIt != partKv.second.end()) {
|
||||||
|
QUuid fillMeshLinkedId = QUuid(fillMeshIt->second);
|
||||||
|
if (!fillMeshLinkedId.isNull())
|
||||||
|
part.fillMeshLinkedId = fillMeshLinkedId;
|
||||||
|
}
|
||||||
if (isTrueValueString(valueOfKeyInMapOrEmpty(partKv.second, "inverse")))
|
if (isTrueValueString(valueOfKeyInMapOrEmpty(partKv.second, "inverse")))
|
||||||
inversePartIds.insert(part.id);
|
inversePartIds.insert(part.id);
|
||||||
const auto &colorIt = partKv.second.find("color");
|
const auto &colorIt = partKv.second.find("color");
|
||||||
|
@ -1863,15 +1892,15 @@ void Document::resetScript()
|
||||||
void Document::fromSnapshot(const Snapshot &snapshot)
|
void Document::fromSnapshot(const Snapshot &snapshot)
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
addFromSnapshot(snapshot, false);
|
addFromSnapshot(snapshot, SnapshotSource::Unknown);
|
||||||
emit uncheckAll();
|
emit uncheckAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
MeshLoader *Document::takeResultMesh()
|
Model *Document::takeResultMesh()
|
||||||
{
|
{
|
||||||
if (nullptr == m_resultMesh)
|
if (nullptr == m_resultMesh)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
MeshLoader *resultMesh = new MeshLoader(*m_resultMesh);
|
Model *resultMesh = new Model(*m_resultMesh);
|
||||||
return resultMesh;
|
return resultMesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1880,32 +1909,32 @@ bool Document::isMeshGenerationSucceed()
|
||||||
return m_isMeshGenerationSucceed;
|
return m_isMeshGenerationSucceed;
|
||||||
}
|
}
|
||||||
|
|
||||||
MeshLoader *Document::takeResultTextureMesh()
|
Model *Document::takeResultTextureMesh()
|
||||||
{
|
{
|
||||||
if (nullptr == m_resultTextureMesh)
|
if (nullptr == m_resultTextureMesh)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
MeshLoader *resultTextureMesh = new MeshLoader(*m_resultTextureMesh);
|
Model *resultTextureMesh = new Model(*m_resultTextureMesh);
|
||||||
return resultTextureMesh;
|
return resultTextureMesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
MeshLoader *Document::takeResultRigWeightMesh()
|
Model *Document::takeResultRigWeightMesh()
|
||||||
{
|
{
|
||||||
if (nullptr == m_resultRigWeightMesh)
|
if (nullptr == m_resultRigWeightMesh)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
MeshLoader *resultMesh = new MeshLoader(*m_resultRigWeightMesh);
|
Model *resultMesh = new Model(*m_resultRigWeightMesh);
|
||||||
return resultMesh;
|
return resultMesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Document::meshReady()
|
void Document::meshReady()
|
||||||
{
|
{
|
||||||
MeshLoader *resultMesh = m_meshGenerator->takeResultMesh();
|
Model *resultMesh = m_meshGenerator->takeResultMesh();
|
||||||
Outcome *outcome = m_meshGenerator->takeOutcome();
|
Outcome *outcome = m_meshGenerator->takeOutcome();
|
||||||
bool isSucceed = m_meshGenerator->isSucceed();
|
bool isSuccessful = m_meshGenerator->isSuccessful();
|
||||||
|
|
||||||
for (auto &partId: m_meshGenerator->generatedPreviewPartIds()) {
|
for (auto &partId: m_meshGenerator->generatedPreviewPartIds()) {
|
||||||
auto part = partMap.find(partId);
|
auto part = partMap.find(partId);
|
||||||
if (part != partMap.end()) {
|
if (part != partMap.end()) {
|
||||||
MeshLoader *resultPartPreviewMesh = m_meshGenerator->takePartPreviewMesh(partId);
|
Model *resultPartPreviewMesh = m_meshGenerator->takePartPreviewMesh(partId);
|
||||||
part->second.updatePreviewMesh(resultPartPreviewMesh);
|
part->second.updatePreviewMesh(resultPartPreviewMesh);
|
||||||
emit partPreviewChanged(partId);
|
emit partPreviewChanged(partId);
|
||||||
}
|
}
|
||||||
|
@ -1922,7 +1951,7 @@ void Document::meshReady()
|
||||||
|
|
||||||
//addToolToMesh(m_resultMesh);
|
//addToolToMesh(m_resultMesh);
|
||||||
|
|
||||||
m_isMeshGenerationSucceed = isSucceed;
|
m_isMeshGenerationSucceed = isSuccessful;
|
||||||
|
|
||||||
delete m_currentOutcome;
|
delete m_currentOutcome;
|
||||||
m_currentOutcome = outcome;
|
m_currentOutcome = outcome;
|
||||||
|
@ -1946,7 +1975,7 @@ void Document::meshReady()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//void Document::addToolToMesh(MeshLoader *mesh)
|
//void Document::addToolToMesh(Model *mesh)
|
||||||
//{
|
//{
|
||||||
// if (nullptr == mesh)
|
// if (nullptr == mesh)
|
||||||
// return;
|
// return;
|
||||||
|
@ -2136,7 +2165,7 @@ void Document::postProcess()
|
||||||
m_isPostProcessResultObsolete = false;
|
m_isPostProcessResultObsolete = false;
|
||||||
|
|
||||||
if (!m_currentOutcome) {
|
if (!m_currentOutcome) {
|
||||||
qDebug() << "MeshLoader is null";
|
qDebug() << "Model is null";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2188,7 +2217,7 @@ void Document::doPickMouseTarget()
|
||||||
m_isMouseTargetResultObsolete = false;
|
m_isMouseTargetResultObsolete = false;
|
||||||
|
|
||||||
if (!m_currentOutcome) {
|
if (!m_currentOutcome) {
|
||||||
qDebug() << "MeshLoader is null";
|
qDebug() << "Model is null";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3179,7 +3208,7 @@ void Document::paste()
|
||||||
QXmlStreamReader xmlStreamReader(mimeData->text());
|
QXmlStreamReader xmlStreamReader(mimeData->text());
|
||||||
Snapshot snapshot;
|
Snapshot snapshot;
|
||||||
loadSkeletonFromXmlStream(&snapshot, xmlStreamReader);
|
loadSkeletonFromXmlStream(&snapshot, xmlStreamReader);
|
||||||
addFromSnapshot(snapshot, true);
|
addFromSnapshot(snapshot, SnapshotSource::Paste);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3496,7 +3525,7 @@ void Document::generateRig()
|
||||||
|
|
||||||
void Document::rigReady()
|
void Document::rigReady()
|
||||||
{
|
{
|
||||||
m_currentRigSucceed = m_rigGenerator->isSucceed();
|
m_currentRigSucceed = m_rigGenerator->isSuccessful();
|
||||||
|
|
||||||
delete m_resultRigWeightMesh;
|
delete m_resultRigWeightMesh;
|
||||||
m_resultRigWeightMesh = m_rigGenerator->takeResultMesh();
|
m_resultRigWeightMesh = m_rigGenerator->takeResultMesh();
|
||||||
|
@ -3701,7 +3730,7 @@ void Document::posePreviewsReady()
|
||||||
for (const auto &poseIdAndFrame: m_posePreviewsGenerator->generatedPreviewPoseIdAndFrames()) {
|
for (const auto &poseIdAndFrame: m_posePreviewsGenerator->generatedPreviewPoseIdAndFrames()) {
|
||||||
auto pose = poseMap.find(poseIdAndFrame.first);
|
auto pose = poseMap.find(poseIdAndFrame.first);
|
||||||
if (pose != poseMap.end()) {
|
if (pose != poseMap.end()) {
|
||||||
MeshLoader *resultPartPreviewMesh = m_posePreviewsGenerator->takePreview(poseIdAndFrame);
|
Model *resultPartPreviewMesh = m_posePreviewsGenerator->takePreview(poseIdAndFrame);
|
||||||
pose->second.updatePreviewMesh(resultPartPreviewMesh);
|
pose->second.updatePreviewMesh(resultPartPreviewMesh);
|
||||||
emit posePreviewChanged(poseIdAndFrame.first);
|
emit posePreviewChanged(poseIdAndFrame.first);
|
||||||
}
|
}
|
||||||
|
@ -3717,6 +3746,12 @@ void Document::posePreviewsReady()
|
||||||
|
|
||||||
void Document::addMaterial(QUuid materialId, QString name, std::vector<MaterialLayer> layers)
|
void Document::addMaterial(QUuid materialId, QString name, std::vector<MaterialLayer> layers)
|
||||||
{
|
{
|
||||||
|
auto findMaterialResult = materialMap.find(materialId);
|
||||||
|
if (findMaterialResult != materialMap.end()) {
|
||||||
|
qDebug() << "Material already exist:" << materialId;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
QUuid newMaterialId = materialId;
|
QUuid newMaterialId = materialId;
|
||||||
auto &material = materialMap[newMaterialId];
|
auto &material = materialMap[newMaterialId];
|
||||||
material.id = newMaterialId;
|
material.id = newMaterialId;
|
||||||
|
@ -3815,7 +3850,7 @@ void Document::materialPreviewsReady()
|
||||||
for (const auto &materialId: m_materialPreviewsGenerator->generatedPreviewMaterialIds()) {
|
for (const auto &materialId: m_materialPreviewsGenerator->generatedPreviewMaterialIds()) {
|
||||||
auto material = materialMap.find(materialId);
|
auto material = materialMap.find(materialId);
|
||||||
if (material != materialMap.end()) {
|
if (material != materialMap.end()) {
|
||||||
MeshLoader *resultPartPreviewMesh = m_materialPreviewsGenerator->takePreview(materialId);
|
Model *resultPartPreviewMesh = m_materialPreviewsGenerator->takePreview(materialId);
|
||||||
material->second.updatePreviewMesh(resultPartPreviewMesh);
|
material->second.updatePreviewMesh(resultPartPreviewMesh);
|
||||||
emit materialPreviewChanged(materialId);
|
emit materialPreviewChanged(materialId);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <QPolygon>
|
#include <QPolygon>
|
||||||
#include "snapshot.h"
|
#include "snapshot.h"
|
||||||
#include "meshloader.h"
|
#include "model.h"
|
||||||
#include "meshgenerator.h"
|
#include "meshgenerator.h"
|
||||||
#include "theme.h"
|
#include "theme.h"
|
||||||
#include "texturegenerator.h"
|
#include "texturegenerator.h"
|
||||||
|
@ -231,16 +231,16 @@ public:
|
||||||
QUuid turnaroundImageId;
|
QUuid turnaroundImageId;
|
||||||
float yTranslationScale = 1.0;
|
float yTranslationScale = 1.0;
|
||||||
std::vector<std::pair<std::map<QString, QString>, std::map<QString, std::map<QString, QString>>>> frames; // pair<attributes, parameters>
|
std::vector<std::pair<std::map<QString, QString>, std::map<QString, std::map<QString, QString>>>> frames; // pair<attributes, parameters>
|
||||||
void updatePreviewMesh(MeshLoader *previewMesh)
|
void updatePreviewMesh(Model *previewMesh)
|
||||||
{
|
{
|
||||||
delete m_previewMesh;
|
delete m_previewMesh;
|
||||||
m_previewMesh = previewMesh;
|
m_previewMesh = previewMesh;
|
||||||
}
|
}
|
||||||
MeshLoader *takePreviewMesh() const
|
Model *takePreviewMesh() const
|
||||||
{
|
{
|
||||||
if (nullptr == m_previewMesh)
|
if (nullptr == m_previewMesh)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
return new MeshLoader(*m_previewMesh);
|
return new Model(*m_previewMesh);
|
||||||
}
|
}
|
||||||
bool yTranslationScaleAdjusted() const
|
bool yTranslationScaleAdjusted() const
|
||||||
{
|
{
|
||||||
|
@ -248,7 +248,7 @@ public:
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
Q_DISABLE_COPY(Pose);
|
Q_DISABLE_COPY(Pose);
|
||||||
MeshLoader *m_previewMesh = nullptr;
|
Model *m_previewMesh = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class MotionClipType
|
enum class MotionClipType
|
||||||
|
@ -327,18 +327,18 @@ public:
|
||||||
bool dirty = true;
|
bool dirty = true;
|
||||||
std::vector<MotionClip> clips;
|
std::vector<MotionClip> clips;
|
||||||
std::vector<std::pair<float, JointNodeTree>> jointNodeTrees;
|
std::vector<std::pair<float, JointNodeTree>> jointNodeTrees;
|
||||||
void updatePreviewMeshs(std::vector<std::pair<float, MeshLoader *>> &previewMeshs)
|
void updatePreviewMeshs(std::vector<std::pair<float, Model *>> &previewMeshs)
|
||||||
{
|
{
|
||||||
releasePreviewMeshs();
|
releasePreviewMeshs();
|
||||||
m_previewMeshs = previewMeshs;
|
m_previewMeshs = previewMeshs;
|
||||||
previewMeshs.clear();
|
previewMeshs.clear();
|
||||||
}
|
}
|
||||||
MeshLoader *takePreviewMesh() const
|
Model *takePreviewMesh() const
|
||||||
{
|
{
|
||||||
if (m_previewMeshs.empty())
|
if (m_previewMeshs.empty())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
int middle = std::max((int)m_previewMeshs.size() / 2 - 1, (int)0);
|
int middle = std::max((int)m_previewMeshs.size() / 2 - 1, (int)0);
|
||||||
return new MeshLoader(*m_previewMeshs[middle].second);
|
return new Model(*m_previewMeshs[middle].second);
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
Q_DISABLE_COPY(Motion);
|
Q_DISABLE_COPY(Motion);
|
||||||
|
@ -349,7 +349,7 @@ private:
|
||||||
}
|
}
|
||||||
m_previewMeshs.clear();
|
m_previewMeshs.clear();
|
||||||
}
|
}
|
||||||
std::vector<std::pair<float, MeshLoader *>> m_previewMeshs;
|
std::vector<std::pair<float, Model *>> m_previewMeshs;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MaterialMap
|
class MaterialMap
|
||||||
|
@ -380,20 +380,20 @@ public:
|
||||||
QString name;
|
QString name;
|
||||||
bool dirty = true;
|
bool dirty = true;
|
||||||
std::vector<MaterialLayer> layers;
|
std::vector<MaterialLayer> layers;
|
||||||
void updatePreviewMesh(MeshLoader *previewMesh)
|
void updatePreviewMesh(Model *previewMesh)
|
||||||
{
|
{
|
||||||
delete m_previewMesh;
|
delete m_previewMesh;
|
||||||
m_previewMesh = previewMesh;
|
m_previewMesh = previewMesh;
|
||||||
}
|
}
|
||||||
MeshLoader *takePreviewMesh() const
|
Model *takePreviewMesh() const
|
||||||
{
|
{
|
||||||
if (nullptr == m_previewMesh)
|
if (nullptr == m_previewMesh)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
return new MeshLoader(*m_previewMesh);
|
return new Model(*m_previewMesh);
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
Q_DISABLE_COPY(Material);
|
Q_DISABLE_COPY(Material);
|
||||||
MeshLoader *m_previewMesh = nullptr;
|
Model *m_previewMesh = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class DocumentToSnapshotFor
|
enum class DocumentToSnapshotFor
|
||||||
|
@ -434,7 +434,7 @@ signals:
|
||||||
void nodeCutRotationChanged(QUuid nodeId);
|
void nodeCutRotationChanged(QUuid nodeId);
|
||||||
void nodeCutFaceChanged(QUuid nodeId);
|
void nodeCutFaceChanged(QUuid nodeId);
|
||||||
void nodeOriginChanged(QUuid nodeId);
|
void nodeOriginChanged(QUuid nodeId);
|
||||||
void edgeChanged(QUuid edgeId);
|
void edgeReversed(QUuid edgeId);
|
||||||
void partPreviewChanged(QUuid partId);
|
void partPreviewChanged(QUuid partId);
|
||||||
void resultMeshChanged();
|
void resultMeshChanged();
|
||||||
void turnaroundChanged();
|
void turnaroundChanged();
|
||||||
|
@ -562,17 +562,23 @@ public:
|
||||||
const std::set<QUuid> &limitMotionIds=std::set<QUuid>(),
|
const std::set<QUuid> &limitMotionIds=std::set<QUuid>(),
|
||||||
const std::set<QUuid> &limitMaterialIds=std::set<QUuid>()) const;
|
const std::set<QUuid> &limitMaterialIds=std::set<QUuid>()) const;
|
||||||
void fromSnapshot(const Snapshot &snapshot);
|
void fromSnapshot(const Snapshot &snapshot);
|
||||||
void addFromSnapshot(const Snapshot &snapshot, bool fromPaste=true);
|
enum class SnapshotSource
|
||||||
|
{
|
||||||
|
Unknown,
|
||||||
|
Paste,
|
||||||
|
Import
|
||||||
|
};
|
||||||
|
void addFromSnapshot(const Snapshot &snapshot, enum SnapshotSource source=SnapshotSource::Paste);
|
||||||
const Component *findComponent(QUuid componentId) const;
|
const Component *findComponent(QUuid componentId) const;
|
||||||
const Component *findComponentParent(QUuid componentId) const;
|
const Component *findComponentParent(QUuid componentId) const;
|
||||||
QUuid findComponentParentId(QUuid componentId) const;
|
QUuid findComponentParentId(QUuid componentId) const;
|
||||||
const Material *findMaterial(QUuid materialId) const;
|
const Material *findMaterial(QUuid materialId) const;
|
||||||
const Pose *findPose(QUuid poseId) const;
|
const Pose *findPose(QUuid poseId) const;
|
||||||
const Motion *findMotion(QUuid motionId) const;
|
const Motion *findMotion(QUuid motionId) const;
|
||||||
MeshLoader *takeResultMesh();
|
Model *takeResultMesh();
|
||||||
bool isMeshGenerationSucceed();
|
bool isMeshGenerationSucceed();
|
||||||
MeshLoader *takeResultTextureMesh();
|
Model *takeResultTextureMesh();
|
||||||
MeshLoader *takeResultRigWeightMesh();
|
Model *takeResultRigWeightMesh();
|
||||||
const std::vector<RiggerBone> *resultRigBones() const;
|
const std::vector<RiggerBone> *resultRigBones() const;
|
||||||
const std::map<int, RiggerVertexWeights> *resultRigWeights() const;
|
const std::map<int, RiggerVertexWeights> *resultRigWeights() const;
|
||||||
void updateTurnaround(const QImage &image);
|
void updateTurnaround(const QImage &image);
|
||||||
|
@ -707,6 +713,7 @@ public slots:
|
||||||
void silentReset();
|
void silentReset();
|
||||||
void silentResetScript();
|
void silentResetScript();
|
||||||
void breakEdge(QUuid edgeId);
|
void breakEdge(QUuid edgeId);
|
||||||
|
void reverseEdge(QUuid edgeId);
|
||||||
void setXlockState(bool locked);
|
void setXlockState(bool locked);
|
||||||
void setYlockState(bool locked);
|
void setYlockState(bool locked);
|
||||||
void setZlockState(bool locked);
|
void setZlockState(bool locked);
|
||||||
|
@ -760,13 +767,13 @@ private:
|
||||||
void markAllDirty();
|
void markAllDirty();
|
||||||
void removeRigResults();
|
void removeRigResults();
|
||||||
void updateLinkedPart(QUuid oldPartId, QUuid newPartId);
|
void updateLinkedPart(QUuid oldPartId, QUuid newPartId);
|
||||||
//void addToolToMesh(MeshLoader *mesh);
|
//void addToolToMesh(Model *mesh);
|
||||||
bool updateDefaultVariables(const std::map<QString, std::map<QString, QString>> &defaultVariables);
|
bool updateDefaultVariables(const std::map<QString, std::map<QString, QString>> &defaultVariables);
|
||||||
void checkPartGrid(QUuid partId);
|
void checkPartGrid(QUuid partId);
|
||||||
private: // need initialize
|
private: // need initialize
|
||||||
bool m_isResultMeshObsolete;
|
bool m_isResultMeshObsolete;
|
||||||
MeshGenerator *m_meshGenerator;
|
MeshGenerator *m_meshGenerator;
|
||||||
MeshLoader *m_resultMesh;
|
Model *m_resultMesh;
|
||||||
std::map<QUuid, StrokeMeshBuilder::CutFaceTransform> *m_resultMeshCutFaceTransforms;
|
std::map<QUuid, StrokeMeshBuilder::CutFaceTransform> *m_resultMeshCutFaceTransforms;
|
||||||
std::map<QUuid, std::map<QString, QVector2D>> *m_resultMeshNodesCutFaces;
|
std::map<QUuid, std::map<QString, QVector2D>> *m_resultMeshNodesCutFaces;
|
||||||
bool m_isMeshGenerationSucceed;
|
bool m_isMeshGenerationSucceed;
|
||||||
|
@ -777,13 +784,13 @@ private: // need initialize
|
||||||
bool m_isPostProcessResultObsolete;
|
bool m_isPostProcessResultObsolete;
|
||||||
MeshResultPostProcessor *m_postProcessor;
|
MeshResultPostProcessor *m_postProcessor;
|
||||||
Outcome *m_postProcessedOutcome;
|
Outcome *m_postProcessedOutcome;
|
||||||
MeshLoader *m_resultTextureMesh;
|
Model *m_resultTextureMesh;
|
||||||
unsigned long long m_textureImageUpdateVersion;
|
unsigned long long m_textureImageUpdateVersion;
|
||||||
QUuid m_currentCanvasComponentId;
|
QUuid m_currentCanvasComponentId;
|
||||||
bool m_allPositionRelatedLocksEnabled;
|
bool m_allPositionRelatedLocksEnabled;
|
||||||
bool m_smoothNormal;
|
bool m_smoothNormal;
|
||||||
RigGenerator *m_rigGenerator;
|
RigGenerator *m_rigGenerator;
|
||||||
MeshLoader *m_resultRigWeightMesh;
|
Model *m_resultRigWeightMesh;
|
||||||
std::vector<RiggerBone> *m_resultRigBones;
|
std::vector<RiggerBone> *m_resultRigBones;
|
||||||
std::map<int, RiggerVertexWeights> *m_resultRigWeights;
|
std::map<int, RiggerVertexWeights> *m_resultRigWeights;
|
||||||
bool m_isRigObsolete;
|
bool m_isRigObsolete;
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
#include <QXmlStreamWriter>
|
#include <QXmlStreamWriter>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
#include <QGuiApplication>
|
||||||
#include "documentsaver.h"
|
#include "documentsaver.h"
|
||||||
#include "imageforever.h"
|
#include "imageforever.h"
|
||||||
#include "ds3file.h"
|
#include "ds3file.h"
|
||||||
#include "snapshotxml.h"
|
#include "snapshotxml.h"
|
||||||
#include "variablesxml.h"
|
#include "variablesxml.h"
|
||||||
|
#include "fileforever.h"
|
||||||
|
|
||||||
DocumentSaver::DocumentSaver(const QString *filename,
|
DocumentSaver::DocumentSaver(const QString *filename,
|
||||||
Snapshot *snapshot,
|
Snapshot *snapshot,
|
||||||
|
@ -34,6 +36,7 @@ void DocumentSaver::process()
|
||||||
m_turnaroundPngByteArray,
|
m_turnaroundPngByteArray,
|
||||||
m_script,
|
m_script,
|
||||||
m_variables);
|
m_variables);
|
||||||
|
this->moveToThread(QGuiApplication::instance()->thread());
|
||||||
emit finished();
|
emit finished();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,6 +71,7 @@ bool DocumentSaver::save(const QString *filename,
|
||||||
}
|
}
|
||||||
|
|
||||||
std::set<QUuid> imageIds;
|
std::set<QUuid> imageIds;
|
||||||
|
std::set<QUuid> fileIds;
|
||||||
|
|
||||||
for (const auto &material: snapshot->materials) {
|
for (const auto &material: snapshot->materials) {
|
||||||
for (auto &layer: material.second) {
|
for (auto &layer: material.second) {
|
||||||
|
@ -80,6 +84,7 @@ bool DocumentSaver::save(const QString *filename,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto &part: snapshot->parts) {
|
for (const auto &part: snapshot->parts) {
|
||||||
auto findImageIdString = part.second.find("deformMapImageId");
|
auto findImageIdString = part.second.find("deformMapImageId");
|
||||||
if (findImageIdString == part.second.end())
|
if (findImageIdString == part.second.end())
|
||||||
|
@ -88,6 +93,16 @@ bool DocumentSaver::save(const QString *filename,
|
||||||
imageIds.insert(imageId);
|
imageIds.insert(imageId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const auto &part: snapshot->parts) {
|
||||||
|
auto fillMeshLinkedIdString = part.second.find("fillMesh");
|
||||||
|
if (fillMeshLinkedIdString == part.second.end())
|
||||||
|
continue;
|
||||||
|
QUuid fileId = QUuid(fillMeshLinkedIdString->second);
|
||||||
|
if (fileId.isNull())
|
||||||
|
continue;
|
||||||
|
fileIds.insert(fileId);
|
||||||
|
}
|
||||||
|
|
||||||
for (auto &pose: snapshot->poses) {
|
for (auto &pose: snapshot->poses) {
|
||||||
auto findCanvasImageId = pose.first.find("canvasImageId");
|
auto findCanvasImageId = pose.first.find("canvasImageId");
|
||||||
if (findCanvasImageId != pose.first.end()) {
|
if (findCanvasImageId != pose.first.end()) {
|
||||||
|
@ -104,5 +119,20 @@ bool DocumentSaver::save(const QString *filename,
|
||||||
ds3Writer.add("images/" + imageId.toString() + ".png", "asset", pngByteArray);
|
ds3Writer.add("images/" + imageId.toString() + ".png", "asset", pngByteArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const auto &fileId: fileIds) {
|
||||||
|
const QByteArray *byteArray = FileForever::getContent(fileId);
|
||||||
|
if (nullptr == byteArray)
|
||||||
|
continue;
|
||||||
|
QString suffix = ".bin";
|
||||||
|
const QString *name = FileForever::getName(fileId);
|
||||||
|
if (nullptr != name) {
|
||||||
|
int suffixBegin = name->lastIndexOf(".");
|
||||||
|
if (-1 != suffixBegin)
|
||||||
|
suffix = name->mid(suffixBegin);
|
||||||
|
}
|
||||||
|
if (byteArray->size() > 0)
|
||||||
|
ds3Writer.add("files/" + fileId.toString() + suffix, "asset", byteArray);
|
||||||
|
}
|
||||||
|
|
||||||
return ds3Writer.save(*filename);
|
return ds3Writer.save(*filename);
|
||||||
}
|
}
|
|
@ -16,6 +16,11 @@ public:
|
||||||
QString *script,
|
QString *script,
|
||||||
std::map<QString, std::map<QString, QString>> *variables);
|
std::map<QString, std::map<QString, QString>> *variables);
|
||||||
~DocumentSaver();
|
~DocumentSaver();
|
||||||
|
static bool save(const QString *filename,
|
||||||
|
Snapshot *snapshot,
|
||||||
|
const QByteArray *turnaroundPngByteArray,
|
||||||
|
const QString *script,
|
||||||
|
const std::map<QString, std::map<QString, QString>> *variables);
|
||||||
signals:
|
signals:
|
||||||
void finished();
|
void finished();
|
||||||
public slots:
|
public slots:
|
||||||
|
@ -26,12 +31,6 @@ private:
|
||||||
QByteArray *m_turnaroundPngByteArray = nullptr;
|
QByteArray *m_turnaroundPngByteArray = nullptr;
|
||||||
QString *m_script = nullptr;
|
QString *m_script = nullptr;
|
||||||
std::map<QString, std::map<QString, QString>> *m_variables = nullptr;
|
std::map<QString, std::map<QString, QString>> *m_variables = nullptr;
|
||||||
|
|
||||||
static bool save(const QString *filename,
|
|
||||||
Snapshot *snapshot,
|
|
||||||
const QByteArray *turnaroundPngByteArray,
|
|
||||||
const QString *script,
|
|
||||||
const std::map<QString, std::map<QString, QString>> *variables);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -45,7 +45,9 @@
|
||||||
#include "scriptwidget.h"
|
#include "scriptwidget.h"
|
||||||
#include "variablesxml.h"
|
#include "variablesxml.h"
|
||||||
#include "updatescheckwidget.h"
|
#include "updatescheckwidget.h"
|
||||||
#include "modelofflinerender.h"
|
#include "modeloffscreenrender.h"
|
||||||
|
#include "fileforever.h"
|
||||||
|
#include "documentsaver.h"
|
||||||
|
|
||||||
int DocumentWindow::m_modelRenderWidgetInitialX = 16;
|
int DocumentWindow::m_modelRenderWidgetInitialX = 16;
|
||||||
int DocumentWindow::m_modelRenderWidgetInitialY = 16;
|
int DocumentWindow::m_modelRenderWidgetInitialY = 16;
|
||||||
|
@ -233,12 +235,12 @@ DocumentWindow::DocumentWindow() :
|
||||||
//rotateClockwiseButton->setToolTip(tr("Rotate whole model"));
|
//rotateClockwiseButton->setToolTip(tr("Rotate whole model"));
|
||||||
//Theme::initAwesomeButton(rotateClockwiseButton);
|
//Theme::initAwesomeButton(rotateClockwiseButton);
|
||||||
|
|
||||||
auto updateRegenerateIconAndTips = [&](SpinnableAwesomeButton *regenerateButton, bool isSucceed, bool forceUpdate=false) {
|
auto updateRegenerateIconAndTips = [&](SpinnableAwesomeButton *regenerateButton, bool isSuccessful, bool forceUpdate=false) {
|
||||||
if (!forceUpdate) {
|
if (!forceUpdate) {
|
||||||
if (m_isLastMeshGenerationSucceed == isSucceed)
|
if (m_isLastMeshGenerationSucceed == isSuccessful)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_isLastMeshGenerationSucceed = isSucceed;
|
m_isLastMeshGenerationSucceed = isSuccessful;
|
||||||
regenerateButton->setToolTip(m_isLastMeshGenerationSucceed ? tr("Regenerate") : tr("Mesh generation failed, please undo or adjust recent changed nodes\nTips:\n - Don't let generated mesh self-intersect\n - Make multiple parts instead of one single part for whole model"));
|
regenerateButton->setToolTip(m_isLastMeshGenerationSucceed ? tr("Regenerate") : tr("Mesh generation failed, please undo or adjust recent changed nodes\nTips:\n - Don't let generated mesh self-intersect\n - Make multiple parts instead of one single part for whole model"));
|
||||||
regenerateButton->setAwesomeIcon(m_isLastMeshGenerationSucceed ? QChar(fa::recycle) : QChar(fa::warning));
|
regenerateButton->setAwesomeIcon(m_isLastMeshGenerationSucceed ? QChar(fa::recycle) : QChar(fa::warning));
|
||||||
};
|
};
|
||||||
|
@ -468,6 +470,7 @@ DocumentWindow::DocumentWindow() :
|
||||||
m_openExampleMenu = new QMenu(tr("Open Example"));
|
m_openExampleMenu = new QMenu(tr("Open Example"));
|
||||||
std::vector<QString> exampleModels = {
|
std::vector<QString> exampleModels = {
|
||||||
"Addax",
|
"Addax",
|
||||||
|
"Backpacker",
|
||||||
"Bicycle",
|
"Bicycle",
|
||||||
"Cat",
|
"Cat",
|
||||||
"Dog",
|
"Dog",
|
||||||
|
@ -507,6 +510,12 @@ DocumentWindow::DocumentWindow() :
|
||||||
|
|
||||||
m_fileMenu->addSeparator();
|
m_fileMenu->addSeparator();
|
||||||
|
|
||||||
|
m_importAction = new QAction(tr("Import..."), this);
|
||||||
|
connect(m_importAction, &QAction::triggered, this, &DocumentWindow::import, Qt::QueuedConnection);
|
||||||
|
m_fileMenu->addAction(m_importAction);
|
||||||
|
|
||||||
|
m_fileMenu->addSeparator();
|
||||||
|
|
||||||
//m_exportMenu = m_fileMenu->addMenu(tr("Export"));
|
//m_exportMenu = m_fileMenu->addMenu(tr("Export"));
|
||||||
|
|
||||||
m_exportAction = new QAction(tr("Export..."), this);
|
m_exportAction = new QAction(tr("Export..."), this);
|
||||||
|
@ -568,6 +577,10 @@ DocumentWindow::DocumentWindow() :
|
||||||
connect(m_breakAction, &QAction::triggered, m_graphicsWidget, &SkeletonGraphicsWidget::breakSelected);
|
connect(m_breakAction, &QAction::triggered, m_graphicsWidget, &SkeletonGraphicsWidget::breakSelected);
|
||||||
m_editMenu->addAction(m_breakAction);
|
m_editMenu->addAction(m_breakAction);
|
||||||
|
|
||||||
|
m_reverseAction = new QAction(tr("Reverse"), this);
|
||||||
|
connect(m_reverseAction, &QAction::triggered, m_graphicsWidget, &SkeletonGraphicsWidget::reverseSelectedEdges);
|
||||||
|
m_editMenu->addAction(m_reverseAction);
|
||||||
|
|
||||||
m_connectAction = new QAction(tr("Connect"), this);
|
m_connectAction = new QAction(tr("Connect"), this);
|
||||||
connect(m_connectAction, &QAction::triggered, m_graphicsWidget, &SkeletonGraphicsWidget::connectSelected);
|
connect(m_connectAction, &QAction::triggered, m_graphicsWidget, &SkeletonGraphicsWidget::connectSelected);
|
||||||
m_editMenu->addAction(m_connectAction);
|
m_editMenu->addAction(m_connectAction);
|
||||||
|
@ -710,6 +723,7 @@ DocumentWindow::DocumentWindow() :
|
||||||
m_redoAction->setEnabled(m_document->redoable());
|
m_redoAction->setEnabled(m_document->redoable());
|
||||||
m_deleteAction->setEnabled(m_graphicsWidget->hasSelection());
|
m_deleteAction->setEnabled(m_graphicsWidget->hasSelection());
|
||||||
m_breakAction->setEnabled(m_graphicsWidget->hasEdgeSelection());
|
m_breakAction->setEnabled(m_graphicsWidget->hasEdgeSelection());
|
||||||
|
m_reverseAction->setEnabled(m_graphicsWidget->hasEdgeSelection());
|
||||||
m_connectAction->setEnabled(m_graphicsWidget->hasTwoDisconnectedNodesSelection());
|
m_connectAction->setEnabled(m_graphicsWidget->hasTwoDisconnectedNodesSelection());
|
||||||
m_cutAction->setEnabled(m_graphicsWidget->hasSelection());
|
m_cutAction->setEnabled(m_graphicsWidget->hasSelection());
|
||||||
m_copyAction->setEnabled(m_graphicsWidget->hasSelection());
|
m_copyAction->setEnabled(m_graphicsWidget->hasSelection());
|
||||||
|
@ -766,7 +780,7 @@ DocumentWindow::DocumentWindow() :
|
||||||
m_toggleColorAction = new QAction(tr("Toggle Color"), this);
|
m_toggleColorAction = new QAction(tr("Toggle Color"), this);
|
||||||
connect(m_toggleColorAction, &QAction::triggered, [&]() {
|
connect(m_toggleColorAction, &QAction::triggered, [&]() {
|
||||||
m_modelRemoveColor = !m_modelRemoveColor;
|
m_modelRemoveColor = !m_modelRemoveColor;
|
||||||
MeshLoader *mesh = nullptr;
|
Model *mesh = nullptr;
|
||||||
if (m_document->isMeshGenerating() &&
|
if (m_document->isMeshGenerating() &&
|
||||||
m_document->isPostProcessing() &&
|
m_document->isPostProcessing() &&
|
||||||
m_document->isTextureGenerating()) {
|
m_document->isTextureGenerating()) {
|
||||||
|
@ -990,6 +1004,7 @@ DocumentWindow::DocumentWindow() :
|
||||||
connect(graphicsWidget, &SkeletonGraphicsWidget::batchChangeBegin, m_document, &Document::batchChangeBegin);
|
connect(graphicsWidget, &SkeletonGraphicsWidget::batchChangeBegin, m_document, &Document::batchChangeBegin);
|
||||||
connect(graphicsWidget, &SkeletonGraphicsWidget::batchChangeEnd, m_document, &Document::batchChangeEnd);
|
connect(graphicsWidget, &SkeletonGraphicsWidget::batchChangeEnd, m_document, &Document::batchChangeEnd);
|
||||||
connect(graphicsWidget, &SkeletonGraphicsWidget::breakEdge, m_document, &Document::breakEdge);
|
connect(graphicsWidget, &SkeletonGraphicsWidget::breakEdge, m_document, &Document::breakEdge);
|
||||||
|
connect(graphicsWidget, &SkeletonGraphicsWidget::reverseEdge, m_document, &Document::reverseEdge);
|
||||||
connect(graphicsWidget, &SkeletonGraphicsWidget::moveOriginBy, m_document, &Document::moveOriginBy);
|
connect(graphicsWidget, &SkeletonGraphicsWidget::moveOriginBy, m_document, &Document::moveOriginBy);
|
||||||
connect(graphicsWidget, &SkeletonGraphicsWidget::partChecked, m_document, &Document::partChecked);
|
connect(graphicsWidget, &SkeletonGraphicsWidget::partChecked, m_document, &Document::partChecked);
|
||||||
connect(graphicsWidget, &SkeletonGraphicsWidget::partUnchecked, m_document, &Document::partUnchecked);
|
connect(graphicsWidget, &SkeletonGraphicsWidget::partUnchecked, m_document, &Document::partUnchecked);
|
||||||
|
@ -1026,6 +1041,7 @@ DocumentWindow::DocumentWindow() :
|
||||||
connect(m_document, &Document::nodeRadiusChanged, graphicsWidget, &SkeletonGraphicsWidget::nodeRadiusChanged);
|
connect(m_document, &Document::nodeRadiusChanged, graphicsWidget, &SkeletonGraphicsWidget::nodeRadiusChanged);
|
||||||
connect(m_document, &Document::nodeBoneMarkChanged, graphicsWidget, &SkeletonGraphicsWidget::nodeBoneMarkChanged);
|
connect(m_document, &Document::nodeBoneMarkChanged, graphicsWidget, &SkeletonGraphicsWidget::nodeBoneMarkChanged);
|
||||||
connect(m_document, &Document::nodeOriginChanged, graphicsWidget, &SkeletonGraphicsWidget::nodeOriginChanged);
|
connect(m_document, &Document::nodeOriginChanged, graphicsWidget, &SkeletonGraphicsWidget::nodeOriginChanged);
|
||||||
|
connect(m_document, &Document::edgeReversed, graphicsWidget, &SkeletonGraphicsWidget::edgeReversed);
|
||||||
connect(m_document, &Document::partVisibleStateChanged, graphicsWidget, &SkeletonGraphicsWidget::partVisibleStateChanged);
|
connect(m_document, &Document::partVisibleStateChanged, graphicsWidget, &SkeletonGraphicsWidget::partVisibleStateChanged);
|
||||||
connect(m_document, &Document::partDisableStateChanged, graphicsWidget, &SkeletonGraphicsWidget::partVisibleStateChanged);
|
connect(m_document, &Document::partDisableStateChanged, graphicsWidget, &SkeletonGraphicsWidget::partVisibleStateChanged);
|
||||||
connect(m_document, &Document::cleanup, graphicsWidget, &SkeletonGraphicsWidget::removeAllContent);
|
connect(m_document, &Document::cleanup, graphicsWidget, &SkeletonGraphicsWidget::removeAllContent);
|
||||||
|
@ -1470,82 +1486,138 @@ void DocumentWindow::saveTo(const QString &saveAsFilename)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Merge code here and the code in documentsaver.cpp
|
|
||||||
|
|
||||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||||
|
|
||||||
Ds3FileWriter ds3Writer;
|
|
||||||
|
|
||||||
QByteArray modelXml;
|
|
||||||
QXmlStreamWriter stream(&modelXml);
|
|
||||||
Snapshot snapshot;
|
Snapshot snapshot;
|
||||||
m_document->toSnapshot(&snapshot);
|
m_document->toSnapshot(&snapshot);
|
||||||
saveSkeletonToXmlStream(&snapshot, &stream);
|
if (DocumentSaver::save(&filename,
|
||||||
if (modelXml.size() > 0)
|
&snapshot,
|
||||||
ds3Writer.add("model.xml", "model", &modelXml);
|
(!m_document->turnaround.isNull() && m_document->turnaroundPngByteArray.size() > 0) ?
|
||||||
|
&m_document->turnaroundPngByteArray : nullptr,
|
||||||
if (!m_document->turnaround.isNull() && m_document->turnaroundPngByteArray.size() > 0) {
|
(!m_document->script().isEmpty()) ? &m_document->script() : nullptr,
|
||||||
ds3Writer.add("canvas.png", "asset", &m_document->turnaroundPngByteArray);
|
(!m_document->variables().empty()) ? &m_document->variables() : nullptr)) {
|
||||||
|
setCurrentFilename(filename);
|
||||||
}
|
}
|
||||||
|
QApplication::restoreOverrideCursor();
|
||||||
|
}
|
||||||
|
|
||||||
if (!m_document->script().isEmpty()) {
|
void DocumentWindow::importPath(const QString &path)
|
||||||
auto script = m_document->script().toUtf8();
|
{
|
||||||
ds3Writer.add("model.js", "script", &script);
|
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||||
}
|
Ds3FileReader ds3Reader(path);
|
||||||
|
bool documentChanged = false;
|
||||||
|
|
||||||
const auto &variables = m_document->variables();
|
for (int i = 0; i < ds3Reader.items().size(); ++i) {
|
||||||
if (!variables.empty()) {
|
Ds3ReaderItem item = ds3Reader.items().at(i);
|
||||||
QByteArray variablesXml;
|
if (item.type == "asset") {
|
||||||
QXmlStreamWriter variablesXmlStream(&variablesXml);
|
if (item.name.startsWith("images/")) {
|
||||||
saveVariablesToXmlStream(variables, &variablesXmlStream);
|
QString filename = item.name.split("/")[1];
|
||||||
if (variablesXml.size() > 0)
|
QString imageIdString = filename.split(".")[0];
|
||||||
ds3Writer.add("variables.xml", "variable", &variablesXml);
|
QUuid imageId = QUuid(imageIdString);
|
||||||
}
|
if (!imageId.isNull()) {
|
||||||
|
QByteArray data;
|
||||||
std::set<QUuid> imageIds;
|
ds3Reader.loadItem(item.name, &data);
|
||||||
|
QImage image = QImage::fromData(data, "PNG");
|
||||||
for (const auto &material: snapshot.materials) {
|
(void)ImageForever::add(&image, imageId);
|
||||||
for (auto &layer: material.second) {
|
}
|
||||||
for (auto &mapItem: layer.second) {
|
|
||||||
auto findImageIdString = mapItem.find("linkData");
|
|
||||||
if (findImageIdString == mapItem.end())
|
|
||||||
continue;
|
|
||||||
QUuid imageId = QUuid(findImageIdString->second);
|
|
||||||
imageIds.insert(imageId);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const auto &part: snapshot.parts) {
|
|
||||||
auto findImageIdString = part.second.find("deformMapImageId");
|
|
||||||
if (findImageIdString == part.second.end())
|
|
||||||
continue;
|
|
||||||
QUuid imageId = QUuid(findImageIdString->second);
|
|
||||||
imageIds.insert(imageId);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto &pose: snapshot.poses) {
|
for (int i = 0; i < ds3Reader.items().size(); ++i) {
|
||||||
auto findCanvasImageId = pose.first.find("canvasImageId");
|
Ds3ReaderItem item = ds3Reader.items().at(i);
|
||||||
if (findCanvasImageId != pose.first.end()) {
|
if (item.type == "model") {
|
||||||
QUuid imageId = QUuid(findCanvasImageId->second);
|
{
|
||||||
imageIds.insert(imageId);
|
QByteArray data;
|
||||||
|
ds3Reader.loadItem(item.name, &data);
|
||||||
|
QXmlStreamReader stream(data);
|
||||||
|
|
||||||
|
Snapshot snapshot;
|
||||||
|
loadSkeletonFromXmlStream(&snapshot, stream, SNAPSHOT_ITEM_MATERIAL);
|
||||||
|
m_document->addFromSnapshot(snapshot, Document::SnapshotSource::Import);
|
||||||
|
documentChanged = true;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
QByteArray data;
|
||||||
|
ds3Reader.loadItem(item.name, &data);
|
||||||
|
QXmlStreamReader stream(data);
|
||||||
|
|
||||||
|
Snapshot snapshot;
|
||||||
|
loadSkeletonFromXmlStream(&snapshot, stream, SNAPSHOT_ITEM_CANVAS | SNAPSHOT_ITEM_COMPONENT);
|
||||||
|
|
||||||
|
QByteArray modelXml;
|
||||||
|
QXmlStreamWriter modelStream(&modelXml);
|
||||||
|
saveSkeletonToXmlStream(&snapshot, &modelStream);
|
||||||
|
if (modelXml.size() > 0) {
|
||||||
|
QUuid fillMeshFileId = FileForever::add(item.name, modelXml);
|
||||||
|
if (!fillMeshFileId.isNull()) {
|
||||||
|
Snapshot partSnapshot;
|
||||||
|
createPartSnapshotForFillMesh(fillMeshFileId, &partSnapshot);
|
||||||
|
m_document->addFromSnapshot(partSnapshot, Document::SnapshotSource::Paste);
|
||||||
|
documentChanged = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto &imageId: imageIds) {
|
if (documentChanged)
|
||||||
const QByteArray *pngByteArray = ImageForever::getPngByteArray(imageId);
|
m_document->saveSnapshot();
|
||||||
if (nullptr == pngByteArray)
|
|
||||||
continue;
|
|
||||||
if (pngByteArray->size() > 0)
|
|
||||||
ds3Writer.add("images/" + imageId.toString() + ".png", "asset", pngByteArray);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ds3Writer.save(filename)) {
|
|
||||||
setCurrentFilename(filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
QApplication::restoreOverrideCursor();
|
QApplication::restoreOverrideCursor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DocumentWindow::createPartSnapshotForFillMesh(const QUuid &fillMeshFileId, Snapshot *snapshot)
|
||||||
|
{
|
||||||
|
if (fillMeshFileId.isNull())
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto partId = QUuid::createUuid();
|
||||||
|
auto partIdString = partId.toString();
|
||||||
|
std::map<QString, QString> snapshotPart;
|
||||||
|
snapshotPart["id"] = partIdString;
|
||||||
|
snapshotPart["fillMesh"] = fillMeshFileId.toString();
|
||||||
|
snapshot->parts[partIdString] = snapshotPart;
|
||||||
|
|
||||||
|
auto componentId = QUuid::createUuid();
|
||||||
|
auto componentIdString = componentId.toString();
|
||||||
|
std::map<QString, QString> snapshotComponent;
|
||||||
|
snapshotComponent["id"] = componentIdString;
|
||||||
|
snapshotComponent["combineMode"] = "Uncombined";
|
||||||
|
snapshotComponent["linkDataType"] = "partId";
|
||||||
|
snapshotComponent["linkData"] = partIdString;
|
||||||
|
snapshot->components[componentIdString] = snapshotComponent;
|
||||||
|
|
||||||
|
snapshot->rootComponent["children"] = componentIdString;
|
||||||
|
|
||||||
|
auto createNode = [&](const QVector3D &position, float radius) {
|
||||||
|
auto nodeId = QUuid::createUuid();
|
||||||
|
auto nodeIdString = nodeId.toString();
|
||||||
|
std::map<QString, QString> snapshotNode;
|
||||||
|
snapshotNode["id"] = nodeIdString;
|
||||||
|
snapshotNode["x"] = QString::number(position.x());
|
||||||
|
snapshotNode["y"] = QString::number(position.y());
|
||||||
|
snapshotNode["z"] = QString::number(position.z());
|
||||||
|
snapshotNode["radius"] = QString::number(radius);
|
||||||
|
snapshotNode["partId"] = partIdString;
|
||||||
|
snapshot->nodes[nodeIdString] = snapshotNode;
|
||||||
|
return nodeIdString;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto createEdge = [&](const QString &fromNode, const QString &toNode) {
|
||||||
|
auto edgeId = QUuid::createUuid();
|
||||||
|
auto edgeIdString = edgeId.toString();
|
||||||
|
std::map<QString, QString> snapshotEdge;
|
||||||
|
snapshotEdge["id"] = edgeIdString;
|
||||||
|
snapshotEdge["from"] = fromNode;
|
||||||
|
snapshotEdge["to"] = toNode;
|
||||||
|
snapshotEdge["partId"] = partIdString;
|
||||||
|
snapshot->edges[edgeIdString] = snapshotEdge;
|
||||||
|
};
|
||||||
|
|
||||||
|
createEdge(createNode(QVector3D(0.5, 0.5, 1.0), 0.1),
|
||||||
|
createNode(QVector3D(0.5, 0.3, 1.0), 0.1));
|
||||||
|
}
|
||||||
|
|
||||||
void DocumentWindow::openPathAs(const QString &path, const QString &asName)
|
void DocumentWindow::openPathAs(const QString &path, const QString &asName)
|
||||||
{
|
{
|
||||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||||
|
@ -1569,6 +1641,15 @@ void DocumentWindow::openPathAs(const QString &path, const QString &asName)
|
||||||
QImage image = QImage::fromData(data, "PNG");
|
QImage image = QImage::fromData(data, "PNG");
|
||||||
(void)ImageForever::add(&image, imageId);
|
(void)ImageForever::add(&image, imageId);
|
||||||
}
|
}
|
||||||
|
} else if (item.name.startsWith("files/")) {
|
||||||
|
QString filename = item.name.split("/")[1];
|
||||||
|
QString fileIdString = filename.split(".")[0];
|
||||||
|
QUuid fileId = QUuid(fileIdString);
|
||||||
|
if (!fileId.isNull()) {
|
||||||
|
QByteArray data;
|
||||||
|
ds3Reader.loadItem(item.name, &data);
|
||||||
|
(void)FileForever::add(item.name, data, fileId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1682,7 +1763,7 @@ void DocumentWindow::exportObjResult()
|
||||||
void DocumentWindow::exportObjToFilename(const QString &filename)
|
void DocumentWindow::exportObjToFilename(const QString &filename)
|
||||||
{
|
{
|
||||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||||
MeshLoader *resultMesh = m_document->takeResultMesh();
|
Model *resultMesh = m_document->takeResultMesh();
|
||||||
if (nullptr != resultMesh) {
|
if (nullptr != resultMesh) {
|
||||||
resultMesh->exportAsObj(filename);
|
resultMesh->exportAsObj(filename);
|
||||||
delete resultMesh;
|
delete resultMesh;
|
||||||
|
@ -1822,7 +1903,7 @@ void DocumentWindow::updateRadiusLockButtonState()
|
||||||
|
|
||||||
void DocumentWindow::updateRigWeightRenderWidget()
|
void DocumentWindow::updateRigWeightRenderWidget()
|
||||||
{
|
{
|
||||||
MeshLoader *resultRigWeightMesh = m_document->takeResultRigWeightMesh();
|
Model *resultRigWeightMesh = m_document->takeResultRigWeightMesh();
|
||||||
if (nullptr == resultRigWeightMesh) {
|
if (nullptr == resultRigWeightMesh) {
|
||||||
m_rigWidget->rigWeightRenderWidget()->hide();
|
m_rigWidget->rigWeightRenderWidget()->hide();
|
||||||
} else {
|
} else {
|
||||||
|
@ -1984,17 +2065,17 @@ void DocumentWindow::checkExportWaitingList()
|
||||||
auto list = m_waitingForExportToFilenames;
|
auto list = m_waitingForExportToFilenames;
|
||||||
m_waitingForExportToFilenames.clear();
|
m_waitingForExportToFilenames.clear();
|
||||||
|
|
||||||
bool isSucceed = m_document->isMeshGenerationSucceed();
|
bool isSuccessful = m_document->isMeshGenerationSucceed();
|
||||||
for (const auto &filename: list) {
|
for (const auto &filename: list) {
|
||||||
if (filename.endsWith(".obj")) {
|
if (filename.endsWith(".obj")) {
|
||||||
exportObjToFilename(filename);
|
exportObjToFilename(filename);
|
||||||
emit waitingExportFinished(filename, isSucceed);
|
emit waitingExportFinished(filename, isSuccessful);
|
||||||
} else if (filename.endsWith(".fbx")) {
|
} else if (filename.endsWith(".fbx")) {
|
||||||
exportFbxToFilename(filename);
|
exportFbxToFilename(filename);
|
||||||
emit waitingExportFinished(filename, isSucceed);
|
emit waitingExportFinished(filename, isSuccessful);
|
||||||
} else if (filename.endsWith(".glb")) {
|
} else if (filename.endsWith(".glb")) {
|
||||||
exportGlbToFilename(filename);
|
exportGlbToFilename(filename);
|
||||||
emit waitingExportFinished(filename, isSucceed);
|
emit waitingExportFinished(filename, isSuccessful);
|
||||||
} else {
|
} else {
|
||||||
emit waitingExportFinished(filename, false);
|
emit waitingExportFinished(filename, false);
|
||||||
}
|
}
|
||||||
|
@ -2013,11 +2094,11 @@ void DocumentWindow::normalAndDepthMapsReady()
|
||||||
|
|
||||||
m_modelRenderWidget->updateToonNormalAndDepthMaps(normalMap, depthMap);
|
m_modelRenderWidget->updateToonNormalAndDepthMaps(normalMap, depthMap);
|
||||||
|
|
||||||
//m_normalAndDepthMapsGenerator->setRenderThread(QGuiApplication::instance()->thread());
|
|
||||||
|
|
||||||
delete m_normalAndDepthMapsGenerator;
|
delete m_normalAndDepthMapsGenerator;
|
||||||
m_normalAndDepthMapsGenerator = nullptr;
|
m_normalAndDepthMapsGenerator = nullptr;
|
||||||
|
|
||||||
|
qDebug() << "Normal and depth maps generation done";
|
||||||
|
|
||||||
if (m_isNormalAndDepthMapsObsolete) {
|
if (m_isNormalAndDepthMapsObsolete) {
|
||||||
generateNormalAndDepthMaps();
|
generateNormalAndDepthMaps();
|
||||||
}
|
}
|
||||||
|
@ -2036,21 +2117,18 @@ void DocumentWindow::generateNormalAndDepthMaps()
|
||||||
if (nullptr == resultMesh)
|
if (nullptr == resultMesh)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
qDebug() << "Normal and depth maps generating...";
|
||||||
|
|
||||||
QThread *thread = new QThread;
|
QThread *thread = new QThread;
|
||||||
m_normalAndDepthMapsGenerator = new NormalAndDepthMapsGenerator(m_modelRenderWidget);
|
m_normalAndDepthMapsGenerator = new NormalAndDepthMapsGenerator(m_modelRenderWidget);
|
||||||
m_normalAndDepthMapsGenerator->updateMesh(resultMesh);
|
m_normalAndDepthMapsGenerator->updateMesh(resultMesh);
|
||||||
m_normalAndDepthMapsGenerator->moveToThread(thread);
|
m_normalAndDepthMapsGenerator->moveToThread(thread);
|
||||||
//m_normalAndDepthMapsGenerator->setRenderThread(thread);
|
m_normalAndDepthMapsGenerator->setRenderThread(thread);
|
||||||
connect(thread, &QThread::started, m_normalAndDepthMapsGenerator, &NormalAndDepthMapsGenerator::process);
|
connect(thread, &QThread::started, m_normalAndDepthMapsGenerator, &NormalAndDepthMapsGenerator::process);
|
||||||
connect(m_normalAndDepthMapsGenerator, &NormalAndDepthMapsGenerator::finished, this, &DocumentWindow::normalAndDepthMapsReady);
|
connect(m_normalAndDepthMapsGenerator, &NormalAndDepthMapsGenerator::finished, this, &DocumentWindow::normalAndDepthMapsReady);
|
||||||
connect(m_normalAndDepthMapsGenerator, &NormalAndDepthMapsGenerator::finished, thread, &QThread::quit);
|
connect(m_normalAndDepthMapsGenerator, &NormalAndDepthMapsGenerator::finished, thread, &QThread::quit);
|
||||||
connect(thread, &QThread::finished, thread, &QThread::deleteLater);
|
connect(thread, &QThread::finished, thread, &QThread::deleteLater);
|
||||||
thread->start();
|
thread->start();
|
||||||
|
|
||||||
//m_normalAndDepthMapsGenerator = new NormalAndDepthMapsGenerator(m_modelRenderWidget);
|
|
||||||
//m_normalAndDepthMapsGenerator->updateMesh(resultMesh);
|
|
||||||
//connect(m_normalAndDepthMapsGenerator, &NormalAndDepthMapsGenerator::finished, this, &DocumentWindow::normalAndDepthMapsReady);
|
|
||||||
//m_normalAndDepthMapsGenerator->process();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DocumentWindow::delayedGenerateNormalAndDepthMaps()
|
void DocumentWindow::delayedGenerateNormalAndDepthMaps()
|
||||||
|
@ -2058,22 +2136,15 @@ void DocumentWindow::delayedGenerateNormalAndDepthMaps()
|
||||||
if (!Preferences::instance().toonShading())
|
if (!Preferences::instance().toonShading())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
//delete m_normalAndDepthMapsDelayTimer;
|
generateNormalAndDepthMaps();
|
||||||
//m_normalAndDepthMapsDelayTimer = new QTimer(this);
|
|
||||||
//m_normalAndDepthMapsDelayTimer->setSingleShot(true);
|
|
||||||
//m_normalAndDepthMapsDelayTimer->setInterval(250);
|
|
||||||
//connect(m_normalAndDepthMapsDelayTimer, &QTimer::timeout, [=] {
|
|
||||||
generateNormalAndDepthMaps();
|
|
||||||
//});
|
|
||||||
//m_normalAndDepthMapsDelayTimer->start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DocumentWindow::exportImageToFilename(const QString &filename)
|
void DocumentWindow::exportImageToFilename(const QString &filename)
|
||||||
{
|
{
|
||||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||||
MeshLoader *resultMesh = m_modelRenderWidget->fetchCurrentMesh();
|
Model *resultMesh = m_modelRenderWidget->fetchCurrentMesh();
|
||||||
if (nullptr != resultMesh) {
|
if (nullptr != resultMesh) {
|
||||||
ModelOfflineRender *offlineRender = new ModelOfflineRender(m_modelRenderWidget->format());
|
ModelOffscreenRender *offlineRender = new ModelOffscreenRender(m_modelRenderWidget->format());
|
||||||
offlineRender->setXRotation(m_modelRenderWidget->xRot());
|
offlineRender->setXRotation(m_modelRenderWidget->xRot());
|
||||||
offlineRender->setYRotation(m_modelRenderWidget->yRot());
|
offlineRender->setYRotation(m_modelRenderWidget->yRot());
|
||||||
offlineRender->setZRotation(m_modelRenderWidget->zRot());
|
offlineRender->setZRotation(m_modelRenderWidget->zRot());
|
||||||
|
@ -2095,3 +2166,12 @@ void DocumentWindow::exportImageToFilename(const QString &filename)
|
||||||
}
|
}
|
||||||
QApplication::restoreOverrideCursor();
|
QApplication::restoreOverrideCursor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DocumentWindow::import()
|
||||||
|
{
|
||||||
|
QString fileName = QFileDialog::getOpenFileName(this, QString(), QString(),
|
||||||
|
tr("Dust3D Document (*.ds3)")).trimmed();
|
||||||
|
if (fileName.isEmpty())
|
||||||
|
return;
|
||||||
|
importPath(fileName);
|
||||||
|
}
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QTimer>
|
|
||||||
#include "document.h"
|
#include "document.h"
|
||||||
#include "modelwidget.h"
|
#include "modelwidget.h"
|
||||||
#include "exportpreviewwidget.h"
|
#include "exportpreviewwidget.h"
|
||||||
|
@ -30,7 +29,7 @@ class DocumentWindow : public QMainWindow
|
||||||
signals:
|
signals:
|
||||||
void initialized();
|
void initialized();
|
||||||
void uninialized();
|
void uninialized();
|
||||||
void waitingExportFinished(const QString &filename, bool succeed);
|
void waitingExportFinished(const QString &filename, bool isSuccessful);
|
||||||
void mouseTargetVertexPositionChanged(const QVector3D &position);
|
void mouseTargetVertexPositionChanged(const QVector3D &position);
|
||||||
public:
|
public:
|
||||||
DocumentWindow();
|
DocumentWindow();
|
||||||
|
@ -93,10 +92,13 @@ public slots:
|
||||||
void delayedGenerateNormalAndDepthMaps();
|
void delayedGenerateNormalAndDepthMaps();
|
||||||
void normalAndDepthMapsReady();
|
void normalAndDepthMapsReady();
|
||||||
void autoRecover();
|
void autoRecover();
|
||||||
|
void import();
|
||||||
|
void importPath(const QString &filename);
|
||||||
private:
|
private:
|
||||||
void initLockButton(QPushButton *button);
|
void initLockButton(QPushButton *button);
|
||||||
void setCurrentFilename(const QString &filename);
|
void setCurrentFilename(const QString &filename);
|
||||||
void updateTitle();
|
void updateTitle();
|
||||||
|
void createPartSnapshotForFillMesh(const QUuid &fillMeshFileId, Snapshot *snapshot);
|
||||||
private:
|
private:
|
||||||
Document *m_document;
|
Document *m_document;
|
||||||
bool m_firstShow;
|
bool m_firstShow;
|
||||||
|
@ -130,6 +132,8 @@ private:
|
||||||
QAction *m_changeTurnaroundAction;
|
QAction *m_changeTurnaroundAction;
|
||||||
QAction *m_quitAction;
|
QAction *m_quitAction;
|
||||||
|
|
||||||
|
QAction *m_importAction;
|
||||||
|
|
||||||
QAction *m_exportAsObjAction;
|
QAction *m_exportAsObjAction;
|
||||||
QAction *m_exportAsObjPlusMaterialsAction;
|
QAction *m_exportAsObjPlusMaterialsAction;
|
||||||
QAction *m_exportAction;
|
QAction *m_exportAction;
|
||||||
|
@ -141,6 +145,7 @@ private:
|
||||||
QAction *m_redoAction;
|
QAction *m_redoAction;
|
||||||
QAction *m_deleteAction;
|
QAction *m_deleteAction;
|
||||||
QAction *m_breakAction;
|
QAction *m_breakAction;
|
||||||
|
QAction *m_reverseAction;
|
||||||
QAction *m_connectAction;
|
QAction *m_connectAction;
|
||||||
QAction *m_cutAction;
|
QAction *m_cutAction;
|
||||||
QAction *m_copyAction;
|
QAction *m_copyAction;
|
||||||
|
@ -211,7 +216,6 @@ private:
|
||||||
QMetaObject::Connection m_partListDockerVisibleSwitchConnection;
|
QMetaObject::Connection m_partListDockerVisibleSwitchConnection;
|
||||||
|
|
||||||
NormalAndDepthMapsGenerator *m_normalAndDepthMapsGenerator = nullptr;
|
NormalAndDepthMapsGenerator *m_normalAndDepthMapsGenerator = nullptr;
|
||||||
QTimer *m_normalAndDepthMapsDelayTimer = nullptr;
|
|
||||||
bool m_isNormalAndDepthMapsObsolete = false;
|
bool m_isNormalAndDepthMapsObsolete = false;
|
||||||
|
|
||||||
AutoSaver *m_autoSaver = nullptr;
|
AutoSaver *m_autoSaver = nullptr;
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "jointnodetree.h"
|
#include "jointnodetree.h"
|
||||||
#include "meshloader.h"
|
#include "model.h"
|
||||||
|
|
||||||
// Play with glTF online:
|
// Play with glTF online:
|
||||||
// https://gltf-viewer.donmccurdy.com/
|
// https://gltf-viewer.donmccurdy.com/
|
||||||
|
@ -168,8 +168,8 @@ GlbFileWriter::GlbFileWriter(Outcome &outcome,
|
||||||
}
|
}
|
||||||
int textureIndex = 0;
|
int textureIndex = 0;
|
||||||
m_json["materials"][primitiveIndex]["pbrMetallicRoughness"]["baseColorTexture"]["index"] = textureIndex++;
|
m_json["materials"][primitiveIndex]["pbrMetallicRoughness"]["baseColorTexture"]["index"] = textureIndex++;
|
||||||
m_json["materials"][primitiveIndex]["pbrMetallicRoughness"]["metallicFactor"] = MeshLoader::m_defaultMetalness;
|
m_json["materials"][primitiveIndex]["pbrMetallicRoughness"]["metallicFactor"] = Model::m_defaultMetalness;
|
||||||
m_json["materials"][primitiveIndex]["pbrMetallicRoughness"]["roughnessFactor"] = MeshLoader::m_defaultRoughness;
|
m_json["materials"][primitiveIndex]["pbrMetallicRoughness"]["roughnessFactor"] = Model::m_defaultRoughness;
|
||||||
if (textureHasTransparencySettings)
|
if (textureHasTransparencySettings)
|
||||||
m_json["materials"][primitiveIndex]["alphaMode"] = "BLEND";
|
m_json["materials"][primitiveIndex]["alphaMode"] = "BLEND";
|
||||||
if (normalImage) {
|
if (normalImage) {
|
||||||
|
|
|
@ -1,20 +1,29 @@
|
||||||
#include "logbrowser.h"
|
|
||||||
// Modified from https://wiki.qt.io/Browser_for_QDebug_output
|
// Modified from https://wiki.qt.io/Browser_for_QDebug_output
|
||||||
#include <QMetaType>
|
#include <QMetaType>
|
||||||
#include <stdio.h>
|
#include <QDir>
|
||||||
|
#include "logbrowser.h"
|
||||||
#include "logbrowserdialog.h"
|
#include "logbrowserdialog.h"
|
||||||
|
|
||||||
|
bool LogBrowser::m_enableOutputToFile = false;
|
||||||
|
|
||||||
LogBrowser::LogBrowser(QObject *parent) :
|
LogBrowser::LogBrowser(QObject *parent) :
|
||||||
QObject(parent)
|
QObject(parent)
|
||||||
{
|
{
|
||||||
qRegisterMetaType<QtMsgType>("QtMsgType");
|
qRegisterMetaType<QtMsgType>("QtMsgType");
|
||||||
m_browserDialog = new LogBrowserDialog;
|
m_browserDialog = new LogBrowserDialog;
|
||||||
connect(this, &LogBrowser::sendMessage, m_browserDialog, &LogBrowserDialog::outputMessage, Qt::QueuedConnection);
|
connect(this, &LogBrowser::sendMessage, m_browserDialog, &LogBrowserDialog::outputMessage, Qt::QueuedConnection);
|
||||||
|
|
||||||
|
if (m_enableOutputToFile) {
|
||||||
|
QString filePath = "dust3d.log";
|
||||||
|
m_outputTo = fopen(filePath.toUtf8().constData(), "w");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LogBrowser::~LogBrowser()
|
LogBrowser::~LogBrowser()
|
||||||
{
|
{
|
||||||
delete m_browserDialog;
|
delete m_browserDialog;
|
||||||
|
if (m_outputTo)
|
||||||
|
fclose(m_outputTo);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LogBrowser::showDialog()
|
void LogBrowser::showDialog()
|
||||||
|
@ -36,5 +45,9 @@ bool LogBrowser::isDialogVisible()
|
||||||
|
|
||||||
void LogBrowser::outputMessage(QtMsgType type, const QString &msg, const QString &source, int line)
|
void LogBrowser::outputMessage(QtMsgType type, const QString &msg, const QString &source, int line)
|
||||||
{
|
{
|
||||||
|
if (m_outputTo) {
|
||||||
|
fprintf(m_outputTo, "[%s:%d]: %s\n", source.toUtf8().constData(), line, msg.toUtf8().constData());
|
||||||
|
fflush(m_outputTo);
|
||||||
|
}
|
||||||
emit sendMessage(type, msg, source, line);
|
emit sendMessage(type, msg, source, line);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#define DUST3D_LOG_BROWSER_H
|
#define DUST3D_LOG_BROWSER_H
|
||||||
// Modified from https://wiki.qt.io/Browser_for_QDebug_output
|
// Modified from https://wiki.qt.io/Browser_for_QDebug_output
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
class LogBrowserDialog;
|
class LogBrowserDialog;
|
||||||
|
|
||||||
|
@ -9,7 +10,7 @@ class LogBrowser : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit LogBrowser(QObject *parent = 0);
|
explicit LogBrowser(QObject *parent=0);
|
||||||
~LogBrowser();
|
~LogBrowser();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
@ -22,7 +23,9 @@ signals:
|
||||||
void sendMessage(QtMsgType type, const QString &msg, const QString &source, int line);
|
void sendMessage(QtMsgType type, const QString &msg, const QString &source, int line);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
LogBrowserDialog *m_browserDialog;
|
LogBrowserDialog *m_browserDialog = nullptr;
|
||||||
|
FILE *m_outputTo = nullptr;
|
||||||
|
static bool m_enableOutputToFile;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // LOGBROWSER_H
|
#endif // LOGBROWSER_H
|
||||||
|
|
|
@ -97,10 +97,10 @@ int main(int argc, char ** argv)
|
||||||
openFileList.size() == 1) {
|
openFileList.size() == 1) {
|
||||||
totalExportFileNum = openFileList.size() * waitingExportList.size();
|
totalExportFileNum = openFileList.size() * waitingExportList.size();
|
||||||
for (int i = 0; i < openFileList.size(); ++i) {
|
for (int i = 0; i < openFileList.size(); ++i) {
|
||||||
QObject::connect(windowList[i], &DocumentWindow::waitingExportFinished, &app, [&](const QString &filename, bool succeed) {
|
QObject::connect(windowList[i], &DocumentWindow::waitingExportFinished, &app, [&](const QString &filename, bool isSuccessful) {
|
||||||
qDebug() << "Export to" << filename << (succeed ? "succeed" : "failed");
|
qDebug() << "Export to" << filename << (isSuccessful ? "isSuccessful" : "failed");
|
||||||
++finishedExportFileNum;
|
++finishedExportFileNum;
|
||||||
if (succeed)
|
if (isSuccessful)
|
||||||
++succeedExportNum;
|
++succeedExportNum;
|
||||||
if (finishedExportFileNum == totalExportFileNum) {
|
if (finishedExportFileNum == totalExportFileNum) {
|
||||||
if (succeedExportNum == totalExportFileNum) {
|
if (succeedExportNum == totalExportFileNum) {
|
||||||
|
|
|
@ -29,9 +29,9 @@ const std::set<QUuid> &MaterialPreviewsGenerator::generatedPreviewMaterialIds()
|
||||||
return m_generatedMaterialIds;
|
return m_generatedMaterialIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
MeshLoader *MaterialPreviewsGenerator::takePreview(QUuid materialId)
|
Model *MaterialPreviewsGenerator::takePreview(QUuid materialId)
|
||||||
{
|
{
|
||||||
MeshLoader *resultMesh = m_previews[materialId];
|
Model *resultMesh = m_previews[materialId];
|
||||||
m_previews[materialId] = nullptr;
|
m_previews[materialId] = nullptr;
|
||||||
return resultMesh;
|
return resultMesh;
|
||||||
}
|
}
|
||||||
|
@ -96,9 +96,9 @@ void MaterialPreviewsGenerator::generate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
textureGenerator->generate();
|
textureGenerator->generate();
|
||||||
MeshLoader *texturedResultMesh = textureGenerator->takeResultMesh();
|
Model *texturedResultMesh = textureGenerator->takeResultMesh();
|
||||||
if (nullptr != texturedResultMesh) {
|
if (nullptr != texturedResultMesh) {
|
||||||
m_previews[material.first] = new MeshLoader(*texturedResultMesh);
|
m_previews[material.first] = new Model(*texturedResultMesh);
|
||||||
m_generatedMaterialIds.insert(material.first);
|
m_generatedMaterialIds.insert(material.first);
|
||||||
delete texturedResultMesh;
|
delete texturedResultMesh;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <QUuid>
|
#include <QUuid>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "meshloader.h"
|
#include "model.h"
|
||||||
#include "document.h"
|
#include "document.h"
|
||||||
|
|
||||||
class MaterialPreviewsGenerator : public QObject
|
class MaterialPreviewsGenerator : public QObject
|
||||||
|
@ -15,7 +15,7 @@ public:
|
||||||
~MaterialPreviewsGenerator();
|
~MaterialPreviewsGenerator();
|
||||||
void addMaterial(QUuid materialId, const std::vector<MaterialLayer> &layers);
|
void addMaterial(QUuid materialId, const std::vector<MaterialLayer> &layers);
|
||||||
const std::set<QUuid> &generatedPreviewMaterialIds();
|
const std::set<QUuid> &generatedPreviewMaterialIds();
|
||||||
MeshLoader *takePreview(QUuid materialId);
|
Model *takePreview(QUuid materialId);
|
||||||
void generate();
|
void generate();
|
||||||
signals:
|
signals:
|
||||||
void finished();
|
void finished();
|
||||||
|
@ -23,7 +23,7 @@ public slots:
|
||||||
void process();
|
void process();
|
||||||
private:
|
private:
|
||||||
std::vector<std::pair<QUuid, std::vector<MaterialLayer>>> m_materials;
|
std::vector<std::pair<QUuid, std::vector<MaterialLayer>>> m_materials;
|
||||||
std::map<QUuid, MeshLoader *> m_previews;
|
std::map<QUuid, Model *> m_previews;
|
||||||
std::set<QUuid> m_generatedMaterialIds;
|
std::set<QUuid> m_generatedMaterialIds;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -77,7 +77,7 @@ void MaterialWidget::updatePreview(QUuid materialId)
|
||||||
qDebug() << "Material not found:" << m_materialId;
|
qDebug() << "Material not found:" << m_materialId;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
MeshLoader *previewMesh = material->takePreviewMesh();
|
Model *previewMesh = material->takePreviewMesh();
|
||||||
m_previewWidget->updateMesh(previewMesh);
|
m_previewWidget->updateMesh(previewMesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,9 @@
|
||||||
#include "projectfacestonodes.h"
|
#include "projectfacestonodes.h"
|
||||||
#include "document.h"
|
#include "document.h"
|
||||||
#include "simulateclothmeshes.h"
|
#include "simulateclothmeshes.h"
|
||||||
|
#include "meshstroketifier.h"
|
||||||
|
#include "fileforever.h"
|
||||||
|
#include "snapshotxml.h"
|
||||||
|
|
||||||
MeshGenerator::MeshGenerator(Snapshot *snapshot) :
|
MeshGenerator::MeshGenerator(Snapshot *snapshot) :
|
||||||
m_snapshot(snapshot)
|
m_snapshot(snapshot)
|
||||||
|
@ -49,21 +52,21 @@ quint64 MeshGenerator::id()
|
||||||
return m_id;
|
return m_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MeshGenerator::isSucceed()
|
bool MeshGenerator::isSuccessful()
|
||||||
{
|
{
|
||||||
return m_isSucceed;
|
return m_isSuccessful;
|
||||||
}
|
}
|
||||||
|
|
||||||
MeshLoader *MeshGenerator::takeResultMesh()
|
Model *MeshGenerator::takeResultMesh()
|
||||||
{
|
{
|
||||||
MeshLoader *resultMesh = m_resultMesh;
|
Model *resultMesh = m_resultMesh;
|
||||||
m_resultMesh = nullptr;
|
m_resultMesh = nullptr;
|
||||||
return resultMesh;
|
return resultMesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
MeshLoader *MeshGenerator::takePartPreviewMesh(const QUuid &partId)
|
Model *MeshGenerator::takePartPreviewMesh(const QUuid &partId)
|
||||||
{
|
{
|
||||||
MeshLoader *resultMesh = m_partPreviewMeshes[partId];
|
Model *resultMesh = m_partPreviewMeshes[partId];
|
||||||
m_partPreviewMeshes[partId] = nullptr;
|
m_partPreviewMeshes[partId] = nullptr;
|
||||||
return resultMesh;
|
return resultMesh;
|
||||||
}
|
}
|
||||||
|
@ -325,7 +328,7 @@ void MeshGenerator::cutFaceStringToCutTemplate(const QString &cutFaceString, std
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MeshCombiner::Mesh *MeshGenerator::combinePartMesh(const QString &partIdString, bool *hasError, bool addIntermediateNodes)
|
MeshCombiner::Mesh *MeshGenerator::combinePartMesh(const QString &partIdString, bool *hasError, bool *retryable, bool addIntermediateNodes)
|
||||||
{
|
{
|
||||||
auto findPart = m_snapshot->parts.find(partIdString);
|
auto findPart = m_snapshot->parts.find(partIdString);
|
||||||
if (findPart == m_snapshot->parts.end()) {
|
if (findPart == m_snapshot->parts.end()) {
|
||||||
|
@ -335,6 +338,9 @@ MeshCombiner::Mesh *MeshGenerator::combinePartMesh(const QString &partIdString,
|
||||||
|
|
||||||
QUuid partId = QUuid(partIdString);
|
QUuid partId = QUuid(partIdString);
|
||||||
auto &part = findPart->second;
|
auto &part = findPart->second;
|
||||||
|
|
||||||
|
*retryable = true;
|
||||||
|
|
||||||
bool isDisabled = isTrueValueString(valueOfKeyInMapOrEmpty(part, "disabled"));
|
bool isDisabled = isTrueValueString(valueOfKeyInMapOrEmpty(part, "disabled"));
|
||||||
bool xMirrored = isTrueValueString(valueOfKeyInMapOrEmpty(part, "xMirrored"));
|
bool xMirrored = isTrueValueString(valueOfKeyInMapOrEmpty(part, "xMirrored"));
|
||||||
bool subdived = isTrueValueString(valueOfKeyInMapOrEmpty(part, "subdived"));
|
bool subdived = isTrueValueString(valueOfKeyInMapOrEmpty(part, "subdived"));
|
||||||
|
@ -349,7 +355,6 @@ MeshCombiner::Mesh *MeshGenerator::combinePartMesh(const QString &partIdString,
|
||||||
float hollowThickness = 0.0;
|
float hollowThickness = 0.0;
|
||||||
auto target = PartTargetFromString(valueOfKeyInMapOrEmpty(part, "target").toUtf8().constData());
|
auto target = PartTargetFromString(valueOfKeyInMapOrEmpty(part, "target").toUtf8().constData());
|
||||||
auto base = PartBaseFromString(valueOfKeyInMapOrEmpty(part, "base").toUtf8().constData());
|
auto base = PartBaseFromString(valueOfKeyInMapOrEmpty(part, "base").toUtf8().constData());
|
||||||
//bool gridded = isTrueValueString(valueOfKeyInMapOrEmpty(part, "gridded"));
|
|
||||||
|
|
||||||
QString cutFaceString = valueOfKeyInMapOrEmpty(part, "cutFace");
|
QString cutFaceString = valueOfKeyInMapOrEmpty(part, "cutFace");
|
||||||
std::vector<QVector2D> cutTemplate;
|
std::vector<QVector2D> cutTemplate;
|
||||||
|
@ -404,6 +409,16 @@ MeshCombiner::Mesh *MeshGenerator::combinePartMesh(const QString &partIdString,
|
||||||
if (!colorSolubilityString.isEmpty())
|
if (!colorSolubilityString.isEmpty())
|
||||||
colorSolubility = colorSolubilityString.toFloat();
|
colorSolubility = colorSolubilityString.toFloat();
|
||||||
|
|
||||||
|
QUuid fillMeshFileId;
|
||||||
|
QString fillMeshString = valueOfKeyInMapOrEmpty(part, "fillMesh");
|
||||||
|
if (!fillMeshString.isEmpty()) {
|
||||||
|
fillMeshFileId = QUuid(fillMeshString);
|
||||||
|
if (!fillMeshFileId.isNull()) {
|
||||||
|
*retryable = false;
|
||||||
|
xMirrored = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto &partCache = m_cacheContext->parts[partIdString];
|
auto &partCache = m_cacheContext->parts[partIdString];
|
||||||
partCache.outcomeNodes.clear();
|
partCache.outcomeNodes.clear();
|
||||||
partCache.outcomeEdges.clear();
|
partCache.outcomeEdges.clear();
|
||||||
|
@ -414,7 +429,7 @@ MeshCombiner::Mesh *MeshGenerator::combinePartMesh(const QString &partIdString,
|
||||||
partCache.faces.clear();
|
partCache.faces.clear();
|
||||||
partCache.previewTriangles.clear();
|
partCache.previewTriangles.clear();
|
||||||
partCache.previewVertices.clear();
|
partCache.previewVertices.clear();
|
||||||
partCache.isSucceed = false;
|
partCache.isSuccessful = false;
|
||||||
partCache.joined = (target == PartTarget::Model && !isDisabled);
|
partCache.joined = (target == PartTarget::Model && !isDisabled);
|
||||||
delete partCache.mesh;
|
delete partCache.mesh;
|
||||||
partCache.mesh = nullptr;
|
partCache.mesh = nullptr;
|
||||||
|
@ -497,8 +512,7 @@ MeshCombiner::Mesh *MeshGenerator::combinePartMesh(const QString &partIdString,
|
||||||
bool buildSucceed = false;
|
bool buildSucceed = false;
|
||||||
std::map<QString, int> nodeIdStringToIndexMap;
|
std::map<QString, int> nodeIdStringToIndexMap;
|
||||||
std::map<int, QString> nodeIndexToIdStringMap;
|
std::map<int, QString> nodeIndexToIdStringMap;
|
||||||
StrokeModifier *nodeMeshModifier = nullptr;
|
StrokeModifier *strokeModifier = nullptr;
|
||||||
StrokeMeshBuilder *nodeMeshBuilder = nullptr;
|
|
||||||
|
|
||||||
QString mirroredPartIdString;
|
QString mirroredPartIdString;
|
||||||
QUuid mirroredPartId;
|
QUuid mirroredPartId;
|
||||||
|
@ -508,7 +522,7 @@ MeshCombiner::Mesh *MeshGenerator::combinePartMesh(const QString &partIdString,
|
||||||
m_cacheContext->partMirrorIdMap[mirroredPartIdString] = partIdString;
|
m_cacheContext->partMirrorIdMap[mirroredPartIdString] = partIdString;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto addNode = [&](const QString &nodeIdString, const NodeInfo &nodeInfo) {
|
auto addNodeToPartCache = [&](const QString &nodeIdString, const NodeInfo &nodeInfo) {
|
||||||
OutcomeNode outcomeNode;
|
OutcomeNode outcomeNode;
|
||||||
outcomeNode.partId = QUuid(partIdString);
|
outcomeNode.partId = QUuid(partIdString);
|
||||||
outcomeNode.nodeId = QUuid(nodeIdString);
|
outcomeNode.nodeId = QUuid(nodeIdString);
|
||||||
|
@ -519,7 +533,7 @@ MeshCombiner::Mesh *MeshGenerator::combinePartMesh(const QString &partIdString,
|
||||||
outcomeNode.countershaded = countershaded;
|
outcomeNode.countershaded = countershaded;
|
||||||
outcomeNode.colorSolubility = colorSolubility;
|
outcomeNode.colorSolubility = colorSolubility;
|
||||||
outcomeNode.boneMark = nodeInfo.boneMark;
|
outcomeNode.boneMark = nodeInfo.boneMark;
|
||||||
outcomeNode.mirroredByPartId = mirroredPartIdString;
|
outcomeNode.mirroredByPartId = mirroredPartId;
|
||||||
outcomeNode.joined = partCache.joined;
|
outcomeNode.joined = partCache.joined;
|
||||||
partCache.outcomeNodes.push_back(outcomeNode);
|
partCache.outcomeNodes.push_back(outcomeNode);
|
||||||
if (xMirrored) {
|
if (xMirrored) {
|
||||||
|
@ -530,7 +544,7 @@ MeshCombiner::Mesh *MeshGenerator::combinePartMesh(const QString &partIdString,
|
||||||
partCache.outcomeNodes.push_back(outcomeNode);
|
partCache.outcomeNodes.push_back(outcomeNode);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
auto addEdge = [&](const QString &firstNodeIdString, const QString &secondNodeIdString) {
|
auto addEdgeToPartCache = [&](const QString &firstNodeIdString, const QString &secondNodeIdString) {
|
||||||
partCache.outcomeEdges.push_back({
|
partCache.outcomeEdges.push_back({
|
||||||
{QUuid(partIdString), QUuid(firstNodeIdString)},
|
{QUuid(partIdString), QUuid(firstNodeIdString)},
|
||||||
{QUuid(partIdString), QUuid(secondNodeIdString)}
|
{QUuid(partIdString), QUuid(secondNodeIdString)}
|
||||||
|
@ -543,10 +557,10 @@ MeshCombiner::Mesh *MeshGenerator::combinePartMesh(const QString &partIdString,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
nodeMeshModifier = new StrokeModifier;
|
strokeModifier = new StrokeModifier;
|
||||||
|
|
||||||
if (addIntermediateNodes)
|
if (addIntermediateNodes)
|
||||||
nodeMeshModifier->enableIntermediateAddition();
|
strokeModifier->enableIntermediateAddition();
|
||||||
|
|
||||||
for (const auto &nodeIt: nodeInfos) {
|
for (const auto &nodeIt: nodeInfos) {
|
||||||
const auto &nodeIdString = nodeIt.first;
|
const auto &nodeIdString = nodeIt.first;
|
||||||
|
@ -557,14 +571,12 @@ MeshCombiner::Mesh *MeshGenerator::combinePartMesh(const QString &partIdString,
|
||||||
cutFaceStringToCutTemplate(nodeInfo.cutFace, nodeCutTemplate);
|
cutFaceStringToCutTemplate(nodeInfo.cutFace, nodeCutTemplate);
|
||||||
if (chamfered)
|
if (chamfered)
|
||||||
chamferFace2D(&nodeCutTemplate);
|
chamferFace2D(&nodeCutTemplate);
|
||||||
nodeIndex = nodeMeshModifier->addNode(nodeInfo.position, nodeInfo.radius, nodeCutTemplate, nodeInfo.cutRotation);
|
nodeIndex = strokeModifier->addNode(nodeInfo.position, nodeInfo.radius, nodeCutTemplate, nodeInfo.cutRotation);
|
||||||
} else {
|
} else {
|
||||||
nodeIndex = nodeMeshModifier->addNode(nodeInfo.position, nodeInfo.radius, cutTemplate, cutRotation);
|
nodeIndex = strokeModifier->addNode(nodeInfo.position, nodeInfo.radius, cutTemplate, cutRotation);
|
||||||
}
|
}
|
||||||
nodeIdStringToIndexMap[nodeIdString] = nodeIndex;
|
nodeIdStringToIndexMap[nodeIdString] = nodeIndex;
|
||||||
nodeIndexToIdStringMap[nodeIndex] = nodeIdString;
|
nodeIndexToIdStringMap[nodeIndex] = nodeIdString;
|
||||||
|
|
||||||
addNode(nodeIdString, nodeInfo);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto &edgeIt: edges) {
|
for (const auto &edgeIt: edges) {
|
||||||
|
@ -583,76 +595,100 @@ MeshCombiner::Mesh *MeshGenerator::combinePartMesh(const QString &partIdString,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
nodeMeshModifier->addEdge(findFromNodeIndex->second, findToNodeIndex->second);
|
strokeModifier->addEdge(findFromNodeIndex->second, findToNodeIndex->second);
|
||||||
addEdge(fromNodeIdString, toNodeIdString);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (subdived)
|
if (subdived)
|
||||||
nodeMeshModifier->subdivide();
|
strokeModifier->subdivide();
|
||||||
|
|
||||||
if (rounded)
|
if (rounded)
|
||||||
nodeMeshModifier->roundEnd();
|
strokeModifier->roundEnd();
|
||||||
|
|
||||||
nodeMeshModifier->finalize();
|
strokeModifier->finalize();
|
||||||
|
|
||||||
nodeMeshBuilder = new StrokeMeshBuilder;
|
std::vector<size_t> sourceNodeIndices;
|
||||||
nodeMeshBuilder->setDeformThickness(deformThickness);
|
|
||||||
nodeMeshBuilder->setDeformWidth(deformWidth);
|
StrokeMeshBuilder *strokeMeshBuilder = new StrokeMeshBuilder;
|
||||||
nodeMeshBuilder->setDeformMapScale(deformMapScale);
|
|
||||||
nodeMeshBuilder->setHollowThickness(hollowThickness);
|
strokeMeshBuilder->setDeformThickness(deformThickness);
|
||||||
|
strokeMeshBuilder->setDeformWidth(deformWidth);
|
||||||
|
strokeMeshBuilder->setDeformMapScale(deformMapScale);
|
||||||
|
strokeMeshBuilder->setHollowThickness(hollowThickness);
|
||||||
if (nullptr != deformImage)
|
if (nullptr != deformImage)
|
||||||
nodeMeshBuilder->setDeformMapImage(deformImage);
|
strokeMeshBuilder->setDeformMapImage(deformImage);
|
||||||
if (PartBase::YZ == base) {
|
if (PartBase::YZ == base) {
|
||||||
nodeMeshBuilder->enableBaseNormalOnX(false);
|
strokeMeshBuilder->enableBaseNormalOnX(false);
|
||||||
} else if (PartBase::Average == base) {
|
} else if (PartBase::Average == base) {
|
||||||
nodeMeshBuilder->enableBaseNormalAverage(true);
|
strokeMeshBuilder->enableBaseNormalAverage(true);
|
||||||
} else if (PartBase::XY == base) {
|
} else if (PartBase::XY == base) {
|
||||||
nodeMeshBuilder->enableBaseNormalOnZ(false);
|
strokeMeshBuilder->enableBaseNormalOnZ(false);
|
||||||
} else if (PartBase::ZX == base) {
|
} else if (PartBase::ZX == base) {
|
||||||
nodeMeshBuilder->enableBaseNormalOnY(false);
|
strokeMeshBuilder->enableBaseNormalOnY(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<size_t> builderNodeIndices;
|
for (const auto &node: strokeModifier->nodes()) {
|
||||||
for (const auto &node: nodeMeshModifier->nodes()) {
|
auto nodeIndex = strokeMeshBuilder->addNode(node.position, node.radius, node.cutTemplate, node.cutRotation);
|
||||||
auto nodeIndex = nodeMeshBuilder->addNode(node.position, node.radius, node.cutTemplate, node.cutRotation);
|
strokeMeshBuilder->setNodeOriginInfo(nodeIndex, node.nearOriginNodeIndex, node.farOriginNodeIndex);
|
||||||
nodeMeshBuilder->setNodeOriginInfo(nodeIndex, node.nearOriginNodeIndex, node.farOriginNodeIndex);
|
|
||||||
builderNodeIndices.push_back(nodeIndex);
|
|
||||||
|
|
||||||
const auto &originNodeIdString = nodeIndexToIdStringMap[node.originNodeIndex];
|
|
||||||
|
|
||||||
OutcomePaintNode paintNode;
|
|
||||||
paintNode.originNodeIndex = node.originNodeIndex;
|
|
||||||
paintNode.originNodeId = QUuid(originNodeIdString);
|
|
||||||
paintNode.radius = node.radius;
|
|
||||||
paintNode.origin = node.position;
|
|
||||||
|
|
||||||
partCache.outcomePaintMap.paintNodes.push_back(paintNode);
|
|
||||||
}
|
}
|
||||||
for (const auto &edge: nodeMeshModifier->edges())
|
for (const auto &edge: strokeModifier->edges())
|
||||||
nodeMeshBuilder->addEdge(edge.firstNodeIndex, edge.secondNodeIndex);
|
strokeMeshBuilder->addEdge(edge.firstNodeIndex, edge.secondNodeIndex);
|
||||||
buildSucceed = nodeMeshBuilder->build();
|
|
||||||
|
|
||||||
partCache.vertices = nodeMeshBuilder->generatedVertices();
|
if (fillMeshFileId.isNull()) {
|
||||||
partCache.faces = nodeMeshBuilder->generatedFaces();
|
for (const auto &nodeIt: nodeInfos) {
|
||||||
for (size_t i = 0; i < partCache.vertices.size(); ++i) {
|
const auto &nodeIdString = nodeIt.first;
|
||||||
const auto &position = partCache.vertices[i];
|
const auto &nodeInfo = nodeIt.second;
|
||||||
const auto &source = nodeMeshBuilder->generatedVerticesSourceNodeIndices()[i];
|
addNodeToPartCache(nodeIdString, nodeInfo);
|
||||||
size_t nodeIndex = nodeMeshModifier->nodes()[source].originNodeIndex;
|
}
|
||||||
const auto &nodeIdString = nodeIndexToIdStringMap[nodeIndex];
|
|
||||||
partCache.outcomeNodeVertices.push_back({position, {partIdString, nodeIdString}});
|
|
||||||
|
|
||||||
auto &paintNode = partCache.outcomePaintMap.paintNodes[source];
|
for (const auto &edgeIt: edges) {
|
||||||
paintNode.vertices.push_back(position);
|
const QString &fromNodeIdString = edgeIt.first;
|
||||||
|
const QString &toNodeIdString = edgeIt.second;
|
||||||
|
addEdgeToPartCache(fromNodeIdString, toNodeIdString);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &node: strokeModifier->nodes()) {
|
||||||
|
const auto &originNodeIdString = nodeIndexToIdStringMap[node.originNodeIndex];
|
||||||
|
|
||||||
|
OutcomePaintNode paintNode;
|
||||||
|
paintNode.originNodeIndex = node.originNodeIndex;
|
||||||
|
paintNode.originNodeId = QUuid(originNodeIdString);
|
||||||
|
paintNode.radius = node.radius;
|
||||||
|
paintNode.origin = node.position;
|
||||||
|
|
||||||
|
partCache.outcomePaintMap.paintNodes.push_back(paintNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
buildSucceed = strokeMeshBuilder->build();
|
||||||
|
|
||||||
|
partCache.vertices = strokeMeshBuilder->generatedVertices();
|
||||||
|
partCache.faces = strokeMeshBuilder->generatedFaces();
|
||||||
|
sourceNodeIndices = strokeMeshBuilder->generatedVerticesSourceNodeIndices();
|
||||||
|
for (size_t i = 0; i < partCache.vertices.size(); ++i) {
|
||||||
|
const auto &position = partCache.vertices[i];
|
||||||
|
const auto &source = strokeMeshBuilder->generatedVerticesSourceNodeIndices()[i];
|
||||||
|
size_t nodeIndex = strokeModifier->nodes()[source].originNodeIndex;
|
||||||
|
const auto &nodeIdString = nodeIndexToIdStringMap[nodeIndex];
|
||||||
|
partCache.outcomeNodeVertices.push_back({position, {partIdString, nodeIdString}});
|
||||||
|
|
||||||
|
auto &paintNode = partCache.outcomePaintMap.paintNodes[source];
|
||||||
|
paintNode.vertices.push_back(position);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < partCache.outcomePaintMap.paintNodes.size(); ++i) {
|
||||||
|
auto &paintNode = partCache.outcomePaintMap.paintNodes[i];
|
||||||
|
paintNode.baseNormal = strokeMeshBuilder->nodeBaseNormal(i);
|
||||||
|
paintNode.direction = strokeMeshBuilder->nodeTraverseDirection(i);
|
||||||
|
paintNode.order = strokeMeshBuilder->nodeTraverseOrder(i);
|
||||||
|
|
||||||
|
partCache.outcomeNodes[paintNode.originNodeIndex].direction = paintNode.direction;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (strokeMeshBuilder->buildBaseNormalsOnly())
|
||||||
|
buildSucceed = fillPartWithMesh(partCache, fillMeshFileId, cutRotation, strokeMeshBuilder);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < partCache.outcomePaintMap.paintNodes.size(); ++i) {
|
delete strokeMeshBuilder;
|
||||||
auto &paintNode = partCache.outcomePaintMap.paintNodes[i];
|
strokeMeshBuilder = nullptr;
|
||||||
paintNode.baseNormal = nodeMeshBuilder->nodeBaseNormal(i);
|
|
||||||
paintNode.direction = nodeMeshBuilder->nodeTraverseDirection(i);
|
|
||||||
paintNode.order = nodeMeshBuilder->nodeTraverseOrder(i);
|
|
||||||
|
|
||||||
partCache.outcomeNodes[paintNode.originNodeIndex].direction = paintNode.direction;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hasMeshError = false;
|
bool hasMeshError = false;
|
||||||
MeshCombiner::Mesh *mesh = nullptr;
|
MeshCombiner::Mesh *mesh = nullptr;
|
||||||
|
@ -667,8 +703,8 @@ MeshCombiner::Mesh *MeshGenerator::combinePartMesh(const QString &partIdString,
|
||||||
for (size_t i = 0; i < xMirroredVertices.size(); ++i) {
|
for (size_t i = 0; i < xMirroredVertices.size(); ++i) {
|
||||||
const auto &position = xMirroredVertices[i];
|
const auto &position = xMirroredVertices[i];
|
||||||
size_t nodeIndex = 0;
|
size_t nodeIndex = 0;
|
||||||
const auto &source = nodeMeshBuilder->generatedVerticesSourceNodeIndices()[i];
|
const auto &source = sourceNodeIndices[i];
|
||||||
nodeIndex = nodeMeshModifier->nodes()[source].originNodeIndex;
|
nodeIndex = strokeModifier->nodes()[source].originNodeIndex;
|
||||||
const auto &nodeIdString = nodeIndexToIdStringMap[nodeIndex];
|
const auto &nodeIdString = nodeIndexToIdStringMap[nodeIndex];
|
||||||
partCache.outcomeNodeVertices.push_back({position, {mirroredPartIdString, nodeIdString}});
|
partCache.outcomeNodeVertices.push_back({position, {mirroredPartIdString, nodeIdString}});
|
||||||
}
|
}
|
||||||
|
@ -716,14 +752,14 @@ MeshCombiner::Mesh *MeshGenerator::combinePartMesh(const QString &partIdString,
|
||||||
partCache.mesh = new MeshCombiner::Mesh(*mesh);
|
partCache.mesh = new MeshCombiner::Mesh(*mesh);
|
||||||
mesh->fetch(partPreviewVertices, partCache.previewTriangles);
|
mesh->fetch(partPreviewVertices, partCache.previewTriangles);
|
||||||
partCache.previewVertices = partPreviewVertices;
|
partCache.previewVertices = partPreviewVertices;
|
||||||
partCache.isSucceed = true;
|
partCache.isSuccessful = true;
|
||||||
}
|
}
|
||||||
if (partCache.previewTriangles.empty()) {
|
if (partCache.previewTriangles.empty()) {
|
||||||
partPreviewVertices = partCache.vertices;
|
partPreviewVertices = partCache.vertices;
|
||||||
triangulateFacesWithoutKeepVertices(partPreviewVertices, partCache.faces, partCache.previewTriangles);
|
triangulateFacesWithoutKeepVertices(partPreviewVertices, partCache.faces, partCache.previewTriangles);
|
||||||
partCache.previewVertices = partPreviewVertices;
|
partCache.previewVertices = partPreviewVertices;
|
||||||
partPreviewColor = Qt::red;
|
partPreviewColor = Qt::red;
|
||||||
partCache.isSucceed = false;
|
partCache.isSuccessful = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
trim(&partPreviewVertices, true);
|
trim(&partPreviewVertices, true);
|
||||||
|
@ -746,14 +782,13 @@ MeshCombiner::Mesh *MeshGenerator::combinePartMesh(const QString &partIdString,
|
||||||
if (!partCache.previewTriangles.empty()) {
|
if (!partCache.previewTriangles.empty()) {
|
||||||
if (target == PartTarget::CutFace)
|
if (target == PartTarget::CutFace)
|
||||||
partPreviewColor = Theme::red;
|
partPreviewColor = Theme::red;
|
||||||
m_partPreviewMeshes[partId] = new MeshLoader(partPreviewVertices,
|
m_partPreviewMeshes[partId] = new Model(partPreviewVertices,
|
||||||
partCache.previewTriangles,
|
partCache.previewTriangles,
|
||||||
partPreviewTriangleVertexNormals,
|
partPreviewTriangleVertexNormals,
|
||||||
partPreviewColor);
|
partPreviewColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
delete nodeMeshBuilder;
|
delete strokeModifier;
|
||||||
delete nodeMeshModifier;
|
|
||||||
|
|
||||||
if (mesh && mesh->isNull()) {
|
if (mesh && mesh->isNull()) {
|
||||||
delete mesh;
|
delete mesh;
|
||||||
|
@ -772,12 +807,79 @@ MeshCombiner::Mesh *MeshGenerator::combinePartMesh(const QString &partIdString,
|
||||||
|
|
||||||
if (hasMeshError && target == PartTarget::Model) {
|
if (hasMeshError && target == PartTarget::Model) {
|
||||||
*hasError = true;
|
*hasError = true;
|
||||||
//m_isSucceed = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return mesh;
|
return mesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MeshGenerator::fillPartWithMesh(GeneratedPart &partCache,
|
||||||
|
const QUuid &fillMeshFileId,
|
||||||
|
float cutRotation,
|
||||||
|
const StrokeMeshBuilder *strokeMeshBuilder)
|
||||||
|
{
|
||||||
|
bool fillIsSucessful = false;
|
||||||
|
const QByteArray *fillMeshByteArray = FileForever::getContent(fillMeshFileId);
|
||||||
|
if (nullptr == fillMeshByteArray)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
QXmlStreamReader fillMeshStream(*fillMeshByteArray);
|
||||||
|
Snapshot *fillMeshSnapshot = new Snapshot;
|
||||||
|
loadSkeletonFromXmlStream(fillMeshSnapshot, fillMeshStream);
|
||||||
|
|
||||||
|
GeneratedCacheContext *fillMeshCacheContext = new GeneratedCacheContext();
|
||||||
|
MeshGenerator *meshGenerator = new MeshGenerator(fillMeshSnapshot);
|
||||||
|
meshGenerator->setWeldEnabled(false);
|
||||||
|
meshGenerator->setGeneratedCacheContext(fillMeshCacheContext);
|
||||||
|
meshGenerator->generate();
|
||||||
|
fillIsSucessful = meshGenerator->isSuccessful();
|
||||||
|
Outcome *outcome = meshGenerator->takeOutcome();
|
||||||
|
if (nullptr != outcome) {
|
||||||
|
MeshStroketifier stroketifier;
|
||||||
|
std::vector<MeshStroketifier::Node> strokeNodes;
|
||||||
|
for (const auto &nodeIndex: strokeMeshBuilder->nodeIndices()) {
|
||||||
|
const auto &node = strokeMeshBuilder->nodes()[nodeIndex];
|
||||||
|
MeshStroketifier::Node strokeNode;
|
||||||
|
strokeNode.position = node.position;
|
||||||
|
strokeNode.radius = node.radius;
|
||||||
|
strokeNodes.push_back(strokeNode);
|
||||||
|
}
|
||||||
|
stroketifier.setCutRotation(cutRotation);
|
||||||
|
if (stroketifier.prepare(strokeNodes, outcome->vertices)) {
|
||||||
|
stroketifier.stroketify(&outcome->vertices);
|
||||||
|
std::vector<MeshStroketifier::Node> agentNodes(outcome->nodes.size());
|
||||||
|
for (size_t i = 0; i < outcome->nodes.size(); ++i) {
|
||||||
|
auto &dest = agentNodes[i];
|
||||||
|
const auto &src = outcome->nodes[i];
|
||||||
|
dest.position = src.origin;
|
||||||
|
dest.radius = src.radius;
|
||||||
|
}
|
||||||
|
stroketifier.stroketify(&agentNodes);
|
||||||
|
for (size_t i = 0; i < outcome->nodes.size(); ++i) {
|
||||||
|
const auto &src = agentNodes[i];
|
||||||
|
auto &dest = outcome->nodes[i];
|
||||||
|
dest.origin = src.position;
|
||||||
|
dest.radius = src.radius;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
partCache.outcomeNodes.insert(partCache.outcomeNodes.end(), outcome->nodes.begin(), outcome->nodes.end());
|
||||||
|
partCache.outcomeEdges.insert(partCache.outcomeEdges.end(), outcome->edges.begin(), outcome->edges.end());
|
||||||
|
partCache.vertices.insert(partCache.vertices.end(), outcome->vertices.begin(), outcome->vertices.end());
|
||||||
|
if (!strokeNodes.empty()) {
|
||||||
|
for (auto &it: partCache.vertices)
|
||||||
|
it += strokeNodes.front().position;
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < outcome->vertexSourceNodes.size(); ++i)
|
||||||
|
partCache.outcomeNodeVertices.push_back({partCache.vertices[i], outcome->vertexSourceNodes[i]});
|
||||||
|
partCache.faces.insert(partCache.faces.end(), outcome->triangleAndQuads.begin(), outcome->triangleAndQuads.end());
|
||||||
|
fillIsSucessful = true;
|
||||||
|
}
|
||||||
|
delete outcome;
|
||||||
|
delete meshGenerator;
|
||||||
|
delete fillMeshCacheContext;
|
||||||
|
|
||||||
|
return fillIsSucessful;
|
||||||
|
}
|
||||||
|
|
||||||
const std::map<QString, QString> *MeshGenerator::findComponent(const QString &componentIdString)
|
const std::map<QString, QString> *MeshGenerator::findComponent(const QString &componentIdString)
|
||||||
{
|
{
|
||||||
const std::map<QString, QString> *component = &m_snapshot->rootComponent;
|
const std::map<QString, QString> *component = &m_snapshot->rootComponent;
|
||||||
|
@ -935,14 +1037,18 @@ MeshCombiner::Mesh *MeshGenerator::combineComponentMesh(const QString &component
|
||||||
if ("partId" == linkDataType) {
|
if ("partId" == linkDataType) {
|
||||||
QString partIdString = valueOfKeyInMapOrEmpty(*component, "linkData");
|
QString partIdString = valueOfKeyInMapOrEmpty(*component, "linkData");
|
||||||
bool hasError = false;
|
bool hasError = false;
|
||||||
mesh = combinePartMesh(partIdString, &hasError);
|
bool retryable = true;
|
||||||
|
mesh = combinePartMesh(partIdString, &hasError, &retryable);
|
||||||
if (hasError) {
|
if (hasError) {
|
||||||
delete mesh;
|
delete mesh;
|
||||||
hasError = false;
|
mesh = nullptr;
|
||||||
qDebug() << "Try combine part again without adding intermediate nodes";
|
if (retryable) {
|
||||||
mesh = combinePartMesh(partIdString, &hasError, false);
|
hasError = false;
|
||||||
|
qDebug() << "Try combine part again without adding intermediate nodes";
|
||||||
|
mesh = combinePartMesh(partIdString, &hasError, &retryable, false);
|
||||||
|
}
|
||||||
if (hasError) {
|
if (hasError) {
|
||||||
m_isSucceed = false;
|
m_isSuccessful = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1176,7 +1282,7 @@ MeshCombiner::Mesh *MeshGenerator::combineMultipleMeshes(const std::vector<std::
|
||||||
delete mesh;
|
delete mesh;
|
||||||
mesh = newMesh;
|
mesh = newMesh;
|
||||||
} else {
|
} else {
|
||||||
m_isSucceed = false;
|
m_isSuccessful = false;
|
||||||
qDebug() << "Mesh combine failed";
|
qDebug() << "Mesh combine failed";
|
||||||
delete newMesh;
|
delete newMesh;
|
||||||
}
|
}
|
||||||
|
@ -1318,7 +1424,7 @@ void MeshGenerator::generate()
|
||||||
if (nullptr == m_snapshot)
|
if (nullptr == m_snapshot)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_isSucceed = true;
|
m_isSuccessful = true;
|
||||||
|
|
||||||
QElapsedTimer countTimeConsumed;
|
QElapsedTimer countTimeConsumed;
|
||||||
countTimeConsumed.start();
|
countTimeConsumed.start();
|
||||||
|
@ -1399,23 +1505,22 @@ void MeshGenerator::generate()
|
||||||
std::vector<std::vector<size_t>> combinedFaces;
|
std::vector<std::vector<size_t>> combinedFaces;
|
||||||
if (nullptr != combinedMesh) {
|
if (nullptr != combinedMesh) {
|
||||||
combinedMesh->fetch(combinedVertices, combinedFaces);
|
combinedMesh->fetch(combinedVertices, combinedFaces);
|
||||||
|
if (m_weldEnabled) {
|
||||||
if (!remeshed) {
|
if (!remeshed) {
|
||||||
size_t totalAffectedNum = 0;
|
size_t totalAffectedNum = 0;
|
||||||
size_t affectedNum = 0;
|
size_t affectedNum = 0;
|
||||||
do {
|
do {
|
||||||
std::vector<QVector3D> weldedVertices;
|
std::vector<QVector3D> weldedVertices;
|
||||||
std::vector<std::vector<size_t>> weldedFaces;
|
std::vector<std::vector<size_t>> weldedFaces;
|
||||||
affectedNum = weldSeam(combinedVertices, combinedFaces,
|
affectedNum = weldSeam(combinedVertices, combinedFaces,
|
||||||
0.025, componentCache.noneSeamVertices,
|
0.025, componentCache.noneSeamVertices,
|
||||||
weldedVertices, weldedFaces);
|
weldedVertices, weldedFaces);
|
||||||
combinedVertices = weldedVertices;
|
combinedVertices = weldedVertices;
|
||||||
combinedFaces = weldedFaces;
|
combinedFaces = weldedFaces;
|
||||||
totalAffectedNum += affectedNum;
|
totalAffectedNum += affectedNum;
|
||||||
} while (affectedNum > 0);
|
} while (affectedNum > 0);
|
||||||
qDebug() << "Total weld affected triangles:" << totalAffectedNum;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_outcome->nodes = componentCache.outcomeNodes;
|
m_outcome->nodes = componentCache.outcomeNodes;
|
||||||
m_outcome->edges = componentCache.outcomeEdges;
|
m_outcome->edges = componentCache.outcomeEdges;
|
||||||
m_outcome->paintMaps = componentCache.outcomePaintMaps;
|
m_outcome->paintMaps = componentCache.outcomePaintMaps;
|
||||||
|
@ -1447,10 +1552,30 @@ void MeshGenerator::generate()
|
||||||
}
|
}
|
||||||
|
|
||||||
collectClothComponent(QUuid().toString());
|
collectClothComponent(QUuid().toString());
|
||||||
|
collectErroredParts();
|
||||||
|
postprocessOutcome(m_outcome);
|
||||||
|
|
||||||
// Collect errored parts
|
m_resultMesh = new Model(*m_outcome);
|
||||||
|
|
||||||
|
delete combinedMesh;
|
||||||
|
|
||||||
|
if (needDeleteCacheContext) {
|
||||||
|
delete m_cacheContext;
|
||||||
|
m_cacheContext = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << "The mesh generation took" << countTimeConsumed.elapsed() << "milliseconds";
|
||||||
|
}
|
||||||
|
|
||||||
|
void MeshGenerator::setWeldEnabled(bool enabled)
|
||||||
|
{
|
||||||
|
m_weldEnabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MeshGenerator::collectErroredParts()
|
||||||
|
{
|
||||||
for (const auto &it: m_cacheContext->parts) {
|
for (const auto &it: m_cacheContext->parts) {
|
||||||
if (!it.second.isSucceed) {
|
if (!it.second.isSuccessful) {
|
||||||
if (!it.second.joined)
|
if (!it.second.joined)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -1472,56 +1597,44 @@ void MeshGenerator::generate()
|
||||||
m_outcome->triangles.insert(m_outcome->triangles.end(), errorTriangles.begin(), errorTriangles.end());
|
m_outcome->triangles.insert(m_outcome->triangles.end(), errorTriangles.begin(), errorTriangles.end());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto postprocessOutcome = [this](Outcome *outcome) {
|
void MeshGenerator::postprocessOutcome(Outcome *outcome)
|
||||||
std::vector<QVector3D> combinedFacesNormals;
|
{
|
||||||
for (const auto &face: outcome->triangles) {
|
std::vector<QVector3D> combinedFacesNormals;
|
||||||
combinedFacesNormals.push_back(QVector3D::normal(
|
for (const auto &face: outcome->triangles) {
|
||||||
outcome->vertices[face[0]],
|
combinedFacesNormals.push_back(QVector3D::normal(
|
||||||
outcome->vertices[face[1]],
|
outcome->vertices[face[0]],
|
||||||
outcome->vertices[face[2]]
|
outcome->vertices[face[1]],
|
||||||
));
|
outcome->vertices[face[2]]
|
||||||
}
|
));
|
||||||
|
|
||||||
outcome->triangleNormals = combinedFacesNormals;
|
|
||||||
|
|
||||||
std::vector<std::pair<QUuid, QUuid>> sourceNodes;
|
|
||||||
triangleSourceNodeResolve(*outcome, sourceNodes, &outcome->vertexSourceNodes);
|
|
||||||
outcome->setTriangleSourceNodes(sourceNodes);
|
|
||||||
|
|
||||||
std::map<std::pair<QUuid, QUuid>, QColor> sourceNodeToColorMap;
|
|
||||||
for (const auto &node: outcome->nodes)
|
|
||||||
sourceNodeToColorMap.insert({{node.partId, node.nodeId}, node.color});
|
|
||||||
|
|
||||||
outcome->triangleColors.resize(outcome->triangles.size(), Qt::white);
|
|
||||||
const std::vector<std::pair<QUuid, QUuid>> *triangleSourceNodes = outcome->triangleSourceNodes();
|
|
||||||
if (nullptr != triangleSourceNodes) {
|
|
||||||
for (size_t triangleIndex = 0; triangleIndex < outcome->triangles.size(); triangleIndex++) {
|
|
||||||
const auto &source = (*triangleSourceNodes)[triangleIndex];
|
|
||||||
outcome->triangleColors[triangleIndex] = sourceNodeToColorMap[source];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::vector<QVector3D>> triangleVertexNormals;
|
|
||||||
generateSmoothTriangleVertexNormals(outcome->vertices,
|
|
||||||
outcome->triangles,
|
|
||||||
outcome->triangleNormals,
|
|
||||||
&triangleVertexNormals);
|
|
||||||
outcome->setTriangleVertexNormals(triangleVertexNormals);
|
|
||||||
};
|
|
||||||
|
|
||||||
postprocessOutcome(m_outcome);
|
|
||||||
|
|
||||||
m_resultMesh = new MeshLoader(*m_outcome);
|
|
||||||
|
|
||||||
delete combinedMesh;
|
|
||||||
|
|
||||||
if (needDeleteCacheContext) {
|
|
||||||
delete m_cacheContext;
|
|
||||||
m_cacheContext = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
qDebug() << "The mesh generation took" << countTimeConsumed.elapsed() << "milliseconds";
|
outcome->triangleNormals = combinedFacesNormals;
|
||||||
|
|
||||||
|
std::vector<std::pair<QUuid, QUuid>> sourceNodes;
|
||||||
|
triangleSourceNodeResolve(*outcome, sourceNodes, &outcome->vertexSourceNodes);
|
||||||
|
outcome->setTriangleSourceNodes(sourceNodes);
|
||||||
|
|
||||||
|
std::map<std::pair<QUuid, QUuid>, QColor> sourceNodeToColorMap;
|
||||||
|
for (const auto &node: outcome->nodes)
|
||||||
|
sourceNodeToColorMap.insert({{node.partId, node.nodeId}, node.color});
|
||||||
|
|
||||||
|
outcome->triangleColors.resize(outcome->triangles.size(), Qt::white);
|
||||||
|
const std::vector<std::pair<QUuid, QUuid>> *triangleSourceNodes = outcome->triangleSourceNodes();
|
||||||
|
if (nullptr != triangleSourceNodes) {
|
||||||
|
for (size_t triangleIndex = 0; triangleIndex < outcome->triangles.size(); triangleIndex++) {
|
||||||
|
const auto &source = (*triangleSourceNodes)[triangleIndex];
|
||||||
|
outcome->triangleColors[triangleIndex] = sourceNodeToColorMap[source];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::vector<QVector3D>> triangleVertexNormals;
|
||||||
|
generateSmoothTriangleVertexNormals(outcome->vertices,
|
||||||
|
outcome->triangles,
|
||||||
|
outcome->triangleNormals,
|
||||||
|
&triangleVertexNormals);
|
||||||
|
outcome->setTriangleVertexNormals(triangleVertexNormals);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshGenerator::remesh(const std::vector<OutcomeNode> &inputNodes,
|
void MeshGenerator::remesh(const std::vector<OutcomeNode> &inputNodes,
|
||||||
|
|
|
@ -10,9 +10,10 @@
|
||||||
#include "outcome.h"
|
#include "outcome.h"
|
||||||
#include "snapshot.h"
|
#include "snapshot.h"
|
||||||
#include "combinemode.h"
|
#include "combinemode.h"
|
||||||
#include "meshloader.h"
|
#include "model.h"
|
||||||
#include "componentlayer.h"
|
#include "componentlayer.h"
|
||||||
#include "clothforce.h"
|
#include "clothforce.h"
|
||||||
|
#include "strokemodifier.h"
|
||||||
|
|
||||||
class GeneratedPart
|
class GeneratedPart
|
||||||
{
|
{
|
||||||
|
@ -30,7 +31,7 @@ public:
|
||||||
std::vector<QVector3D> previewVertices;
|
std::vector<QVector3D> previewVertices;
|
||||||
std::vector<std::vector<size_t>> previewTriangles;
|
std::vector<std::vector<size_t>> previewTriangles;
|
||||||
OutcomePaintMap outcomePaintMap;
|
OutcomePaintMap outcomePaintMap;
|
||||||
bool isSucceed = false;
|
bool isSuccessful = false;
|
||||||
bool joined = true;
|
bool joined = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -65,9 +66,9 @@ class MeshGenerator : public QObject
|
||||||
public:
|
public:
|
||||||
MeshGenerator(Snapshot *snapshot);
|
MeshGenerator(Snapshot *snapshot);
|
||||||
~MeshGenerator();
|
~MeshGenerator();
|
||||||
bool isSucceed();
|
bool isSuccessful();
|
||||||
MeshLoader *takeResultMesh();
|
Model *takeResultMesh();
|
||||||
MeshLoader *takePartPreviewMesh(const QUuid &partId);
|
Model *takePartPreviewMesh(const QUuid &partId);
|
||||||
const std::set<QUuid> &generatedPreviewPartIds();
|
const std::set<QUuid> &generatedPreviewPartIds();
|
||||||
Outcome *takeOutcome();
|
Outcome *takeOutcome();
|
||||||
std::map<QUuid, StrokeMeshBuilder::CutFaceTransform> *takeCutFaceTransforms();
|
std::map<QUuid, StrokeMeshBuilder::CutFaceTransform> *takeCutFaceTransforms();
|
||||||
|
@ -77,6 +78,7 @@ public:
|
||||||
void setSmoothShadingThresholdAngleDegrees(float degrees);
|
void setSmoothShadingThresholdAngleDegrees(float degrees);
|
||||||
void setDefaultPartColor(const QColor &color);
|
void setDefaultPartColor(const QColor &color);
|
||||||
void setId(quint64 id);
|
void setId(quint64 id);
|
||||||
|
void setWeldEnabled(bool enabled);
|
||||||
quint64 id();
|
quint64 id();
|
||||||
signals:
|
signals:
|
||||||
void finished();
|
void finished();
|
||||||
|
@ -96,9 +98,9 @@ private:
|
||||||
std::map<QString, std::set<QString>> m_partNodeIds;
|
std::map<QString, std::set<QString>> m_partNodeIds;
|
||||||
std::map<QString, std::set<QString>> m_partEdgeIds;
|
std::map<QString, std::set<QString>> m_partEdgeIds;
|
||||||
std::set<QUuid> m_generatedPreviewPartIds;
|
std::set<QUuid> m_generatedPreviewPartIds;
|
||||||
MeshLoader *m_resultMesh = nullptr;
|
Model *m_resultMesh = nullptr;
|
||||||
std::map<QUuid, MeshLoader *> m_partPreviewMeshes;
|
std::map<QUuid, Model *> m_partPreviewMeshes;
|
||||||
bool m_isSucceed = false;
|
bool m_isSuccessful = false;
|
||||||
bool m_cacheEnabled = false;
|
bool m_cacheEnabled = false;
|
||||||
float m_smoothShadingThresholdAngleDegrees = 60;
|
float m_smoothShadingThresholdAngleDegrees = 60;
|
||||||
std::map<QUuid, StrokeMeshBuilder::CutFaceTransform> *m_cutFaceTransforms = nullptr;
|
std::map<QUuid, StrokeMeshBuilder::CutFaceTransform> *m_cutFaceTransforms = nullptr;
|
||||||
|
@ -106,13 +108,18 @@ private:
|
||||||
quint64 m_id = 0;
|
quint64 m_id = 0;
|
||||||
std::vector<QVector3D> m_clothCollisionVertices;
|
std::vector<QVector3D> m_clothCollisionVertices;
|
||||||
std::vector<std::vector<size_t>> m_clothCollisionTriangles;
|
std::vector<std::vector<size_t>> m_clothCollisionTriangles;
|
||||||
|
bool m_weldEnabled = true;
|
||||||
|
|
||||||
void collectParts();
|
void collectParts();
|
||||||
bool checkIsComponentDirty(const QString &componentIdString);
|
bool checkIsComponentDirty(const QString &componentIdString);
|
||||||
bool checkIsPartDirty(const QString &partIdString);
|
bool checkIsPartDirty(const QString &partIdString);
|
||||||
bool checkIsPartDependencyDirty(const QString &partIdString);
|
bool checkIsPartDependencyDirty(const QString &partIdString);
|
||||||
void checkDirtyFlags();
|
void checkDirtyFlags();
|
||||||
MeshCombiner::Mesh *combinePartMesh(const QString &partIdString, bool *hasError, bool addIntermediateNodes=true);
|
bool fillPartWithMesh(GeneratedPart &partCache,
|
||||||
|
const QUuid &fillMeshFileId,
|
||||||
|
float cutRotation,
|
||||||
|
const StrokeMeshBuilder *strokeMeshBuilder);
|
||||||
|
MeshCombiner::Mesh *combinePartMesh(const QString &partIdString, bool *hasError, bool *retryable, bool addIntermediateNodes=true);
|
||||||
MeshCombiner::Mesh *combineComponentMesh(const QString &componentIdString, CombineMode *combineMode);
|
MeshCombiner::Mesh *combineComponentMesh(const QString &componentIdString, CombineMode *combineMode);
|
||||||
void makeXmirror(const std::vector<QVector3D> &sourceVertices, const std::vector<std::vector<size_t>> &sourceFaces,
|
void makeXmirror(const std::vector<QVector3D> &sourceVertices, const std::vector<std::vector<size_t>> &sourceFaces,
|
||||||
std::vector<QVector3D> *destVertices, std::vector<std::vector<size_t>> *destFaces);
|
std::vector<QVector3D> *destVertices, std::vector<std::vector<size_t>> *destFaces);
|
||||||
|
@ -150,6 +157,8 @@ private:
|
||||||
std::vector<std::vector<size_t>> *outputQuads,
|
std::vector<std::vector<size_t>> *outputQuads,
|
||||||
std::vector<std::vector<size_t>> *outputTriangles,
|
std::vector<std::vector<size_t>> *outputTriangles,
|
||||||
std::vector<std::pair<QVector3D, std::pair<QUuid, QUuid>>> *outputNodeVertices);
|
std::vector<std::pair<QVector3D, std::pair<QUuid, QUuid>>> *outputNodeVertices);
|
||||||
|
void postprocessOutcome(Outcome *outcome);
|
||||||
|
void collectErroredParts();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -97,7 +97,7 @@ size_t MeshRecombiner::splitSeamVerticesToIslands(const std::map<size_t, std::ve
|
||||||
|
|
||||||
bool MeshRecombiner::buildHalfEdgeToFaceMap(std::map<std::pair<size_t, size_t>, size_t> &halfEdgeToFaceMap)
|
bool MeshRecombiner::buildHalfEdgeToFaceMap(std::map<std::pair<size_t, size_t>, size_t> &halfEdgeToFaceMap)
|
||||||
{
|
{
|
||||||
bool succeed = true;
|
bool isSuccessful = true;
|
||||||
for (size_t faceIndex = 0; faceIndex < m_faces->size(); ++faceIndex) {
|
for (size_t faceIndex = 0; faceIndex < m_faces->size(); ++faceIndex) {
|
||||||
const auto &face = (*m_faces)[faceIndex];
|
const auto &face = (*m_faces)[faceIndex];
|
||||||
for (size_t i = 0; i < face.size(); ++i) {
|
for (size_t i = 0; i < face.size(); ++i) {
|
||||||
|
@ -105,11 +105,11 @@ bool MeshRecombiner::buildHalfEdgeToFaceMap(std::map<std::pair<size_t, size_t>,
|
||||||
const auto insertResult = halfEdgeToFaceMap.insert({{face[i], face[j]}, faceIndex});
|
const auto insertResult = halfEdgeToFaceMap.insert({{face[i], face[j]}, faceIndex});
|
||||||
if (!insertResult.second) {
|
if (!insertResult.second) {
|
||||||
//qDebug() << "Non manifold edge found:" << face[i] << face[j];
|
//qDebug() << "Non manifold edge found:" << face[i] << face[j];
|
||||||
succeed = false;
|
isSuccessful = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return succeed;
|
return isSuccessful;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MeshRecombiner::recombine()
|
bool MeshRecombiner::recombine()
|
||||||
|
|
|
@ -0,0 +1,198 @@
|
||||||
|
#include <QMatrix4x4>
|
||||||
|
#include <QQuaternion>
|
||||||
|
#include <set>
|
||||||
|
#include "meshstroketifier.h"
|
||||||
|
|
||||||
|
void MeshStroketifier::setCutRotation(float cutRotation)
|
||||||
|
{
|
||||||
|
m_cutRotation = cutRotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MeshStroketifier::prepare(const std::vector<Node> &strokeNodes,
|
||||||
|
const std::vector<QVector3D> &vertices)
|
||||||
|
{
|
||||||
|
if (strokeNodes.empty() || vertices.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
float boundingBoxMinX = 0.0;
|
||||||
|
float boundingBoxMaxX = 0.0;
|
||||||
|
float boundingBoxMinY = 0.0;
|
||||||
|
float boundingBoxMaxY = 0.0;
|
||||||
|
float boundingBoxMinZ = 0.0;
|
||||||
|
float boundingBoxMaxZ = 0.0;
|
||||||
|
calculateBoundingBox(vertices,
|
||||||
|
&boundingBoxMinX, &boundingBoxMaxX,
|
||||||
|
&boundingBoxMinY, &boundingBoxMaxY,
|
||||||
|
&boundingBoxMinZ, &boundingBoxMaxZ);
|
||||||
|
float xLength = boundingBoxMaxX - boundingBoxMinX;
|
||||||
|
float yLength = boundingBoxMaxY - boundingBoxMinY;
|
||||||
|
float zLength = boundingBoxMaxZ - boundingBoxMinZ;
|
||||||
|
if (yLength >= xLength && yLength >= zLength) {
|
||||||
|
// Y-axis
|
||||||
|
m_modelOrigin = QVector3D((boundingBoxMinX + boundingBoxMaxX) * 0.5,
|
||||||
|
boundingBoxMinY,
|
||||||
|
(boundingBoxMinZ + boundingBoxMaxZ) * 0.5);
|
||||||
|
m_modelAlignDirection = QVector3D(0.0, 1.0, 0.0);
|
||||||
|
m_modelLength = yLength;
|
||||||
|
} else if (zLength >= xLength && zLength >= yLength) {
|
||||||
|
// Z-axis
|
||||||
|
m_modelOrigin = QVector3D((boundingBoxMinX + boundingBoxMaxX) * 0.5,
|
||||||
|
(boundingBoxMinY + boundingBoxMaxY) * 0.5,
|
||||||
|
boundingBoxMinZ);
|
||||||
|
m_modelAlignDirection = QVector3D(0.0, 0.0, 1.0);
|
||||||
|
m_modelLength = zLength;
|
||||||
|
} else {
|
||||||
|
// X-axis
|
||||||
|
m_modelOrigin = QVector3D(boundingBoxMinX,
|
||||||
|
(boundingBoxMinY + boundingBoxMaxY) * 0.5,
|
||||||
|
(boundingBoxMinZ + boundingBoxMaxZ) * 0.5);
|
||||||
|
m_modelAlignDirection = QVector3D(1.0, 0.0, 0.0);
|
||||||
|
m_modelLength = xLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<float> strokeSegmentLengths;
|
||||||
|
float strokeLength = calculateStrokeLengths(strokeNodes, &strokeSegmentLengths);
|
||||||
|
|
||||||
|
if (strokeLength > 0)
|
||||||
|
m_scaleAmount = strokeLength / (m_modelLength + std::numeric_limits<float>::epsilon());
|
||||||
|
|
||||||
|
if (!strokeSegmentLengths.empty()) {
|
||||||
|
float offset = 0;
|
||||||
|
for (size_t i = 0; i < strokeSegmentLengths.size(); ++i) {
|
||||||
|
offset += strokeSegmentLengths[i];
|
||||||
|
m_modelJointPositions.push_back(m_modelAlignDirection * offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
QMatrix4x4 matrix;
|
||||||
|
|
||||||
|
if (!qFuzzyIsNull(m_cutRotation)) {
|
||||||
|
QMatrix4x4 cutRotationMatrix;
|
||||||
|
cutRotationMatrix.rotate(m_cutRotation * 180, m_modelAlignDirection);
|
||||||
|
matrix *= cutRotationMatrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector3D rotateFromDirection = m_modelAlignDirection;
|
||||||
|
for (size_t i = 1; i < strokeNodes.size(); ++i) {
|
||||||
|
size_t h = i - 1;
|
||||||
|
|
||||||
|
auto newDirection = (strokeNodes[i].position - strokeNodes[h].position).normalized();
|
||||||
|
auto rotation = QQuaternion::rotationTo(rotateFromDirection, newDirection);
|
||||||
|
rotateFromDirection = newDirection;
|
||||||
|
|
||||||
|
QMatrix4x4 rotationMatrix;
|
||||||
|
rotationMatrix.rotate(rotation);
|
||||||
|
|
||||||
|
matrix *= rotationMatrix;
|
||||||
|
|
||||||
|
m_modelTransforms.push_back(matrix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MeshStroketifier::stroketify(std::vector<QVector3D> *vertices)
|
||||||
|
{
|
||||||
|
translate(vertices);
|
||||||
|
scale(vertices);
|
||||||
|
deform(vertices);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MeshStroketifier::stroketify(std::vector<Node> *nodes)
|
||||||
|
{
|
||||||
|
std::vector<QVector3D> positions(nodes->size());
|
||||||
|
for (size_t i = 0; i < nodes->size(); ++i)
|
||||||
|
positions[i] = (*nodes)[i].position;
|
||||||
|
stroketify(&positions);
|
||||||
|
for (size_t i = 0; i < nodes->size(); ++i) {
|
||||||
|
auto &node = (*nodes)[i];
|
||||||
|
node.position = positions[i];
|
||||||
|
node.radius *= m_scaleAmount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float MeshStroketifier::calculateStrokeLengths(const std::vector<Node> &strokeNodes,
|
||||||
|
std::vector<float> *lengths)
|
||||||
|
{
|
||||||
|
float total = 0.0;
|
||||||
|
for (size_t i = 1; i < strokeNodes.size(); ++i) {
|
||||||
|
size_t h = i - 1;
|
||||||
|
const auto &strokeNodeH = strokeNodes[h];
|
||||||
|
const auto &strokeNodeI = strokeNodes[i];
|
||||||
|
float distance = (strokeNodeH.position - strokeNodeI.position).length();
|
||||||
|
total += distance;
|
||||||
|
if (nullptr != lengths)
|
||||||
|
lengths->push_back(distance);
|
||||||
|
}
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MeshStroketifier::calculateBoundingBox(const std::vector<QVector3D> &vertices,
|
||||||
|
float *minX, float *maxX,
|
||||||
|
float *minY, float *maxY,
|
||||||
|
float *minZ, float *maxZ)
|
||||||
|
{
|
||||||
|
*minX = *minY = *minZ = std::numeric_limits<float>::max();
|
||||||
|
*maxX = *maxY = *maxZ = std::numeric_limits<float>::lowest();
|
||||||
|
for (const auto &it: vertices) {
|
||||||
|
if (it.x() < *minX)
|
||||||
|
*minX = it.x();
|
||||||
|
if (it.x() > *maxX)
|
||||||
|
*maxX = it.x();
|
||||||
|
if (it.y() < *minY)
|
||||||
|
*minY = it.y();
|
||||||
|
if (it.y() > *maxY)
|
||||||
|
*maxY = it.y();
|
||||||
|
if (it.z() < *minZ)
|
||||||
|
*minZ = it.z();
|
||||||
|
if (it.z() > *maxZ)
|
||||||
|
*maxZ = it.z();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MeshStroketifier::translate(std::vector<QVector3D> *vertices)
|
||||||
|
{
|
||||||
|
for (auto &it: *vertices)
|
||||||
|
it += -m_modelOrigin;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MeshStroketifier::scale(std::vector<QVector3D> *vertices)
|
||||||
|
{
|
||||||
|
for (auto &it: *vertices)
|
||||||
|
it *= m_scaleAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MeshStroketifier::deform(std::vector<QVector3D> *vertices)
|
||||||
|
{
|
||||||
|
if (m_modelJointPositions.empty() ||
|
||||||
|
m_modelTransforms.empty() ||
|
||||||
|
m_modelJointPositions.size() != m_modelTransforms.size()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::set<size_t> remaining;
|
||||||
|
for (size_t i = 0; i < vertices->size(); ++i)
|
||||||
|
remaining.insert(i);
|
||||||
|
|
||||||
|
std::vector<std::vector<size_t>> skinnedIndices;
|
||||||
|
for (size_t i = 0; i < m_modelJointPositions.size(); ++i) {
|
||||||
|
std::vector<size_t> indices;
|
||||||
|
for (const auto &index: remaining) {
|
||||||
|
if (QVector3D::dotProduct(((*vertices)[index] - m_modelJointPositions[i]).normalized(),
|
||||||
|
m_modelAlignDirection) < 0) {
|
||||||
|
indices.push_back(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const auto &index: indices)
|
||||||
|
remaining.erase(index);
|
||||||
|
skinnedIndices.push_back(indices);
|
||||||
|
}
|
||||||
|
if (!remaining.empty())
|
||||||
|
skinnedIndices.back().insert(skinnedIndices.back().end(), remaining.begin(), remaining.end());
|
||||||
|
|
||||||
|
for (size_t i = 0; i < skinnedIndices.size() && i < m_modelTransforms.size(); ++i) {
|
||||||
|
const auto &matrix = m_modelTransforms[i];
|
||||||
|
for (const auto &index: skinnedIndices[i])
|
||||||
|
(*vertices)[index] = matrix * (*vertices)[index];
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
#ifndef DUST3D_MESH_STROKETIFIER_H
|
||||||
|
#define DUST3D_MESH_STROKETIFIER_H
|
||||||
|
#include <QObject>
|
||||||
|
#include <QVector3D>
|
||||||
|
#include <QMatrix4x4>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class MeshStroketifier : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
struct Node
|
||||||
|
{
|
||||||
|
QVector3D position;
|
||||||
|
float radius;
|
||||||
|
};
|
||||||
|
void setCutRotation(float cutRotation);
|
||||||
|
bool prepare(const std::vector<Node> &strokeNodes,
|
||||||
|
const std::vector<QVector3D> &vertices);
|
||||||
|
void stroketify(std::vector<QVector3D> *vertices);
|
||||||
|
void stroketify(std::vector<Node> *nodes);
|
||||||
|
private:
|
||||||
|
float m_cutRotation = 0.0;
|
||||||
|
|
||||||
|
QVector3D m_modelOrigin;
|
||||||
|
float m_modelLength = 0.0;
|
||||||
|
float m_scaleAmount = 1.0;
|
||||||
|
QVector3D m_modelAlignDirection;
|
||||||
|
std::vector<QVector3D> m_modelJointPositions;
|
||||||
|
std::vector<QMatrix4x4> m_modelTransforms;
|
||||||
|
|
||||||
|
static float calculateStrokeLengths(const std::vector<Node> &strokeNodes,
|
||||||
|
std::vector<float> *lengths);
|
||||||
|
static void calculateBoundingBox(const std::vector<QVector3D> &vertices,
|
||||||
|
float *minX, float *maxX,
|
||||||
|
float *minY, float *maxY,
|
||||||
|
float *minZ, float *maxZ);
|
||||||
|
|
||||||
|
void translate(std::vector<QVector3D> *vertices);
|
||||||
|
void scale(std::vector<QVector3D> *vertices);
|
||||||
|
void deform(std::vector<QVector3D> *vertices);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -2,15 +2,15 @@
|
||||||
#include <QTextStream>
|
#include <QTextStream>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include "meshloader.h"
|
#include "model.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
|
||||||
#define MAX_VERTICES_PER_FACE 100
|
#define MAX_VERTICES_PER_FACE 100
|
||||||
|
|
||||||
float MeshLoader::m_defaultMetalness = 0.0;
|
float Model::m_defaultMetalness = 0.0;
|
||||||
float MeshLoader::m_defaultRoughness = 1.0;
|
float Model::m_defaultRoughness = 1.0;
|
||||||
|
|
||||||
MeshLoader::MeshLoader(const MeshLoader &mesh) :
|
Model::Model(const Model &mesh) :
|
||||||
m_triangleVertices(nullptr),
|
m_triangleVertices(nullptr),
|
||||||
m_triangleVertexCount(0),
|
m_triangleVertexCount(0),
|
||||||
m_edgeVertices(nullptr),
|
m_edgeVertices(nullptr),
|
||||||
|
@ -57,7 +57,7 @@ MeshLoader::MeshLoader(const MeshLoader &mesh) :
|
||||||
this->m_meshId = mesh.meshId();
|
this->m_meshId = mesh.meshId();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshLoader::removeColor()
|
void Model::removeColor()
|
||||||
{
|
{
|
||||||
delete this->m_textureImage;
|
delete this->m_textureImage;
|
||||||
this->m_textureImage = nullptr;
|
this->m_textureImage = nullptr;
|
||||||
|
@ -80,7 +80,7 @@ void MeshLoader::removeColor()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MeshLoader::MeshLoader(ShaderVertex *triangleVertices, int vertexNum, ShaderVertex *edgeVertices, int edgeVertexCount) :
|
Model::Model(ShaderVertex *triangleVertices, int vertexNum, ShaderVertex *edgeVertices, int edgeVertexCount) :
|
||||||
m_triangleVertices(triangleVertices),
|
m_triangleVertices(triangleVertices),
|
||||||
m_triangleVertexCount(vertexNum),
|
m_triangleVertexCount(vertexNum),
|
||||||
m_edgeVertices(edgeVertices),
|
m_edgeVertices(edgeVertices),
|
||||||
|
@ -89,7 +89,7 @@ MeshLoader::MeshLoader(ShaderVertex *triangleVertices, int vertexNum, ShaderVert
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
MeshLoader::MeshLoader(const std::vector<QVector3D> &vertices, const std::vector<std::vector<size_t>> &triangles,
|
Model::Model(const std::vector<QVector3D> &vertices, const std::vector<std::vector<size_t>> &triangles,
|
||||||
const std::vector<std::vector<QVector3D>> &triangleVertexNormals,
|
const std::vector<std::vector<QVector3D>> &triangleVertexNormals,
|
||||||
const QColor &color)
|
const QColor &color)
|
||||||
{
|
{
|
||||||
|
@ -124,7 +124,7 @@ MeshLoader::MeshLoader(const std::vector<QVector3D> &vertices, const std::vector
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MeshLoader::MeshLoader(Outcome &outcome) :
|
Model::Model(Outcome &outcome) :
|
||||||
m_triangleVertices(nullptr),
|
m_triangleVertices(nullptr),
|
||||||
m_triangleVertexCount(0),
|
m_triangleVertexCount(0),
|
||||||
m_edgeVertices(nullptr),
|
m_edgeVertices(nullptr),
|
||||||
|
@ -210,7 +210,7 @@ MeshLoader::MeshLoader(Outcome &outcome) :
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MeshLoader::MeshLoader() :
|
Model::Model() :
|
||||||
m_triangleVertices(nullptr),
|
m_triangleVertices(nullptr),
|
||||||
m_triangleVertexCount(0),
|
m_triangleVertexCount(0),
|
||||||
m_edgeVertices(nullptr),
|
m_edgeVertices(nullptr),
|
||||||
|
@ -219,7 +219,7 @@ MeshLoader::MeshLoader() :
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
MeshLoader::~MeshLoader()
|
Model::~Model()
|
||||||
{
|
{
|
||||||
delete[] m_triangleVertices;
|
delete[] m_triangleVertices;
|
||||||
m_triangleVertexCount = 0;
|
m_triangleVertexCount = 0;
|
||||||
|
@ -232,117 +232,117 @@ MeshLoader::~MeshLoader()
|
||||||
delete m_metalnessRoughnessAmbientOcclusionImage;
|
delete m_metalnessRoughnessAmbientOcclusionImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<QVector3D> &MeshLoader::vertices()
|
const std::vector<QVector3D> &Model::vertices()
|
||||||
{
|
{
|
||||||
return m_vertices;
|
return m_vertices;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<std::vector<size_t>> &MeshLoader::faces()
|
const std::vector<std::vector<size_t>> &Model::faces()
|
||||||
{
|
{
|
||||||
return m_faces;
|
return m_faces;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<QVector3D> &MeshLoader::triangulatedVertices()
|
const std::vector<QVector3D> &Model::triangulatedVertices()
|
||||||
{
|
{
|
||||||
return m_triangulatedVertices;
|
return m_triangulatedVertices;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<TriangulatedFace> &MeshLoader::triangulatedFaces()
|
const std::vector<TriangulatedFace> &Model::triangulatedFaces()
|
||||||
{
|
{
|
||||||
return m_triangulatedFaces;
|
return m_triangulatedFaces;
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderVertex *MeshLoader::triangleVertices()
|
ShaderVertex *Model::triangleVertices()
|
||||||
{
|
{
|
||||||
return m_triangleVertices;
|
return m_triangleVertices;
|
||||||
}
|
}
|
||||||
|
|
||||||
int MeshLoader::triangleVertexCount()
|
int Model::triangleVertexCount()
|
||||||
{
|
{
|
||||||
return m_triangleVertexCount;
|
return m_triangleVertexCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderVertex *MeshLoader::edgeVertices()
|
ShaderVertex *Model::edgeVertices()
|
||||||
{
|
{
|
||||||
return m_edgeVertices;
|
return m_edgeVertices;
|
||||||
}
|
}
|
||||||
|
|
||||||
int MeshLoader::edgeVertexCount()
|
int Model::edgeVertexCount()
|
||||||
{
|
{
|
||||||
return m_edgeVertexCount;
|
return m_edgeVertexCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderVertex *MeshLoader::toolVertices()
|
ShaderVertex *Model::toolVertices()
|
||||||
{
|
{
|
||||||
return m_toolVertices;
|
return m_toolVertices;
|
||||||
}
|
}
|
||||||
|
|
||||||
int MeshLoader::toolVertexCount()
|
int Model::toolVertexCount()
|
||||||
{
|
{
|
||||||
return m_toolVertexCount;
|
return m_toolVertexCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshLoader::setTextureImage(QImage *textureImage)
|
void Model::setTextureImage(QImage *textureImage)
|
||||||
{
|
{
|
||||||
m_textureImage = textureImage;
|
m_textureImage = textureImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QImage *MeshLoader::textureImage()
|
const QImage *Model::textureImage()
|
||||||
{
|
{
|
||||||
return m_textureImage;
|
return m_textureImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshLoader::setNormalMapImage(QImage *normalMapImage)
|
void Model::setNormalMapImage(QImage *normalMapImage)
|
||||||
{
|
{
|
||||||
m_normalMapImage = normalMapImage;
|
m_normalMapImage = normalMapImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QImage *MeshLoader::normalMapImage()
|
const QImage *Model::normalMapImage()
|
||||||
{
|
{
|
||||||
return m_normalMapImage;
|
return m_normalMapImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QImage *MeshLoader::metalnessRoughnessAmbientOcclusionImage()
|
const QImage *Model::metalnessRoughnessAmbientOcclusionImage()
|
||||||
{
|
{
|
||||||
return m_metalnessRoughnessAmbientOcclusionImage;
|
return m_metalnessRoughnessAmbientOcclusionImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshLoader::setMetalnessRoughnessAmbientOcclusionImage(QImage *image)
|
void Model::setMetalnessRoughnessAmbientOcclusionImage(QImage *image)
|
||||||
{
|
{
|
||||||
m_metalnessRoughnessAmbientOcclusionImage = image;
|
m_metalnessRoughnessAmbientOcclusionImage = image;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MeshLoader::hasMetalnessInImage()
|
bool Model::hasMetalnessInImage()
|
||||||
{
|
{
|
||||||
return m_hasMetalnessInImage;
|
return m_hasMetalnessInImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshLoader::setHasMetalnessInImage(bool hasInImage)
|
void Model::setHasMetalnessInImage(bool hasInImage)
|
||||||
{
|
{
|
||||||
m_hasMetalnessInImage = hasInImage;
|
m_hasMetalnessInImage = hasInImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MeshLoader::hasRoughnessInImage()
|
bool Model::hasRoughnessInImage()
|
||||||
{
|
{
|
||||||
return m_hasRoughnessInImage;
|
return m_hasRoughnessInImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshLoader::setHasRoughnessInImage(bool hasInImage)
|
void Model::setHasRoughnessInImage(bool hasInImage)
|
||||||
{
|
{
|
||||||
m_hasRoughnessInImage = hasInImage;
|
m_hasRoughnessInImage = hasInImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MeshLoader::hasAmbientOcclusionInImage()
|
bool Model::hasAmbientOcclusionInImage()
|
||||||
{
|
{
|
||||||
return m_hasAmbientOcclusionInImage;
|
return m_hasAmbientOcclusionInImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshLoader::setHasAmbientOcclusionInImage(bool hasInImage)
|
void Model::setHasAmbientOcclusionInImage(bool hasInImage)
|
||||||
{
|
{
|
||||||
m_hasAmbientOcclusionInImage = hasInImage;
|
m_hasAmbientOcclusionInImage = hasInImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshLoader::exportAsObj(QTextStream *textStream)
|
void Model::exportAsObj(QTextStream *textStream)
|
||||||
{
|
{
|
||||||
auto &stream = *textStream;
|
auto &stream = *textStream;
|
||||||
stream << "# " << APP_NAME << " " << APP_HUMAN_VER << endl;
|
stream << "# " << APP_NAME << " " << APP_HUMAN_VER << endl;
|
||||||
|
@ -359,7 +359,7 @@ void MeshLoader::exportAsObj(QTextStream *textStream)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshLoader::exportAsObj(const QString &filename)
|
void Model::exportAsObj(const QString &filename)
|
||||||
{
|
{
|
||||||
QFile file(filename);
|
QFile file(filename);
|
||||||
if (file.open(QIODevice::WriteOnly)) {
|
if (file.open(QIODevice::WriteOnly)) {
|
||||||
|
@ -368,7 +368,7 @@ void MeshLoader::exportAsObj(const QString &filename)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshLoader::updateTool(ShaderVertex *toolVertices, int vertexNum)
|
void Model::updateTool(ShaderVertex *toolVertices, int vertexNum)
|
||||||
{
|
{
|
||||||
delete[] m_toolVertices;
|
delete[] m_toolVertices;
|
||||||
m_toolVertices = nullptr;
|
m_toolVertices = nullptr;
|
||||||
|
@ -378,7 +378,7 @@ void MeshLoader::updateTool(ShaderVertex *toolVertices, int vertexNum)
|
||||||
m_toolVertexCount = vertexNum;
|
m_toolVertexCount = vertexNum;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshLoader::updateEdges(ShaderVertex *edgeVertices, int edgeVertexCount)
|
void Model::updateEdges(ShaderVertex *edgeVertices, int edgeVertexCount)
|
||||||
{
|
{
|
||||||
delete[] m_edgeVertices;
|
delete[] m_edgeVertices;
|
||||||
m_edgeVertices = nullptr;
|
m_edgeVertices = nullptr;
|
||||||
|
@ -388,7 +388,7 @@ void MeshLoader::updateEdges(ShaderVertex *edgeVertices, int edgeVertexCount)
|
||||||
m_edgeVertexCount = edgeVertexCount;
|
m_edgeVertexCount = edgeVertexCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshLoader::updateTriangleVertices(ShaderVertex *triangleVertices, int triangleVertexCount)
|
void Model::updateTriangleVertices(ShaderVertex *triangleVertices, int triangleVertexCount)
|
||||||
{
|
{
|
||||||
delete[] m_triangleVertices;
|
delete[] m_triangleVertices;
|
||||||
m_triangleVertices = 0;
|
m_triangleVertices = 0;
|
||||||
|
@ -398,12 +398,12 @@ void MeshLoader::updateTriangleVertices(ShaderVertex *triangleVertices, int tria
|
||||||
m_triangleVertexCount = triangleVertexCount;
|
m_triangleVertexCount = triangleVertexCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
quint64 MeshLoader::meshId() const
|
quint64 Model::meshId() const
|
||||||
{
|
{
|
||||||
return m_meshId;
|
return m_meshId;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshLoader::setMeshId(quint64 id)
|
void Model::setMeshId(quint64 id)
|
||||||
{
|
{
|
||||||
m_meshId = id;
|
m_meshId = id;
|
||||||
}
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
#ifndef DUST3D_MESH_LOADER_H
|
#ifndef DUST3D_MODEL_H
|
||||||
#define DUST3D_MESH_LOADER_H
|
#define DUST3D_MODEL_H
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <QVector3D>
|
#include <QVector3D>
|
||||||
|
@ -15,17 +15,17 @@ struct TriangulatedFace
|
||||||
QColor color;
|
QColor color;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MeshLoader
|
class Model
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MeshLoader(const std::vector<QVector3D> &vertices, const std::vector<std::vector<size_t>> &triangles,
|
Model(const std::vector<QVector3D> &vertices, const std::vector<std::vector<size_t>> &triangles,
|
||||||
const std::vector<std::vector<QVector3D>> &triangleVertexNormals,
|
const std::vector<std::vector<QVector3D>> &triangleVertexNormals,
|
||||||
const QColor &color=Qt::white);
|
const QColor &color=Qt::white);
|
||||||
MeshLoader(Outcome &outcome);
|
Model(Outcome &outcome);
|
||||||
MeshLoader(ShaderVertex *triangleVertices, int vertexNum, ShaderVertex *edgeVertices=nullptr, int edgeVertexCount=0);
|
Model(ShaderVertex *triangleVertices, int vertexNum, ShaderVertex *edgeVertices=nullptr, int edgeVertexCount=0);
|
||||||
MeshLoader(const MeshLoader &mesh);
|
Model(const Model &mesh);
|
||||||
MeshLoader();
|
Model();
|
||||||
~MeshLoader();
|
~Model();
|
||||||
ShaderVertex *triangleVertices();
|
ShaderVertex *triangleVertices();
|
||||||
int triangleVertexCount();
|
int triangleVertexCount();
|
||||||
ShaderVertex *edgeVertices();
|
ShaderVertex *edgeVertices();
|
|
@ -31,7 +31,7 @@ ModelMeshBinder::~ModelMeshBinder()
|
||||||
delete m_currentToonDepthMap;
|
delete m_currentToonDepthMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelMeshBinder::updateMesh(MeshLoader *mesh)
|
void ModelMeshBinder::updateMesh(Model *mesh)
|
||||||
{
|
{
|
||||||
QMutexLocker lock(&m_newMeshMutex);
|
QMutexLocker lock(&m_newMeshMutex);
|
||||||
if (mesh != m_mesh) {
|
if (mesh != m_mesh) {
|
||||||
|
@ -43,12 +43,12 @@ void ModelMeshBinder::updateMesh(MeshLoader *mesh)
|
||||||
|
|
||||||
void ModelMeshBinder::reloadMesh()
|
void ModelMeshBinder::reloadMesh()
|
||||||
{
|
{
|
||||||
MeshLoader *mesh = nullptr;
|
Model *mesh = nullptr;
|
||||||
{
|
{
|
||||||
QMutexLocker lock(&m_newMeshMutex);
|
QMutexLocker lock(&m_newMeshMutex);
|
||||||
if (nullptr == m_mesh)
|
if (nullptr == m_mesh)
|
||||||
return;
|
return;
|
||||||
mesh = new MeshLoader(*m_mesh);
|
mesh = new Model(*m_mesh);
|
||||||
}
|
}
|
||||||
if (nullptr != mesh)
|
if (nullptr != mesh)
|
||||||
updateMesh(mesh);
|
updateMesh(mesh);
|
||||||
|
@ -67,17 +67,17 @@ void ModelMeshBinder::enableEnvironmentLight()
|
||||||
m_environmentLightEnabled = true;
|
m_environmentLightEnabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
MeshLoader *ModelMeshBinder::fetchCurrentMesh()
|
Model *ModelMeshBinder::fetchCurrentMesh()
|
||||||
{
|
{
|
||||||
QMutexLocker lock(&m_meshMutex);
|
QMutexLocker lock(&m_meshMutex);
|
||||||
if (nullptr == m_mesh)
|
if (nullptr == m_mesh)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
return new MeshLoader(*m_mesh);
|
return new Model(*m_mesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelMeshBinder::paint(ModelShaderProgram *program)
|
void ModelMeshBinder::paint(ModelShaderProgram *program)
|
||||||
{
|
{
|
||||||
MeshLoader *newMesh = nullptr;
|
Model *newMesh = nullptr;
|
||||||
bool hasNewMesh = false;
|
bool hasNewMesh = false;
|
||||||
if (m_newMeshComing) {
|
if (m_newMeshComing) {
|
||||||
QMutexLocker lock(&m_newMeshMutex);
|
QMutexLocker lock(&m_newMeshMutex);
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#include <QOpenGLBuffer>
|
#include <QOpenGLBuffer>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QOpenGLTexture>
|
#include <QOpenGLTexture>
|
||||||
#include "meshloader.h"
|
#include "model.h"
|
||||||
#include "modelshaderprogram.h"
|
#include "modelshaderprogram.h"
|
||||||
|
|
||||||
class ModelMeshBinder
|
class ModelMeshBinder
|
||||||
|
@ -13,8 +13,8 @@ class ModelMeshBinder
|
||||||
public:
|
public:
|
||||||
ModelMeshBinder(bool toolEnabled=false);
|
ModelMeshBinder(bool toolEnabled=false);
|
||||||
~ModelMeshBinder();
|
~ModelMeshBinder();
|
||||||
MeshLoader *fetchCurrentMesh();
|
Model *fetchCurrentMesh();
|
||||||
void updateMesh(MeshLoader *mesh);
|
void updateMesh(Model *mesh);
|
||||||
void initialize();
|
void initialize();
|
||||||
void paint(ModelShaderProgram *program);
|
void paint(ModelShaderProgram *program);
|
||||||
void cleanup();
|
void cleanup();
|
||||||
|
@ -29,8 +29,8 @@ public:
|
||||||
void fetchCurrentToonNormalAndDepthMaps(QImage *normalMap, QImage *depthMap);
|
void fetchCurrentToonNormalAndDepthMaps(QImage *normalMap, QImage *depthMap);
|
||||||
void updateToonNormalAndDepthMaps(QImage *normalMap, QImage *depthMap);
|
void updateToonNormalAndDepthMaps(QImage *normalMap, QImage *depthMap);
|
||||||
private:
|
private:
|
||||||
MeshLoader *m_mesh = nullptr;
|
Model *m_mesh = nullptr;
|
||||||
MeshLoader *m_newMesh = nullptr;
|
Model *m_newMesh = nullptr;
|
||||||
int m_renderTriangleVertexCount = 0;
|
int m_renderTriangleVertexCount = 0;
|
||||||
int m_renderEdgeVertexCount = 0;
|
int m_renderEdgeVertexCount = 0;
|
||||||
int m_renderToolVertexCount = 0;
|
int m_renderToolVertexCount = 0;
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
#include <QOpenGLFramebufferObjectFormat>
|
#include <QOpenGLFramebufferObjectFormat>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include "modelofflinerender.h"
|
#include "modeloffscreenrender.h"
|
||||||
|
|
||||||
ModelOfflineRender::ModelOfflineRender(const QSurfaceFormat &format, QScreen *targetScreen) :
|
ModelOffscreenRender::ModelOffscreenRender(const QSurfaceFormat &format, QScreen *targetScreen) :
|
||||||
QOffscreenSurface(targetScreen),
|
QOffscreenSurface(targetScreen),
|
||||||
m_context(nullptr),
|
m_context(nullptr),
|
||||||
m_mesh(nullptr)
|
m_mesh(nullptr)
|
||||||
|
@ -11,10 +11,10 @@ ModelOfflineRender::ModelOfflineRender(const QSurfaceFormat &format, QScreen *ta
|
||||||
setFormat(format);
|
setFormat(format);
|
||||||
create();
|
create();
|
||||||
if (!isValid())
|
if (!isValid())
|
||||||
qDebug() << "ModelOfflineRender is invalid";
|
qDebug() << "ModelOffscreenRender is invalid";
|
||||||
}
|
}
|
||||||
|
|
||||||
ModelOfflineRender::~ModelOfflineRender()
|
ModelOffscreenRender::~ModelOffscreenRender()
|
||||||
{
|
{
|
||||||
destroy();
|
destroy();
|
||||||
delete m_mesh;
|
delete m_mesh;
|
||||||
|
@ -22,43 +22,43 @@ ModelOfflineRender::~ModelOfflineRender()
|
||||||
delete m_depthMap;
|
delete m_depthMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelOfflineRender::updateMesh(MeshLoader *mesh)
|
void ModelOffscreenRender::updateMesh(Model *mesh)
|
||||||
{
|
{
|
||||||
delete m_mesh;
|
delete m_mesh;
|
||||||
m_mesh = mesh;
|
m_mesh = mesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelOfflineRender::setRenderThread(QThread *thread)
|
void ModelOffscreenRender::setRenderThread(QThread *thread)
|
||||||
{
|
{
|
||||||
//this->moveToThread(thread);
|
this->moveToThread(thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelOfflineRender::setXRotation(int angle)
|
void ModelOffscreenRender::setXRotation(int angle)
|
||||||
{
|
{
|
||||||
m_xRot = angle;
|
m_xRot = angle;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelOfflineRender::setYRotation(int angle)
|
void ModelOffscreenRender::setYRotation(int angle)
|
||||||
{
|
{
|
||||||
m_yRot = angle;
|
m_yRot = angle;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelOfflineRender::setZRotation(int angle)
|
void ModelOffscreenRender::setZRotation(int angle)
|
||||||
{
|
{
|
||||||
m_zRot = angle;
|
m_zRot = angle;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelOfflineRender::setRenderPurpose(int purpose)
|
void ModelOffscreenRender::setRenderPurpose(int purpose)
|
||||||
{
|
{
|
||||||
m_renderPurpose = purpose;
|
m_renderPurpose = purpose;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelOfflineRender::setToonShading(bool toonShading)
|
void ModelOffscreenRender::setToonShading(bool toonShading)
|
||||||
{
|
{
|
||||||
m_toonShading = toonShading;
|
m_toonShading = toonShading;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelOfflineRender::updateToonNormalAndDepthMaps(QImage *normalMap, QImage *depthMap)
|
void ModelOffscreenRender::updateToonNormalAndDepthMaps(QImage *normalMap, QImage *depthMap)
|
||||||
{
|
{
|
||||||
delete m_normalMap;
|
delete m_normalMap;
|
||||||
m_normalMap = normalMap;
|
m_normalMap = normalMap;
|
||||||
|
@ -67,7 +67,7 @@ void ModelOfflineRender::updateToonNormalAndDepthMaps(QImage *normalMap, QImage
|
||||||
m_depthMap = depthMap;
|
m_depthMap = depthMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
QImage ModelOfflineRender::toImage(const QSize &size)
|
QImage ModelOffscreenRender::toImage(const QSize &size)
|
||||||
{
|
{
|
||||||
QImage image;
|
QImage image;
|
||||||
|
|
||||||
|
@ -175,7 +175,9 @@ QImage ModelOfflineRender::toImage(const QSize &size)
|
||||||
|
|
||||||
image = renderFbo->toImage();
|
image = renderFbo->toImage();
|
||||||
|
|
||||||
|
qDebug() << "bindDefault begin...";
|
||||||
renderFbo->bindDefault();
|
renderFbo->bindDefault();
|
||||||
|
qDebug() << "bindDefault end";
|
||||||
delete renderFbo;
|
delete renderFbo;
|
||||||
|
|
||||||
m_context->doneCurrent();
|
m_context->doneCurrent();
|
|
@ -1,5 +1,5 @@
|
||||||
#ifndef DUST3D_MODEL_OFFLINE_RENDER_H
|
#ifndef DUST3D_MODEL_OFFSCREEN_RENDER_H
|
||||||
#define DUST3D_MODEL_OFFLINE_RENDER_H
|
#define DUST3D_MODEL_OFFSCREEN_RENDER_H
|
||||||
#include <QOffscreenSurface>
|
#include <QOffscreenSurface>
|
||||||
#include <QScreen>
|
#include <QScreen>
|
||||||
#include <QOpenGLFunctions>
|
#include <QOpenGLFunctions>
|
||||||
|
@ -8,19 +8,19 @@
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
#include "modelshaderprogram.h"
|
#include "modelshaderprogram.h"
|
||||||
#include "modelmeshbinder.h"
|
#include "modelmeshbinder.h"
|
||||||
#include "meshloader.h"
|
#include "model.h"
|
||||||
|
|
||||||
class ModelOfflineRender : QOffscreenSurface
|
class ModelOffscreenRender : QOffscreenSurface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ModelOfflineRender(const QSurfaceFormat &format, QScreen *targetScreen = Q_NULLPTR);
|
ModelOffscreenRender(const QSurfaceFormat &format, QScreen *targetScreen = Q_NULLPTR);
|
||||||
~ModelOfflineRender();
|
~ModelOffscreenRender();
|
||||||
void setXRotation(int angle);
|
void setXRotation(int angle);
|
||||||
void setYRotation(int angle);
|
void setYRotation(int angle);
|
||||||
void setZRotation(int angle);
|
void setZRotation(int angle);
|
||||||
void setRenderPurpose(int purpose);
|
void setRenderPurpose(int purpose);
|
||||||
void setRenderThread(QThread *thread);
|
void setRenderThread(QThread *thread);
|
||||||
void updateMesh(MeshLoader *mesh);
|
void updateMesh(Model *mesh);
|
||||||
void updateToonNormalAndDepthMaps(QImage *normalMap, QImage *depthMap);
|
void updateToonNormalAndDepthMaps(QImage *normalMap, QImage *depthMap);
|
||||||
void setToonShading(bool toonShading);
|
void setToonShading(bool toonShading);
|
||||||
QImage toImage(const QSize &size);
|
QImage toImage(const QSize &size);
|
||||||
|
@ -30,7 +30,7 @@ private:
|
||||||
int m_zRot = 0;
|
int m_zRot = 0;
|
||||||
int m_renderPurpose = 0;
|
int m_renderPurpose = 0;
|
||||||
QOpenGLContext *m_context = nullptr;
|
QOpenGLContext *m_context = nullptr;
|
||||||
MeshLoader *m_mesh = nullptr;
|
Model *m_mesh = nullptr;
|
||||||
QImage *m_normalMap = nullptr;
|
QImage *m_normalMap = nullptr;
|
||||||
QImage *m_depthMap = nullptr;
|
QImage *m_depthMap = nullptr;
|
||||||
bool m_toonShading = false;
|
bool m_toonShading = false;
|
|
@ -114,7 +114,7 @@ void ModelWidget::setZRotation(int angle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MeshLoader *ModelWidget::fetchCurrentMesh()
|
Model *ModelWidget::fetchCurrentMesh()
|
||||||
{
|
{
|
||||||
return m_meshBinder.fetchCurrentMesh();
|
return m_meshBinder.fetchCurrentMesh();
|
||||||
}
|
}
|
||||||
|
@ -422,7 +422,7 @@ void ModelWidget::setMousePickRadius(float radius)
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelWidget::updateMesh(MeshLoader *mesh)
|
void ModelWidget::updateMesh(Model *mesh)
|
||||||
{
|
{
|
||||||
m_meshBinder.updateMesh(mesh);
|
m_meshBinder.updateMesh(mesh);
|
||||||
emit renderParametersChanged();
|
emit renderParametersChanged();
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
#include <QRubberBand>
|
#include <QRubberBand>
|
||||||
#include <QVector2D>
|
#include <QVector2D>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include "meshloader.h"
|
#include "model.h"
|
||||||
#include "modelshaderprogram.h"
|
#include "modelshaderprogram.h"
|
||||||
#include "modelmeshbinder.h"
|
#include "modelmeshbinder.h"
|
||||||
|
|
||||||
|
@ -35,8 +35,8 @@ public:
|
||||||
{
|
{
|
||||||
m_transparent = t;
|
m_transparent = t;
|
||||||
}
|
}
|
||||||
MeshLoader *fetchCurrentMesh();
|
Model *fetchCurrentMesh();
|
||||||
void updateMesh(MeshLoader *mesh);
|
void updateMesh(Model *mesh);
|
||||||
void setGraphicsFunctions(SkeletonGraphicsFunctions *graphicsFunctions);
|
void setGraphicsFunctions(SkeletonGraphicsFunctions *graphicsFunctions);
|
||||||
void toggleWireframe();
|
void toggleWireframe();
|
||||||
void toggleRotation();
|
void toggleRotation();
|
||||||
|
|
|
@ -80,7 +80,7 @@ std::vector<std::pair<std::map<QString, QString>, std::map<QString, std::map<QSt
|
||||||
return &frames;
|
return &frames;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MotionsGenerator::generatePreviewsForOutcomes(const std::vector<std::pair<float, JointNodeTree>> &outcomes, std::vector<std::pair<float, MeshLoader *>> &previews)
|
void MotionsGenerator::generatePreviewsForOutcomes(const std::vector<std::pair<float, JointNodeTree>> &outcomes, std::vector<std::pair<float, Model *>> &previews)
|
||||||
{
|
{
|
||||||
for (const auto &item: outcomes) {
|
for (const auto &item: outcomes) {
|
||||||
PoseMeshCreator *poseMeshCreator = new PoseMeshCreator(item.second.nodes(), m_outcome, m_rigWeights);
|
PoseMeshCreator *poseMeshCreator = new PoseMeshCreator(item.second.nodes(), m_outcome, m_rigWeights);
|
||||||
|
@ -114,7 +114,7 @@ const std::vector<std::pair<float, JointNodeTree>> &MotionsGenerator::getProcedu
|
||||||
std::vector<std::pair<float, JointNodeTree>> &resultFrames = m_proceduralAnimations[(int)proceduralAnimation];
|
std::vector<std::pair<float, JointNodeTree>> &resultFrames = m_proceduralAnimations[(int)proceduralAnimation];
|
||||||
if (ProceduralAnimation::FallToDeath == proceduralAnimation) {
|
if (ProceduralAnimation::FallToDeath == proceduralAnimation) {
|
||||||
#if ENABLE_PROCEDURAL_DEBUG
|
#if ENABLE_PROCEDURAL_DEBUG
|
||||||
std::vector<MeshLoader *> &resultPreviews = m_proceduralDebugPreviews[(int)proceduralAnimation];
|
std::vector<Model *> &resultPreviews = m_proceduralDebugPreviews[(int)proceduralAnimation];
|
||||||
#endif
|
#endif
|
||||||
RagDoll ragdoll(&m_rigBones, initialJointNodeTree);
|
RagDoll ragdoll(&m_rigBones, initialJointNodeTree);
|
||||||
float stepSeconds = 1.0 / 60;
|
float stepSeconds = 1.0 / 60;
|
||||||
|
@ -124,7 +124,7 @@ const std::vector<std::pair<float, JointNodeTree>> &MotionsGenerator::getProcedu
|
||||||
while (steps < maxSteps && ragdoll.stepSimulation(stepSeconds)) {
|
while (steps < maxSteps && ragdoll.stepSimulation(stepSeconds)) {
|
||||||
resultFrames.push_back(std::make_pair(stepSeconds * 2, ragdoll.getStepJointNodeTree()));
|
resultFrames.push_back(std::make_pair(stepSeconds * 2, ragdoll.getStepJointNodeTree()));
|
||||||
#if ENABLE_PROCEDURAL_DEBUG
|
#if ENABLE_PROCEDURAL_DEBUG
|
||||||
MeshLoader *preview = buildBoundingBoxMesh(ragdoll.getStepBonePositions());
|
Model *preview = buildBoundingBoxMesh(ragdoll.getStepBonePositions());
|
||||||
resultPreviews.push_back(preview);
|
resultPreviews.push_back(preview);
|
||||||
#endif
|
#endif
|
||||||
++steps;
|
++steps;
|
||||||
|
@ -178,7 +178,7 @@ float MotionsGenerator::calculateMotionDuration(const QUuid &motionId, std::set<
|
||||||
return totalDuration;
|
return totalDuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MotionsGenerator::generateMotion(const QUuid &motionId, std::set<QUuid> &visited, std::vector<std::pair<float, JointNodeTree>> &outcomes, std::vector<MeshLoader *> *previews)
|
void MotionsGenerator::generateMotion(const QUuid &motionId, std::set<QUuid> &visited, std::vector<std::pair<float, JointNodeTree>> &outcomes, std::vector<Model *> *previews)
|
||||||
{
|
{
|
||||||
if (visited.find(motionId) != visited.end()) {
|
if (visited.find(motionId) != visited.end()) {
|
||||||
qDebug() << "Found recursive motion link";
|
qDebug() << "Found recursive motion link";
|
||||||
|
@ -386,7 +386,7 @@ const JointNodeTree *MotionsGenerator::findClipEndJointNodeTree(const MotionClip
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::pair<float, MeshLoader *>> MotionsGenerator::takeResultPreviewMeshs(const QUuid &motionId)
|
std::vector<std::pair<float, Model *>> MotionsGenerator::takeResultPreviewMeshs(const QUuid &motionId)
|
||||||
{
|
{
|
||||||
auto findResult = m_resultPreviewMeshs.find(motionId);
|
auto findResult = m_resultPreviewMeshs.find(motionId);
|
||||||
if (findResult == m_resultPreviewMeshs.end())
|
if (findResult == m_resultPreviewMeshs.end())
|
||||||
|
@ -413,7 +413,7 @@ void MotionsGenerator::generate()
|
||||||
for (const auto &motionId: m_requiredMotionIds) {
|
for (const auto &motionId: m_requiredMotionIds) {
|
||||||
std::set<QUuid> visited;
|
std::set<QUuid> visited;
|
||||||
#if ENABLE_PROCEDURAL_DEBUG
|
#if ENABLE_PROCEDURAL_DEBUG
|
||||||
std::vector<MeshLoader *> previews;
|
std::vector<Model *> previews;
|
||||||
generateMotion(motionId, visited, m_resultJointNodeTrees[motionId], &previews);
|
generateMotion(motionId, visited, m_resultJointNodeTrees[motionId], &previews);
|
||||||
#else
|
#else
|
||||||
generateMotion(motionId, visited, m_resultJointNodeTrees[motionId]);
|
generateMotion(motionId, visited, m_resultJointNodeTrees[motionId]);
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include "meshloader.h"
|
#include "model.h"
|
||||||
#include "rigger.h"
|
#include "rigger.h"
|
||||||
#include "jointnodetree.h"
|
#include "jointnodetree.h"
|
||||||
#include "document.h"
|
#include "document.h"
|
||||||
|
@ -24,7 +24,7 @@ public:
|
||||||
void addPoseToLibrary(const QUuid &poseId, const std::vector<std::pair<std::map<QString, QString>, std::map<QString, std::map<QString, QString>>>> &frames, float yTranslationScale);
|
void addPoseToLibrary(const QUuid &poseId, const std::vector<std::pair<std::map<QString, QString>, std::map<QString, std::map<QString, QString>>>> &frames, float yTranslationScale);
|
||||||
void addMotionToLibrary(const QUuid &motionId, const std::vector<MotionClip> &clips);
|
void addMotionToLibrary(const QUuid &motionId, const std::vector<MotionClip> &clips);
|
||||||
void addRequirement(const QUuid &motionId);
|
void addRequirement(const QUuid &motionId);
|
||||||
std::vector<std::pair<float, MeshLoader *>> takeResultPreviewMeshs(const QUuid &motionId);
|
std::vector<std::pair<float, Model *>> takeResultPreviewMeshs(const QUuid &motionId);
|
||||||
std::vector<std::pair<float, JointNodeTree>> takeResultJointNodeTrees(const QUuid &motionId);
|
std::vector<std::pair<float, JointNodeTree>> takeResultJointNodeTrees(const QUuid &motionId);
|
||||||
const std::set<QUuid> &requiredMotionIds();
|
const std::set<QUuid> &requiredMotionIds();
|
||||||
const std::set<QUuid> &generatedMotionIds();
|
const std::set<QUuid> &generatedMotionIds();
|
||||||
|
@ -37,14 +37,14 @@ public slots:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void generateMotion(const QUuid &motionId, std::set<QUuid> &visited, std::vector<std::pair<float, JointNodeTree>> &outcomes,
|
void generateMotion(const QUuid &motionId, std::set<QUuid> &visited, std::vector<std::pair<float, JointNodeTree>> &outcomes,
|
||||||
std::vector<MeshLoader *> *previews=nullptr);
|
std::vector<Model *> *previews=nullptr);
|
||||||
const JointNodeTree &poseJointNodeTree(const QUuid &poseId, int frame);
|
const JointNodeTree &poseJointNodeTree(const QUuid &poseId, int frame);
|
||||||
JointNodeTree generateInterpolation(InterpolationType interpolationType, const JointNodeTree &first, const JointNodeTree &second, float progress);
|
JointNodeTree generateInterpolation(InterpolationType interpolationType, const JointNodeTree &first, const JointNodeTree &second, float progress);
|
||||||
const JointNodeTree *findClipBeginJointNodeTree(const MotionClip &clip);
|
const JointNodeTree *findClipBeginJointNodeTree(const MotionClip &clip);
|
||||||
const JointNodeTree *findClipEndJointNodeTree(const MotionClip &clip);
|
const JointNodeTree *findClipEndJointNodeTree(const MotionClip &clip);
|
||||||
std::vector<MotionClip> *findMotionClips(const QUuid &motionId);
|
std::vector<MotionClip> *findMotionClips(const QUuid &motionId);
|
||||||
std::vector<std::pair<std::map<QString, QString>, std::map<QString, std::map<QString, QString>>>> *findPoseFrames(const QUuid &poseId);
|
std::vector<std::pair<std::map<QString, QString>, std::map<QString, std::map<QString, QString>>>> *findPoseFrames(const QUuid &poseId);
|
||||||
void generatePreviewsForOutcomes(const std::vector<std::pair<float, JointNodeTree>> &outcomes, std::vector<std::pair<float, MeshLoader *>> &previews);
|
void generatePreviewsForOutcomes(const std::vector<std::pair<float, JointNodeTree>> &outcomes, std::vector<std::pair<float, Model *>> &previews);
|
||||||
float calculateMotionDuration(const QUuid &motionId, std::set<QUuid> &visited);
|
float calculateMotionDuration(const QUuid &motionId, std::set<QUuid> &visited);
|
||||||
float calculatePoseDuration(const QUuid &poseId);
|
float calculatePoseDuration(const QUuid &poseId);
|
||||||
float calculateProceduralAnimationDuration(ProceduralAnimation proceduralAnimation,
|
float calculateProceduralAnimationDuration(ProceduralAnimation proceduralAnimation,
|
||||||
|
@ -57,7 +57,7 @@ private:
|
||||||
std::map<int, RiggerVertexWeights> m_rigWeights;
|
std::map<int, RiggerVertexWeights> m_rigWeights;
|
||||||
std::map<int, std::vector<std::pair<float, JointNodeTree>>> m_proceduralAnimations;
|
std::map<int, std::vector<std::pair<float, JointNodeTree>>> m_proceduralAnimations;
|
||||||
#if ENABLE_PROCEDURAL_DEBUG
|
#if ENABLE_PROCEDURAL_DEBUG
|
||||||
std::map<int, std::vector<MeshLoader *>> m_proceduralDebugPreviews;
|
std::map<int, std::vector<Model *>> m_proceduralDebugPreviews;
|
||||||
#endif
|
#endif
|
||||||
Outcome m_outcome;
|
Outcome m_outcome;
|
||||||
std::map<QUuid, std::vector<std::pair<std::map<QString, QString>, std::map<QString, std::map<QString, QString>>>>> m_poses;
|
std::map<QUuid, std::vector<std::pair<std::map<QString, QString>, std::map<QString, std::map<QString, QString>>>>> m_poses;
|
||||||
|
@ -65,7 +65,7 @@ private:
|
||||||
std::map<QUuid, std::vector<MotionClip>> m_motions;
|
std::map<QUuid, std::vector<MotionClip>> m_motions;
|
||||||
std::set<QUuid> m_requiredMotionIds;
|
std::set<QUuid> m_requiredMotionIds;
|
||||||
std::set<QUuid> m_generatedMotionIds;
|
std::set<QUuid> m_generatedMotionIds;
|
||||||
std::map<QUuid, std::vector<std::pair<float, MeshLoader *>>> m_resultPreviewMeshs;
|
std::map<QUuid, std::vector<std::pair<float, Model *>>> m_resultPreviewMeshs;
|
||||||
std::map<QUuid, std::vector<std::pair<float, JointNodeTree>>> m_resultJointNodeTrees;
|
std::map<QUuid, std::vector<std::pair<float, JointNodeTree>>> m_resultJointNodeTrees;
|
||||||
std::map<std::pair<QUuid, int>, JointNodeTree> m_poseJointNodeTreeMap;
|
std::map<std::pair<QUuid, int>, JointNodeTree> m_poseJointNodeTreeMap;
|
||||||
Poser *m_poser = nullptr;
|
Poser *m_poser = nullptr;
|
||||||
|
|
|
@ -82,7 +82,7 @@ void MotionWidget::updatePreview()
|
||||||
qDebug() << "Motion not found:" << m_motionId;
|
qDebug() << "Motion not found:" << m_motionId;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
MeshLoader *previewMesh = motion->takePreviewMesh();
|
Model *previewMesh = motion->takePreviewMesh();
|
||||||
m_previewWidget->updateMesh(previewMesh);
|
m_previewWidget->updateMesh(previewMesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include <QRadialGradient>
|
#include <QRadialGradient>
|
||||||
#include <QBrush>
|
#include <QBrush>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
|
#include <QGuiApplication>
|
||||||
#include "mousepicker.h"
|
#include "mousepicker.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "imageforever.h"
|
#include "imageforever.h"
|
||||||
|
@ -114,7 +115,7 @@ void MousePicker::pick()
|
||||||
void MousePicker::process()
|
void MousePicker::process()
|
||||||
{
|
{
|
||||||
pick();
|
pick();
|
||||||
|
this->moveToThread(QGuiApplication::instance()->thread());
|
||||||
emit finished();
|
emit finished();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QGuiApplication>
|
||||||
#include "normalanddepthmapsgenerator.h"
|
#include "normalanddepthmapsgenerator.h"
|
||||||
|
|
||||||
NormalAndDepthMapsGenerator::NormalAndDepthMapsGenerator(ModelWidget *modelWidget)
|
NormalAndDepthMapsGenerator::NormalAndDepthMapsGenerator(ModelWidget *modelWidget)
|
||||||
|
@ -8,26 +10,26 @@ NormalAndDepthMapsGenerator::NormalAndDepthMapsGenerator(ModelWidget *modelWidge
|
||||||
m_depthMapRender = createOfflineRender(modelWidget, 2);
|
m_depthMapRender = createOfflineRender(modelWidget, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NormalAndDepthMapsGenerator::updateMesh(MeshLoader *mesh)
|
void NormalAndDepthMapsGenerator::updateMesh(Model *mesh)
|
||||||
{
|
{
|
||||||
if (nullptr == mesh) {
|
if (nullptr == mesh) {
|
||||||
m_normalMapRender->updateMesh(nullptr);
|
m_normalMapRender->updateMesh(nullptr);
|
||||||
m_depthMapRender->updateMesh(nullptr);
|
m_depthMapRender->updateMesh(nullptr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_normalMapRender->updateMesh(new MeshLoader(*mesh));
|
m_normalMapRender->updateMesh(new Model(*mesh));
|
||||||
m_depthMapRender->updateMesh(mesh);
|
m_depthMapRender->updateMesh(mesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NormalAndDepthMapsGenerator::setRenderThread(QThread *thread)
|
void NormalAndDepthMapsGenerator::setRenderThread(QThread *thread)
|
||||||
{
|
{
|
||||||
//m_normalMapRender->setRenderThread(thread);
|
m_normalMapRender->setRenderThread(thread);
|
||||||
//m_depthMapRender->setRenderThread(thread);
|
m_depthMapRender->setRenderThread(thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
ModelOfflineRender *NormalAndDepthMapsGenerator::createOfflineRender(ModelWidget *modelWidget, int purpose)
|
ModelOffscreenRender *NormalAndDepthMapsGenerator::createOfflineRender(ModelWidget *modelWidget, int purpose)
|
||||||
{
|
{
|
||||||
ModelOfflineRender *offlineRender = new ModelOfflineRender(modelWidget->format());
|
ModelOffscreenRender *offlineRender = new ModelOffscreenRender(modelWidget->format());
|
||||||
offlineRender->setXRotation(modelWidget->xRot());
|
offlineRender->setXRotation(modelWidget->xRot());
|
||||||
offlineRender->setYRotation(modelWidget->yRot());
|
offlineRender->setYRotation(modelWidget->yRot());
|
||||||
offlineRender->setZRotation(modelWidget->zRot());
|
offlineRender->setZRotation(modelWidget->zRot());
|
||||||
|
@ -52,6 +54,9 @@ void NormalAndDepthMapsGenerator::generate()
|
||||||
void NormalAndDepthMapsGenerator::process()
|
void NormalAndDepthMapsGenerator::process()
|
||||||
{
|
{
|
||||||
generate();
|
generate();
|
||||||
|
m_normalMapRender->setRenderThread(QGuiApplication::instance()->thread());
|
||||||
|
m_depthMapRender->setRenderThread(QGuiApplication::instance()->thread());
|
||||||
|
this->moveToThread(QGuiApplication::instance()->thread());
|
||||||
emit finished();
|
emit finished();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,15 +3,15 @@
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
#include "modelwidget.h"
|
#include "modelwidget.h"
|
||||||
#include "modelofflinerender.h"
|
#include "modeloffscreenrender.h"
|
||||||
#include "meshloader.h"
|
#include "model.h"
|
||||||
|
|
||||||
class NormalAndDepthMapsGenerator : public QObject
|
class NormalAndDepthMapsGenerator : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
NormalAndDepthMapsGenerator(ModelWidget *modelWidget);
|
NormalAndDepthMapsGenerator(ModelWidget *modelWidget);
|
||||||
void updateMesh(MeshLoader *mesh);
|
void updateMesh(Model *mesh);
|
||||||
void setRenderThread(QThread *thread);
|
void setRenderThread(QThread *thread);
|
||||||
~NormalAndDepthMapsGenerator();
|
~NormalAndDepthMapsGenerator();
|
||||||
QImage *takeNormalMap();
|
QImage *takeNormalMap();
|
||||||
|
@ -21,13 +21,13 @@ signals:
|
||||||
public slots:
|
public slots:
|
||||||
void process();
|
void process();
|
||||||
private:
|
private:
|
||||||
ModelOfflineRender *m_normalMapRender = nullptr;
|
ModelOffscreenRender *m_normalMapRender = nullptr;
|
||||||
ModelOfflineRender *m_depthMapRender = nullptr;
|
ModelOffscreenRender *m_depthMapRender = nullptr;
|
||||||
QSize m_viewPortSize;
|
QSize m_viewPortSize;
|
||||||
QImage *m_normalMap = nullptr;
|
QImage *m_normalMap = nullptr;
|
||||||
QImage *m_depthMap = nullptr;
|
QImage *m_depthMap = nullptr;
|
||||||
|
|
||||||
ModelOfflineRender *createOfflineRender(ModelWidget *modelWidget, int purpose);
|
ModelOffscreenRender *createOfflineRender(ModelWidget *modelWidget, int purpose);
|
||||||
void generate();
|
void generate();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -792,7 +792,7 @@ void PartWidget::updatePreview()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//m_previewLabel->setPixmap(QPixmap::fromImage(part->preview));
|
//m_previewLabel->setPixmap(QPixmap::fromImage(part->preview));
|
||||||
MeshLoader *previewMesh = part->takePreviewMesh();
|
Model *previewMesh = part->takePreviewMesh();
|
||||||
m_previewWidget->updateMesh(previewMesh);
|
m_previewWidget->updateMesh(previewMesh);
|
||||||
if (PartTarget::CutFace == part->target) {
|
if (PartTarget::CutFace == part->target) {
|
||||||
if (0 != m_previewWidget->xRot()) {
|
if (0 != m_previewWidget->xRot()) {
|
||||||
|
|
|
@ -16,9 +16,9 @@ PoseMeshCreator::~PoseMeshCreator()
|
||||||
delete m_resultMesh;
|
delete m_resultMesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
MeshLoader *PoseMeshCreator::takeResultMesh()
|
Model *PoseMeshCreator::takeResultMesh()
|
||||||
{
|
{
|
||||||
MeshLoader *resultMesh = m_resultMesh;
|
Model *resultMesh = m_resultMesh;
|
||||||
m_resultMesh = nullptr;
|
m_resultMesh = nullptr;
|
||||||
return resultMesh;
|
return resultMesh;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#ifndef DUST3D_POSE_MESH_CREATOR_H
|
#ifndef DUST3D_POSE_MESH_CREATOR_H
|
||||||
#define DUST3D_POSE_MESH_CREATOR_H
|
#define DUST3D_POSE_MESH_CREATOR_H
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include "meshloader.h"
|
#include "model.h"
|
||||||
#include "jointnodetree.h"
|
#include "jointnodetree.h"
|
||||||
#include "outcome.h"
|
#include "outcome.h"
|
||||||
|
|
||||||
|
@ -16,14 +16,14 @@ public:
|
||||||
const std::map<int, RiggerVertexWeights> &resultWeights);
|
const std::map<int, RiggerVertexWeights> &resultWeights);
|
||||||
~PoseMeshCreator();
|
~PoseMeshCreator();
|
||||||
void createMesh();
|
void createMesh();
|
||||||
MeshLoader *takeResultMesh();
|
Model *takeResultMesh();
|
||||||
public slots:
|
public slots:
|
||||||
void process();
|
void process();
|
||||||
private:
|
private:
|
||||||
std::vector<JointNode> m_resultNodes;
|
std::vector<JointNode> m_resultNodes;
|
||||||
Outcome m_outcome;
|
Outcome m_outcome;
|
||||||
std::map<int, RiggerVertexWeights> m_resultWeights;
|
std::map<int, RiggerVertexWeights> m_resultWeights;
|
||||||
MeshLoader *m_resultMesh = nullptr;
|
Model *m_resultMesh = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -37,11 +37,11 @@ bool PosePreviewManager::postUpdate(const Poser &poser,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
MeshLoader *PosePreviewManager::takeResultPreviewMesh()
|
Model *PosePreviewManager::takeResultPreviewMesh()
|
||||||
{
|
{
|
||||||
if (nullptr == m_previewMesh)
|
if (nullptr == m_previewMesh)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
return new MeshLoader(*m_previewMesh);
|
return new Model(*m_previewMesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PosePreviewManager::poseMeshReady()
|
void PosePreviewManager::poseMeshReady()
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
#include "document.h"
|
#include "document.h"
|
||||||
#include "poser.h"
|
#include "poser.h"
|
||||||
#include "posemeshcreator.h"
|
#include "posemeshcreator.h"
|
||||||
#include "meshloader.h"
|
#include "model.h"
|
||||||
|
|
||||||
class PosePreviewManager : public QObject
|
class PosePreviewManager : public QObject
|
||||||
{
|
{
|
||||||
|
@ -16,7 +16,7 @@ public:
|
||||||
bool postUpdate(const Poser &poser,
|
bool postUpdate(const Poser &poser,
|
||||||
const Outcome &outcome,
|
const Outcome &outcome,
|
||||||
const std::map<int, RiggerVertexWeights> &resultWeights);
|
const std::map<int, RiggerVertexWeights> &resultWeights);
|
||||||
MeshLoader *takeResultPreviewMesh();
|
Model *takeResultPreviewMesh();
|
||||||
private slots:
|
private slots:
|
||||||
void poseMeshReady();
|
void poseMeshReady();
|
||||||
signals:
|
signals:
|
||||||
|
@ -24,7 +24,7 @@ signals:
|
||||||
void renderDone();
|
void renderDone();
|
||||||
private:
|
private:
|
||||||
PoseMeshCreator *m_poseMeshCreator = nullptr;
|
PoseMeshCreator *m_poseMeshCreator = nullptr;
|
||||||
MeshLoader *m_previewMesh = nullptr;
|
Model *m_previewMesh = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -34,9 +34,9 @@ const std::set<std::pair<QUuid, int>> &PosePreviewsGenerator::generatedPreviewPo
|
||||||
return m_generatedPoseIdAndFrames;
|
return m_generatedPoseIdAndFrames;
|
||||||
}
|
}
|
||||||
|
|
||||||
MeshLoader *PosePreviewsGenerator::takePreview(std::pair<QUuid, int> idAndFrame)
|
Model *PosePreviewsGenerator::takePreview(std::pair<QUuid, int> idAndFrame)
|
||||||
{
|
{
|
||||||
MeshLoader *resultMesh = m_previews[idAndFrame];
|
Model *resultMesh = m_previews[idAndFrame];
|
||||||
m_previews[idAndFrame] = nullptr;
|
m_previews[idAndFrame] = nullptr;
|
||||||
return resultMesh;
|
return resultMesh;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <QUuid>
|
#include <QUuid>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "meshloader.h"
|
#include "model.h"
|
||||||
#include "rigger.h"
|
#include "rigger.h"
|
||||||
#include "outcome.h"
|
#include "outcome.h"
|
||||||
#include "rigtype.h"
|
#include "rigtype.h"
|
||||||
|
@ -20,7 +20,7 @@ public:
|
||||||
~PosePreviewsGenerator();
|
~PosePreviewsGenerator();
|
||||||
void addPose(std::pair<QUuid, int> idAndFrame, const std::map<QString, std::map<QString, QString>> &pose);
|
void addPose(std::pair<QUuid, int> idAndFrame, const std::map<QString, std::map<QString, QString>> &pose);
|
||||||
const std::set<std::pair<QUuid, int>> &generatedPreviewPoseIdAndFrames();
|
const std::set<std::pair<QUuid, int>> &generatedPreviewPoseIdAndFrames();
|
||||||
MeshLoader *takePreview(std::pair<QUuid, int> idAndFrame);
|
Model *takePreview(std::pair<QUuid, int> idAndFrame);
|
||||||
signals:
|
signals:
|
||||||
void finished();
|
void finished();
|
||||||
public slots:
|
public slots:
|
||||||
|
@ -31,7 +31,7 @@ private:
|
||||||
std::map<int, RiggerVertexWeights> m_rigWeights;
|
std::map<int, RiggerVertexWeights> m_rigWeights;
|
||||||
Outcome *m_outcome = nullptr;
|
Outcome *m_outcome = nullptr;
|
||||||
std::vector<std::pair<std::pair<QUuid, int>, std::map<QString, std::map<QString, QString>>>> m_poses;
|
std::vector<std::pair<std::pair<QUuid, int>, std::map<QString, std::map<QString, QString>>>> m_poses;
|
||||||
std::map<std::pair<QUuid, int>, MeshLoader *> m_previews;
|
std::map<std::pair<QUuid, int>, Model *> m_previews;
|
||||||
std::set<std::pair<QUuid, int>> m_generatedPoseIdAndFrames;
|
std::set<std::pair<QUuid, int>> m_generatedPoseIdAndFrames;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -82,7 +82,7 @@ void PoseWidget::updatePreview()
|
||||||
qDebug() << "Pose not found:" << m_poseId;
|
qDebug() << "Pose not found:" << m_poseId;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
MeshLoader *previewMesh = pose->takePreviewMesh();
|
Model *previewMesh = pose->takePreviewMesh();
|
||||||
m_previewWidget->updateMesh(previewMesh);
|
m_previewWidget->updateMesh(previewMesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -94,16 +94,16 @@ std::map<int, RiggerVertexWeights> *RigGenerator::takeResultWeights()
|
||||||
return resultWeights;
|
return resultWeights;
|
||||||
}
|
}
|
||||||
|
|
||||||
MeshLoader *RigGenerator::takeResultMesh()
|
Model *RigGenerator::takeResultMesh()
|
||||||
{
|
{
|
||||||
MeshLoader *resultMesh = m_resultMesh;
|
Model *resultMesh = m_resultMesh;
|
||||||
m_resultMesh = nullptr;
|
m_resultMesh = nullptr;
|
||||||
return resultMesh;
|
return resultMesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RigGenerator::isSucceed()
|
bool RigGenerator::isSuccessful()
|
||||||
{
|
{
|
||||||
return m_isSucceed;
|
return m_isSuccessful;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<std::pair<QtMsgType, QString>> &RigGenerator::messages()
|
const std::vector<std::pair<QtMsgType, QString>> &RigGenerator::messages()
|
||||||
|
@ -603,7 +603,7 @@ void RigGenerator::buildSkeleton()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_isSucceed = true;
|
m_isSuccessful = true;
|
||||||
|
|
||||||
//for (size_t i = 0; i < m_resultBones->size(); ++i) {
|
//for (size_t i = 0; i < m_resultBones->size(); ++i) {
|
||||||
// const auto &bone = (*m_resultBones)[i];
|
// const auto &bone = (*m_resultBones)[i];
|
||||||
|
@ -617,7 +617,7 @@ void RigGenerator::buildSkeleton()
|
||||||
|
|
||||||
void RigGenerator::computeSkinWeights()
|
void RigGenerator::computeSkinWeights()
|
||||||
{
|
{
|
||||||
if (!m_isSucceed)
|
if (!m_isSuccessful)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto collectNodeIndices = [&](size_t chainIndex,
|
auto collectNodeIndices = [&](size_t chainIndex,
|
||||||
|
@ -1026,7 +1026,7 @@ void RigGenerator::buildDemoMesh()
|
||||||
// Blend vertices colors according to bone weights
|
// Blend vertices colors according to bone weights
|
||||||
|
|
||||||
std::vector<QColor> inputVerticesColors(m_outcome->vertices.size(), Qt::black);
|
std::vector<QColor> inputVerticesColors(m_outcome->vertices.size(), Qt::black);
|
||||||
if (m_isSucceed) {
|
if (m_isSuccessful) {
|
||||||
const auto &resultWeights = *m_resultWeights;
|
const auto &resultWeights = *m_resultWeights;
|
||||||
const auto &resultBones = *m_resultBones;
|
const auto &resultBones = *m_resultBones;
|
||||||
|
|
||||||
|
@ -1060,7 +1060,7 @@ void RigGenerator::buildDemoMesh()
|
||||||
|
|
||||||
ShaderVertex *triangleVertices = nullptr;
|
ShaderVertex *triangleVertices = nullptr;
|
||||||
int triangleVerticesNum = 0;
|
int triangleVerticesNum = 0;
|
||||||
if (m_isSucceed) {
|
if (m_isSuccessful) {
|
||||||
triangleVertices = new ShaderVertex[m_outcome->triangles.size() * 3];
|
triangleVertices = new ShaderVertex[m_outcome->triangles.size() * 3];
|
||||||
const QVector3D defaultUv = QVector3D(0, 0, 0);
|
const QVector3D defaultUv = QVector3D(0, 0, 0);
|
||||||
const QVector3D defaultTangents = QVector3D(0, 0, 0);
|
const QVector3D defaultTangents = QVector3D(0, 0, 0);
|
||||||
|
@ -1087,8 +1087,8 @@ void RigGenerator::buildDemoMesh()
|
||||||
currentVertex.normX = sourceNormal->x();
|
currentVertex.normX = sourceNormal->x();
|
||||||
currentVertex.normY = sourceNormal->y();
|
currentVertex.normY = sourceNormal->y();
|
||||||
currentVertex.normZ = sourceNormal->z();
|
currentVertex.normZ = sourceNormal->z();
|
||||||
currentVertex.metalness = MeshLoader::m_defaultMetalness;
|
currentVertex.metalness = Model::m_defaultMetalness;
|
||||||
currentVertex.roughness = MeshLoader::m_defaultRoughness;
|
currentVertex.roughness = Model::m_defaultRoughness;
|
||||||
currentVertex.tangentX = sourceTangent->x();
|
currentVertex.tangentX = sourceTangent->x();
|
||||||
currentVertex.tangentY = sourceTangent->y();
|
currentVertex.tangentY = sourceTangent->y();
|
||||||
currentVertex.tangentZ = sourceTangent->z();
|
currentVertex.tangentZ = sourceTangent->z();
|
||||||
|
@ -1101,7 +1101,7 @@ void RigGenerator::buildDemoMesh()
|
||||||
ShaderVertex *edgeVertices = nullptr;
|
ShaderVertex *edgeVertices = nullptr;
|
||||||
int edgeVerticesNum = 0;
|
int edgeVerticesNum = 0;
|
||||||
|
|
||||||
if (m_isSucceed) {
|
if (m_isSuccessful) {
|
||||||
const auto &resultBones = *m_resultBones;
|
const auto &resultBones = *m_resultBones;
|
||||||
std::vector<std::tuple<QVector3D, QVector3D, float, float, QColor>> boxes;
|
std::vector<std::tuple<QVector3D, QVector3D, float, float, QColor>> boxes;
|
||||||
for (const auto &bone: resultBones) {
|
for (const auto &bone: resultBones) {
|
||||||
|
@ -1122,7 +1122,7 @@ void RigGenerator::buildDemoMesh()
|
||||||
m_debugEdgeVerticesNum = 0;
|
m_debugEdgeVerticesNum = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_resultMesh = new MeshLoader(triangleVertices, triangleVerticesNum,
|
m_resultMesh = new Model(triangleVertices, triangleVerticesNum,
|
||||||
edgeVertices, edgeVerticesNum);
|
edgeVertices, edgeVerticesNum);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
#include "outcome.h"
|
#include "outcome.h"
|
||||||
#include "meshloader.h"
|
#include "model.h"
|
||||||
#include "rigger.h"
|
#include "rigger.h"
|
||||||
#include "rigtype.h"
|
#include "rigtype.h"
|
||||||
|
|
||||||
|
@ -15,12 +15,12 @@ class RigGenerator : public QObject
|
||||||
public:
|
public:
|
||||||
RigGenerator(RigType rigType, const Outcome &outcome);
|
RigGenerator(RigType rigType, const Outcome &outcome);
|
||||||
~RigGenerator();
|
~RigGenerator();
|
||||||
MeshLoader *takeResultMesh();
|
Model *takeResultMesh();
|
||||||
std::vector<RiggerBone> *takeResultBones();
|
std::vector<RiggerBone> *takeResultBones();
|
||||||
std::map<int, RiggerVertexWeights> *takeResultWeights();
|
std::map<int, RiggerVertexWeights> *takeResultWeights();
|
||||||
const std::vector<std::pair<QtMsgType, QString>> &messages();
|
const std::vector<std::pair<QtMsgType, QString>> &messages();
|
||||||
Outcome *takeOutcome();
|
Outcome *takeOutcome();
|
||||||
bool isSucceed();
|
bool isSuccessful();
|
||||||
void generate();
|
void generate();
|
||||||
signals:
|
signals:
|
||||||
void finished();
|
void finished();
|
||||||
|
@ -37,7 +37,7 @@ private:
|
||||||
|
|
||||||
RigType m_rigType = RigType::None;
|
RigType m_rigType = RigType::None;
|
||||||
Outcome *m_outcome = nullptr;
|
Outcome *m_outcome = nullptr;
|
||||||
MeshLoader *m_resultMesh = nullptr;
|
Model *m_resultMesh = nullptr;
|
||||||
std::vector<RiggerBone> *m_resultBones = nullptr;
|
std::vector<RiggerBone> *m_resultBones = nullptr;
|
||||||
std::map<int, RiggerVertexWeights> *m_resultWeights = nullptr;
|
std::map<int, RiggerVertexWeights> *m_resultWeights = nullptr;
|
||||||
std::vector<std::pair<QtMsgType, QString>> m_messages;
|
std::vector<std::pair<QtMsgType, QString>> m_messages;
|
||||||
|
@ -61,7 +61,7 @@ private:
|
||||||
ShaderVertex *m_debugEdgeVertices = nullptr;
|
ShaderVertex *m_debugEdgeVertices = nullptr;
|
||||||
int m_debugEdgeVerticesNum = 0;
|
int m_debugEdgeVerticesNum = 0;
|
||||||
bool m_isSpineVertical = false;
|
bool m_isSpineVertical = false;
|
||||||
bool m_isSucceed = false;
|
bool m_isSuccessful = false;
|
||||||
void buildNeighborMap();
|
void buildNeighborMap();
|
||||||
void buildBoneNodeChain();
|
void buildBoneNodeChain();
|
||||||
void buildSkeleton();
|
void buildSkeleton();
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
|
||||||
#ifndef DUST3D_SKELETON_DOCUMENT_H
|
#ifndef DUST3D_SKELETON_DOCUMENT_H
|
||||||
#define DUST3D_SKELETON_DOCUMENT_H
|
#define DUST3D_SKELETON_DOCUMENT_H
|
||||||
#include <QUuid>
|
#include <QUuid>
|
||||||
|
@ -8,7 +9,7 @@
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
#include "bonemark.h"
|
#include "bonemark.h"
|
||||||
#include "theme.h"
|
#include "theme.h"
|
||||||
#include "meshloader.h"
|
#include "model.h"
|
||||||
#include "cutface.h"
|
#include "cutface.h"
|
||||||
#include "parttarget.h"
|
#include "parttarget.h"
|
||||||
#include "partbase.h"
|
#include "partbase.h"
|
||||||
|
@ -181,6 +182,7 @@ public:
|
||||||
float hollowThickness;
|
float hollowThickness;
|
||||||
bool countershaded;
|
bool countershaded;
|
||||||
bool gridded;
|
bool gridded;
|
||||||
|
QUuid fillMeshLinkedId;
|
||||||
SkeletonPart(const QUuid &withId=QUuid()) :
|
SkeletonPart(const QUuid &withId=QUuid()) :
|
||||||
visible(true),
|
visible(true),
|
||||||
locked(false),
|
locked(false),
|
||||||
|
@ -318,20 +320,20 @@ public:
|
||||||
colorSolubility = other.colorSolubility;
|
colorSolubility = other.colorSolubility;
|
||||||
countershaded = other.countershaded;
|
countershaded = other.countershaded;
|
||||||
}
|
}
|
||||||
void updatePreviewMesh(MeshLoader *previewMesh)
|
void updatePreviewMesh(Model *previewMesh)
|
||||||
{
|
{
|
||||||
delete m_previewMesh;
|
delete m_previewMesh;
|
||||||
m_previewMesh = previewMesh;
|
m_previewMesh = previewMesh;
|
||||||
}
|
}
|
||||||
MeshLoader *takePreviewMesh() const
|
Model *takePreviewMesh() const
|
||||||
{
|
{
|
||||||
if (nullptr == m_previewMesh)
|
if (nullptr == m_previewMesh)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
return new MeshLoader(*m_previewMesh);
|
return new Model(*m_previewMesh);
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
Q_DISABLE_COPY(SkeletonPart);
|
Q_DISABLE_COPY(SkeletonPart);
|
||||||
MeshLoader *m_previewMesh = nullptr;
|
Model *m_previewMesh = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class SkeletonDocumentEditMode
|
enum class SkeletonDocumentEditMode
|
||||||
|
|
|
@ -193,6 +193,12 @@ void SkeletonGraphicsWidget::showContextMenu(const QPoint &pos)
|
||||||
contextMenu.addAction(&breakAction);
|
contextMenu.addAction(&breakAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QAction reverseAction(tr("Reverse"), this);
|
||||||
|
if (!m_nodePositionModifyOnly && hasEdgeSelection()) {
|
||||||
|
connect(&reverseAction, &QAction::triggered, this, &SkeletonGraphicsWidget::reverseSelectedEdges);
|
||||||
|
contextMenu.addAction(&reverseAction);
|
||||||
|
}
|
||||||
|
|
||||||
QAction connectAction(tr("Connect"), this);
|
QAction connectAction(tr("Connect"), this);
|
||||||
if (!m_nodePositionModifyOnly && hasTwoDisconnectedNodesSelection()) {
|
if (!m_nodePositionModifyOnly && hasTwoDisconnectedNodesSelection()) {
|
||||||
connect(&connectAction, &QAction::triggered, this, &SkeletonGraphicsWidget::connectSelected);
|
connect(&connectAction, &QAction::triggered, this, &SkeletonGraphicsWidget::connectSelected);
|
||||||
|
@ -521,6 +527,23 @@ void SkeletonGraphicsWidget::breakSelected()
|
||||||
emit groupOperationAdded();
|
emit groupOperationAdded();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SkeletonGraphicsWidget::reverseSelectedEdges()
|
||||||
|
{
|
||||||
|
std::set<QUuid> edgeIds;
|
||||||
|
for (const auto &it: m_rangeSelectionSet) {
|
||||||
|
if (it->data(0) == "edge")
|
||||||
|
edgeIds.insert(((SkeletonGraphicsEdgeItem *)it)->id());
|
||||||
|
}
|
||||||
|
if (edgeIds.empty())
|
||||||
|
return;
|
||||||
|
emit batchChangeBegin();
|
||||||
|
for (const auto &it: edgeIds) {
|
||||||
|
emit reverseEdge(it);
|
||||||
|
}
|
||||||
|
emit batchChangeEnd();
|
||||||
|
emit groupOperationAdded();
|
||||||
|
}
|
||||||
|
|
||||||
void SkeletonGraphicsWidget::connectSelected()
|
void SkeletonGraphicsWidget::connectSelected()
|
||||||
{
|
{
|
||||||
std::vector<QUuid> nodeIds;
|
std::vector<QUuid> nodeIds;
|
||||||
|
@ -2102,6 +2125,22 @@ void SkeletonGraphicsWidget::nodeAdded(QUuid nodeId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SkeletonGraphicsWidget::edgeReversed(QUuid edgeId)
|
||||||
|
{
|
||||||
|
const SkeletonEdge *edge = m_document->findEdge(edgeId);
|
||||||
|
if (nullptr == edge) {
|
||||||
|
qDebug() << "Edge changed but edge id not exist:" << edgeId;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto edgeItemIt = edgeItemMap.find(edgeId);
|
||||||
|
if (edgeItemIt == edgeItemMap.end()) {
|
||||||
|
qDebug() << "Edge removed but edge id not exist:" << edgeId;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
edgeItemIt->second.first->reverse();
|
||||||
|
edgeItemIt->second.second->reverse();
|
||||||
|
}
|
||||||
|
|
||||||
void SkeletonGraphicsWidget::edgeAdded(QUuid edgeId)
|
void SkeletonGraphicsWidget::edgeAdded(QUuid edgeId)
|
||||||
{
|
{
|
||||||
const SkeletonEdge *edge = m_document->findEdge(edgeId);
|
const SkeletonEdge *edge = m_document->findEdge(edgeId);
|
||||||
|
@ -2257,10 +2296,6 @@ void SkeletonGraphicsWidget::nodeOriginChanged(QUuid nodeId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkeletonGraphicsWidget::edgeChanged(QUuid edgeId)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void SkeletonGraphicsWidget::partVisibleStateChanged(QUuid partId)
|
void SkeletonGraphicsWidget::partVisibleStateChanged(QUuid partId)
|
||||||
{
|
{
|
||||||
const SkeletonPart *part = m_document->findPart(partId);
|
const SkeletonPart *part = m_document->findPart(partId);
|
||||||
|
|
|
@ -429,6 +429,11 @@ public:
|
||||||
m_deactivated = deactivated;
|
m_deactivated = deactivated;
|
||||||
updateAppearance();
|
updateAppearance();
|
||||||
}
|
}
|
||||||
|
void reverse()
|
||||||
|
{
|
||||||
|
std::swap(m_firstItem, m_secondItem);
|
||||||
|
updateAppearance();
|
||||||
|
}
|
||||||
bool deactivated()
|
bool deactivated()
|
||||||
{
|
{
|
||||||
return m_deactivated;
|
return m_deactivated;
|
||||||
|
@ -477,6 +482,7 @@ signals:
|
||||||
void open();
|
void open();
|
||||||
void exportResult();
|
void exportResult();
|
||||||
void breakEdge(QUuid edgeId);
|
void breakEdge(QUuid edgeId);
|
||||||
|
void reverseEdge(QUuid edgeId);
|
||||||
void moveOriginBy(float x, float y, float z);
|
void moveOriginBy(float x, float y, float z);
|
||||||
void partChecked(QUuid partId);
|
void partChecked(QUuid partId);
|
||||||
void partUnchecked(QUuid partId);
|
void partUnchecked(QUuid partId);
|
||||||
|
@ -555,7 +561,7 @@ public slots:
|
||||||
void nodeRadiusChanged(QUuid nodeId);
|
void nodeRadiusChanged(QUuid nodeId);
|
||||||
void nodeBoneMarkChanged(QUuid nodeId);
|
void nodeBoneMarkChanged(QUuid nodeId);
|
||||||
void nodeOriginChanged(QUuid nodeId);
|
void nodeOriginChanged(QUuid nodeId);
|
||||||
void edgeChanged(QUuid edgeId);
|
void edgeReversed(QUuid edgeId);
|
||||||
void turnaroundChanged();
|
void turnaroundChanged();
|
||||||
void canvasResized();
|
void canvasResized();
|
||||||
void editModeChanged();
|
void editModeChanged();
|
||||||
|
@ -580,6 +586,7 @@ public slots:
|
||||||
void fadeSelected();
|
void fadeSelected();
|
||||||
void colorizeSelected();
|
void colorizeSelected();
|
||||||
void breakSelected();
|
void breakSelected();
|
||||||
|
void reverseSelectedEdges();
|
||||||
void connectSelected();
|
void connectSelected();
|
||||||
void rotateSelected(int degree);
|
void rotateSelected(int degree);
|
||||||
void zoomSelected(float delta);
|
void zoomSelected(float delta);
|
||||||
|
|
|
@ -36,7 +36,7 @@ SkinnedMeshCreator::SkinnedMeshCreator(const Outcome &outcome,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MeshLoader *SkinnedMeshCreator::createMeshFromTransform(const std::vector<QMatrix4x4> &matricies)
|
Model *SkinnedMeshCreator::createMeshFromTransform(const std::vector<QMatrix4x4> &matricies)
|
||||||
{
|
{
|
||||||
std::vector<std::vector<QVector3D>> transformedPositions = m_verticesBindPositions;
|
std::vector<std::vector<QVector3D>> transformedPositions = m_verticesBindPositions;
|
||||||
std::vector<std::vector<QVector3D>> transformedPoseNormals = m_verticesBindNormals;
|
std::vector<std::vector<QVector3D>> transformedPoseNormals = m_verticesBindNormals;
|
||||||
|
@ -78,10 +78,10 @@ MeshLoader *SkinnedMeshCreator::createMeshFromTransform(const std::vector<QMatri
|
||||||
currentVertex.normX = sourceNormal.x();
|
currentVertex.normX = sourceNormal.x();
|
||||||
currentVertex.normY = sourceNormal.y();
|
currentVertex.normY = sourceNormal.y();
|
||||||
currentVertex.normZ = sourceNormal.z();
|
currentVertex.normZ = sourceNormal.z();
|
||||||
currentVertex.metalness = MeshLoader::m_defaultMetalness;
|
currentVertex.metalness = Model::m_defaultMetalness;
|
||||||
currentVertex.roughness = MeshLoader::m_defaultRoughness;
|
currentVertex.roughness = Model::m_defaultRoughness;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new MeshLoader(triangleVertices, triangleVerticesNum);
|
return new Model(triangleVertices, triangleVerticesNum);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <QVector3D>
|
#include <QVector3D>
|
||||||
#include <QColor>
|
#include <QColor>
|
||||||
#include "meshloader.h"
|
#include "model.h"
|
||||||
#include "outcome.h"
|
#include "outcome.h"
|
||||||
#include "jointnodetree.h"
|
#include "jointnodetree.h"
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ class SkinnedMeshCreator
|
||||||
public:
|
public:
|
||||||
SkinnedMeshCreator(const Outcome &outcome,
|
SkinnedMeshCreator(const Outcome &outcome,
|
||||||
const std::map<int, RiggerVertexWeights> &resultWeights);
|
const std::map<int, RiggerVertexWeights> &resultWeights);
|
||||||
MeshLoader *createMeshFromTransform(const std::vector<QMatrix4x4> &matricies);
|
Model *createMeshFromTransform(const std::vector<QMatrix4x4> &matricies);
|
||||||
private:
|
private:
|
||||||
Outcome m_outcome;
|
Outcome m_outcome;
|
||||||
std::map<int, RiggerVertexWeights> m_resultWeights;
|
std::map<int, RiggerVertexWeights> m_resultWeights;
|
||||||
|
|
|
@ -194,7 +194,7 @@ void saveSkeletonToXmlStream(Snapshot *snapshot, QXmlStreamWriter *writer)
|
||||||
writer->writeEndDocument();
|
writer->writeEndDocument();
|
||||||
}
|
}
|
||||||
|
|
||||||
void loadSkeletonFromXmlStream(Snapshot *snapshot, QXmlStreamReader &reader)
|
void loadSkeletonFromXmlStream(Snapshot *snapshot, QXmlStreamReader &reader, quint32 flags)
|
||||||
{
|
{
|
||||||
std::stack<QString> componentStack;
|
std::stack<QString> componentStack;
|
||||||
std::vector<QString> elementNameStack;
|
std::vector<QString> elementNameStack;
|
||||||
|
@ -223,46 +223,56 @@ void loadSkeletonFromXmlStream(Snapshot *snapshot, QXmlStreamReader &reader)
|
||||||
//qDebug() << (reader.isStartElement() ? "<" : ">") << "fullName:" << fullName << "baseName:" << baseName;
|
//qDebug() << (reader.isStartElement() ? "<" : ">") << "fullName:" << fullName << "baseName:" << baseName;
|
||||||
if (reader.isStartElement()) {
|
if (reader.isStartElement()) {
|
||||||
if (fullName == "canvas") {
|
if (fullName == "canvas") {
|
||||||
foreach(const QXmlStreamAttribute &attr, reader.attributes()) {
|
if (flags & SNAPSHOT_ITEM_CANVAS) {
|
||||||
snapshot->canvas[attr.name().toString()] = attr.value().toString();
|
foreach(const QXmlStreamAttribute &attr, reader.attributes()) {
|
||||||
|
snapshot->canvas[attr.name().toString()] = attr.value().toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (fullName == "canvas.nodes.node") {
|
} else if (fullName == "canvas.nodes.node") {
|
||||||
QString nodeId = reader.attributes().value("id").toString();
|
QString nodeId = reader.attributes().value("id").toString();
|
||||||
if (nodeId.isEmpty())
|
if (nodeId.isEmpty())
|
||||||
continue;
|
continue;
|
||||||
std::map<QString, QString> *nodeMap = &snapshot->nodes[nodeId];
|
if (flags & SNAPSHOT_ITEM_COMPONENT) {
|
||||||
foreach(const QXmlStreamAttribute &attr, reader.attributes()) {
|
std::map<QString, QString> *nodeMap = &snapshot->nodes[nodeId];
|
||||||
(*nodeMap)[attr.name().toString()] = attr.value().toString();
|
foreach(const QXmlStreamAttribute &attr, reader.attributes()) {
|
||||||
|
(*nodeMap)[attr.name().toString()] = attr.value().toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (fullName == "canvas.edges.edge") {
|
} else if (fullName == "canvas.edges.edge") {
|
||||||
QString edgeId = reader.attributes().value("id").toString();
|
QString edgeId = reader.attributes().value("id").toString();
|
||||||
if (edgeId.isEmpty())
|
if (edgeId.isEmpty())
|
||||||
continue;
|
continue;
|
||||||
std::map<QString, QString> *edgeMap = &snapshot->edges[edgeId];
|
if (flags & SNAPSHOT_ITEM_COMPONENT) {
|
||||||
foreach(const QXmlStreamAttribute &attr, reader.attributes()) {
|
std::map<QString, QString> *edgeMap = &snapshot->edges[edgeId];
|
||||||
(*edgeMap)[attr.name().toString()] = attr.value().toString();
|
foreach(const QXmlStreamAttribute &attr, reader.attributes()) {
|
||||||
|
(*edgeMap)[attr.name().toString()] = attr.value().toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (fullName == "canvas.parts.part") {
|
} else if (fullName == "canvas.parts.part") {
|
||||||
QString partId = reader.attributes().value("id").toString();
|
QString partId = reader.attributes().value("id").toString();
|
||||||
if (partId.isEmpty())
|
if (partId.isEmpty())
|
||||||
continue;
|
continue;
|
||||||
std::map<QString, QString> *partMap = &snapshot->parts[partId];
|
if (flags & SNAPSHOT_ITEM_COMPONENT) {
|
||||||
foreach(const QXmlStreamAttribute &attr, reader.attributes()) {
|
std::map<QString, QString> *partMap = &snapshot->parts[partId];
|
||||||
(*partMap)[attr.name().toString()] = attr.value().toString();
|
foreach(const QXmlStreamAttribute &attr, reader.attributes()) {
|
||||||
|
(*partMap)[attr.name().toString()] = attr.value().toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (fullName == "canvas.partIdList.partId") {
|
} else if (fullName == "canvas.partIdList.partId") {
|
||||||
QString partId = reader.attributes().value("id").toString();
|
QString partId = reader.attributes().value("id").toString();
|
||||||
if (partId.isEmpty())
|
if (partId.isEmpty())
|
||||||
continue;
|
continue;
|
||||||
QString componentId = QUuid::createUuid().toString();
|
if (flags & SNAPSHOT_ITEM_COMPONENT) {
|
||||||
auto &component = snapshot->components[componentId];
|
QString componentId = QUuid::createUuid().toString();
|
||||||
component["id"] = componentId;
|
auto &component = snapshot->components[componentId];
|
||||||
component["linkData"] = partId;
|
component["id"] = componentId;
|
||||||
component["linkDataType"] = "partId";
|
component["linkData"] = partId;
|
||||||
auto &childrenIds = snapshot->rootComponent["children"];
|
component["linkDataType"] = "partId";
|
||||||
if (!childrenIds.isEmpty())
|
auto &childrenIds = snapshot->rootComponent["children"];
|
||||||
childrenIds += ",";
|
if (!childrenIds.isEmpty())
|
||||||
childrenIds += componentId;
|
childrenIds += ",";
|
||||||
|
childrenIds += componentId;
|
||||||
|
}
|
||||||
} else if (fullName.startsWith("canvas.components.component")) {
|
} else if (fullName.startsWith("canvas.components.component")) {
|
||||||
QString componentId = reader.attributes().value("id").toString();
|
QString componentId = reader.attributes().value("id").toString();
|
||||||
QString parentId;
|
QString parentId;
|
||||||
|
@ -271,14 +281,16 @@ void loadSkeletonFromXmlStream(Snapshot *snapshot, QXmlStreamReader &reader)
|
||||||
componentStack.push(componentId);
|
componentStack.push(componentId);
|
||||||
if (componentId.isEmpty())
|
if (componentId.isEmpty())
|
||||||
continue;
|
continue;
|
||||||
std::map<QString, QString> *componentMap = &snapshot->components[componentId];
|
if (flags & SNAPSHOT_ITEM_COMPONENT) {
|
||||||
foreach(const QXmlStreamAttribute &attr, reader.attributes()) {
|
std::map<QString, QString> *componentMap = &snapshot->components[componentId];
|
||||||
(*componentMap)[attr.name().toString()] = attr.value().toString();
|
foreach(const QXmlStreamAttribute &attr, reader.attributes()) {
|
||||||
|
(*componentMap)[attr.name().toString()] = attr.value().toString();
|
||||||
|
}
|
||||||
|
auto &parentChildrenIds = parentId.isEmpty() ? snapshot->rootComponent["children"] : snapshot->components[parentId]["children"];
|
||||||
|
if (!parentChildrenIds.isEmpty())
|
||||||
|
parentChildrenIds += ",";
|
||||||
|
parentChildrenIds += componentId;
|
||||||
}
|
}
|
||||||
auto &parentChildrenIds = parentId.isEmpty() ? snapshot->rootComponent["children"] : snapshot->components[parentId]["children"];
|
|
||||||
if (!parentChildrenIds.isEmpty())
|
|
||||||
parentChildrenIds += ",";
|
|
||||||
parentChildrenIds += componentId;
|
|
||||||
} else if (fullName == "canvas.materials.material.layers.layer") {
|
} else if (fullName == "canvas.materials.material.layers.layer") {
|
||||||
currentMaterialLayer = decltype(currentMaterialLayer)();
|
currentMaterialLayer = decltype(currentMaterialLayer)();
|
||||||
foreach(const QXmlStreamAttribute &attr, reader.attributes()) {
|
foreach(const QXmlStreamAttribute &attr, reader.attributes()) {
|
||||||
|
@ -340,13 +352,19 @@ void loadSkeletonFromXmlStream(Snapshot *snapshot, QXmlStreamReader &reader)
|
||||||
} else if (fullName == "canvas.materials.material.layers.layer") {
|
} else if (fullName == "canvas.materials.material.layers.layer") {
|
||||||
currentMaterial.second.push_back(currentMaterialLayer);
|
currentMaterial.second.push_back(currentMaterialLayer);
|
||||||
} else if (fullName == "canvas.materials.material") {
|
} else if (fullName == "canvas.materials.material") {
|
||||||
snapshot->materials.push_back(currentMaterial);
|
if (flags & SNAPSHOT_ITEM_MATERIAL) {
|
||||||
|
snapshot->materials.push_back(currentMaterial);
|
||||||
|
}
|
||||||
} else if (fullName == "canvas.poses.pose.frames.frame") {
|
} else if (fullName == "canvas.poses.pose.frames.frame") {
|
||||||
currentPose.second.push_back(currentPoseFrame);
|
currentPose.second.push_back(currentPoseFrame);
|
||||||
} else if (fullName == "canvas.poses.pose") {
|
} else if (fullName == "canvas.poses.pose") {
|
||||||
snapshot->poses.push_back(currentPose);
|
if (flags & SNAPSHOT_ITEM_POSE) {
|
||||||
|
snapshot->poses.push_back(currentPose);
|
||||||
|
}
|
||||||
} else if (fullName == "canvas.motions.motion") {
|
} else if (fullName == "canvas.motions.motion") {
|
||||||
snapshot->motions.push_back(currentMotion);
|
if (flags & SNAPSHOT_ITEM_MOTION) {
|
||||||
|
snapshot->motions.push_back(currentMotion);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,21 @@
|
||||||
#include <QXmlStreamWriter>
|
#include <QXmlStreamWriter>
|
||||||
#include "snapshot.h"
|
#include "snapshot.h"
|
||||||
|
|
||||||
|
#define SNAPSHOT_ITEM_CANVAS 0x00000001
|
||||||
|
#define SNAPSHOT_ITEM_COMPONENT 0x00000002
|
||||||
|
#define SNAPSHOT_ITEM_MATERIAL 0x00000004
|
||||||
|
#define SNAPSHOT_ITEM_POSE 0x00000008
|
||||||
|
#define SNAPSHOT_ITEM_MOTION 0x00000010
|
||||||
|
#define SNAPSHOT_ITEM_ALL ( \
|
||||||
|
SNAPSHOT_ITEM_CANVAS | \
|
||||||
|
SNAPSHOT_ITEM_COMPONENT | \
|
||||||
|
SNAPSHOT_ITEM_MATERIAL | \
|
||||||
|
SNAPSHOT_ITEM_POSE | \
|
||||||
|
SNAPSHOT_ITEM_MOTION \
|
||||||
|
)
|
||||||
|
|
||||||
void saveSkeletonToXmlStream(Snapshot *snapshot, QXmlStreamWriter *writer);
|
void saveSkeletonToXmlStream(Snapshot *snapshot, QXmlStreamWriter *writer);
|
||||||
void loadSkeletonFromXmlStream(Snapshot *snapshot, QXmlStreamReader &reader);
|
void loadSkeletonFromXmlStream(Snapshot *snapshot, QXmlStreamReader &reader,
|
||||||
|
quint32 flags=SNAPSHOT_ITEM_ALL);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,5 +1,5 @@
|
||||||
#ifndef DUST3D_BUILDER_H
|
#ifndef DUST3D_STOKE_MESH_BUILDER_H
|
||||||
#define DUST3D_BUILDER_H
|
#define DUST3D_STOKE_MESH_BUILDER_H
|
||||||
#include <QVector3D>
|
#include <QVector3D>
|
||||||
#include <QVector2D>
|
#include <QVector2D>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -22,8 +22,28 @@ public:
|
||||||
bool reverse = false;
|
bool reverse = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Node
|
||||||
|
{
|
||||||
|
float radius;
|
||||||
|
QVector3D position;
|
||||||
|
std::vector<QVector2D> cutTemplate;
|
||||||
|
float cutRotation;
|
||||||
|
int nearOriginNodeIndex = -1;
|
||||||
|
int farOriginNodeIndex = -1;
|
||||||
|
|
||||||
|
size_t index;
|
||||||
|
std::vector<size_t> neighbors;
|
||||||
|
size_t next;
|
||||||
|
QVector3D cutNormal;
|
||||||
|
QVector3D traverseDirection;
|
||||||
|
QVector3D baseNormal;
|
||||||
|
size_t traverseOrder;
|
||||||
|
|
||||||
|
size_t nextOrNeighborOtherThan(size_t neighborIndex) const;
|
||||||
|
};
|
||||||
|
|
||||||
size_t addNode(const QVector3D &position, float radius, const std::vector<QVector2D> &cutTemplate, float cutRotation);
|
size_t addNode(const QVector3D &position, float radius, const std::vector<QVector2D> &cutTemplate, float cutRotation);
|
||||||
size_t addEdge(size_t firstNodeIndex, size_t secondNodeIndex);
|
void addEdge(size_t firstNodeIndex, size_t secondNodeIndex);
|
||||||
void setNodeOriginInfo(size_t nodeIndex, int nearOriginNodeIndex, int farOriginNodeIndex);
|
void setNodeOriginInfo(size_t nodeIndex, int nearOriginNodeIndex, int farOriginNodeIndex);
|
||||||
void setDeformThickness(float thickness);
|
void setDeformThickness(float thickness);
|
||||||
void setDeformWidth(float width);
|
void setDeformWidth(float width);
|
||||||
|
@ -34,78 +54,18 @@ public:
|
||||||
void enableBaseNormalOnY(bool enabled);
|
void enableBaseNormalOnY(bool enabled);
|
||||||
void enableBaseNormalOnZ(bool enabled);
|
void enableBaseNormalOnZ(bool enabled);
|
||||||
void enableBaseNormalAverage(bool enabled);
|
void enableBaseNormalAverage(bool enabled);
|
||||||
const std::vector<QVector3D> &generatedVertices();
|
bool buildBaseNormalsOnly();
|
||||||
const std::vector<std::vector<size_t>> &generatedFaces();
|
const std::vector<Node> &nodes() const;
|
||||||
const std::vector<size_t> &generatedVerticesSourceNodeIndices();
|
const std::vector<size_t> &nodeIndices() const;
|
||||||
void exportAsObj(const QString &filename);
|
|
||||||
bool build();
|
|
||||||
const CutFaceTransform *nodeAdjustableCutFaceTransform(size_t nodeIndex);
|
|
||||||
const QVector3D &nodeTraverseDirection(size_t nodeIndex) const;
|
const QVector3D &nodeTraverseDirection(size_t nodeIndex) const;
|
||||||
const QVector3D &nodeBaseNormal(size_t nodeIndex) const;
|
const QVector3D &nodeBaseNormal(size_t nodeIndex) const;
|
||||||
size_t nodeTraverseOrder(size_t nodeIndex) const;
|
size_t nodeTraverseOrder(size_t nodeIndex) const;
|
||||||
|
bool build();
|
||||||
|
const std::vector<QVector3D> &generatedVertices();
|
||||||
|
const std::vector<std::vector<size_t>> &generatedFaces();
|
||||||
|
const std::vector<size_t> &generatedVerticesSourceNodeIndices();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
struct Edge;
|
|
||||||
|
|
||||||
struct Node
|
|
||||||
{
|
|
||||||
float radius;
|
|
||||||
QVector3D position;
|
|
||||||
std::vector<size_t> edges;
|
|
||||||
std::vector<QVector2D> cutTemplate;
|
|
||||||
float cutRotation;
|
|
||||||
std::vector<QVector3D> raysToNeibors;
|
|
||||||
QVector3D cutNormal;
|
|
||||||
CutFaceTransform cutFaceTransform;
|
|
||||||
QVector3D initialTraverseDirection;
|
|
||||||
QVector3D traverseDirection;
|
|
||||||
QVector3D growthDirection;
|
|
||||||
QVector3D initialBaseNormal;
|
|
||||||
QVector3D baseNormal;
|
|
||||||
size_t reversedTraverseOrder;
|
|
||||||
bool hasInitialBaseNormal = false;
|
|
||||||
bool baseNormalResolved = false;
|
|
||||||
bool baseNormalSearched = false;
|
|
||||||
bool hasInitialTraverseDirection = false;
|
|
||||||
bool hasAdjustableCutFace = false;
|
|
||||||
int nearOriginNodeIndex = -1;
|
|
||||||
int farOriginNodeIndex = -1;
|
|
||||||
|
|
||||||
size_t anotherEdge(size_t edgeIndex) const
|
|
||||||
{
|
|
||||||
if (edges.size() != 2)
|
|
||||||
return edgeIndex;
|
|
||||||
const auto &otherIndex = edges[0];
|
|
||||||
if (otherIndex == edgeIndex)
|
|
||||||
return edges[1];
|
|
||||||
return otherIndex;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Edge
|
|
||||||
{
|
|
||||||
std::vector<size_t> nodes;
|
|
||||||
std::vector<std::pair<std::vector<size_t>, QVector3D>> cuts;
|
|
||||||
|
|
||||||
size_t neiborOf(size_t nodeIndex) const
|
|
||||||
{
|
|
||||||
const auto &otherIndex = nodes[0];
|
|
||||||
if (otherIndex == nodeIndex)
|
|
||||||
return nodes[1];
|
|
||||||
return otherIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
void updateNodeIndex(size_t fromNodeIndex, size_t toNodeIndex)
|
|
||||||
{
|
|
||||||
if (nodes[0] == fromNodeIndex) {
|
|
||||||
nodes[0] = toNodeIndex;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
nodes[1] = toNodeIndex;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct GeneratedVertexInfo
|
struct GeneratedVertexInfo
|
||||||
{
|
{
|
||||||
size_t orderInCut;
|
size_t orderInCut;
|
||||||
|
@ -113,16 +73,6 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<Node> m_nodes;
|
std::vector<Node> m_nodes;
|
||||||
std::vector<Edge> m_edges;
|
|
||||||
std::vector<QVector3D> m_generatedVertices;
|
|
||||||
std::vector<QVector3D> m_generatedVerticesCutDirects;
|
|
||||||
std::vector<size_t> m_generatedVerticesSourceNodeIndices;
|
|
||||||
std::vector<GeneratedVertexInfo> m_generatedVerticesInfos;
|
|
||||||
std::vector<std::vector<size_t>> m_generatedFaces;
|
|
||||||
std::vector<size_t> m_sortedNodeIndices;
|
|
||||||
std::map<size_t, size_t> m_weldMap;
|
|
||||||
std::set<size_t> m_swallowedEdges;
|
|
||||||
std::set<size_t> m_swallowedNodes;
|
|
||||||
float m_deformThickness = 1.0f;
|
float m_deformThickness = 1.0f;
|
||||||
float m_deformWidth = 1.0f;
|
float m_deformWidth = 1.0f;
|
||||||
float m_cutRotation = 0.0f;
|
float m_cutRotation = 0.0f;
|
||||||
|
@ -132,48 +82,38 @@ private:
|
||||||
bool m_baseNormalAverageEnabled = false;
|
bool m_baseNormalAverageEnabled = false;
|
||||||
const QImage *m_deformMapImage = nullptr;
|
const QImage *m_deformMapImage = nullptr;
|
||||||
float m_deformMapScale = 0.0f;
|
float m_deformMapScale = 0.0f;
|
||||||
float m_hollowThickness = 0.2f;
|
float m_hollowThickness = 0.0f;
|
||||||
std::vector<std::vector<size_t>> m_endCuts;
|
|
||||||
|
|
||||||
void sortNodeIndices();
|
bool m_isRing = false;
|
||||||
void prepareNode(size_t nodeIndex);
|
std::vector<size_t> m_nodeIndices;
|
||||||
std::pair<QVector3D, bool> calculateBaseNormal(const std::vector<QVector3D> &inputDirects,
|
std::vector<QVector3D> m_generatedVertices;
|
||||||
const std::vector<QVector3D> &inputPositions,
|
std::vector<QVector3D> m_generatedVerticesCutDirects;
|
||||||
const std::vector<float> &weights);
|
std::vector<size_t> m_generatedVerticesSourceNodeIndices;
|
||||||
bool validateNormal(const QVector3D &normal);
|
std::vector<GeneratedVertexInfo> m_generatedVerticesInfos;
|
||||||
void resolveBaseNormalRecursively(size_t nodeIndex);
|
std::vector<std::vector<size_t>> m_generatedFaces;
|
||||||
void resolveBaseNormalForLeavesRecursively(size_t nodeIndex, const QVector3D &baseNormal);
|
|
||||||
std::pair<QVector3D, bool> searchBaseNormalFromNeighborsRecursively(size_t nodeIndex);
|
bool prepare();
|
||||||
QVector3D revisedBaseNormalAcordingToCutNormal(const QVector3D &baseNormal, const QVector3D &cutNormal);
|
QVector3D calculateBaseNormalFromTraverseDirection(const QVector3D &traverseDirection);
|
||||||
void resolveInitialTraverseDirectionRecursively(size_t nodeIndex, const QVector3D *from, std::set<size_t> *visited);
|
std::vector<QVector3D> makeCut(const QVector3D &cutCenter,
|
||||||
void unifyBaseNormals();
|
|
||||||
void localAverageBaseNormals();
|
|
||||||
void resolveTraverseDirection(size_t nodeIndex);
|
|
||||||
bool generateCutsForNode(size_t nodeIndex);
|
|
||||||
bool tryWrapMultipleBranchesForNode(size_t nodeIndex, std::vector<float> &offsets, bool &offsetsChanged);
|
|
||||||
void makeCut(const QVector3D &position,
|
|
||||||
float radius,
|
float radius,
|
||||||
const std::vector<QVector2D> &cutTemplate,
|
const std::vector<QVector2D> &cutTemplate,
|
||||||
float cutRotation,
|
const QVector3D &cutNormal,
|
||||||
QVector3D &baseNormal,
|
const QVector3D &baseNormal);
|
||||||
QVector3D &cutNormal,
|
|
||||||
const QVector3D &traverseDirection,
|
|
||||||
std::vector<QVector3D> &resultCut,
|
|
||||||
CutFaceTransform *cutFaceTransform=nullptr,
|
|
||||||
bool *cutFlipped=nullptr);
|
|
||||||
void insertCutVertices(const std::vector<QVector3D> &cut,
|
void insertCutVertices(const std::vector<QVector3D> &cut,
|
||||||
std::vector<size_t> &vertices,
|
std::vector<size_t> *vertices,
|
||||||
size_t nodeIndex,
|
size_t nodeIndex,
|
||||||
const QVector3D &cutDirect,
|
const QVector3D &cutNormal);
|
||||||
bool cutFlipped);
|
void buildMesh();
|
||||||
void stitchEdgeCuts();
|
std::vector<size_t> sortedNodeIndices(bool *isRing);
|
||||||
void applyWeld();
|
bool calculateStartingNodeIndex(size_t *startingNodeIndex,
|
||||||
|
bool *isRing);
|
||||||
|
void reviseTraverseDirections();
|
||||||
|
void localAverageBaseNormals();
|
||||||
|
void unifyBaseNormals();
|
||||||
|
std::vector<size_t> edgeloopFlipped(const std::vector<size_t> &edgeLoop);
|
||||||
|
void reviseNodeBaseNormal(Node &node);
|
||||||
|
static QVector3D calculateDeformPosition(const QVector3D &vertexPosition, const QVector3D &ray, const QVector3D &deformNormal, float deformFactor);
|
||||||
void applyDeform();
|
void applyDeform();
|
||||||
void finalizeHollow();
|
|
||||||
QVector3D calculateDeformPosition(const QVector3D &vertexPosition, const QVector3D &ray, const QVector3D &deformNormal, float deformFactor);
|
|
||||||
bool swallowEdgeForNode(size_t nodeIndex, size_t edgeOrder);
|
|
||||||
static QVector3D calculateBaseNormalFromTraverseDirection(const QVector3D &traverseDirection);
|
|
||||||
void layoutNodes();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -179,12 +179,12 @@ void StrokeModifier::finalize()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<StrokeModifier::Node> &StrokeModifier::nodes()
|
const std::vector<StrokeModifier::Node> &StrokeModifier::nodes() const
|
||||||
{
|
{
|
||||||
return m_nodes;
|
return m_nodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<StrokeModifier::Edge> &StrokeModifier::edges()
|
const std::vector<StrokeModifier::Edge> &StrokeModifier::edges() const
|
||||||
{
|
{
|
||||||
return m_edges;
|
return m_edges;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,8 +30,8 @@ public:
|
||||||
void subdivide();
|
void subdivide();
|
||||||
void roundEnd();
|
void roundEnd();
|
||||||
void enableIntermediateAddition();
|
void enableIntermediateAddition();
|
||||||
const std::vector<Node> &nodes();
|
const std::vector<Node> &nodes() const;
|
||||||
const std::vector<Edge> &edges();
|
const std::vector<Edge> &edges() const;
|
||||||
void finalize();
|
void finalize();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -120,9 +120,9 @@ Outcome *TextureGenerator::takeOutcome()
|
||||||
return outcome;
|
return outcome;
|
||||||
}
|
}
|
||||||
|
|
||||||
MeshLoader *TextureGenerator::takeResultMesh()
|
Model *TextureGenerator::takeResultMesh()
|
||||||
{
|
{
|
||||||
MeshLoader *resultMesh = m_resultMesh;
|
Model *resultMesh = m_resultMesh;
|
||||||
m_resultMesh = nullptr;
|
m_resultMesh = nullptr;
|
||||||
return resultMesh;
|
return resultMesh;
|
||||||
}
|
}
|
||||||
|
@ -221,7 +221,7 @@ bool TextureGenerator::hasTransparencySettings()
|
||||||
|
|
||||||
void TextureGenerator::generate()
|
void TextureGenerator::generate()
|
||||||
{
|
{
|
||||||
m_resultMesh = new MeshLoader(*m_outcome);
|
m_resultMesh = new Model(*m_outcome);
|
||||||
|
|
||||||
if (nullptr == m_outcome->triangleVertexUvs())
|
if (nullptr == m_outcome->triangleVertexUvs())
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
#include <QColor>
|
#include <QColor>
|
||||||
#include <QPixmap>
|
#include <QPixmap>
|
||||||
#include "outcome.h"
|
#include "outcome.h"
|
||||||
#include "meshloader.h"
|
#include "model.h"
|
||||||
#include "snapshot.h"
|
#include "snapshot.h"
|
||||||
|
|
||||||
class TextureGenerator : public QObject
|
class TextureGenerator : public QObject
|
||||||
|
@ -25,7 +25,7 @@ public:
|
||||||
QImage *takeResultTextureMetalnessImage();
|
QImage *takeResultTextureMetalnessImage();
|
||||||
QImage *takeResultTextureAmbientOcclusionImage();
|
QImage *takeResultTextureAmbientOcclusionImage();
|
||||||
Outcome *takeOutcome();
|
Outcome *takeOutcome();
|
||||||
MeshLoader *takeResultMesh();
|
Model *takeResultMesh();
|
||||||
bool hasTransparencySettings();
|
bool hasTransparencySettings();
|
||||||
void addPartColorMap(QUuid partId, const QImage *image, float tileScale);
|
void addPartColorMap(QUuid partId, const QImage *image, float tileScale);
|
||||||
void addPartNormalMap(QUuid partId, const QImage *image, float tileScale);
|
void addPartNormalMap(QUuid partId, const QImage *image, float tileScale);
|
||||||
|
@ -52,7 +52,7 @@ private:
|
||||||
QImage *m_resultTextureRoughnessImage;
|
QImage *m_resultTextureRoughnessImage;
|
||||||
QImage *m_resultTextureMetalnessImage;
|
QImage *m_resultTextureMetalnessImage;
|
||||||
QImage *m_resultTextureAmbientOcclusionImage;
|
QImage *m_resultTextureAmbientOcclusionImage;
|
||||||
MeshLoader *m_resultMesh;
|
Model *m_resultMesh;
|
||||||
std::map<QUuid, std::pair<QImage, float>> m_partColorTextureMap;
|
std::map<QUuid, std::pair<QImage, float>> m_partColorTextureMap;
|
||||||
std::map<QUuid, std::pair<QImage, float>> m_partNormalTextureMap;
|
std::map<QUuid, std::pair<QImage, float>> m_partNormalTextureMap;
|
||||||
std::map<QUuid, std::pair<QImage, float>> m_partMetalnessTextureMap;
|
std::map<QUuid, std::pair<QImage, float>> m_partMetalnessTextureMap;
|
||||||
|
|
|
@ -13,8 +13,8 @@ typedef CGAL::Surface_mesh<InexactKernel::Point_3> InexactMesh;
|
||||||
bool triangulateFacesWithoutKeepVertices(std::vector<QVector3D> &vertices, const std::vector<std::vector<size_t>> &faces, std::vector<std::vector<size_t>> &triangles)
|
bool triangulateFacesWithoutKeepVertices(std::vector<QVector3D> &vertices, const std::vector<std::vector<size_t>> &faces, std::vector<std::vector<size_t>> &triangles)
|
||||||
{
|
{
|
||||||
auto cgalMesh = buildCgalMesh<InexactKernel>(vertices, faces);
|
auto cgalMesh = buildCgalMesh<InexactKernel>(vertices, faces);
|
||||||
bool isSucceed = CGAL::Polygon_mesh_processing::triangulate_faces(*cgalMesh);
|
bool isSuccessful = CGAL::Polygon_mesh_processing::triangulate_faces(*cgalMesh);
|
||||||
if (isSucceed) {
|
if (isSuccessful) {
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
fetchFromCgalMesh<InexactKernel>(cgalMesh, vertices, triangles);
|
fetchFromCgalMesh<InexactKernel>(cgalMesh, vertices, triangles);
|
||||||
delete cgalMesh;
|
delete cgalMesh;
|
||||||
|
@ -24,7 +24,7 @@ bool triangulateFacesWithoutKeepVertices(std::vector<QVector3D> &vertices, const
|
||||||
|
|
||||||
// fallback to our own imeplementation
|
// fallback to our own imeplementation
|
||||||
|
|
||||||
isSucceed = true;
|
isSuccessful = true;
|
||||||
std::vector<std::vector<size_t>> rings;
|
std::vector<std::vector<size_t>> rings;
|
||||||
for (const auto &face: faces) {
|
for (const auto &face: faces) {
|
||||||
if (face.size() > 3) {
|
if (face.size() > 3) {
|
||||||
|
@ -79,8 +79,8 @@ bool triangulateFacesWithoutKeepVertices(std::vector<QVector3D> &vertices, const
|
||||||
triangles.push_back(newFace);
|
triangles.push_back(newFace);
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "Triangulate failed, ring size:" << fillRing.size();
|
qDebug() << "Triangulate failed, ring size:" << fillRing.size();
|
||||||
isSucceed = false;
|
isSuccessful = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return isSucceed;
|
return isSuccessful;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
#include <QGuiApplication>
|
||||||
#include "turnaroundloader.h"
|
#include "turnaroundloader.h"
|
||||||
|
|
||||||
TurnaroundLoader::TurnaroundLoader(const QString &filename, QSize viewSize) :
|
TurnaroundLoader::TurnaroundLoader(const QString &filename, QSize viewSize) :
|
||||||
|
@ -33,5 +34,6 @@ void TurnaroundLoader::process()
|
||||||
} else {
|
} else {
|
||||||
m_resultImage = new QImage(m_inputImage.scaled(m_viewSize, Qt::KeepAspectRatio));
|
m_resultImage = new QImage(m_inputImage.scaled(m_viewSize, Qt::KeepAspectRatio));
|
||||||
}
|
}
|
||||||
|
this->moveToThread(QGuiApplication::instance()->thread());
|
||||||
emit finished();
|
emit finished();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include <QXmlStreamReader>
|
#include <QXmlStreamReader>
|
||||||
|
#include <QGuiApplication>
|
||||||
#include "updateschecker.h"
|
#include "updateschecker.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
|
||||||
|
@ -143,6 +144,6 @@ void UpdatesChecker::downloadFinished(QNetworkReply *reply)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
|
this->moveToThread(QGuiApplication::instance()->thread());
|
||||||
emit finished();
|
emit finished();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue