Compare commits

...
Sign in to create a new pull request.

136 commits

Author SHA1 Message Date
dc59211634 DOCS: object detection usecase 2025-02-27 16:58:24 +03:00
649a426c25 dataset_generation and train_models as modules 2024-12-11 09:15:03 +00:00
69b8512d6b update rcg_pipeline 2024-12-10 18:00:37 +03:00
82f7a7233d update rcg_pipeline version 2024-12-10 17:50:01 +03:00
f4f56e53a8 added blender plugin and freecad workbench as submodules 2024-12-10 17:26:05 +03:00
03f8b86877 Add LICENSE 2024-11-27 12:48:56 +00:00
brothermechanic
045e157266
add obj export format support 2024-07-04 13:58:11 +03:00
8d9f913cbc FreeCAD Workbench: Добавлен интерфейс обратной связи для корректировки планов сборки 2024-06-19 20:46:50 +00:00
Mark Voltov
05b1963a34 Добавлена валидация проекта сборки с выводом в консоль обратной связи 2024-05-10 08:41:24 +00:00
8fa9076f91 Модуль обучения моделей нейросети для навыков 2024-05-10 08:36:51 +00:00
bd0a9865a1 Fix python module for Nix Overlay 2024-05-03 13:54:34 +00:00
9a7d6b9084 add dataset generation script 2024-04-26 08:58:52 +03:00
946e83fd15 FreeCAD Workbench as Python-module 2024-04-19 09:57:35 +00:00
brothermechanic
362e0f7a6f
RCG: add assets data file 2024-04-16 11:02:44 +03:00
brothermechanic
e396b0c01e
RCG: better locator sizes 2024-04-15 22:17:37 +03:00
Mark Voltov
a58dcdafb1 FreeCAD: Workbench Refactor 2024-04-14 18:54:47 +00:00
037827669a RCG Pipeline: Fix Python imports in pyproject.toml 2024-04-12 17:23:29 +00:00
brothermechanic
31f5810bef
RCG: debug fixes 2024-04-11 19:16:08 +03:00
brothermechanic
8aeb802ec8
RCG: data base names 2024-04-10 10:25:50 +03:00
brothermechanic
0ecf214e26
FreeCAD: data base names 2024-04-09 18:08:09 +03:00
brothermechanic
3878990c4e RCG Pipeline Release with Docs 2024-04-09 11:52:13 +00:00
brothermechanic
df0fb32592
Merge remote-tracking branch 'origin/141-cg-pipeline-prepare-for-release' into 143-project-structure-refactoring 2024-04-01 22:10:43 +03:00
brothermechanic
b80db52ea5
FreeCAD: rewrite freecad module as freecad publish plugin 2024-04-01 21:55:13 +03:00
brothermechanic
8401cc51fa
FreeCAD: uber updating function in freecad_to_json WIP 2024-03-26 22:00:41 +03:00
brothermechanic
cc538b719f
FreeCAD: add collect_clones function in freecad_to_json WIP 2024-03-22 03:10:21 +03:00
IDONTSUDO
fe797ebeeb misprint 2024-03-20 14:55:34 +00:00
IDONTSUDO
871d9d735e addding predicate 2024-03-20 14:55:34 +00:00
brothermechanic
bce317a554
cg: update pipeline to lcs property 2 WIP 2024-03-18 11:15:40 +03:00
brothermechanic
6c7e8c46d6
cg: update pipeline to lcs property WIP 2024-03-14 11:29:06 +03:00
brothermechanic
c27b99ff52
bpy-4: update for bpy api 4 2024-03-06 09:23:27 +03:00
brothermechanic
e02bab244d
Blender Addon: entity manager 2024-02-29 11:51:30 +03:00
brothermechanic
db3e0d1273
Blender Addon: import ros2bag animation and assign to blender 2024-02-24 14:11:29 +03:00
Mark Voltov
fd59ab9e26 ASP refactoring, sequence generation via clusterization 2024-02-02 14:22:21 +00:00
IDONTSUDO
d2ab856d64 API with assembly options and constraints; DFS Liaison/Adjacency matrix generation fix; add unit-tests 2024-01-18 10:44:59 +00:00
brothermechanic
c64bbf4a70 Blender Scene Compose & Export addon 2023-12-21 08:45:25 +00:00
brothermechanic
021e5862ff CG Pipelines: User interface refactor 2023-12-18 07:48:45 +00:00
IDONTSUDO
e305d486f2 Add PDDL, 3D-assets & SDF-URDF generator from Blender Scene Config 2023-12-17 13:58:43 +00:00
brothermechanic
b77687ea14
CG Pileline: add export to PLY script and optional scale and forward-up axis 2023-12-08 11:12:01 +03:00
brothermechanic
679a52a041
Robossembler Framework: update readme files 2023-12-01 11:34:37 +03:00
brothermechanic
b3612d8655 [CG Pipeline] Refactor 2023-11-13 13:07:33 +00:00
brothermechanic
6538f70d54
Pipeline: generate material from baked bpr textures 2023-10-28 20:15:45 +03:00
brothermechanic
a1a961e7a7
Pipeline: composing all baked textures 2023-10-26 10:40:04 +03:00
brothermechanic
d9d07b33b1
Pipeline: double bake pass 2023-10-25 15:54:01 +03:00
brothermechanic
10d5ed451a Blender: Bake Wrangler Wrapper 2023-10-25 10:54:36 +00:00
brothermechanic
9222104a1a Blender: improve import Material generation 2023-10-17 07:53:39 +00:00
brothermechanic
25c9cbfbe9 [Blender] Baking optimization 2023-10-16 12:21:34 +00:00
90945c0430 6D Pose Estimation dataset generation tools for BOP format 2023-10-13 08:37:57 +00:00
brothermechanic
184ac7df88 Tool for convert FreeCAD sub-assemblies to URDF-world according to config 2023-10-10 16:32:29 +00:00
IDONTSUDO
03bc34539c Stability process predicate evaluation module 2023-09-12 19:09:33 +00:00
brothermechanic
78e31ea49c [Blender 3.6] UV Packer 2023-09-12 09:07:30 +00:00
brothermechanic
80e3c58913
Pipeline: rewrite cad importer for freecadcmd, freecad part 2023-09-03 21:39:50 +00:00
IDONTSUDO
64b80be028 multiple evaluation of assemblies by sequences 2023-07-22 18:04:39 +00:00
IDONTSUDO
ea742b26d7 Алгоритм поиска всех последовательностей матрицы смежности через Depth First Search (DFS) 2023-07-13 19:55:18 +00:00
IDONTSUDO
c1e7882cbb rewrote URDF generation 2023-07-13 19:58:07 +03:00
IDONTSUDO
502e7a8d76 adding center mass URDF 2023-07-12 17:40:24 +03:00
IDONTSUDO
70e268c455 Adding title to ASP algorithms 2023-07-05 14:14:36 +00:00
IDONTSUDO
33dd320858 Additional comments to assembly sequence planner algorithms 2023-07-05 13:33:45 +00:00
IDONTSUDO
12482ff40f adding comments 2023-07-05 16:03:51 +03:00
Mark Voltov
9eaf12a4fa Сделан и подключен генератор PDDL-доменов 2023-07-04 20:52:26 +00:00
IDONTSUDO
8dfbe38878 adding assembly_order case 2023-07-04 16:32:15 +03:00
IDONTSUDO
5239e6d091 Resolve "Предикат стабильности" 2023-07-04 07:57:09 +00:00
brothermechanic
247c84d718 Tessellation: add optional FEM tessellation method 2023-07-04 07:32:14 +00:00
IDONTSUDO
c1e4b0e0f0 Веб интерфейс для корректировки работы ASP, его интеграция с алгоритмами генерации 2023-07-04 07:19:55 +00:00
23edfea360 Добавлен опциональный алгоритм тесселяции 2023-07-01 14:52:09 +03:00
brothermechanic
839ce36c70 [Blender] Implemented tesselation for CAD-model, retopology and optimisation tesselation's result, assigning physical properties with assigned material 2023-06-24 13:54:49 +00:00
Mark Voltov
9fa936cfba Export helper object from FreeCAD: grasp poses, part's zero positions, planar (tables, surfaces) and volumetric zones (storage, boxes) 2023-06-18 15:55:12 +00:00
IDONTSUDO
a38c3bec5a Support "Assemble them all" trajectory generation from CAD 2023-06-18 15:33:16 +00:00
brothermechanic
47773be8d4 .obj additional exporters/importers 2023-06-18 15:30:44 +00:00
IDONTSUDO
1fb7077774 Prototype of web-based preview for subassemblies 2023-06-18 15:27:23 +00:00
brothermechanic
6560a4359d [Blender] Доработаны процедуры ретопологии мешей 2023-05-19 18:35:03 +00:00
IDONTSUDO
45e0d29ea0 Экспорт URDF из FreeCAD 2023-04-24 19:42:48 +00:00
Mark Voltov
7cadf0741f Добавлен файл анализа gcode 2023-04-21 21:24:02 +00:00
IDONTSUDO
e65236aab6 Экспорт подсборок с мешами (SDF) и плана сборки (PDDL) из FreeCAD в виде архива zip 2023-04-18 14:01:46 +00:00
brothermechanic
7f13c0056f [Freecad] Реализован интерфейс добавления свойства (property) к фрейм объекту" 2023-04-12 09:19:17 +00:00
brothermechanic
b744fe30a0 Добавлен импорт иерархии объектов из FreeCAD в Blender 2023-04-06 11:33:50 +00:00
brothermechanic
5208577d86 Импорт фрейма (объекта локальных осей) в качестве локальной матрицы 2023-04-05 11:26:09 +00:00
brothermechanic
16f6f375b5 change rotation export as XYZW quaternion 2023-04-01 07:12:12 +00:00
IDONTSUDO
b376c78e3b adding domain 2023-03-14 05:44:32 +00:00
brothermechanic
37bdfcd5e9
solid test and disable importing nonsolid objects 2023-03-10 19:37:15 +03:00
brothermechanic
1ea7e50ecd Сброшены трансформации в asp_sdf_to_asset.py и унифицированы за счет freecad_to_asset.py 2023-03-06 12:50:35 +00:00
IDONTSUDO
748fcd1351 asm4 pddl 2023-03-05 16:58:37 +03:00
IDONTSUDO
3d3a063a5d asm4 parse feature 2023-03-03 19:02:46 +03:00
brothermechanic
6fcd2566b5 add fem materials 2023-03-03 07:38:59 +00:00
12f9caa69c + описание команд для обнаружения в тестовых изобр 2023-03-02 16:04:39 +03:00
35223a1af1 добавлено описание процедуры ObjectDetection 2023-02-21 14:41:44 +03:00
74f1a1493e Добавлен алгоритм генерации набора данных и обучения навыка распознаванию объектов на базе YOLOv4" 2023-02-21 10:15:34 +00:00
brothermechanic
0c433c10d5 Доработан плагин экспорта SDF для FreeCAD 2023-02-21 10:13:11 +00:00
brothermechanic
95437a4527
subassembly models setup from SDFormat file 2023-02-08 10:47:54 +03:00
brothermechanic
6af0f188a7 Интегрирован модуль импорта моделей из FreeCAD в Blender 2023-02-01 13:43:23 +00:00
brothermechanic
d26698d1a6 update readme and structure 2023-01-30 19:06:13 +00:00
brothermechanic
dada2d9dd5 update readme 2023-01-30 19:06:13 +00:00
brothermechanic
6e1a26504d add blender settings script 2023-01-30 19:06:13 +00:00
db14ac643e Добавлено описание функциональных модулей на русском 2023-01-24 13:53:35 +03:00
fff6800d3b git repo clone fix 2023-01-16 06:24:18 +00:00
42762512c8 Добавлен ASP-модуль 2023-01-15 12:37:01 +00:00
8bf8235add Added GraspPose.py as module and UI button; SDF export with another placements 2022-03-28 11:50:31 +03:00
32e9b53fad Fix collada part scaling 2022-03-10 17:00:44 +03:00
b2543c3672 Export Grasp Poses only for parts with Grasp Poses 2022-03-10 17:00:29 +03:00
20900e4eba Export Grasp poses in json; export mesh once for same parts 2022-03-02 23:49:29 +03:00
7f6e9c98aa Grasp Pose json export function moved to ARTools module; export format adopted to geometry_msgs/Pose 2022-02-22 20:45:54 +03:00
3941c7aae6 Grasp Pose Export 2022-02-17 17:50:05 +00:00
8241627436 Merge branch '6-model-config-xml' into 'master'
Gazebo Export Package restucturing

Closes #5 and #6

See merge request robosphere/forks/ARBench!2
2022-02-07 20:54:17 +00:00
e2da384085 Gazebo Export Package restucturing 2022-02-07 20:54:17 +00:00
2111b33c75 Merge branch 'freecad0.19' into 'master'
Merge freecad_to_gazebo to ARBench & FreeCAD 0.19 support

See merge request robosphere/forks/ARBench!1
2022-02-03 18:25:53 +00:00
b8f1ffc618 Delete A2Plus dependency and URDF export, add freecad_to_gazebo info to README.md 2022-02-03 21:19:12 +03:00
f221e5366e Merge branch 'freecad_to_gazebo' into freecad0.19 2022-01-25 16:21:41 +03:00
5a4daa42a2 Move README to exporter dir and remove another files 2022-01-25 16:18:59 +03:00
2d704442c8 Prepare to use freecad_to_gazebo as ARBench mesh exporter. No need to run as binary 2022-01-25 16:18:07 +03:00
c410442b98 FreeCAD 0.19 support 2021-12-17 16:57:58 +03:00
Dave-Elec
cf43039dae Fixed python2/3 compatiblities 2020-09-04 13:37:02 +03:00
Dawit Abate
8547f5884c
Fixed wrong script name 2020-09-02 05:54:47 +03:00
Dawit Abate
04c866b60b
Python2 compatibility (changed scandir to listdir) 2020-09-02 05:48:25 +03:00
Dawit Abate
dd556e1a70
Merge pull request #2 from pxalcantara/master
change project name
2020-09-02 04:02:10 +03:00
pxalcantara
cfd44313a3 change project name
Signed-off-by: pxalcantara <pxalcantara@gmail.com>
2020-09-01 19:47:30 -03:00
Dawit Abate
e28ff36674 Added friction and damping support 2019-07-05 16:38:45 +03:00
Dawit Abate
c407cd82b9 Added dummy link as a parent of root link to support inertia 2019-07-05 15:57:55 +03:00
Dawit Abate
06cd9fafb0 Fixed typo and moved pid gains to namespace 2019-07-05 13:54:23 +03:00
Dawit Abate
d601655fca Fixed typos and added moving the origin to center of mass on the meshes 2019-07-04 18:03:09 +03:00
Dawit Abate
e7c7796b6b Added usage modifications 2019-07-04 16:49:33 +03:00
Dawit Abate
a3ba5dab37 Added setup.py 2019-07-04 16:46:47 +03:00
Dawit Abate
34d528afc5 Added catkin package files 2019-07-04 16:46:35 +03:00
Dawit Abate
327955c231 fixed platform detection bug 2019-07-04 16:45:45 +03:00
Dawit Abate
c94427f37c moved freecad2gazebo.py to freecad2gazebo 2019-07-04 16:45:21 +03:00
Dawit Abate
17a91d11d3 Added frecad2gazebo script as a command line tool with arguments 2019-07-04 15:50:06 +03:00
Dawit Abate
a78c3ef73a Added actual freecad exporter 2019-07-04 15:48:56 +03:00
Dawit Abate
b6dce011f4 removed unwanted FreeCAD import from conversions 2019-07-04 15:48:26 +03:00
Dawit Abate
226dd4b34b renamed exporter.py to mesh_exporter.py 2019-07-04 15:17:49 +03:00
Dawit Abate
c1df40b3db Added urdf origin calculations 2019-07-04 15:17:14 +03:00
Dawit Abate
251d79e9f8 changed freecad libs searching to hard-coded per platform 2019-07-04 15:16:03 +03:00
Dawit Abate
d8aa4eb76e Added basic classes for representing model/robot to export to xml 2019-06-27 12:10:46 +03:00
Dawit Abate
26e6c96493 Added conversion helpers 2019-06-26 13:45:46 +03:00
Dawit Abate
4401848d8f Added a basic freecad collada mesh exporter 2019-06-26 13:42:08 +03:00
Dawit Abate
83bc0e922b Added searching methods for freecad libraries 2019-06-26 13:24:09 +03:00
Dawit Abate
4fc65e3c80 Added README.md 2019-06-20 17:53:28 +03:00
Dawit Abate
e610313349
Initial commit 2019-06-19 06:11:06 +03:00
Mathias Hauan Arbo
23905b1000 Cleaning up ARFrames 2019-03-03 13:21:06 +01:00
107 changed files with 8915 additions and 6191 deletions

18
.gitignore vendored
View file

@ -99,3 +99,21 @@ ENV/
# mypy
.mypy_cache/
# blender backup files
*.blend1
install_plugin_cad.sh
.vscode
.DS_Store
# emacs backup files
~*
*~
*#
.#*
\#*\#
out/
#freecad_workbench
freecad_workbench/freecad/update_workbench.sh
*.FCBak

9
.gitmodules vendored Normal file
View file

@ -0,0 +1,9 @@
[submodule "rcg_pipeline"]
path = rcg_pipeline
url = https://gitlab.com/robossembler/rcg-pipeline.git
[submodule "freecad_workbench"]
path = freecad_workbench
url = https://gitlab.com/robossembler/robossembler-freecad-workbench.git
[submodule "simulation/insertion_vector_predicate/assembly"]
path = simulation/insertion_vector_predicate/assembly
url = https://github.com/yunshengtian/Assemble-Them-All

View file

@ -1,752 +0,0 @@
import FreeCAD
import ARTools
if FreeCAD.GuiUp:
import FreeCADGui
from pivy import coin
from PySide import QtCore, QtGui, QtSvg
import Part
import os
__title__ = "ARFrames"
__author__ = "Mathias Hauan Arbo"
__workbenchname__ = "ARBench"
__version__ = "0.1"
__url__ = "https://github.com/mahaarbo/ARBench"
__doc__ = """"""
############################################################
# Frame Objects
############################################################
class Frame(object):
"""Basic freestanding frame"""
def __init__(self, obj):
obj.addProperty("App::PropertyPlacement",
"Placement", "Base",
"Placement of the frame")
obj.Placement = FreeCAD.Placement()
obj.Proxy = self
self.obj = obj
self.additional_data = {}
def onChanged(self, fp, prop):
pass
def execute(self, obj):
pass
def __getstate__(self):
return None
def __setstate__(self, state):
return None
def getDict(self):
d = {}
d["label"] = str(self.obj.Label)
d["placement"] = ARTools.placement2axisvec(self.obj.Placement)
d.update(self.additional_data)
return d
class PartFrame(Frame):
"""Frame rigidly attached to a part frame.
Inherits the base placement from the part's frame, and placement is
relative to the part frame.
"""
def __init__(self, obj, partobj):
Frame.__init__(self, obj)
obj.addProperty("App::PropertyPlacementLink",
"Part", "Parent",
"The part to attach to.")
obj.Part = partobj
obj.setEditorMode("Part", 1)
def execute(self, obj):
if FreeCAD.GuiUp:
obj.ViewObject.Proxy.updateData(obj, "Placement")
def getDict(self):
d = Frame.getDict(self)
d["part"] = str(self.obj.Part.Label)
return d
class FeatureFrame(PartFrame):
"""Frame rigidly attached to a feature.
The feature frame is attached to a feature on a part. It gives both the
placement of the feature w.r.t. the part, and the placement from the
feature."""
def __init__(self, obj, partobj, featurePlacement):
PartFrame.__init__(self, obj, partobj)
obj.addProperty("App::PropertyPlacement",
"FeaturePlacement", "Feature",
"The frame attached to the feature.")
obj.addProperty("App::PropertyString",
"PrimitiveType", "Feature",
"The primitive type of the feature.")
obj.addProperty("App::PropertyString",
"ShapeType", "Feature",
"The shape type of the feature.")
obj.addProperty("App::PropertyString",
"Positioning", "Feature",
"The type of positioning used during creation.")
obj.FeaturePlacement = featurePlacement
def getDict(self):
d = PartFrame.getDict(self)
d["featureplacement"] = ARTools.placement2axisvec(self.obj.FeaturePlacement)
d["shapetype"] = str(self.obj.ShapeType)
d["positioning"] = str(self.obj.Positioning)
return d
############################################################
# ViewProvider to the frames
############################################################
class ViewProviderFrame(object):
"""ViewProvider for the basic frame.
Uses the SOAxiscrosskit to create axises with constant length regardless
of zoom. Updates position when placement is changed.
"""
def __init__(self, vobj):
vobj.addProperty("App::PropertyFloat", "Scale")
vobj.Scale = 0.12
vobj.addProperty("App::PropertyFloat", "HeadSize")
vobj.HeadSize = 3.0
vobj.addProperty("App::PropertyFloat", "LineWidth")
vobj.LineWidth = 2.0
vobj.Proxy = self
def attach(self, vobj):
# We only have a shaded visual group
self.shaded = coin.SoGroup()
# Takes heavily from SoAxisCrosskit.h,
# and Toggle_DH_Frames by galou_breizh on the forums
self.vframe = coin.SoType.fromName("SoShapeScale").createInstance()
self.vframe.setPart("shape", coin.SoType.fromName("SoAxisCrossKit").createInstance())
self.vframe.scaleFactor.setValue(0.1)
ax = self.vframe.getPart("shape", 0)
cone = ax.getPart("xHead.shape", 0)
cone.bottomRadius.setValue(vobj.HeadSize)
cone = ax.getPart("yHead.shape", 0)
cone.bottomRadius.setValue(vobj.HeadSize)
cone = ax.getPart("zHead.shape", 0)
cone.bottomRadius.setValue(vobj.HeadSize)
lwstring = "lineWidth {0}".format(vobj.LineWidth)
ax.set("xAxis.appearance.drawStyle", lwstring)
ax.set("yAxis.appearance.drawStyle", lwstring)
ax.set("zAxis.appearance.drawStyle", lwstring)
ax.set("xAxis.pickStyle", "style SHAPE")
ax.set("yAxis.pickStyle", "style SHAPE")
ax.set("zAxis.pickStyle", "style SHAPE")
# Then remember to make it selectable in the viewer
selectionNode = coin.SoType.fromName("SoFCSelection").createInstance()
selectionNode.documentName.setValue(FreeCAD.ActiveDocument.Name)
selectionNode.objectName.setValue(vobj.Object.Name)
selectionNode.subElementName.setValue("Frame")
selectionNode.addChild(self.vframe)
# We would like to place it where we want
self.transform = coin.SoTransform()
self.shaded.addChild(self.transform)
self.shaded.addChild(self.vframe)
self.shaded.addChild(selectionNode)
vobj.addDisplayMode(self.shaded, "Shaded")
def updateData(self, fp, prop):
if prop == "Placement":
pl = fp.getPropertyByName("Placement")
self.transform.translation = (pl.Base.x,
pl.Base.y,
pl.Base.z)
self.transform.rotation = pl.Rotation.Q
def getDisplayModes(self, vobj):
modes = ["Shaded"]
return modes
def getDefaultDisplayMode(self):
return "Shaded"
def getIcon(self):
icondir = os.path.join(FreeCAD.getUserAppDataDir(), "Mod", __workbenchname__, "UI", "icons")
return str(os.path.join(icondir, "frame.svg"))
def onChanged(self, vp, prop):
if prop == "Scale":
s = vp.getPropertyByName("Scale")
self.vframe.scaleFactor.setValue(float(s))
elif prop == "HeadSize":
hs = vp.getPropertyByName("HeadSize")
xcone = self.vframe.getPart("shape", 0).getPart("xHead.shape", 0)
xcone.bottomRadius.setValue(float(hs))
ycone = self.vframe.getPart("shape", 0).getPart("yHead.shape", 0)
ycone.bottomRadius.setValue(float(hs))
zcone = self.vframe.getPart("shape", 0).getPart("zHead.shape", 0)
zcone.bottomRadius.setValue(float(hs))
elif prop == "LineWidth":
lw = vp.getPropertyByName("LineWidth")
lwstring = "lineWidth {0}".format(lw)
ax = self.vframe.getPart("shape", 0)
ax.set("xAxis.appearance.drawStyle", lwstring)
ax.set("yAxis.appearance.drawStyle", lwstring)
ax.set("zAxis.appearance.drawStyle", lwstring)
def __getstate__(self):
return None
def __setstate__(self, state):
pass
class ViewProviderPartFrame(ViewProviderFrame):
"""View provider to the part frame."""
def updateData(self, fp, prop):
if prop == "Placement":
parentpl = fp.getPropertyByName("Part").Placement
localpl = fp.Placement
pl = parentpl.multiply(localpl)
self.transform.translation = (pl.Base.x,
pl.Base.y,
pl.Base.z)
self.transform.rotation = pl.Rotation.Q
class ViewProviderFeatureFrame(ViewProviderFrame):
"""View provider to the feature frames."""
def updateData(self, fp, prop):
if prop == "Placement":
parentpl = fp.getPropertyByName("Part").Placement
featurepl = fp.getPropertyByName("FeaturePlacement")
localpl = fp.Placement
pl = parentpl.multiply(featurepl.multiply(localpl))
self.transform.translation = (pl.Base.x,
pl.Base.y,
pl.Base.z)
self.transform.rotation = pl.Rotation.Q
###################################################################
# Base functions
###################################################################
def makeFrame(placement=FreeCAD.Placement()):
obj = FreeCAD.ActiveDocument.addObject("App::FeaturePython", "Frame")
Frame(obj)
if FreeCAD.GuiUp:
ViewProviderFrame(obj.ViewObject)
return obj
def makePartFrame(part):
obj = FreeCAD.ActiveDocument.addObject("App::FeaturePython", "PartFrame")
PartFrame(obj, part)
if int(FreeCAD.Version()[1]) > 16:
geo_feature_group = part.getParentGeoFeatureGroup()
geo_feature_group.addObject(obj)
if FreeCAD.GuiUp:
ViewProviderPartFrame(obj.ViewObject)
return obj
def makeFeatureFrame(part, featurepl):
obj = FreeCAD.ActiveDocument.addObject("App::FeaturePython",
"FeatureFrame")
FeatureFrame(obj, part, featurepl)
# If we're >0.16, add the feature frame to the assembly
if int(FreeCAD.Version()[1]) > 16:
geo_feature_group = part.getParentGeoFeatureGroup()
geo_feature_group.addObject(obj)
if FreeCAD.GuiUp:
ViewProviderFeatureFrame(obj.ViewObject)
return obj
def makeAllPartFrames():
dc = FreeCAD.activeDocument()
for part in dc.Objects:
if isinstance(part, Part.Feature):
pf = makePartFrame(part)
pf.Label = "Frame"+str(part.Label)
def spawnFeatureFrameCreator():
ffpanel = FeatureFramePanel()
FreeCADGui.Control.showDialog(ffpanel)
###################################################################
# GUI Related
###################################################################
uidir = os.path.join(FreeCAD.getUserAppDataDir(),
"Mod", __workbenchname__, "UI")
icondir = os.path.join(uidir, "icons")
ARTools.spawnClassCommand("FrameCommand",
makeFrame,
{"Pixmap": str(os.path.join(icondir, "frame.svg")),
"MenuText": "Make a free frame",
"ToolTip": "Make a freestanding reference frame."})
ARTools.spawnClassCommand("AllPartFramesCommand",
makeAllPartFrames,
{"Pixmap": str(os.path.join(icondir, "allpartframes.svg")),
"MenuText": "All part frames",
"ToolTip": "Make all part frames."})
ARTools.spawnClassCommand("FeatureFrameCommand",
spawnFeatureFrameCreator,
{"Pixmap": str(os.path.join(icondir, "featureframecreator.svg")),
"MenuText": "Feature frame creator",
"ToolTip": "Create a feature frame on selected primitive."})
###################################################################
# GUI buttons
###################################################################
class FeatureFramePanel:
"""Spawn panel choices for a feature."""
def __init__(self):
selected = FreeCADGui.Selection.getSelectionEx()
# Check selection
if len(selected) == 1:
selected = selected[0]
self.selected = selected
else:
FreeCAD.Console.PrintError("Multipart selection not available.")
self.reject()
if not selected.HasSubObjects:
FreeCAD.Console.PrintError("Part selected not feature.")
self.reject()
elif not len(selected.SubObjects) == 1:
FreeCAD.Console.PrintError("Multifeature selection not available")
self.reject()
# Choices related to selection
so_desc = ARTools.describeSubObject(selected.SubObjects[0])
self.so_desc = so_desc
shape_choices = {
"Vertex": [],
"Edge": ["PointOnEdge"],
"Face": ["PointOnSurface"]
}
prim_choices = {
"ArcOfCircle": ["Center"],
"ArcOfEllipse": ["Center"],
"ArcOfHyperBola": ["Center"],
"ArcOfParabola": ["Center"],
"BSplineCurve": ["Center"],
"BezierCurve": ["Center"],
"Circle": ["Center"],
"Ellipse": ["Center"],
"Hyperbola": ["Center"],
"Parabola": ["Center"],
"Line": [],
"BSplineSurface": ["Center"],
"BezierSurface": ["Center"],
"Cylinder": ["PointOnCenterline"],
"Plane": ["Center"],
"Sphere": ["Center"],
"Toroid": ["Center"],
"Cone": ["PointOnCenterline"]
}
self.choices = ["PickedPoint"]
self.choices = self.choices + shape_choices[so_desc[1]]
self.choices = self.choices + prim_choices[so_desc[0]]
# Setting up QT form
uiform_path = os.path.join(uidir, "FeatureFrameCreator.ui")
self.form = FreeCADGui.PySideUic.loadUi(uiform_path)
self.form.ChoicesBox.addItems(self.choices)
self.form.PickedTypeLabel.setText(so_desc[0])
QtCore.QObject.connect(self.form.ChoicesBox,
QtCore.SIGNAL("currentIndexChanged(QString)"),
self.choiceChanged)
self.scenes = {}
for choice in self.choices:
sc = QtGui.QGraphicsScene()
icon = str(os.path.join(icondir, choice+".svg"))
sc.addItem(QtSvg.QGraphicsSvgItem(icon))
self.scenes[choice] = sc
self.choiceChanged(self.form.ChoicesBox.currentText())
def choiceChanged(self, choice):
if choice in self.scenes.keys():
self.form.Preview.setScene(self.scenes[choice])
def accept(self):
sel_choice = self.form.ChoicesBox.currentText()
paneldict = {"PickedPoint": PickedPointPanel,
"PointOnEdge": PointOnEdgePanel,
"PointOnSurface": PointOnSurfacePanel,
"Center": CenterPanel,
"PointOnCenterline": PointOnCenterlinePanel}
pan = paneldict[sel_choice](self.selected, self.so_desc)
FreeCADGui.Control.closeDialog()
# The dialog is actually closed after the accept function has
# completed. So we need to use a delayed task to open the new dialog:
QtCore.QTimer.singleShot(0,
lambda: FreeCADGui.Control.showDialog(pan))
def reject(self):
FreeCADGui.Control.closeDialog()
class BaseFeaturePanel(object):
"""Base feature panel to be inherited from."""
def __init__(self, selected, so_desc):
# Handle selected and FF placement
self.selected = selected
self.so_desc = so_desc
# Connect offset to spinboxes
QtCore.QObject.connect(self.form.XBox,
QtCore.SIGNAL("valueChanged(double)"),
self.offsetChanged)
QtCore.QObject.connect(self.form.YBox,
QtCore.SIGNAL("valueChanged(double)"),
self.offsetChanged)
QtCore.QObject.connect(self.form.ZBox,
QtCore.SIGNAL("valueChanged(double)"),
self.offsetChanged)
QtCore.QObject.connect(self.form.RollBox,
QtCore.SIGNAL("valueChanged(double)"),
self.offsetChanged)
QtCore.QObject.connect(self.form.PitchBox,
QtCore.SIGNAL("valueChanged(double)"),
self.offsetChanged)
QtCore.QObject.connect(self.form.YawBox,
QtCore.SIGNAL("valueChanged(double)"),
self.offsetChanged)
QtCore.QObject.connect(self.form.ScaleBox,
QtCore.SIGNAL("valueChanged(double)"),
self.scaleChanged)
def createFrame(self):
self.fframe = makeFeatureFrame(self.selected.Object, self.local_ffpl)
self.fframe.PrimitiveType = self.so_desc[0]
self.fframe.ShapeType = self.so_desc[1]
ad = ARTools.getPrimitiveInfo(self.so_desc[0],
self.selected.SubObjects[0])
self.fframe.Proxy.additional_data.update(ad)
def scaleChanged(self):
scale = self.form.ScaleBox.value()
self.fframe.ViewObject.Scale = scale
def offsetChanged(self):
disp = FreeCAD.Vector(self.form.XBox.value(),
self.form.YBox.value(),
self.form.ZBox.value())
rot = FreeCAD.Rotation(self.form.YawBox.value(),
self.form.PitchBox.value(),
self.form.RollBox.value())
offset = FreeCAD.Placement(disp, rot)
self.fframe.Placement = offset
def accept(self):
framelabel = self.form.FrameLabelField.toPlainText()
if not len(framelabel) == 0:
self.fframe.Label = framelabel
FreeCADGui.Control.closeDialog()
def reject(self):
FreeCAD.activeDocument().removeObject(self.fframe.Name)
FreeCADGui.Control.closeDialog()
class PickedPointPanel(BaseFeaturePanel):
"""Create a feature frame at the picked point."""
# Not very clever. It just places the frame with default rotation.
def __init__(self, selected, so_desc):
uiform_path = os.path.join(uidir, "FramePlacer.ui")
self.form = FreeCADGui.PySideUic.loadUi(uiform_path)
BaseFeaturePanel.__init__(self, selected, so_desc)
parent_pl = selected.Object.Placement
abs_pl = FreeCAD.Placement(selected.PickedPoints[0],
FreeCAD.Rotation())
self.local_ffpl = parent_pl.inverse().multiply(abs_pl)
self.createFrame()
self.fframe.Positioning = "PickedPoint"
class PointOnEdgePanel(BaseFeaturePanel):
"""Create a feature frame on an edge."""
def __init__(self, selected, so_desc):
uiform_path = os.path.join(uidir, "FramePlacer.ui")
self.form = FreeCADGui.PySideUic.loadUi(uiform_path)
# Enable the first parameter
self.form.VLabel.setEnabled(True)
self.form.VLabel.setVisible(True)
self.form.VLabel.setText("u")
self.form.VBox.setEnabled(True)
self.form.VBox.setVisible(True)
QtCore.QObject.connect(self.form.VBox,
QtCore.SIGNAL("valueChanged(double)"),
self.parameterChanged)
# Enable percentage or param selection
self.form.OptionsLabel.setEnabled(True)
self.form.OptionsLabel.setVisible(True)
self.form.OptionsLabel.setText("Arc param.")
self.form.OptionsBox.setEnabled(True)
self.form.OptionsBox.setVisible(True)
self.form.OptionsBox.addItems(["mm", "%"])
QtCore.QObject.connect(self.form.OptionsBox,
QtCore.SIGNAL("currentIndexChanged(QString)"),
self.choiceChanged)
BaseFeaturePanel.__init__(self, selected, so_desc)
# Place the frame wherever the values are atm
self.local_ffpl = FreeCAD.Placement()
self.createFrame()
self.fframe.Positioning = "PointOnEdge"
self.choiceChanged(self.form.OptionsBox.currentText())
self.parameterChanged()
def parameterChanged(self):
value = self.form.VBox.value()
if self.form.OptionsBox.currentText() == "%":
value = self.p2mm(value)
edge = self.selected.SubObjects[0]
point = edge.valueAt(value)
tangentdir = edge.tangentAt(value)
rot = FreeCAD.Rotation(FreeCAD.Vector(1, 0, 0),
tangentdir)
abs_ffpl = FreeCAD.Placement(point, rot)
parent_pl = self.selected.Object.Placement
self.local_ffpl = parent_pl.inverse().multiply(abs_ffpl)
self.fframe.FeaturePlacement = self.local_ffpl
# force recompute of placement?
self.fframe.Placement = self.fframe.Placement
def choiceChanged(self, choice):
value = self.form.VBox.value()
if choice == "mm":
value = self.p2mm(value)
self.form.VBox.setSuffix("mm")
parameter_range = self.selected.SubObjects[0].ParameterRange
self.form.VBox.setRange(*parameter_range)
self.form.VBox.setSingleStep(0.1)
elif choice == "%":
value = self.mm2p(value)
self.form.VBox.setSuffix("%")
self.form.VBox.setRange(0, 100.0)
self.form.VBox.setSingleStep(1.0)
self.form.VBox.setValue(value)
def p2mm(self, value):
parameter_range = self.selected.SubObjects[0].ParameterRange
delta = parameter_range[1] - parameter_range[0]
return 0.01*value*delta + parameter_range[0]
def mm2p(self, value):
parameter_range = self.selected.SubObjects[0].ParameterRange
delta = parameter_range[1] - parameter_range[0]
return 100.0*(value - parameter_range[0])/delta
class PointOnSurfacePanel(BaseFeaturePanel):
"""Create a feature on a surface."""
def __init__(self, selected, so_desc):
uiform_path = os.path.join(uidir, "FramePlacer.ui")
self.form = FreeCADGui.PySideUic.loadUi(uiform_path)
# Enable both parameters
self.form.ULabel.setVisible(True)
self.form.VLabel.setVisible(True)
self.form.UBox.setVisible(True)
self.form.VBox.setVisible(True)
QtCore.QObject.connect(self.form.VBox,
QtCore.SIGNAL("valueChanged(double)"),
self.parameterChanged)
QtCore.QObject.connect(self.form.UBox,
QtCore.SIGNAL("valueChanged(double)"),
self.parameterChanged)
# Enable percentage or param selection
self.form.OptionsLabel.setEnabled(True)
self.form.OptionsLabel.setVisible(True)
self.form.OptionsLabel.setText("Surf. param.")
self.form.OptionsBox.setEnabled(True)
self.form.OptionsBox.setVisible(True)
self.form.OptionsBox.addItems(["mm", "%"])
QtCore.QObject.connect(self.form.OptionsBox,
QtCore.SIGNAL("currentIndexChanged(QString)"),
self.choiceChanged)
BaseFeaturePanel.__init__(self, selected, so_desc)
# Place the frame wherever the values are atm
self.local_ffpl = FreeCAD.Placement()
self.createFrame()
self.fframe.Positioning = "PointOnSurface"
self.choiceChanged(self.form.OptionsBox.currentText())
self.parameterChanged()
def parameterChanged(self):
value = (self.form.UBox.value(), self.form.VBox.value())
if self.form.OptionsBox.currentText() == "%":
value = self.p2mm(value)
face = self.selected.SubObjects[0]
point = face.valueAt(*value)
normaldir = face.normalAt(*value)
rotation = FreeCAD.Rotation(FreeCAD.Vector(0, 0, 1),
normaldir)
abs_ffpl = FreeCAD.Placement(point, rotation)
parent_pl = self.selected.Object.Placement
self.local_ffpl = parent_pl.inverse().multiply(abs_ffpl)
self.fframe.FeaturePlacement = self.local_ffpl
# Force recompute of placement
self.fframe.Placement = self.fframe.Placement
def choiceChanged(self, choice):
value = (self.form.UBox.value(), self.form.VBox.value())
if choice == "mm":
value = self.p2mm(value)
parameter_range = self.selected.SubObjects[0].ParameterRange
self.form.UBox.setRange(parameter_range[0], parameter_range[1])
self.form.UBox.setSuffix("mm")
self.form.UBox.setSingleStep(0.1)
self.form.VBox.setRange(parameter_range[2], parameter_range[3])
self.form.VBox.setSuffix("mm")
self.form.VBox.setSingleStep(0.1)
elif choice == "%":
value = self.mm2p(value)
self.form.UBox.setRange(0.0, 100.0)
self.form.UBox.setSuffix("%")
self.form.VBox.setRange(0.0, 100.0)
self.form.UBox.setSingleStep(1.0)
self.form.VBox.setSuffix("%")
self.form.VBox.setSingleStep(1.0)
self.form.UBox.setValue(value[0])
self.form.VBox.setValue(value[1])
def p2mm(self, value):
parameter_range = self.selected.SubObjects[0].ParameterRange
delta = [parameter_range[1] - parameter_range[0],
parameter_range[3] - parameter_range[2]]
u = 0.01*value[0]*delta[0] + parameter_range[0]
v = 0.01*value[1]*delta[1] + parameter_range[2]
return (u, v)
def mm2p(self, value):
parameter_range = self.selected.SubObjects[0].ParameterRange
delta = [parameter_range[1] - parameter_range[0],
parameter_range[3] - parameter_range[2]]
u = 100.0*(value[0] - parameter_range[0])/delta[0]
v = 100.0*(value[1] - parameter_range[2])/delta[1]
return (u, v)
class CenterPanel(BaseFeaturePanel):
"""Create a feature frame on center."""
def __init__(self, selected, so_desc):
uiform_path = os.path.join(uidir, "FramePlacer.ui")
self.form = FreeCADGui.PySideUic.loadUi(uiform_path)
BaseFeaturePanel.__init__(self, selected, so_desc)
edge_curve_list = ["ArcOfCircle",
"ArcOfEllipse",
"ArcOfHyperbola",
"ArcOfParabola",
"Circle",
"Ellipse",
"Hyperbola",
"Parabola"]
face_surf_list = ["Sphere",
"Toroid"]
if so_desc[0] in edge_curve_list:
edge = selected.SubObjects[0]
axis = edge.Curve.Axis
rotation = FreeCAD.Rotation(FreeCAD.Vector(0, 0, 1),
axis)
center_point = edge.Curve.Center
elif so_desc[0] in face_surf_list:
face = selected.SubObjects[0]
axis = face.Surface.Axis
rotation = FreeCAD.Rotation(FreeCAD.Vector(0, 0, 1),
axis)
center_point = face.Surface.Center
else:
rotation = FreeCAD.Rotation()
center_point = selected.SubObjects[0].CenterOfMass
parent_pl = selected.Object.Placement
abs_pl = FreeCAD.Placement(center_point,
rotation)
self.local_ffpl = parent_pl.inverse().multiply(abs_pl)
self.createFrame()
self.fframe.Positioning = "Center"
class PointOnCenterlinePanel(BaseFeaturePanel):
"""Create a point on centerline of primitive."""
def __init__(self, selected, so_desc):
uiform_path = os.path.join(uidir, "FramePlacer.ui")
self.form = FreeCADGui.PySideUic.loadUi(uiform_path)
BaseFeaturePanel.__init__(self, selected, so_desc)
# Enable the along line parameter
self.form.VLabel.setVisible(True)
self.form.VLabel.setText("u")
self.form.VBox.setVisible(True)
QtCore.QObject.connect(self.form.VBox,
QtCore.SIGNAL("valueChanged(double)"),
self.parameterChanged)
# Enable percentage of param selection
self.form.OptionsLabel.setVisible(True)
self.form.OptionsLabel.setText("Line param.")
self.form.OptionsBox.setVisible(True)
self.form.OptionsBox.addItems(["mm", "%"])
QtCore.QObject.connect(self.form.OptionsBox,
QtCore.SIGNAL("currentIndexChanged(QString)"),
self.choiceChanged)
# Place the frame wherever the values are atm
self.local_ffpl = FreeCAD.Placement()
self.createFrame()
self.fframe.Positioning = "PointOnCenterline"
self.parameterChanged()
def parameterChanged(self):
value = self.form.VBox.value()
if self.form.OptionsBox.currentText() == "%":
value = self.p2mm(value)
displacement_pl = FreeCAD.Placement(FreeCAD.Vector(0, 0, value),
FreeCAD.Rotation())
# Find the center
axis = self.selected.SubObjects[0].Surface.Axis
rotation = FreeCAD.Rotation(FreeCAD.Vector(0, 0, 1),
axis)
center_point = self.selected.SubObjects[0].Surface.Center
center_pl = FreeCAD.Placement(center_point, rotation)
abs_ffpl = center_pl.multiply(displacement_pl)
parent_pl = self.selected.Object.Placement
self.local_ffpl = parent_pl.inverse().multiply(abs_ffpl)
self.fframe.FeaturePlacement = self.local_ffpl
# force recompute of placement
self.fframe.Placement = self.fframe.Placement
def choiceChanged(self, choice):
FreeCAD.Console.PrintMessage("choiceChanged\n")
value = self.form.VBox.value()
FreeCAD.Console.PrintMessage("preval:"+str(value)+"\n")
if choice == "mm":
value = self.p2mm(value)
self.form.VBox.setSuffix("mm")
parameter_range = self.selected.SubObjects[0].ParameterRange[2:]
self.form.VBox.setRange(*parameter_range)
self.form.VBox.setSingleStep(0.1)
elif choice == "%":
value = self.mm2p(value)
self.form.VBox.setSuffix("%")
self.form.VBox.setRange(0, 100)
self.form.VBox.setSingleStep(1.0)
self.form.VBox.setValue(value)
FreeCAD.Console.PrintMessage("postval:"+str(value)+"\n")
def p2mm(self, value):
parameter_range = self.selected.SubObjects[0].ParameterRange[2:]
delta = parameter_range[1] - parameter_range[0]
return 0.01*value*delta + parameter_range[0]
def mm2p(self, value):
parameter_range = self.selected.SubObjects[0].ParameterRange[2:]
delta = parameter_range[1] - parameter_range[0]
return 100.0*(value - parameter_range[0])/delta

View file

@ -1,520 +0,0 @@
import FreeCAD
import Part
import json # For exporting part infos
import os # for safer path handling
if FreeCAD.GuiUp:
import FreeCADGui
from PySide import QtGui
__title__ = "ARTools"
__author__ = "Mathias Hauan Arbo"
__workbenchname__ = "ARBench"
__version__ = "0.1"
__url__ = "https://github.com/mahaarbo/ARBench"
__doc__ = """
Useful tools for the Annotations for Robotics workbench."""
###################################################################
# Module functions
###################################################################
def vector2list(vec, scale=1e-3):
"""Gives the vector as a list, set scale for scaling factor.
default scale = 1e-3 for units in m."""
return [vec.x*scale, vec.y*scale, vec.z*scale]
def matrix2list(mat, scale=1e-3):
"""Gives the transformation matrix as a list, set scale 1 to get in mm."""
return [[mat.A11, mat.A12, mat.A13, mat.A14*scale],
[mat.A21, mat.A22, mat.A23, mat.A24*scale],
[mat.A31, mat.A32, mat.A33, mat.A34*scale],
[mat.A41, mat.A42, mat.A43, mat.A44]]
def placement2axisvec(pl, scale=1e-3):
"""Gives the placement as an dictionary of origin and rotation.
origin: [x,y,z], rotation:{axis:[ax,ay,az], angle:ang}"""
return {"origin": vector2list(pl.Base, scale),
"rotation": {"axis": vector2list(pl.Rotation.Axis, scale=1),
"angle": pl.Rotation.Angle}}
def boundingBox2list(bb, scale=1e-3):
"""Gives the bounding box as a list in m instead of mm"""
return [bb.XMin*scale, bb.XMax*scale,
bb.YMin*scale, bb.YMax*scale,
bb.ZMin*scale, bb.ZMax*scale]
def principalProperties2dict(pp, scale=1e-3):
npp = {}
for key, value in pp.iteritems():
if type(value) is FreeCAD.Vector:
npp[key.lower()] = vector2list(value, scale=1e-3)
else:
npp[key.lower()] = value
return npp
def describeSubObject(subobj):
"""Returns PrimitiveType, ShapeType."""
if isinstance(subobj, Part.Vertex):
return "Vertex", "Vertex"
elif isinstance(subobj, Part.Edge):
if isinstance(subobj.Curve, Part.Arc):
return "Arc", "Edge"
elif isinstance(subobj.Curve, Part.ArcOfCircle):
return "ArcOfCircle", "Edge"
elif isinstance(subobj.Curve, Part.ArcOfEllipse):
return "ArcOfEllipse", "Edge"
elif isinstance(subobj.Curve, Part.ArcOfHyperbola):
return "ArcOfHyperbola", "Edge"
elif isinstance(subobj.Curve, Part.ArcOfParabola):
return "ArcOfParabola", "Edge"
elif isinstance(subobj.Curve, Part.BSplineCurve):
return "BSplineCurve", "Edge"
elif isinstance(subobj.Curve, Part.BezierCurve):
return "BezierCurve", "Edge"
elif isinstance(subobj.Curve, Part.Circle):
return "Circle", "Edge"
elif isinstance(subobj.Curve, Part.Ellipse):
return "Ellipse", "Edge"
elif isinstance(subobj.Curve, Part.Hyperbola):
return "Hyperbola", "Edge"
elif isinstance(subobj.Curve, Part.Line):
return "Line", "Edge"
elif isinstance(subobj.Curve, Part.Parabola):
return "Parabola", "Edge"
else:
FreeCAD.Console.PrintError("Unknown edge type")
elif isinstance(subobj, Part.Face):
if isinstance(subobj.Surface, Part.BSplineSurface):
return "BSplineSurface", "Face"
elif isinstance(subobj.Surface, Part.BezierSurface):
return "BezierSurface", "Face"
elif isinstance(subobj.Surface, Part.Cylinder):
return "Cylinder", "Face"
elif isinstance(subobj.Surface, Part.Plane):
return "Plane", "Face"
elif isinstance(subobj.Surface, Part.Sphere):
return "Sphere", "Face"
elif isinstance(subobj.Surface, Part.Toroid):
return "Toroid", "Face"
elif isinstance(subobj.Surface, Part.Cone):
return "Cone", "Face"
else:
FreeCAD.Console.PrintError("Unknown surface type")
# Better strategy desirable for the following:
elif isinstance(subobj, Part.Wire):
return "Wire", "Wire"
elif isinstance(subobj, Part.Shell):
return "Shell", "Shell"
elif isinstance(subobj, Part.Solid):
return "Solid", "Solid"
elif isinstance(subobj, Part.Compsolid):
return "Compsolid", "Compsolid"
elif isinstance(subobj, Part.Compound):
return "Compound", "Compound"
else:
FreeCAD.Console.PrintError("Unable to identify subobject.")
def closeToZero(a, tol=1e-10):
return abs(a) < tol
def spawnClassCommand(classname, function, resources):
"""
Commands, or buttons, are tedious to write. So this function spawns
one if the function to be executed takes no arguments.
Example usage:
spawnClassCommand("testcommand", testfunc,
{"Pixmap":"", "MenuText":"menutext","ToolTip":"tooltiptext"})
then add "testcommand" to commandlist in InitGui.py
"""
def Activated(s):
function()
def GetResources(s):
return resources
CommandClass = type("classname", (object,), {"Activated": Activated,
"GetResources": GetResources})
FreeCADGui.addCommand(classname, CommandClass())
def getLocalPartProps(obj):
old_placement = obj.Placement
obj.Placement = FreeCAD.Placement()
# Part properties
partprops = {
"label": obj.Label,
"placement": placement2axisvec(old_placement),
"boundingbox": boundingBox2list(obj.Shape.BoundBox),
"volume": obj.Shape.Volume*1e-9,
"centerofmass": vector2list(obj.Shape.CenterOfMass),
"principalproperties": principalProperties2dict(obj.Shape.PrincipalProperties)
}
obj.Placement = old_placement
return partprops
###################################################################
# Export functions
###################################################################
def exportPartInfo(obj, ofile):
"""
Exports part info to a new json file.
The part info includes:
Placement relative to world frame, bounding box, volume, center of mass,
principal properties.
For more information on principal properties, see TopoShape in OCCT
documentation.
"""
# File path stuff
odir, of = os.path.split(ofile)
if not os.path.exists(odir):
os.makedirs(odir)
if not of.lower().endswith(".json"):
ofile = ofile + ".json"
partprops = getLocalPartProps(obj)
with open(ofile, "wb") as propfile:
json.dump(partprops, propfile, indent=1, separators=(',', ': '))
return True
def appendPartInfo(obj, ofile):
"""Rewrites/appends part info to an existing json file.
The part info includes:
Placement relative to world frame, bounding box, volume, center of mass,
principal properties.
For more information on principal properties, see TopoShape in OCCT
documentation.
"""
with open(ofile, "rb") as propfile:
partprops = json.load(propfile)
new_props = getLocalPartProps(obj)
partprops.update(new_props)
with open(ofile, "wb") as propfile:
json.dump(partprops, propfile, indent=1, separators=(',', ': '))
return True
def exportFeatureFrames(obj, ofile):
"""Exports feature frames attached to a part."""
# Get the feature frames
import ARFrames
ff_check = lambda x: isinstance(x.Proxy, ARFrames.FeatureFrame)
ff_list = filter(ff_check, obj.InList)
ff_named = {ff.Label: ff.Proxy.getDict() for ff in ff_list}
feature_dict = {"features": ff_named}
# File stuff
odir, of = os.path.split(ofile)
if not os.path.exists(odir):
os.makedirs(odir)
if not of.lower().endswith(".json"):
ofile = ofile + ".json"
with open(ofile, "wb") as propfile:
json.dump(feature_dict, propfile, indent=1, separators=(',', ': '))
return True
def appendFeatureFrames(obj, ofile):
"""Rewrites/appends featureframes attached to a part to an existing json
file."""
# Get the feature frames
import ARFrames
with open(ofile, "rb") as propfile:
partprops = json.load(propfile)
ff_check = lambda x: isinstance(x.Proxy, ARFrames.FeatureFrame)
ff_list = filter(ff_check, obj.InList)
ff_named = {ff.Label: ff.Proxy.getDict() for ff in ff_list}
feature_dict = {"features": ff_named}
if "features" not in partprops.keys():
partprops.update(feature_dict)
else:
partprops["features"].update(feature_dict["features"])
with open(ofile, "wb") as propfile:
json.dump(partprops, propfile, indent=1, separators=(',', ': '))
return True
def exportPartInfoDialogue():
"""Spawns a dialogue window for part info exporting"""
# Select only true parts
s = FreeCADGui.Selection.getSelection()
FreeCADGui.Selection.clearSelection()
if len(s) == 0:
FreeCAD.Console.PrintError("No part selected.")
return False
unique_selected = []
for item in s:
if item not in unique_selected and isinstance(item, Part.Feature):
# Ensuring that we are parts
unique_selected.append(item)
FreeCADGui.Selection.addSelection(item)
# Fix wording
textprompt = "Save the properties of the part"
if len(unique_selected) > 1:
textprompt = textprompt + "s"
opts = QtGui.QFileDialog.DontConfirmOverwrite
# Create file dialog
ofile, filt = QtGui.QFileDialog.getSaveFileName(None, textprompt,
os.getenv("HOME"),
"*.json", options=opts)
if ofile == "":
# User cancelled
return False
if os.path.exists(ofile):
msgbox = QtGui.QMessageBox()
msgbox.setText("File already exists. We can overwrite the file, or add the information/rewrite only relevant sections.")
append_button = msgbox.addButton(unicode("Append"),
QtGui.QMessageBox.YesRole)
overwrite_button = msgbox.addButton(unicode("Overwrite"),
QtGui.QMessageBox.NoRole)
msgbox.exec_()
if msgbox.clickedButton() == append_button:
NEWFILE = False
elif msgbox.clickedButton() == overwrite_button:
NEWFILE = True
else:
return False
else:
NEWFILE = True
if NEWFILE:
exportPartInfo(unique_selected[0], ofile)
else:
appendPartInfo(unique_selected[0], ofile)
if len(unique_selected) > 1:
FreeCAD.Console.PrintWarning("Multi-part export not yet supported\n")
FreeCAD.Console.PrintMessage("Properties exported to "+str(ofile)+"\n")
def exportFeatureFramesDialogue():
"""Spawns a dialogue window for a part's feature frames to be exported."""
# Select only true parts
s = FreeCADGui.Selection.getSelection()
FreeCADGui.Selection.clearSelection()
if len(s) == 0:
FreeCAD.Console.PrintError("No part selected.")
return False
unique_selected = []
for item in s:
if item not in unique_selected and isinstance(item, Part.Feature):
# Ensuring that we are parts
unique_selected.append(item)
FreeCADGui.Selection.addSelection(item)
# Fix wording
textprompt = "Save the feature frames attached to the part"
if len(unique_selected) > 1:
textprompt = textprompt + "s"
opts = QtGui.QFileDialog.DontConfirmOverwrite
# Create file dialog
ofile, filt = QtGui.QFileDialog.getSaveFileName(None, textprompt,
os.getenv("HOME"),
"*.json", options=opts)
if ofile == "":
# User cancelled
return False
if os.path.exists(ofile):
msgbox = QtGui.QMessageBox()
msgbox.setText("File already exists. We can overwrite the file, or add the information/rewrite only relevant sections.")
append_button = msgbox.addButton(unicode("Append"),
QtGui.QMessageBox.YesRole)
overwrite_button = msgbox.addButton(unicode("Overwrite"),
QtGui.QMessageBox.NoRole)
msgbox.exec_()
if msgbox.clickedButton() == append_button:
NEWFILE = False
elif msgbox.clickedButton() == overwrite_button:
NEWFILE = True
else:
return False
else:
NEWFILE = True
if NEWFILE:
exportFeatureFrames(unique_selected[0], ofile)
else:
appendFeatureFrames(unique_selected[0], ofile)
if len(unique_selected) > 1:
FreeCAD.Console.PrintWarning("Multi-part export not yet supported\n")
FreeCAD.Console.PrintMessage("Feature frames of " + str(unique_selected[0].Label) + " exported to " + str(ofile) + "\n")
def exportPartInfoAndFeaturesDialogue():
"""Spawns a dialogue window for exporting both."""
s = FreeCADGui.Selection.getSelection()
FreeCADGui.Selection.clearSelection()
if len(s) == 0:
FreeCAD.Console.PrintError("No part selected.")
return False
unique_selected = []
for item in s:
if item not in unique_selected and isinstance(item, Part.Feature):
# Ensuring that we are parts
unique_selected.append(item)
FreeCADGui.Selection.addSelection(item)
# Fix wording
textprompt = "Save the part info and feature frames attached to the part"
if len(unique_selected) > 1:
textprompt = textprompt + "s"
opts = QtGui.QFileDialog.DontConfirmOverwrite
# Create file dialog
ofile, filt = QtGui.QFileDialog.getSaveFileName(None, textprompt,
os.getenv("HOME"),
"*.json", options=opts)
if ofile == "":
# User cancelled
return False
if os.path.exists(ofile):
msgbox = QtGui.QMessageBox()
msgbox.setText("File already exists. We can overwrite the file, or add the information/rewrite only relevant sections.")
append_button = msgbox.addButton(unicode("Append"),
QtGui.QMessageBox.YesRole)
overwrite_button = msgbox.addButton(unicode("Overwrite"),
QtGui.QMessageBox.NoRole)
msgbox.exec_()
if msgbox.clickedButton() == append_button:
NEWFILE = False
elif msgbox.clickedButton() == overwrite_button:
NEWFILE = True
else:
return False
else:
NEWFILE = True
if NEWFILE:
exportPartInfo(unique_selected[0], ofile)
appendFeatureFrames(unique_selected[0], ofile)
else:
appendPartInfo(unique_selected[0], ofile)
appendFeatureFrames(unique_selected[0], ofile)
if len(unique_selected) > 1:
FreeCAD.Console.PrintWarning("Multi-part export not yet supported.\n")
FreeCAD.Console.PrintMessage("Feature frames of "
+ str(unique_selected[0].Label)
+ " exported to " + str(ofile) + "\n")
###################################################################
# GUI Commands
###################################################################
uidir = os.path.join(FreeCAD.getUserAppDataDir(),
"Mod", __workbenchname__, "UI")
icondir = os.path.join(uidir, "icons")
spawnClassCommand("ExportPartInfoAndFeaturesDialogueCommand",
exportPartInfoAndFeaturesDialogue,
{"Pixmap": str(os.path.join(icondir, "parttojson.svg")),
"MenuText": "Export info and featureframes",
"ToolTip": "Export part properties (placement, C.O.M) and feature frames"})
###################################################################
# Information from primitive type
###################################################################
def getPrimitiveInfo(prim_type, subobj, scale=1e-3):
"""returns a dictionary of the primitive's specific information."""
d = {}
if prim_type == "ArcOfCircle":
d["radius"] = scale*subobj.Curve.Radius
d["center"] = vector2list(subobj.Curve.Center, scale)
d["axis"] = vector2list(subobj.Curve.Axis, scale=1)
d["parameterrange"] = subobj.ParameterRange
elif prim_type == "ArcOfEllipse":
d["center"] = vector2list(subobj.Curve.Center, scale)
d["axis"] = vector2list(subobj.Curve.Axis, scale=1)
d["majorradius"] = scale*subobj.Curve.MajorRadius
d["minorradius"] = scale*subobj.Curve.MinorRadius
d["parameterrange"] = subobj.ParameterRange
elif prim_type == "ArcOfHyperBola":
d["anglexu"] = subobj.Curve.AngleXU
d["axis"] = vector2list(subobj.Curve.Axis, scale=1)
d["center"] = vector2list(subobj.Curve.Center, scale)
d["majorradius"] = scale*subobj.Curve.MajorRadius
d["minorradius"] = scale*subobj.Curve.MinorRadius
d["parameterrange"] = subobj.ParameterRange
elif prim_type == "ArcOfParabola":
d["anglexu"] = subobj.Curve.AngleXU
d["axis"] = vector2list(subobj.Curve.Axis, scale=1)
d["center"] = vector2list(subobj.Curve.Center, scale)
d["focal"] = scale*subobj.Curve.Focal
elif prim_type == "BSplineCurve":
FreeCAD.Console.PrintWarning("getPrimitiveInfo of BSpline incomplete.")
elif prim_type == "BezierCurve":
FreeCAD.Console.PrintWarning("getPrimitiveInfo of Bezier incomplete.")
elif prim_type == "Circle":
d["radius"] = scale*subobj.Curve.Radius
d["center"] = vector2list(subobj.Curve.Center, scale)
d["axis"] = vector2list(subobj.Curve.Axis, scale=1)
d["parameterrange"] = subobj.ParameterRange
elif prim_type == "Ellipse":
d["center"] = vector2list(subobj.Curve.Center, scale)
d["axis"] = vector2list(subobj.Curve.Axis, scale=1)
d["majorradius"] = scale*subobj.Curve.MajorRadius
d["minorradius"] = scale*subobj.Curve.MinorRadius
d["parameterrange"] = subobj.ParameterRange
elif prim_type == "Hyperbola":
d["anglexu"] = subobj.Curve.AngleXU
d["axis"] = vector2list(subobj.Curve.Axis, scale=1)
d["center"] = vector2list(subobj.Curve.Center, scale)
d["majorradius"] = scale*subobj.Curve.MajorRadius
d["minorradius"] = scale*subobj.Curve.MinorRadius
d["parameterrange"] = subobj.ParameterRange
elif prim_type == "Parabola":
d["anglexu"] = subobj.Curve.AngleXU
d["axis"] = vector2list(subobj.Curve.Axis, scale=1)
d["center"] = vector2list(subobj.Curve.Center, scale)
d["focal"] = scale*subobj.Curve.Focal
elif prim_type == "Line":
if int(FreeCAD.Version()[1]) > 16:
sp = subobj.valueAt(subobj.FirstParameter)
ep = subobj.valueAt(subobj.LastParameter)
d["startpoint"] = vector2list(sp)
d["endpoint"] = vector2list
else:
if not hasattr(subobj.Curve, "Infinite"):
d["startpoint"] = vector2list(subobj.Curve.StartPoint)
d["endpoint"] = vector2list(subobj.Curve.EndPoint)
if hasattr(subobj.Curve, "Infinite"):
if subobj.Curve.Infinite:
d["infinite"] = subobj.Curve.Infinite
else:
d["startpoint"] = vector2list(subobj.Curve.StartPoint)
d["endpoint"] = vector2list(subobj.Curve.EndPoint)
elif prim_type == "BSplineSurface":
FreeCAD.Console.PrintWarning("getPrimitiveInfo of BSpline incomplete.")
elif prim_type == "BezierSurface":
FreeCAD.Console.PrintWarning("getPrimitiveInfo of Bezier incomplete.")
elif prim_type == "Cylinder":
d["axis"] = vector2list(subobj.Surface.Axis, scale=1)
d["radius"] = scale*subobj.Surface.Radius
d["center"] = vector2list(subobj.Surface.Center)
PR = list(subobj.ParameterRange)
PR[2] = PR[2]*scale
PR[3] = PR[3]*scale
d["parameterrange"] = PR
elif prim_type == "Plane":
d["axis"] = vector2list(subobj.Surface.Axis, scale=1)
d["position"] = vector2list(subobj.Surface.Position, scale)
d["parameterrange"] = [scale*i for i in subobj.ParameterRange]
elif prim_type == "Sphere":
d["axis"] = vector2list(subobj.Surface.Axis, scale=1)
d["center"] = vector2list(subobj.Surface.Center, scale)
d["radius"] = scale*subobj.Surface.Radius
d["parameterrange"] = subobj.ParameterRange
elif prim_type == "Toroid":
d["axis"] = vector2list(subobj.Surface.Axis, scale=1)
d["center"] = vector2list(subobj.Surface.Center, scale)
d["majorradius"] = scale*subobj.Surface.MajorRadius
d["minorradius"] = scale*subobj.Surface.MinorRadius
d["parameterrange"] = subobj.Surface.ParameterRange
elif prim_type == "Cone":
d["axis"] = vector2list(subobj.Surface.Axis, scale=1)
d["center"] = vector2list(subobj.Surface.Center, scale)
d["radius"] = scale*subobj.Surface.Radius
d["semiangle"] = subobj.Surface.SemiAngle
d["parameterrange"] = subobj.ParameterRange
FreeCAD.Console.PrintWarning("getPrimitiveInfo of Cone may have wrong ParameterRange.")
return d

View file

@ -1 +0,0 @@
#I made this?

View file

@ -1,39 +0,0 @@
class ARBench(Workbench):
MenuText = "ARBench"
ToolTip = "Annotation for Robotics workbench"
Icon = """"""
def __init__(self):
import os
self.Icon = os.path.join(FreeCAD.getUserAppDataDir(), "Mod",
"ARBench", "UI", "icons", "frame.svg")
def Initialize(self):
"""This function is executed when FreeCAD starts"""
import ARFrames
self.framecommands = ["FrameCommand",
"AllPartFramesCommand",
"FeatureFrameCommand"]
self.toolcommands = ["ExportPartInfoAndFeaturesDialogueCommand"]
self.appendToolbar("AR Frames", self.framecommands)
self.appendToolbar("AR Tools", self.toolcommands)
def Activated(self):
"""This function is executed when the workbench is activated."""
#
return
def Deactivated(self):
"""This function is executed when the workbench is deactivated."""
#
return
def ContextMenu(self, recipient):
"""This is execcuted whenever the user right-clicks on screen."""
pass
def GetClassName(self):
# This function is mandatory if this is a full python workbench
return "Gui::PythonWorkbench"
Gui.addWorkbench(ARBench())

1004
LICENSE

File diff suppressed because it is too large Load diff

View file

@ -1,32 +1,31 @@
![implementation preview](https://raw.githubusercontent.com/mahaarbo/ARBench/master/UI/icons/github_preview.png)
# Arbench
Annotation for robotics bench. A FreeCAD workbench for annotating frames of interest, exporting these w.r.t. the part frame, and exporting part information.
# Фреймворк Робосборщик
# Installation instructions
This workbench supports versions of FreeCAD>0.16.
1. [Install FreeCAD](https://www.freecadweb.org/wiki/Installing)
2. If you're not on Ubuntu follow the [workbench installation instructions](https://www.freecadweb.org/wiki/How_to_install_additional_workbenches) or you can do the following on Ubuntu.
3. Custom workbenches are located in `.FreeCAD/Mod/` under your home directory
`cd ~/.FreeCAD/Mod/`
3. Either
- Clone the repository there
- symlink the cloned repo in there (`ln -s ./ARBench ~/.FreeCAD/ARBench`)
4. Start the workbench by
1. Running FreeCAD
2. Open a STEP file
3. Open the `ARBench` workbench
# Usage
Фреймворк Робосборщик (Robossembler Framework) предназначен для автоматизации разработки управляющих программ для роботов-манипуляторов, их отладки в виртуальных средах и оценки производительности.
1. Click a small feature e.g. a circle
2. Press the feature frame creator (cone with a magnifying glass on it icon)
3. Chose type of feature to create
4. Chose feature parameters if relevant and the offset of the frame from the feature.
5. Repeat 4 for each feature you want on each part
6. Click a part and press the export to json button (block->textfile icon)
7. Save json
8. Use the json with whatever you want. E.g. [`arbench_part_publisher`](https://github.com/mahaarbo/arbench_part_publisher)
Фреймворк состоит из следующих функциональных модулей
1. __Модуль автоматической генерации последовательности сборки__ (`as_generator`) генерирует граф сборки из статической модели изделия с учётом дополнительных опций и ограничений.
2. __Модуль построения технологических карт__ (`pddl_configurator`) использует модели производственного оборудования (робот-манипулятор,3D-принтер) для формирования спецификаций задач в PDDL-совместимом формате для передачи в систему планирования совместно с последовательностью сборки.
3. __Модуль экспорта моделей в виртуальные среды__ (`env_exporter`) (игровые движки, движки физики, системы рендеринга, симуляторы) формирует т.н. ассеты, то есть модели, адаптированные для использования в виртуальных средах (тесселированные или подверженные ретопологии).
4. __Модуль генерации наборов данных__ (`dataset_generator`) аггрегирует данные симуляции для их последующей обработки и машинного обучения с целью развития навыков робота.
5. __Модуль исполнения планов__ управляет движениями и задачами робота в режиме реального времени. Совместимый со стандартом ROS2. Исходный код см. в репозитории [robossembler-ros2](https://gitlab.com/robossembler/robossembler-ros2)
6. __Модуль оценки производительности__ (`benchmark`) агрегирует информацию об эффективности методов получения навыков (вычислительная ресурсоёмкость, размер занимаемого дискового пространства) и эффективности самих навыков (скорость, точность).
7. __Модуль управления виртуальными средами__ управляет запуском подходящих отработки конкретных навыков виртуальных сред. Исходный код см. в репозитории [robossembler-ros2](https://gitlab.com/robossembler/robossembler-ros2)
# Генератор последовательности сборки (ASP)
Данный программный модуль(cad_parts_adjacency_matrix.py) предназначен для решения задачи планирования сборки. Он формирует граф сборки состоящий из И/ИЛИ и оценивает полученные там решения по набору из 4-ёх формальных правил для проверки сгенерированного графа, давая обратную связь для инженеров-конструкторов.
Формальный правила называются предикатами. Модуль ASP предусматривает следующие разновидности предикатов:
- __Предикат геометрической осуществимости__. Верен для тех последовательностей сборки, которые удовлетворяют критерию геометрической осуществимости - когда все части графа сборки могут соприкосаться в определенной последовательности без каких либо столконовений.
- __Предикат механической осуществимость__. Верна для последовательности сборки, когда инструменты сборки могут осуществлять указанную операцию без каких либо коллизий с изделием.
- __Предикат стабильной осуществимости__. Верен для последовательности сборки, когда сборка на каждом из этапов приходит к стабильному состоянию.
- __Предикат степеней свободы__. Формируется на основе уже сгенерированных графов/графа сборки. В каких степенях свободы возможно перемещать деталь.
# Генерация сцен
TODO: составить описание
[пример файла описания сцены](docs/scene_generator)
# Todo
-[] Add export all parts to meshes

View file

@ -1,73 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>FeatureFrameCreator</class>
<widget class="QDialog" name="FeatureFrameCreator">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>235</width>
<height>238</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>235</width>
<height>238</height>
</size>
</property>
<property name="baseSize">
<size>
<width>235</width>
<height>238</height>
</size>
</property>
<property name="windowTitle">
<string>Feature Frame</string>
</property>
<widget class="QGraphicsView" name="Preview">
<property name="geometry">
<rect>
<x>30</x>
<y>29</y>
<width>170</width>
<height>151</height>
</rect>
</property>
</widget>
<widget class="QComboBox" name="ChoicesBox">
<property name="geometry">
<rect>
<x>30</x>
<y>190</y>
<width>171</width>
<height>27</height>
</rect>
</property>
</widget>
<widget class="QLabel" name="PickedTypeLabel">
<property name="geometry">
<rect>
<x>35</x>
<y>10</y>
<width>161</width>
<height>20</height>
</rect>
</property>
<property name="text">
<string>TextLabel</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</widget>
<resources/>
<connections/>
</ui>

View file

@ -1,520 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>dialog</class>
<widget class="QDialog" name="dialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>299</width>
<height>292</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>299</width>
<height>292</height>
</size>
</property>
<property name="windowTitle">
<string>Part Frame Creator</string>
</property>
<widget class="QDoubleSpinBox" name="XBox">
<property name="geometry">
<rect>
<x>52</x>
<y>85</y>
<width>103</width>
<height>27</height>
</rect>
</property>
<property name="toolTip">
<string>Offset in part frame x direction</string>
</property>
<property name="suffix">
<string> mm</string>
</property>
<property name="minimum">
<double>-1000.000000000000000</double>
</property>
<property name="maximum">
<double>1000.000000000000000</double>
</property>
</widget>
<widget class="QDoubleSpinBox" name="YBox">
<property name="geometry">
<rect>
<x>52</x>
<y>118</y>
<width>103</width>
<height>27</height>
</rect>
</property>
<property name="toolTip">
<string>offset in part frame z direction</string>
</property>
<property name="suffix">
<string> mm</string>
</property>
<property name="minimum">
<double>-1000.000000000000000</double>
</property>
<property name="maximum">
<double>1000.000000000000000</double>
</property>
</widget>
<widget class="QDoubleSpinBox" name="ZBox">
<property name="geometry">
<rect>
<x>52</x>
<y>151</y>
<width>103</width>
<height>27</height>
</rect>
</property>
<property name="toolTip">
<string>offset in part frame z direction</string>
</property>
<property name="suffix">
<string> mm</string>
</property>
<property name="decimals">
<number>2</number>
</property>
<property name="minimum">
<double>-1000.000000000000000</double>
</property>
<property name="maximum">
<double>1000.000000000000000</double>
</property>
</widget>
<widget class="QLabel" name="XLabel">
<property name="geometry">
<rect>
<x>9</x>
<y>85</y>
<width>16</width>
<height>17</height>
</rect>
</property>
<property name="text">
<string>x</string>
</property>
<property name="buddy">
<cstring>XBox</cstring>
</property>
</widget>
<widget class="QLabel" name="YLabel">
<property name="geometry">
<rect>
<x>9</x>
<y>118</y>
<width>16</width>
<height>17</height>
</rect>
</property>
<property name="text">
<string>y</string>
</property>
<property name="buddy">
<cstring>YBox</cstring>
</property>
</widget>
<widget class="QLabel" name="ZLabel">
<property name="geometry">
<rect>
<x>9</x>
<y>151</y>
<width>16</width>
<height>17</height>
</rect>
</property>
<property name="text">
<string>z</string>
</property>
<property name="buddy">
<cstring>ZBox</cstring>
</property>
</widget>
<widget class="QLabel" name="RollLabel">
<property name="geometry">
<rect>
<x>161</x>
<y>85</y>
<width>24</width>
<height>17</height>
</rect>
</property>
<property name="toolTip">
<string>roll offset from part frame</string>
</property>
<property name="text">
<string>roll</string>
</property>
<property name="buddy">
<cstring>RollBox</cstring>
</property>
</widget>
<widget class="QLabel" name="PitchLabel">
<property name="geometry">
<rect>
<x>161</x>
<y>118</y>
<width>35</width>
<height>17</height>
</rect>
</property>
<property name="toolTip">
<string>pitch offset from part frame</string>
</property>
<property name="text">
<string>pitch</string>
</property>
<property name="buddy">
<cstring>PitchBox</cstring>
</property>
</widget>
<widget class="QLabel" name="YawLabel">
<property name="geometry">
<rect>
<x>161</x>
<y>151</y>
<width>29</width>
<height>17</height>
</rect>
</property>
<property name="toolTip">
<string>yaw offset from part frame</string>
</property>
<property name="text">
<string>yaw</string>
</property>
<property name="buddy">
<cstring>YawBox</cstring>
</property>
</widget>
<widget class="QDoubleSpinBox" name="RollBox">
<property name="geometry">
<rect>
<x>228</x>
<y>85</y>
<width>61</width>
<height>27</height>
</rect>
</property>
<property name="toolTip">
<string>roll offset from part frame</string>
</property>
<property name="suffix">
<string>°</string>
</property>
<property name="decimals">
<number>1</number>
</property>
<property name="maximum">
<double>360.000000000000000</double>
</property>
</widget>
<widget class="QDoubleSpinBox" name="PitchBox">
<property name="geometry">
<rect>
<x>228</x>
<y>118</y>
<width>61</width>
<height>27</height>
</rect>
</property>
<property name="toolTip">
<string>pitch offset from part frame</string>
</property>
<property name="suffix">
<string>°</string>
</property>
<property name="decimals">
<number>1</number>
</property>
<property name="maximum">
<double>360.000000000000000</double>
</property>
</widget>
<widget class="QDoubleSpinBox" name="YawBox">
<property name="geometry">
<rect>
<x>228</x>
<y>151</y>
<width>61</width>
<height>27</height>
</rect>
</property>
<property name="toolTip">
<string>yaw offset from part frame</string>
</property>
<property name="suffix">
<string>°</string>
</property>
<property name="decimals">
<number>1</number>
</property>
<property name="maximum">
<double>360.000000000000000</double>
</property>
</widget>
<widget class="QPlainTextEdit" name="FrameLabelField">
<property name="geometry">
<rect>
<x>94</x>
<y>9</y>
<width>195</width>
<height>31</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Label of the frame</string>
</property>
<property name="statusTip">
<string>Label of the new frame</string>
</property>
<property name="whatsThis">
<string>Label of the new frame, must be unique</string>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
</widget>
<widget class="QLabel" name="FrameLabelLabel">
<property name="geometry">
<rect>
<x>9</x>
<y>9</y>
<width>79</width>
<height>31</height>
</rect>
</property>
<property name="text">
<string>Frame label</string>
</property>
</widget>
<widget class="QLabel" name="OffsetLabel">
<property name="geometry">
<rect>
<x>9</x>
<y>48</y>
<width>281</width>
<height>31</height>
</rect>
</property>
<property name="toolTip">
<string>Define an offset from the part frame if needed</string>
</property>
<property name="text">
<string>Offset from part frame</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
<widget class="QLabel" name="ScaleLabel">
<property name="geometry">
<rect>
<x>160</x>
<y>180</y>
<width>71</width>
<height>21</height>
</rect>
</property>
<property name="toolTip">
<string>Scale of the axis arrows</string>
</property>
<property name="statusTip">
<string>Scale of the axis arrows</string>
</property>
<property name="whatsThis">
<string>Scale of the axis arrows</string>
</property>
<property name="text">
<string>Axis scale</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
<widget class="QDoubleSpinBox" name="ScaleBox">
<property name="geometry">
<rect>
<x>230</x>
<y>180</y>
<width>60</width>
<height>27</height>
</rect>
</property>
<property name="toolTip">
<string>Scale of the axis arrows</string>
</property>
<property name="statusTip">
<string>Scale of the axis arrows</string>
</property>
<property name="whatsThis">
<string>Scale of the axis arrows</string>
</property>
<property name="minimum">
<double>0.100000000000000</double>
</property>
<property name="maximum">
<double>2.000000000000000</double>
</property>
<property name="singleStep">
<double>0.010000000000000</double>
</property>
<property name="value">
<double>0.110000000000000</double>
</property>
</widget>
<widget class="QLabel" name="OptionsLabel">
<property name="enabled">
<bool>true</bool>
</property>
<property name="geometry">
<rect>
<x>20</x>
<y>220</y>
<width>66</width>
<height>31</height>
</rect>
</property>
<property name="visible">
<bool>false</bool>
</property>
<property name="text">
<string>Options</string>
</property>
<property name="buddy">
<cstring>OptionsBox</cstring>
</property>
</widget>
<widget class="QComboBox" name="OptionsBox">
<property name="enabled">
<bool>true</bool>
</property>
<property name="geometry">
<rect>
<x>210</x>
<y>220</y>
<width>78</width>
<height>27</height>
</rect>
</property>
<property name="visible">
<bool>false</bool>
</property>
</widget>
<widget class="QDoubleSpinBox" name="UBox">
<property name="enabled">
<bool>true</bool>
</property>
<property name="geometry">
<rect>
<x>100</x>
<y>250</y>
<width>62</width>
<height>27</height>
</rect>
</property>
<property name="visible">
<bool>false</bool>
</property>
</widget>
<widget class="QDoubleSpinBox" name="VBox">
<property name="enabled">
<bool>true</bool>
</property>
<property name="geometry">
<rect>
<x>220</x>
<y>250</y>
<width>62</width>
<height>27</height>
</rect>
</property>
<property name="visible">
<bool>false</bool>
</property>
</widget>
<widget class="QLabel" name="ULabel">
<property name="enabled">
<bool>true</bool>
</property>
<property name="geometry">
<rect>
<x>80</x>
<y>250</y>
<width>16</width>
<height>31</height>
</rect>
</property>
<property name="visible">
<bool>false</bool>
</property>
<property name="text">
<string>u</string>
</property>
<property name="buddy">
<cstring>UBox</cstring>
</property>
</widget>
<widget class="QLabel" name="VLabel">
<property name="enabled">
<bool>true</bool>
</property>
<property name="geometry">
<rect>
<x>200</x>
<y>250</y>
<width>16</width>
<height>31</height>
</rect>
</property>
<property name="visible">
<bool>false</bool>
</property>
<property name="text">
<string>v</string>
</property>
<property name="buddy">
<cstring>VBox</cstring>
</property>
</widget>
<widget class="QLabel" name="CoordsLabel">
<property name="enabled">
<bool>true</bool>
</property>
<property name="geometry">
<rect>
<x>20</x>
<y>256</y>
<width>51</width>
<height>21</height>
</rect>
</property>
<property name="visible">
<bool>false</bool>
</property>
<property name="text">
<string>Coords:</string>
</property>
</widget>
</widget>
<resources/>
<connections/>
</ui>

View file

@ -1,262 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Dialog</class>
<widget class="QDialog" name="Dialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>323</width>
<height>325</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>316</width>
<height>325</height>
</size>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<widget class="QLabel" name="TaskLabel">
<property name="geometry">
<rect>
<x>10</x>
<y>20</y>
<width>71</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>Task Label</string>
</property>
</widget>
<widget class="QPushButton" name="SelectButton">
<property name="geometry">
<rect>
<x>150</x>
<y>290</y>
<width>161</width>
<height>27</height>
</rect>
</property>
<property name="text">
<string>Get from selection</string>
</property>
</widget>
<widget class="QLineEdit" name="TaskLabelField">
<property name="geometry">
<rect>
<x>100</x>
<y>20</y>
<width>211</width>
<height>27</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</widget>
<widget class="QLabel" name="HoleLabel">
<property name="geometry">
<rect>
<x>10</x>
<y>50</y>
<width>31</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>Hole</string>
</property>
</widget>
<widget class="QLabel" name="PegLabel">
<property name="geometry">
<rect>
<x>10</x>
<y>130</y>
<width>31</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>Peg</string>
</property>
</widget>
<widget class="QLabel" name="HolePartLabel">
<property name="geometry">
<rect>
<x>50</x>
<y>70</y>
<width>41</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>Part:</string>
</property>
</widget>
<widget class="QLabel" name="HoleFaceLabel">
<property name="geometry">
<rect>
<x>50</x>
<y>90</y>
<width>41</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>Face:</string>
</property>
</widget>
<widget class="QLabel" name="PegPartLabel">
<property name="geometry">
<rect>
<x>50</x>
<y>150</y>
<width>41</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>Part:</string>
</property>
</widget>
<widget class="QLabel" name="PegFaceLabel">
<property name="geometry">
<rect>
<x>50</x>
<y>170</y>
<width>41</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>Face:</string>
</property>
</widget>
<widget class="QLabel" name="HolePartField">
<property name="geometry">
<rect>
<x>100</x>
<y>70</y>
<width>231</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>PartLabel</string>
</property>
</widget>
<widget class="QLabel" name="HoleFaceIDField">
<property name="geometry">
<rect>
<x>100</x>
<y>90</y>
<width>231</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>FaceID</string>
</property>
</widget>
<widget class="QLabel" name="PegFaceIDField">
<property name="geometry">
<rect>
<x>100</x>
<y>170</y>
<width>231</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>FaceID</string>
</property>
</widget>
<widget class="QLabel" name="PegPartField">
<property name="geometry">
<rect>
<x>100</x>
<y>150</y>
<width>231</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>PartLabel</string>
</property>
</widget>
<widget class="QLabel" name="HoleFeatureSummary">
<property name="geometry">
<rect>
<x>100</x>
<y>110</y>
<width>231</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>Feature Description</string>
</property>
</widget>
<widget class="QLabel" name="HoleFeatureLabel">
<property name="geometry">
<rect>
<x>30</x>
<y>110</y>
<width>61</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>Feature:</string>
</property>
</widget>
<widget class="QLabel" name="PegFeatureSummary">
<property name="geometry">
<rect>
<x>100</x>
<y>190</y>
<width>231</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>Feature Description</string>
</property>
</widget>
<widget class="QLabel" name="PegFeatureLabel">
<property name="geometry">
<rect>
<x>30</x>
<y>190</y>
<width>61</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>Feature:</string>
</property>
</widget>
<widget class="QPushButton" name="AnimateButton">
<property name="geometry">
<rect>
<x>10</x>
<y>290</y>
<width>131</width>
<height>27</height>
</rect>
</property>
<property name="text">
<string>Animate</string>
</property>
</widget>
</widget>
<resources/>
<connections/>
</ui>

View file

@ -1,401 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Dialog</class>
<widget class="QDialog" name="Dialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>323</width>
<height>325</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>316</width>
<height>325</height>
</size>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<widget class="QLabel" name="TaskLabel">
<property name="geometry">
<rect>
<x>10</x>
<y>20</y>
<width>71</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>Task Label</string>
</property>
</widget>
<widget class="QPushButton" name="PushButton">
<property name="geometry">
<rect>
<x>150</x>
<y>290</y>
<width>161</width>
<height>27</height>
</rect>
</property>
<property name="text">
<string>Get from selection</string>
</property>
</widget>
<widget class="QLineEdit" name="lineEdit">
<property name="geometry">
<rect>
<x>100</x>
<y>20</y>
<width>211</width>
<height>27</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</widget>
<widget class="QLabel" name="HoleLabel">
<property name="geometry">
<rect>
<x>10</x>
<y>50</y>
<width>31</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>Hole</string>
</property>
</widget>
<widget class="QLabel" name="PegLabel">
<property name="geometry">
<rect>
<x>10</x>
<y>130</y>
<width>31</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>Peg</string>
</property>
</widget>
<widget class="QLabel" name="HolePartLabel">
<property name="geometry">
<rect>
<x>50</x>
<y>70</y>
<width>41</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>Part:</string>
</property>
</widget>
<widget class="QLabel" name="HoleFaceLabel">
<property name="geometry">
<rect>
<x>50</x>
<y>90</y>
<width>41</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>Face:</string>
</property>
</widget>
<widget class="QLabel" name="PegPartLabel">
<property name="geometry">
<rect>
<x>50</x>
<y>150</y>
<width>41</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>Part:</string>
</property>
</widget>
<widget class="QLabel" name="PegFaceLabel">
<property name="geometry">
<rect>
<x>50</x>
<y>170</y>
<width>41</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>Face:</string>
</property>
</widget>
<widget class="QLabel" name="HolePartField">
<property name="geometry">
<rect>
<x>100</x>
<y>70</y>
<width>231</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>PartLabel</string>
</property>
</widget>
<widget class="QLabel" name="HoleFaceIDField">
<property name="geometry">
<rect>
<x>100</x>
<y>90</y>
<width>231</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>FaceID</string>
</property>
</widget>
<widget class="QLabel" name="PegFaceIDField">
<property name="geometry">
<rect>
<x>100</x>
<y>170</y>
<width>231</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>FaceID</string>
</property>
</widget>
<widget class="QLabel" name="PegPartField">
<property name="geometry">
<rect>
<x>100</x>
<y>150</y>
<width>231</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>PartLabel</string>
</property>
</widget>
<widget class="QLabel" name="HoleFeatureSummary">
<property name="geometry">
<rect>
<x>100</x>
<y>110</y>
<width>231</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>Feature Description</string>
</property>
</widget>
<widget class="QLabel" name="HoleFeatureLabel">
<property name="geometry">
<rect>
<x>30</x>
<y>110</y>
<width>61</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>Feature:</string>
</property>
</widget>
<widget class="QLabel" name="PegFeatureSummary">
<property name="geometry">
<rect>
<x>100</x>
<y>190</y>
<width>231</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>Feature Description</string>
</property>
</widget>
<widget class="QLabel" name="PegFeatureLabel">
<property name="geometry">
<rect>
<x>30</x>
<y>190</y>
<width>61</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>Feature:</string>
</property>
</widget>
<widget class="QLabel" name="YLabel">
<property name="geometry">
<rect>
<x>80</x>
<y>250</y>
<width>16</width>
<height>17</height>
</rect>
</property>
<property name="text">
<string>y</string>
</property>
<property name="buddy">
<cstring>YBox</cstring>
</property>
</widget>
<widget class="QLabel" name="XLabel">
<property name="geometry">
<rect>
<x>80</x>
<y>230</y>
<width>16</width>
<height>17</height>
</rect>
</property>
<property name="text">
<string>x</string>
</property>
<property name="buddy">
<cstring>XBox</cstring>
</property>
</widget>
<widget class="QLabel" name="ZLabel">
<property name="geometry">
<rect>
<x>80</x>
<y>270</y>
<width>16</width>
<height>17</height>
</rect>
</property>
<property name="text">
<string>z</string>
</property>
<property name="buddy">
<cstring>ZBox</cstring>
</property>
</widget>
<widget class="QDoubleSpinBox" name="YBox">
<property name="geometry">
<rect>
<x>100</x>
<y>250</y>
<width>61</width>
<height>21</height>
</rect>
</property>
<property name="toolTip">
<string>offset in part frame z direction</string>
</property>
<property name="suffix">
<string/>
</property>
<property name="minimum">
<double>-1.000000000000000</double>
</property>
<property name="maximum">
<double>1.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
</widget>
<widget class="QDoubleSpinBox" name="XBox">
<property name="geometry">
<rect>
<x>100</x>
<y>230</y>
<width>61</width>
<height>20</height>
</rect>
</property>
<property name="toolTip">
<string>Offset in part frame x direction</string>
</property>
<property name="suffix">
<string/>
</property>
<property name="minimum">
<double>-1.000000000000000</double>
</property>
<property name="maximum">
<double>1.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
</widget>
<widget class="QDoubleSpinBox" name="ZBox">
<property name="geometry">
<rect>
<x>100</x>
<y>270</y>
<width>61</width>
<height>20</height>
</rect>
</property>
<property name="toolTip">
<string>offset in part frame z direction</string>
</property>
<property name="suffix">
<string/>
</property>
<property name="decimals">
<number>2</number>
</property>
<property name="minimum">
<double>-1.000000000000000</double>
</property>
<property name="maximum">
<double>1.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
</widget>
<widget class="QLabel" name="AssemblyAxisLabel">
<property name="geometry">
<rect>
<x>10</x>
<y>210</y>
<width>121</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>Assembly Axis</string>
</property>
</widget>
<widget class="QPushButton" name="AnimateButton">
<property name="geometry">
<rect>
<x>10</x>
<y>290</y>
<width>131</width>
<height>27</height>
</rect>
</property>
<property name="text">
<string>Animate</string>
</property>
</widget>
</widget>
<resources/>
<connections/>
</ui>

View file

@ -1,520 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>dialog</class>
<widget class="QDialog" name="dialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>299</width>
<height>292</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>299</width>
<height>292</height>
</size>
</property>
<property name="windowTitle">
<string>Part Frame Creator</string>
</property>
<widget class="QDoubleSpinBox" name="XBox">
<property name="geometry">
<rect>
<x>52</x>
<y>85</y>
<width>103</width>
<height>27</height>
</rect>
</property>
<property name="toolTip">
<string>Offset in part frame x direction</string>
</property>
<property name="suffix">
<string> mm</string>
</property>
<property name="minimum">
<double>-1000.000000000000000</double>
</property>
<property name="maximum">
<double>1000.000000000000000</double>
</property>
</widget>
<widget class="QDoubleSpinBox" name="YBox">
<property name="geometry">
<rect>
<x>52</x>
<y>118</y>
<width>103</width>
<height>27</height>
</rect>
</property>
<property name="toolTip">
<string>offset in part frame z direction</string>
</property>
<property name="suffix">
<string> mm</string>
</property>
<property name="minimum">
<double>-1000.000000000000000</double>
</property>
<property name="maximum">
<double>1000.000000000000000</double>
</property>
</widget>
<widget class="QDoubleSpinBox" name="ZBox">
<property name="geometry">
<rect>
<x>52</x>
<y>151</y>
<width>103</width>
<height>27</height>
</rect>
</property>
<property name="toolTip">
<string>offset in part frame z direction</string>
</property>
<property name="suffix">
<string> mm</string>
</property>
<property name="decimals">
<number>2</number>
</property>
<property name="minimum">
<double>-1000.000000000000000</double>
</property>
<property name="maximum">
<double>1000.000000000000000</double>
</property>
</widget>
<widget class="QLabel" name="XLabel">
<property name="geometry">
<rect>
<x>9</x>
<y>85</y>
<width>16</width>
<height>17</height>
</rect>
</property>
<property name="text">
<string>x</string>
</property>
<property name="buddy">
<cstring>XBox</cstring>
</property>
</widget>
<widget class="QLabel" name="YLabel">
<property name="geometry">
<rect>
<x>9</x>
<y>118</y>
<width>16</width>
<height>17</height>
</rect>
</property>
<property name="text">
<string>y</string>
</property>
<property name="buddy">
<cstring>YBox</cstring>
</property>
</widget>
<widget class="QLabel" name="ZLabel">
<property name="geometry">
<rect>
<x>9</x>
<y>151</y>
<width>16</width>
<height>17</height>
</rect>
</property>
<property name="text">
<string>z</string>
</property>
<property name="buddy">
<cstring>ZBox</cstring>
</property>
</widget>
<widget class="QLabel" name="RollLabel">
<property name="geometry">
<rect>
<x>161</x>
<y>85</y>
<width>24</width>
<height>17</height>
</rect>
</property>
<property name="toolTip">
<string>roll offset from part frame</string>
</property>
<property name="text">
<string>roll</string>
</property>
<property name="buddy">
<cstring>RollBox</cstring>
</property>
</widget>
<widget class="QLabel" name="PitchLabel">
<property name="geometry">
<rect>
<x>161</x>
<y>118</y>
<width>35</width>
<height>17</height>
</rect>
</property>
<property name="toolTip">
<string>pitch offset from part frame</string>
</property>
<property name="text">
<string>pitch</string>
</property>
<property name="buddy">
<cstring>PitchBox</cstring>
</property>
</widget>
<widget class="QLabel" name="YawLabel">
<property name="geometry">
<rect>
<x>161</x>
<y>151</y>
<width>29</width>
<height>17</height>
</rect>
</property>
<property name="toolTip">
<string>yaw offset from part frame</string>
</property>
<property name="text">
<string>yaw</string>
</property>
<property name="buddy">
<cstring>YawBox</cstring>
</property>
</widget>
<widget class="QDoubleSpinBox" name="RollBox">
<property name="geometry">
<rect>
<x>228</x>
<y>85</y>
<width>61</width>
<height>27</height>
</rect>
</property>
<property name="toolTip">
<string>roll offset from part frame</string>
</property>
<property name="suffix">
<string>°</string>
</property>
<property name="decimals">
<number>1</number>
</property>
<property name="maximum">
<double>360.000000000000000</double>
</property>
</widget>
<widget class="QDoubleSpinBox" name="PitchBox">
<property name="geometry">
<rect>
<x>228</x>
<y>118</y>
<width>61</width>
<height>27</height>
</rect>
</property>
<property name="toolTip">
<string>pitch offset from part frame</string>
</property>
<property name="suffix">
<string>°</string>
</property>
<property name="decimals">
<number>1</number>
</property>
<property name="maximum">
<double>360.000000000000000</double>
</property>
</widget>
<widget class="QDoubleSpinBox" name="YawBox">
<property name="geometry">
<rect>
<x>228</x>
<y>151</y>
<width>61</width>
<height>27</height>
</rect>
</property>
<property name="toolTip">
<string>yaw offset from part frame</string>
</property>
<property name="suffix">
<string>°</string>
</property>
<property name="decimals">
<number>1</number>
</property>
<property name="maximum">
<double>360.000000000000000</double>
</property>
</widget>
<widget class="QPlainTextEdit" name="FrameLabelField">
<property name="geometry">
<rect>
<x>94</x>
<y>9</y>
<width>195</width>
<height>31</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Label of the frame</string>
</property>
<property name="statusTip">
<string>Label of the new frame</string>
</property>
<property name="whatsThis">
<string>Label of the new frame, must be unique</string>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
</widget>
<widget class="QLabel" name="FrameLabelLabel">
<property name="geometry">
<rect>
<x>9</x>
<y>9</y>
<width>79</width>
<height>31</height>
</rect>
</property>
<property name="text">
<string>Frame label</string>
</property>
</widget>
<widget class="QLabel" name="OffsetLabel">
<property name="geometry">
<rect>
<x>9</x>
<y>48</y>
<width>281</width>
<height>31</height>
</rect>
</property>
<property name="toolTip">
<string>Define an offset from the part frame if needed</string>
</property>
<property name="text">
<string>Offset from part frame</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
<widget class="QLabel" name="ScaleLabel">
<property name="geometry">
<rect>
<x>160</x>
<y>180</y>
<width>71</width>
<height>21</height>
</rect>
</property>
<property name="toolTip">
<string>Scale of the axis arrows</string>
</property>
<property name="statusTip">
<string>Scale of the axis arrows</string>
</property>
<property name="whatsThis">
<string>Scale of the axis arrows</string>
</property>
<property name="text">
<string>Axis scale</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
<widget class="QDoubleSpinBox" name="ScaleBox">
<property name="geometry">
<rect>
<x>230</x>
<y>180</y>
<width>60</width>
<height>27</height>
</rect>
</property>
<property name="toolTip">
<string>Scale of the axis arrows</string>
</property>
<property name="statusTip">
<string>Scale of the axis arrows</string>
</property>
<property name="whatsThis">
<string>Scale of the axis arrows</string>
</property>
<property name="minimum">
<double>0.100000000000000</double>
</property>
<property name="maximum">
<double>2.000000000000000</double>
</property>
<property name="singleStep">
<double>0.010000000000000</double>
</property>
<property name="value">
<double>0.110000000000000</double>
</property>
</widget>
<widget class="QLabel" name="OptionsLabel">
<property name="enabled">
<bool>true</bool>
</property>
<property name="geometry">
<rect>
<x>20</x>
<y>220</y>
<width>66</width>
<height>31</height>
</rect>
</property>
<property name="visible">
<bool>false</bool>
</property>
<property name="text">
<string>Options</string>
</property>
<property name="buddy">
<cstring>OptionsBox</cstring>
</property>
</widget>
<widget class="QComboBox" name="OptionsBox">
<property name="enabled">
<bool>true</bool>
</property>
<property name="geometry">
<rect>
<x>210</x>
<y>220</y>
<width>78</width>
<height>27</height>
</rect>
</property>
<property name="visible">
<bool>false</bool>
</property>
</widget>
<widget class="QDoubleSpinBox" name="UBox">
<property name="enabled">
<bool>true</bool>
</property>
<property name="geometry">
<rect>
<x>100</x>
<y>250</y>
<width>62</width>
<height>27</height>
</rect>
</property>
<property name="visible">
<bool>false</bool>
</property>
</widget>
<widget class="QDoubleSpinBox" name="VBox">
<property name="enabled">
<bool>true</bool>
</property>
<property name="geometry">
<rect>
<x>220</x>
<y>250</y>
<width>62</width>
<height>27</height>
</rect>
</property>
<property name="visible">
<bool>false</bool>
</property>
</widget>
<widget class="QLabel" name="ULabel">
<property name="enabled">
<bool>true</bool>
</property>
<property name="geometry">
<rect>
<x>80</x>
<y>250</y>
<width>16</width>
<height>31</height>
</rect>
</property>
<property name="visible">
<bool>false</bool>
</property>
<property name="text">
<string>u</string>
</property>
<property name="buddy">
<cstring>UBox</cstring>
</property>
</widget>
<widget class="QLabel" name="VLabel">
<property name="enabled">
<bool>true</bool>
</property>
<property name="geometry">
<rect>
<x>200</x>
<y>250</y>
<width>16</width>
<height>31</height>
</rect>
</property>
<property name="visible">
<bool>false</bool>
</property>
<property name="text">
<string>v</string>
</property>
<property name="buddy">
<cstring>VBox</cstring>
</property>
</widget>
<widget class="QLabel" name="CoordsLabel">
<property name="enabled">
<bool>true</bool>
</property>
<property name="geometry">
<rect>
<x>20</x>
<y>256</y>
<width>51</width>
<height>21</height>
</rect>
</property>
<property name="visible">
<bool>false</bool>
</property>
<property name="text">
<string>Coords:</string>
</property>
</widget>
</widget>
<resources/>
<connections/>
</ui>

View file

@ -1,239 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Dialog</class>
<widget class="QDialog" name="Dialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>337</width>
<height>322</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>337</width>
<height>322</height>
</size>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<widget class="QLabel" name="HoleLabel">
<property name="geometry">
<rect>
<x>20</x>
<y>50</y>
<width>31</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>Hole</string>
</property>
</widget>
<widget class="QLabel" name="PegPartLabel">
<property name="geometry">
<rect>
<x>60</x>
<y>150</y>
<width>41</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>Part:</string>
</property>
</widget>
<widget class="QLabel" name="PegFaceLabel">
<property name="geometry">
<rect>
<x>60</x>
<y>170</y>
<width>41</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>Face:</string>
</property>
</widget>
<widget class="QLabel" name="PegFaceIDField">
<property name="geometry">
<rect>
<x>110</x>
<y>170</y>
<width>231</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>FaceID</string>
</property>
</widget>
<widget class="QLabel" name="TaskLabel">
<property name="geometry">
<rect>
<x>20</x>
<y>20</y>
<width>71</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>Task Label</string>
</property>
</widget>
<widget class="QLineEdit" name="TaskLabelField">
<property name="geometry">
<rect>
<x>110</x>
<y>20</y>
<width>211</width>
<height>27</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</widget>
<widget class="QPushButton" name="AnimateButton">
<property name="geometry">
<rect>
<x>20</x>
<y>290</y>
<width>131</width>
<height>27</height>
</rect>
</property>
<property name="text">
<string>Animate</string>
</property>
</widget>
<widget class="QPushButton" name="SelectButton">
<property name="geometry">
<rect>
<x>160</x>
<y>290</y>
<width>161</width>
<height>27</height>
</rect>
</property>
<property name="text">
<string>Get from selection</string>
</property>
</widget>
<widget class="QLabel" name="HoleFaceIDField">
<property name="geometry">
<rect>
<x>110</x>
<y>90</y>
<width>231</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>FaceID</string>
</property>
</widget>
<widget class="QLabel" name="HolePartLabel">
<property name="geometry">
<rect>
<x>60</x>
<y>70</y>
<width>41</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>Part:</string>
</property>
</widget>
<widget class="QLabel" name="HoleFaceLabel">
<property name="geometry">
<rect>
<x>60</x>
<y>90</y>
<width>41</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>Face:</string>
</property>
</widget>
<widget class="QLabel" name="PegLabel">
<property name="geometry">
<rect>
<x>20</x>
<y>130</y>
<width>41</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>Screw</string>
</property>
</widget>
<widget class="QLabel" name="HolePartField">
<property name="geometry">
<rect>
<x>110</x>
<y>70</y>
<width>231</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>PartLabel</string>
</property>
</widget>
<widget class="QLabel" name="PegPartField">
<property name="geometry">
<rect>
<x>110</x>
<y>150</y>
<width>231</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>PartLabel</string>
</property>
</widget>
<widget class="QLabel" name="ScrewTypeLabel">
<property name="geometry">
<rect>
<x>30</x>
<y>190</y>
<width>66</width>
<height>17</height>
</rect>
</property>
<property name="text">
<string>Type:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
<widget class="QLabel" name="ScrewTypeField">
<property name="geometry">
<rect>
<x>110</x>
<y>190</y>
<width>161</width>
<height>17</height>
</rect>
</property>
<property name="text">
<string>ThreadType</string>
</property>
</widget>
</widget>
<resources/>
<connections/>
</ui>

View file

@ -1,237 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="64px"
height="64px"
id="svg5642"
version="1.1"
inkscape:version="0.48.4 r9939"
sodipodi:docname="drawing.svg">
<defs
id="defs5644">
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3801"
id="linearGradient3807"
x1="110"
y1="35"
x2="85"
y2="35"
gradientUnits="userSpaceOnUse"
spreadMethod="reflect"
gradientTransform="translate(-60.636365,31.636364)" />
<linearGradient
inkscape:collect="always"
id="linearGradient3801">
<stop
style="stop-color:#204a87;stop-opacity:1"
offset="0"
id="stop3803" />
<stop
style="stop-color:#729fcf;stop-opacity:1"
offset="1"
id="stop3805" />
</linearGradient>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath6357">
<rect
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:18.81833839;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0;stroke-dasharray:none;stroke-dashoffset:0"
id="rect6359"
width="51.845303"
height="56.390755"
x="6.6228013"
y="1.5318987" />
</clipPath>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3801"
id="linearGradient6363"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(-60.636365,31.636364)"
spreadMethod="reflect"
x1="110"
y1="35"
x2="85"
y2="35" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="5.5"
inkscape:cx="2.3478057"
inkscape:cy="35.001512"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:document-units="px"
inkscape:grid-bbox="true"
inkscape:window-width="1375"
inkscape:window-height="811"
inkscape:window-x="65"
inkscape:window-y="24"
inkscape:window-maximized="1" />
<metadata
id="metadata5647">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer">
<g
id="g6337"
clip-path="url(#clipPath6357)"
transform="matrix(1.1017012,0,0,1.1017012,-3.2190011,-6.7998918)">
<path
sodipodi:nodetypes="sscccs"
inkscape:connector-curvature="0"
id="path2994-3"
d="m 56.363636,84.636364 c 0,4.418278 -10.745166,8 -24,8 -13.254833,0 -23.9999985,-3.581722 -23.9999985,-8 l -2e-6,-42 47.9999985,0 z"
style="fill:#729fcf;stroke:#0b1521;stroke-width:1.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4.5;stroke-opacity:1;stroke-dashoffset:20.4" />
<path
sodipodi:nodetypes="sscccs"
inkscape:connector-curvature="0"
id="path2994-3-6"
d="m 54.363635,83.363637 c 0,4.016616 -9.84973,7.272727 -22,7.272727 -12.150264,0 -21.999999,-3.256111 -21.999999,-7.272727 l -2e-6,-38 44.000001,0 z"
style="fill:url(#linearGradient6363);fill-opacity:1;stroke:#729fcf;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4.5;stroke-opacity:1;stroke-dashoffset:20.4" />
<path
sodipodi:nodetypes="csc"
inkscape:connector-curvature="0"
id="path2994-3-6-9"
d="m 54.363635,47.363637 c -2,3.272727 -9.84973,5.272727 -22,5.272727 -12.150264,0 -19,-2 -21.999999,-5.272727"
style="fill:none;stroke:#729fcf;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4.5;stroke-opacity:1;stroke-dashoffset:20.4" />
<path
transform="matrix(1.1428571,0,0,1.1428571,72.363636,14.064936)"
d="m -14,25 c 0,3.865993 -9.40202,7 -21,7 -11.59798,0 -21,-3.134007 -21,-7 0,-3.865993 9.40202,-7 21,-7 11.59798,0 21,3.134007 21,7 z"
sodipodi:ry="7"
sodipodi:rx="21"
sodipodi:cy="25"
sodipodi:cx="-35"
id="path2994"
style="fill:#729fcf;stroke:#0b1521;stroke-width:1.75;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4.5;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:20.4"
sodipodi:type="arc" />
<g
transform="matrix(1.1251249,0,0,1.2288536,-5.1529457,-1.5237155)"
style="stroke-width:1.60000002;stroke-miterlimit:4;stroke-dasharray:none"
id="g4792">
<path
inkscape:connector-curvature="0"
id="rect3039-1"
d="m 32.679504,12.145359 -1.645803,2.84862 -1.645803,2.848621 2.164344,0 0,15.110077 c -0.652792,0.422664 -1.086869,1.135456 -1.127263,1.961007 l -12.219523,6.832562 -0.969446,-1.733943 -1.578167,2.662841 -1.578167,2.642199 3.088698,0.04128 3.088699,0.04128 -0.9469,-1.672017 12.039161,-6.749993 c 0.426007,0.340749 0.967678,0.536697 1.555622,0.536697 0.97078,0 1.798652,-0.551924 2.209435,-1.362384 l 14.6995,0.206422 -0.02255,2.146787 2.863246,-1.610091 2.863246,-1.61009 -2.818155,-1.672016 -2.818156,-1.692659 -0.02255,2.167429 -14.744591,-0.18578 c -0.276375,-0.539009 -0.738838,-0.954624 -1.307625,-1.176604 l 0,-14.883013 2.164344,0 -1.645803,-2.848621 -1.645803,-2.84862 z"
style="fill:#729fcf;fill-rule:evenodd;stroke:#000000;stroke-width:2.34711409;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<rect
style="fill:#729fcf;fill-rule:evenodd;stroke:none"
id="rect3039"
width="2.271805"
height="19.048214"
x="31.545361"
y="15.941667" />
<path
sodipodi:type="star"
style="fill:#729fcf;fill-rule:evenodd;stroke:none"
id="path3043"
sodipodi:sides="3"
sodipodi:cx="33.727276"
sodipodi:cy="7.6363635"
sodipodi:r1="3.9469614"
sodipodi:r2="1.9734807"
sodipodi:arg1="0.52359878"
sodipodi:arg2="1.5707963"
inkscape:flatsided="false"
inkscape:rounded="0"
inkscape:randomized="0"
d="m 37.145445,9.6098442 -3.418169,0 -3.418169,0 1.709084,-2.960221 1.709085,-2.9602211 1.709084,2.960221 z"
inkscape:transform-center-y="-0.94840389"
transform="matrix(0.96114836,0,0,0.96114836,0.26435064,8.6019885)" />
<rect
style="fill:#ef2929;fill-rule:evenodd;stroke:none"
id="rect3039-3"
width="2.271805"
height="19.048214"
x="33.423866"
y="-52.183987"
transform="matrix(-0.0130695,0.99991459,-0.99991459,-0.0130695,0,0)" />
<path
transform="matrix(-0.01256173,0.96106627,-0.96106627,-0.01256173,59.490575,2.9206132)"
sodipodi:type="star"
style="fill:#ef2929;fill-rule:evenodd;stroke:none"
id="path3043-6"
sodipodi:sides="3"
sodipodi:cx="33.727276"
sodipodi:cy="7.6363635"
sodipodi:r1="3.9469614"
sodipodi:r2="1.9734807"
sodipodi:arg1="0.52359878"
sodipodi:arg2="1.5707963"
inkscape:flatsided="false"
inkscape:rounded="0"
inkscape:randomized="0"
d="m 37.145445,9.6098442 -3.418169,0 -3.418169,0 1.709084,-2.960221 1.709085,-2.9602211 1.709084,2.960221 z"
inkscape:transform-center-y="-0.024790177"
inkscape:transform-center-x="-0.92685398" />
<rect
style="fill:#8ae234;fill-rule:evenodd;stroke:none"
id="rect3039-3-7"
width="2.2567275"
height="18.921833"
x="-47.582092"
y="-7.3576851"
transform="matrix(-0.48864025,-0.87248536,0.87248701,-0.4886373,0,0)" />
<path
transform="matrix(-0.44155795,-0.78841815,0.78842129,-0.4415562,26.06505,73.540728)"
sodipodi:type="star"
style="fill:#8ae234;fill-rule:evenodd;stroke:none"
id="path3043-6-5"
sodipodi:sides="3"
sodipodi:cx="33.727276"
sodipodi:cy="7.6363635"
sodipodi:r1="3.9469614"
sodipodi:r2="1.9734807"
sodipodi:arg1="0.52359878"
sodipodi:arg2="1.5707963"
inkscape:flatsided="false"
inkscape:rounded="0"
inkscape:randomized="0"
d="m 37.145445,9.6098442 -3.418169,0 -3.418169,0 1.709084,-2.960221 1.709085,-2.9602211 1.709084,2.960221 z"
inkscape:transform-center-y="-0.87140186"
inkscape:transform-center-x="0.0233072" />
<path
sodipodi:type="arc"
style="fill:#fce94f;stroke:none"
id="path4366"
sodipodi:cx="35.954548"
sodipodi:cy="37.590908"
sodipodi:rx="2.5909083"
sodipodi:ry="2.590909"
d="m 38.545456,37.590908 c 0,1.43092 -1.159989,2.590909 -2.590908,2.590909 -1.430919,0 -2.590908,-1.159989 -2.590908,-2.590909 0,-1.430919 1.159989,-2.590909 2.590908,-2.590909 1.430919,0 2.590908,1.15999 2.590908,2.590909 z"
transform="matrix(0.96114836,0,0,0.96114836,-1.6579462,-1.0968723)" />
</g>
<path
inkscape:connector-curvature="0"
id="path5806"
d="m 64.181818,63.636364 -63.99999982,0"
style="fill:none;stroke:#000000;stroke-width:7.59999943;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0;stroke-dasharray:none" />
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 10 KiB

View file

@ -1,152 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="64px"
height="64px"
id="svg6384"
version="1.1"
inkscape:version="0.48.4 r9939"
sodipodi:docname="New document 37">
<defs
id="defs6386" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.9445436"
inkscape:cx="33.122262"
inkscape:cy="42.611518"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:document-units="px"
inkscape:grid-bbox="true"
inkscape:window-width="472"
inkscape:window-height="383"
inkscape:window-x="968"
inkscape:window-y="24"
inkscape:window-maximized="0" />
<metadata
id="metadata6389">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer">
<g
id="g4792"
style="stroke-width:1.60000002;stroke-miterlimit:4;stroke-dasharray:none"
transform="matrix(1.3322492,0,0,1.4550733,-13.530887,-8.9206423)">
<path
style="fill:#729fcf;fill-rule:evenodd;stroke:#000000;stroke-width:2.34711409;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 32.679504,12.145359 -1.645803,2.84862 -1.645803,2.848621 2.164344,0 0,15.110077 c -0.652792,0.422664 -1.086869,1.135456 -1.127263,1.961007 l -12.219523,6.832562 -0.969446,-1.733943 -1.578167,2.662841 -1.578167,2.642199 3.088698,0.04128 3.088699,0.04128 -0.9469,-1.672017 12.039161,-6.749993 c 0.426007,0.340749 0.967678,0.536697 1.555622,0.536697 0.97078,0 1.798652,-0.551924 2.209435,-1.362384 l 14.6995,0.206422 -0.02255,2.146787 2.863246,-1.610091 2.863246,-1.61009 -2.818155,-1.672016 -2.818156,-1.692659 -0.02255,2.167429 -14.744591,-0.18578 c -0.276375,-0.539009 -0.738838,-0.954624 -1.307625,-1.176604 l 0,-14.883013 2.164344,0 -1.645803,-2.848621 -1.645803,-2.84862 z"
id="rect3039-1"
inkscape:connector-curvature="0" />
<rect
y="15.941667"
x="31.545361"
height="19.048214"
width="2.271805"
id="rect3039"
style="fill:#729fcf;fill-rule:evenodd;stroke:none" />
<path
transform="matrix(0.96114836,0,0,0.96114836,0.26435064,8.6019885)"
inkscape:transform-center-y="-0.94840389"
d="m 37.145445,9.6098442 -3.418169,0 -3.418169,0 1.709084,-2.960221 1.709085,-2.9602211 1.709084,2.960221 z"
inkscape:randomized="0"
inkscape:rounded="0"
inkscape:flatsided="false"
sodipodi:arg2="1.5707963"
sodipodi:arg1="0.52359878"
sodipodi:r2="1.9734807"
sodipodi:r1="3.9469614"
sodipodi:cy="7.6363635"
sodipodi:cx="33.727276"
sodipodi:sides="3"
id="path3043"
style="fill:#729fcf;fill-rule:evenodd;stroke:none"
sodipodi:type="star" />
<rect
transform="matrix(-0.0130695,0.99991459,-0.99991459,-0.0130695,0,0)"
y="-52.183987"
x="33.423866"
height="19.048214"
width="2.271805"
id="rect3039-3"
style="fill:#ef2929;fill-rule:evenodd;stroke:none" />
<path
inkscape:transform-center-x="-0.92685398"
inkscape:transform-center-y="-0.024790177"
d="m 37.145445,9.6098442 -3.418169,0 -3.418169,0 1.709084,-2.960221 1.709085,-2.9602211 1.709084,2.960221 z"
inkscape:randomized="0"
inkscape:rounded="0"
inkscape:flatsided="false"
sodipodi:arg2="1.5707963"
sodipodi:arg1="0.52359878"
sodipodi:r2="1.9734807"
sodipodi:r1="3.9469614"
sodipodi:cy="7.6363635"
sodipodi:cx="33.727276"
sodipodi:sides="3"
id="path3043-6"
style="fill:#ef2929;fill-rule:evenodd;stroke:none"
sodipodi:type="star"
transform="matrix(-0.01256173,0.96106627,-0.96106627,-0.01256173,59.490575,2.9206132)" />
<rect
transform="matrix(-0.48864025,-0.87248536,0.87248701,-0.4886373,0,0)"
y="-7.3576851"
x="-47.582092"
height="18.921833"
width="2.2567275"
id="rect3039-3-7"
style="fill:#8ae234;fill-rule:evenodd;stroke:none" />
<path
inkscape:transform-center-x="0.0233072"
inkscape:transform-center-y="-0.87140186"
d="m 37.145445,9.6098442 -3.418169,0 -3.418169,0 1.709084,-2.960221 1.709085,-2.9602211 1.709084,2.960221 z"
inkscape:randomized="0"
inkscape:rounded="0"
inkscape:flatsided="false"
sodipodi:arg2="1.5707963"
sodipodi:arg1="0.52359878"
sodipodi:r2="1.9734807"
sodipodi:r1="3.9469614"
sodipodi:cy="7.6363635"
sodipodi:cx="33.727276"
sodipodi:sides="3"
id="path3043-6-5"
style="fill:#8ae234;fill-rule:evenodd;stroke:none"
sodipodi:type="star"
transform="matrix(-0.44155795,-0.78841815,0.78842129,-0.4415562,26.06505,73.540728)" />
<path
transform="matrix(0.96114836,0,0,0.96114836,-1.6579462,-1.0968723)"
d="m 38.545456,37.590908 c 0,1.43092 -1.159989,2.590909 -2.590908,2.590909 -1.430919,0 -2.590908,-1.159989 -2.590908,-2.590909 0,-1.430919 1.159989,-2.590909 2.590908,-2.590909 1.430919,0 2.590908,1.15999 2.590908,2.590909 z"
sodipodi:ry="2.590909"
sodipodi:rx="2.5909083"
sodipodi:cy="37.590908"
sodipodi:cx="35.954548"
id="path4366"
style="fill:#fce94f;stroke:none"
sodipodi:type="arc" />
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 6.1 KiB

View file

@ -1,275 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="64px"
height="64px"
id="svg4339"
version="1.1"
inkscape:version="0.48.4 r9939"
sodipodi:docname="New document 12">
<defs
id="defs4341">
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3801"
id="linearGradient3807"
x1="110"
y1="35"
x2="85"
y2="35"
gradientUnits="userSpaceOnUse"
spreadMethod="reflect"
gradientTransform="translate(-61,23.272727)" />
<linearGradient
inkscape:collect="always"
id="linearGradient3801">
<stop
style="stop-color:#c4a000;stop-opacity:1"
offset="0"
id="stop3803" />
<stop
style="stop-color:#fce94f;stop-opacity:1"
offset="1"
id="stop3805" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3801-5"
id="linearGradient3807-7"
x1="110"
y1="35"
x2="85"
y2="35"
gradientUnits="userSpaceOnUse"
spreadMethod="reflect"
gradientTransform="matrix(0.67526107,0,0,0.67526107,-31.705858,16.546964)" />
<linearGradient
inkscape:collect="always"
id="linearGradient3801-5">
<stop
style="stop-color:#204a87;stop-opacity:1"
offset="0"
id="stop3803-9" />
<stop
style="stop-color:#729fcf;stop-opacity:1"
offset="1"
id="stop3805-2" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3801-5-7"
id="linearGradient3807-7-9"
x1="110"
y1="35"
x2="85"
y2="35"
gradientUnits="userSpaceOnUse"
spreadMethod="reflect"
gradientTransform="matrix(0.72727273,0,0,0.72727273,-36.272728,10.363637)" />
<linearGradient
inkscape:collect="always"
id="linearGradient3801-5-7">
<stop
style="stop-color:#204a87;stop-opacity:1"
offset="0"
id="stop3803-9-3" />
<stop
style="stop-color:#729fcf;stop-opacity:1"
offset="1"
id="stop3805-2-6" />
</linearGradient>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="5.5"
inkscape:cx="13.517284"
inkscape:cy="24.468658"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:document-units="px"
inkscape:grid-bbox="true"
inkscape:snap-global="true"
inkscape:snap-object-midpoints="false"
inkscape:window-width="1375"
inkscape:window-height="811"
inkscape:window-x="65"
inkscape:window-y="24"
inkscape:window-maximized="1" />
<metadata
id="metadata4344">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer">
<path
style="fill:#729fcf;stroke:#0b1521;stroke-width:1.35052204;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4.5;stroke-opacity:1;stroke-dashoffset:20.4"
d="m 47.299687,52.335801 c 0,2.983491 -7.255792,5.402088 -16.206264,5.402088 -8.950473,0 -16.206265,-2.418597 -16.206265,-5.402088 l -10e-7,-28.360965 32.41253,0 z"
id="path2994-3"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sscccs" />
<path
style="opacity:0.51000001;fill:url(#linearGradient3807-7);fill-opacity:1;stroke:#729fcf;stroke-width:1.35052216;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4.5;stroke-opacity:1;stroke-dashoffset:20.4"
d="m 45.949165,51.476378 c 0,2.712264 -6.651139,4.910989 -14.855743,4.910989 -8.2046,0 -14.855743,-2.198725 -14.855743,-4.910989 l -2e-6,-25.659921 29.711488,0 z"
id="path2994-3-6"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sscccs" />
<path
sodipodi:type="arc"
style="fill:#729fcf;stroke:none"
id="path2994-8"
sodipodi:cx="-35"
sodipodi:cy="25"
sodipodi:rx="21"
sodipodi:ry="7"
d="m -14,25 a 21,7 0 1 1 -42,0 21,7 0 1 1 42,0 z"
transform="matrix(0.77172691,0,0,0.77172691,58.103864,4.6816635)" />
<path
style="fill:none;stroke:#000000;stroke-width:1.6886189;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:3.37723797, 3.37723797;stroke-dashoffset:0"
d="m 31.284953,15.183043 0,45.389159"
id="path5504"
inkscape:connector-curvature="0" />
<g
id="g4792-2"
style="stroke-width:1.60000002;stroke-miterlimit:4;stroke-dasharray:none"
transform="matrix(1.236972,0,0,1.3510122,-9.558506,-9.4101622)">
<path
style="fill:#729fcf;fill-rule:evenodd;stroke:#000000;stroke-width:2.34711409;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 32.679504,12.145359 -1.645803,2.84862 -1.645803,2.848621 2.164344,0 0,15.110077 c -0.652792,0.422664 -1.086869,1.135456 -1.127263,1.961007 l -12.219523,6.832562 -0.969446,-1.733943 -1.578167,2.662841 -1.578167,2.642199 3.088698,0.04128 3.088699,0.04128 -0.9469,-1.672017 12.039161,-6.749993 c 0.426007,0.340749 0.967678,0.536697 1.555622,0.536697 0.97078,0 1.798652,-0.551924 2.209435,-1.362384 l 14.6995,0.206422 -0.02255,2.146787 2.863246,-1.610091 2.863246,-1.61009 -2.818155,-1.672016 -2.818156,-1.692659 -0.02255,2.167429 -14.744591,-0.18578 c -0.276375,-0.539009 -0.738838,-0.954624 -1.307625,-1.176604 l 0,-14.883013 2.164344,0 -1.645803,-2.848621 -1.645803,-2.84862 z"
id="rect3039-1"
inkscape:connector-curvature="0" />
<rect
y="15.941667"
x="31.545361"
height="19.048214"
width="2.271805"
id="rect3039-9"
style="fill:#729fcf;fill-rule:evenodd;stroke:none" />
<path
transform="matrix(0.96114836,0,0,0.96114836,0.26435064,8.6019885)"
inkscape:transform-center-y="-0.94840389"
d="m 37.145445,9.6098442 -3.418169,0 -3.418169,0 1.709084,-2.960221 1.709085,-2.9602211 1.709084,2.960221 z"
inkscape:randomized="0"
inkscape:rounded="0"
inkscape:flatsided="false"
sodipodi:arg2="1.5707963"
sodipodi:arg1="0.52359878"
sodipodi:r2="1.9734807"
sodipodi:r1="3.9469614"
sodipodi:cy="7.6363635"
sodipodi:cx="33.727276"
sodipodi:sides="3"
id="path3043-3"
style="fill:#729fcf;fill-rule:evenodd;stroke:none"
sodipodi:type="star" />
<rect
transform="matrix(-0.0130695,0.99991459,-0.99991459,-0.0130695,0,0)"
y="-52.183987"
x="33.423866"
height="19.048214"
width="2.271805"
id="rect3039-3-1"
style="fill:#ef2929;fill-rule:evenodd;stroke:none" />
<path
inkscape:transform-center-x="-0.92685398"
inkscape:transform-center-y="-0.024790177"
d="m 37.145445,9.6098442 -3.418169,0 -3.418169,0 1.709084,-2.960221 1.709085,-2.9602211 1.709084,2.960221 z"
inkscape:randomized="0"
inkscape:rounded="0"
inkscape:flatsided="false"
sodipodi:arg2="1.5707963"
sodipodi:arg1="0.52359878"
sodipodi:r2="1.9734807"
sodipodi:r1="3.9469614"
sodipodi:cy="7.6363635"
sodipodi:cx="33.727276"
sodipodi:sides="3"
id="path3043-6-9"
style="fill:#ef2929;fill-rule:evenodd;stroke:none"
sodipodi:type="star"
transform="matrix(-0.01256173,0.96106627,-0.96106627,-0.01256173,59.490575,2.9206132)" />
<rect
transform="matrix(-0.48864025,-0.87248536,0.87248701,-0.4886373,0,0)"
y="-7.3576851"
x="-47.582092"
height="18.921833"
width="2.2567275"
id="rect3039-3-7-4"
style="fill:#8ae234;fill-rule:evenodd;stroke:none" />
<path
inkscape:transform-center-x="0.0233072"
inkscape:transform-center-y="-0.87140186"
d="m 37.145445,9.6098442 -3.418169,0 -3.418169,0 1.709084,-2.960221 1.709085,-2.9602211 1.709084,2.960221 z"
inkscape:randomized="0"
inkscape:rounded="0"
inkscape:flatsided="false"
sodipodi:arg2="1.5707963"
sodipodi:arg1="0.52359878"
sodipodi:r2="1.9734807"
sodipodi:r1="3.9469614"
sodipodi:cy="7.6363635"
sodipodi:cx="33.727276"
sodipodi:sides="3"
id="path3043-6-5-7"
style="fill:#8ae234;fill-rule:evenodd;stroke:none"
sodipodi:type="star"
transform="matrix(-0.44155795,-0.78841815,0.78842129,-0.4415562,26.06505,73.540728)" />
<path
transform="matrix(0.96114836,0,0,0.96114836,-1.6579462,-1.0968723)"
d="m 38.545456,37.590908 c 0,1.43092 -1.159989,2.590909 -2.590908,2.590909 -1.430919,0 -2.590908,-1.159989 -2.590908,-2.590909 0,-1.430919 1.159989,-2.590909 2.590908,-2.590909 1.430919,0 2.590908,1.15999 2.590908,2.590909 z"
sodipodi:ry="2.590909"
sodipodi:rx="2.5909083"
sodipodi:cy="37.590908"
sodipodi:cx="35.954548"
id="path4366-8"
style="fill:#fce94f;stroke:none"
sodipodi:type="arc" />
</g>
<path
style="fill:none;stroke:#729fcf;stroke-width:1.35052216;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4.5;stroke-opacity:1;stroke-dashoffset:20.4"
d="m 45.949165,27.16698 c -1.350522,2.209945 -6.651139,3.560467 -14.855743,3.560467 -8.2046,0 -12.829961,-1.350522 -14.855743,-3.560467"
id="path2994-3-6-9"
inkscape:connector-curvature="0"
sodipodi:nodetypes="csc" />
<path
sodipodi:type="arc"
style="fill:none;stroke:#0b1521;stroke-width:1.75;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4.5;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:20.4"
id="path2994"
sodipodi:cx="-35"
sodipodi:cy="25"
sodipodi:rx="21"
sodipodi:ry="7"
d="m -14,25 a 21,7 0 1 1 -42,0 21,7 0 1 1 42,0 z"
transform="matrix(0.77172691,0,0,0.77172691,58.103864,4.6816635)" />
<rect
style="fill:#729fcf;stroke:none"
id="rect5584"
width="2.8052049"
height="2.1262856"
x="29.457829"
y="17.427979" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 11 KiB

View file

@ -1,181 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="64px"
height="64px"
id="svg2985"
version="1.1"
inkscape:version="0.48.4 r9939"
sodipodi:docname="frameoncurve.svg">
<defs
id="defs2987">
<marker
inkscape:stockid="Arrow1Lstart"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow1Lstart"
style="overflow:visible">
<path
id="path3859"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt"
transform="scale(0.8) translate(12.5,0)" />
</marker>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="5.5"
inkscape:cx="6.549462"
inkscape:cy="34.388895"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:document-units="px"
inkscape:grid-bbox="true"
inkscape:snap-bbox="true"
inkscape:snap-bbox-midpoints="true"
inkscape:snap-page="false"
inkscape:snap-midpoints="true"
showguides="false"
inkscape:window-width="1266"
inkscape:window-height="783"
inkscape:window-x="65"
inkscape:window-y="24"
inkscape:window-maximized="0"
inkscape:snap-global="false">
<inkscape:grid
type="xygrid"
id="grid4310" />
</sodipodi:namedview>
<metadata
id="metadata2990">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer">
<path
style="fill:none;stroke:#000000;stroke-width:2.88424587;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 4.093678,33.130265 c 0,0 0.670134,7.648668 23.365889,8.028173 C 50.15532,41.537941 50.047635,35.119378 49.356598,25.394822 48.665561,15.670267 35.708619,9.9239398 35.708619,9.9239398"
id="path4811"
inkscape:connector-curvature="0" />
<g
id="g4792"
style="stroke-width:1.60000002;stroke-miterlimit:4;stroke-dasharray:none"
transform="matrix(1.3322492,0,0,1.4550733,-14.352489,-9.6872132)">
<path
style="fill:#729fcf;fill-rule:evenodd;stroke:#000000;stroke-width:2.34711409;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 32.679504,12.145359 -1.645803,2.84862 -1.645803,2.848621 2.164344,0 0,15.110077 c -0.652792,0.422664 -1.086869,1.135456 -1.127263,1.961007 l -12.219523,6.832562 -0.969446,-1.733943 -1.578167,2.662841 -1.578167,2.642199 3.088698,0.04128 3.088699,0.04128 -0.9469,-1.672017 12.039161,-6.749993 c 0.426007,0.340749 0.967678,0.536697 1.555622,0.536697 0.97078,0 1.798652,-0.551924 2.209435,-1.362384 l 14.6995,0.206422 -0.02255,2.146787 2.863246,-1.610091 2.863246,-1.61009 -2.818155,-1.672016 -2.818156,-1.692659 -0.02255,2.167429 -14.744591,-0.18578 c -0.276375,-0.539009 -0.738838,-0.954624 -1.307625,-1.176604 l 0,-14.883013 2.164344,0 -1.645803,-2.848621 -1.645803,-2.84862 z"
id="rect3039-1"
inkscape:connector-curvature="0" />
<rect
y="15.941667"
x="31.545361"
height="19.048214"
width="2.271805"
id="rect3039"
style="fill:#729fcf;fill-rule:evenodd;stroke:none" />
<path
transform="matrix(0.96114836,0,0,0.96114836,0.26435064,8.6019885)"
inkscape:transform-center-y="-0.94840389"
d="m 37.145445,9.6098442 -3.418169,0 -3.418169,0 1.709084,-2.960221 1.709085,-2.9602211 1.709084,2.960221 z"
inkscape:randomized="0"
inkscape:rounded="0"
inkscape:flatsided="false"
sodipodi:arg2="1.5707963"
sodipodi:arg1="0.52359878"
sodipodi:r2="1.9734807"
sodipodi:r1="3.9469614"
sodipodi:cy="7.6363635"
sodipodi:cx="33.727276"
sodipodi:sides="3"
id="path3043"
style="fill:#729fcf;fill-rule:evenodd;stroke:none"
sodipodi:type="star" />
<rect
transform="matrix(-0.0130695,0.99991459,-0.99991459,-0.0130695,0,0)"
y="-52.183987"
x="33.423866"
height="19.048214"
width="2.271805"
id="rect3039-3"
style="fill:#ef2929;fill-rule:evenodd;stroke:none" />
<path
inkscape:transform-center-x="-0.92685398"
inkscape:transform-center-y="-0.024790177"
d="m 37.145445,9.6098442 -3.418169,0 -3.418169,0 1.709084,-2.960221 1.709085,-2.9602211 1.709084,2.960221 z"
inkscape:randomized="0"
inkscape:rounded="0"
inkscape:flatsided="false"
sodipodi:arg2="1.5707963"
sodipodi:arg1="0.52359878"
sodipodi:r2="1.9734807"
sodipodi:r1="3.9469614"
sodipodi:cy="7.6363635"
sodipodi:cx="33.727276"
sodipodi:sides="3"
id="path3043-6"
style="fill:#ef2929;fill-rule:evenodd;stroke:none"
sodipodi:type="star"
transform="matrix(-0.01256173,0.96106627,-0.96106627,-0.01256173,59.490575,2.9206132)" />
<rect
transform="matrix(-0.48864025,-0.87248536,0.87248701,-0.4886373,0,0)"
y="-7.3576851"
x="-47.582092"
height="18.921833"
width="2.2567275"
id="rect3039-3-7"
style="fill:#8ae234;fill-rule:evenodd;stroke:none" />
<path
inkscape:transform-center-x="0.0233072"
inkscape:transform-center-y="-0.87140186"
d="m 37.145445,9.6098442 -3.418169,0 -3.418169,0 1.709084,-2.960221 1.709085,-2.9602211 1.709084,2.960221 z"
inkscape:randomized="0"
inkscape:rounded="0"
inkscape:flatsided="false"
sodipodi:arg2="1.5707963"
sodipodi:arg1="0.52359878"
sodipodi:r2="1.9734807"
sodipodi:r1="3.9469614"
sodipodi:cy="7.6363635"
sodipodi:cx="33.727276"
sodipodi:sides="3"
id="path3043-6-5"
style="fill:#8ae234;fill-rule:evenodd;stroke:none"
sodipodi:type="star"
transform="matrix(-0.44155795,-0.78841815,0.78842129,-0.4415562,26.06505,73.540728)" />
<path
transform="matrix(0.96114836,0,0,0.96114836,-1.6579462,-1.0968723)"
d="m 38.545456,37.590908 a 2.5909083,2.590909 0 1 1 -5.181816,0 2.5909083,2.590909 0 1 1 5.181816,0 z"
sodipodi:ry="2.590909"
sodipodi:rx="2.5909083"
sodipodi:cy="37.590908"
sodipodi:cx="35.954548"
id="path4366"
style="fill:#fce94f;stroke:none"
sodipodi:type="arc" />
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 7.1 KiB

View file

@ -1,44 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="64px" height="64px" id="svg8779" version="1.1" inkscape:version="0.48.4 r9939" sodipodi:docname="frameonsurface.svg">
<defs id="defs8781">
<linearGradient inkscape:collect="always" xlink:href="#linearGradient3855" id="linearGradient3861" x1="38" y1="22" x2="49" y2="42" gradientUnits="userSpaceOnUse" spreadMethod="reflect" />
<linearGradient inkscape:collect="always" id="linearGradient3855">
<stop style="stop-color:#729fcf;stop-opacity:1" offset="0" id="stop3857" />
<stop style="stop-color:#204a87;stop-opacity:1" offset="1" id="stop3859" />
</linearGradient>
<linearGradient gradientTransform="translate(-0.54545473,3.1818182)" inkscape:collect="always" xlink:href="#linearGradient3845" id="linearGradient3851" x1="18" y1="43" x2="11" y2="24" gradientUnits="userSpaceOnUse" />
<linearGradient inkscape:collect="always" id="linearGradient3845">
<stop style="stop-color:#3465a4;stop-opacity:1;" offset="0" id="stop3847" />
<stop style="stop-color:#729fcf;stop-opacity:1" offset="1" id="stop3849" />
</linearGradient>
<linearGradient gradientTransform="translate(-0.54545473,3.1818182)" y2="42" x2="49" y1="22" x1="38" spreadMethod="reflect" gradientUnits="userSpaceOnUse" id="linearGradient9035" xlink:href="#linearGradient3855" inkscape:collect="always" />
</defs>
<sodipodi:namedview id="base" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="5.5" inkscape:cx="32" inkscape:cy="32" inkscape:current-layer="layer1" showgrid="true" inkscape:document-units="px" inkscape:grid-bbox="true" inkscape:window-width="1016" inkscape:window-height="657" inkscape:window-x="65" inkscape:window-y="24" inkscape:window-maximized="0" />
<metadata id="metadata8784">
<rdf:RDF>
<cc:Work rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g id="layer1" inkscape:label="Layer 1" inkscape:groupmode="layer">
<path id="path3846-3" style="color:#000000;fill:url(#linearGradient9035);fill-opacity:1;fill-rule:evenodd;stroke:#0b1521;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" d="m 2.4545453,24.181818 c 19.9999997,0 31.9999997,22 31.9999997,38 l 26,-20 c 0,-16 -12,-32 -26,-32 z" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccc" />
<path id="path3852-7" style="color:#000000;fill:url(#linearGradient3851);fill-opacity:1;fill-rule:evenodd;stroke:#0b1521;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" d="m 34.454545,62.181818 c 0,-16 -12,-38 -31.9999997,-38 l 4,14 c 7.9999997,0 13.9999997,8 13.9999997,18 z" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccc" />
<path id="path3852-7-6" style="color:#000000;fill:none;stroke:#729fcf;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" d="m 32.454545,59.181818 c 0,-12 -12.4,-33 -27.3999997,-33 l 2.9,10.1 c 5.4999997,-0.1 14.4999997,7.9 14.3999997,18.6 z" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccc" />
<path style="fill:none;stroke:#729fcf;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="m 9.4545453,23.181818 25.3999997,-11 c 12.6,0 22.6,13 23.6,29 l -22.3,17.2 c -0.7,-13.2 -11.7,-32.2 -26.6999997,-35.2 z" id="path3853" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccc" />
<g id="g4792" style="stroke-width:1.60000002;stroke-miterlimit:4;stroke-dasharray:none" transform="matrix(0.6931302,0.14339095,-0.15661058,0.75703197,2.2598731,-8.4369758)">
<path style="fill:#729fcf;fill-rule:evenodd;stroke:#000000;stroke-width:2.34711409;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" d="m 32.679504,12.145359 -1.645803,2.84862 -1.645803,2.848621 2.164344,0 0,15.110077 c -0.652792,0.422664 -1.086869,1.135456 -1.127263,1.961007 l -12.219523,6.832562 -0.969446,-1.733943 -1.578167,2.662841 -1.578167,2.642199 3.088698,0.04128 3.088699,0.04128 -0.9469,-1.672017 12.039161,-6.749993 c 0.426007,0.340749 0.967678,0.536697 1.555622,0.536697 0.97078,0 1.798652,-0.551924 2.209435,-1.362384 l 14.6995,0.206422 -0.02255,2.146787 2.863246,-1.610091 2.863246,-1.61009 -2.818155,-1.672016 -2.818156,-1.692659 -0.02255,2.167429 -14.744591,-0.18578 c -0.276375,-0.539009 -0.738838,-0.954624 -1.307625,-1.176604 l 0,-14.883013 2.164344,0 -1.645803,-2.848621 -1.645803,-2.84862 z" id="rect3039-1" inkscape:connector-curvature="0" />
<rect y="15.941667" x="31.545361" height="19.048214" width="2.271805" id="rect3039" style="fill:#729fcf;fill-rule:evenodd;stroke:none" />
<path transform="matrix(0.96114836,0,0,0.96114836,0.26435064,8.6019885)" inkscape:transform-center-y="-0.94840389" d="m 37.145445,9.6098442 -3.418169,0 -3.418169,0 1.709084,-2.960221 1.709085,-2.9602211 1.709084,2.960221 z" inkscape:randomized="0" inkscape:rounded="0" inkscape:flatsided="false" sodipodi:arg2="1.5707963" sodipodi:arg1="0.52359878" sodipodi:r2="1.9734807" sodipodi:r1="3.9469614" sodipodi:cy="7.6363635" sodipodi:cx="33.727276" sodipodi:sides="3" id="path3043" style="fill:#729fcf;fill-rule:evenodd;stroke:none" sodipodi:type="star" />
<rect transform="matrix(-0.0130695,0.99991459,-0.99991459,-0.0130695,0,0)" y="-52.183987" x="33.423866" height="19.048214" width="2.271805" id="rect3039-3" style="fill:#ef2929;fill-rule:evenodd;stroke:none" />
<path inkscape:transform-center-x="-0.92685398" inkscape:transform-center-y="-0.024790177" d="m 37.145445,9.6098442 -3.418169,0 -3.418169,0 1.709084,-2.960221 1.709085,-2.9602211 1.709084,2.960221 z" inkscape:randomized="0" inkscape:rounded="0" inkscape:flatsided="false" sodipodi:arg2="1.5707963" sodipodi:arg1="0.52359878" sodipodi:r2="1.9734807" sodipodi:r1="3.9469614" sodipodi:cy="7.6363635" sodipodi:cx="33.727276" sodipodi:sides="3" id="path3043-6" style="fill:#ef2929;fill-rule:evenodd;stroke:none" sodipodi:type="star" transform="matrix(-0.01256173,0.96106627,-0.96106627,-0.01256173,59.490575,2.9206132)" />
<rect transform="matrix(-0.48864025,-0.87248536,0.87248701,-0.4886373,0,0)" y="-7.3576851" x="-47.582092" height="18.921833" width="2.2567275" id="rect3039-3-7" style="fill:#8ae234;fill-rule:evenodd;stroke:none" />
<path inkscape:transform-center-x="0.0233072" inkscape:transform-center-y="-0.87140186" d="m 37.145445,9.6098442 -3.418169,0 -3.418169,0 1.709084,-2.960221 1.709085,-2.9602211 1.709084,2.960221 z" inkscape:randomized="0" inkscape:rounded="0" inkscape:flatsided="false" sodipodi:arg2="1.5707963" sodipodi:arg1="0.52359878" sodipodi:r2="1.9734807" sodipodi:r1="3.9469614" sodipodi:cy="7.6363635" sodipodi:cx="33.727276" sodipodi:sides="3" id="path3043-6-5" style="fill:#8ae234;fill-rule:evenodd;stroke:none" sodipodi:type="star" transform="matrix(-0.44155795,-0.78841815,0.78842129,-0.4415562,26.06505,73.540728)" />
<path transform="matrix(0.96114836,0,0,0.96114836,-1.6579462,-1.0968723)" d="m 38.545456,37.590908 c 0,1.43092 -1.159989,2.590909 -2.590908,2.590909 -1.430919,0 -2.590908,-1.159989 -2.590908,-2.590909 0,-1.430919 1.159989,-2.590909 2.590908,-2.590909 1.430919,0 2.590908,1.15999 2.590908,2.590909 z" sodipodi:ry="2.590909" sodipodi:rx="2.5909083" sodipodi:cy="37.590908" sodipodi:cx="35.954548" id="path4366" style="fill:#fce94f;stroke:none" sodipodi:type="arc" />
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 8.2 KiB

View file

@ -1,60 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="64px" height="64px" id="svg8033" version="1.1" inkscape:version="0.48.4 r9939" sodipodi:docname="allpartframes.svg">
<defs id="defs8035">
<inkscape:path-effect effect="spiro" id="path-effect3076" is_visible="true" />
<inkscape:path-effect is_visible="true" id="path-effect3075" effect="spiro" />
<inkscape:path-effect is_visible="true" id="path-effect3075-6" effect="spiro" />
<linearGradient inkscape:collect="always" xlink:href="#linearGradient3767" id="linearGradient3222" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.82352937,0,0,0.77272731,8.529415,13.09486)" x1="22.116516" y1="55.717518" x2="17.328547" y2="21.31134" />
<linearGradient inkscape:collect="always" id="linearGradient3767">
<stop style="stop-color:#edd400;stop-opacity:1" offset="0" id="stop3769" />
<stop style="stop-color:#fce94f;stop-opacity:1" offset="1" id="stop3771" />
</linearGradient>
<linearGradient inkscape:collect="always" xlink:href="#linearGradient3777" id="linearGradient3220" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.79109028,0,0,0.78516507,9.037552,12.345152)" x1="53.896763" y1="51.179787" x2="47.502235" y2="21.83742" />
<linearGradient inkscape:collect="always" id="linearGradient3777">
<stop style="stop-color:#c4a000;stop-opacity:1" offset="0" id="stop3779-3" />
<stop style="stop-color:#edd400;stop-opacity:1" offset="1" id="stop3781" />
</linearGradient>
</defs>
<sodipodi:namedview id="base" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="7.7781746" inkscape:cx="42.12947" inkscape:cy="31.89774" inkscape:current-layer="g8668" showgrid="true" inkscape:document-units="px" inkscape:grid-bbox="true" inkscape:snap-object-midpoints="true" inkscape:window-width="1375" inkscape:window-height="811" inkscape:window-x="65" inkscape:window-y="24" inkscape:window-maximized="1" />
<metadata id="metadata8038">
<rdf:RDF>
<cc:Work rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g id="layer1" inkscape:label="Layer 1" inkscape:groupmode="layer">
<path sodipodi:nodetypes="ccccc" inkscape:connector-curvature="0" id="path2993" d="m 11.000002,26.231225 28,5 18,-7 -23.84947,-3.421981 z" style="fill:#fce94f;stroke:#302b00;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" />
<path sodipodi:nodetypes="ccccc" inkscape:connector-curvature="0" id="path2995" d="m 57.000002,24.231225 0,28 -18,8 0,-30 z" style="fill:url(#linearGradient3220);fill-opacity:1;stroke:#302b00;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" />
<path style="fill:url(#linearGradient3222);fill-opacity:1;fill-rule:evenodd;stroke:#302b00;stroke-width:1.99999988;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" d="m 11.000002,26.231225 28,4 0,30.000002 -28,-4.636365 z" id="path3825" sodipodi:nodetypes="ccccc" inkscape:connector-curvature="0" />
<path sodipodi:nodetypes="ccccc" inkscape:connector-curvature="0" id="path3765" d="m 12.993002,28.599479 0.007,25.231746 24,4 -0.007,-25.843 z" style="fill:none;stroke:#fce94f;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path sodipodi:nodetypes="ccccc" inkscape:connector-curvature="0" id="path3775" d="m 41.000002,31.731225 0,25.6 14,-6.4 0,-23.8 z" style="fill:none;stroke:#edd400;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<g id="g4792" style="stroke-width:1.60000002;stroke-miterlimit:4;stroke-dasharray:none" transform="matrix(0.67056429,0,0,0.73238565,-6.618908,-4.8414332)">
<path style="fill:#729fcf;fill-rule:evenodd;stroke:#000000;stroke-width:2.34711409;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" d="m 32.679504,12.145359 -1.645803,2.84862 -1.645803,2.848621 2.164344,0 0,15.110077 c -0.652792,0.422664 -1.086869,1.135456 -1.127263,1.961007 l -12.219523,6.832562 -0.969446,-1.733943 -1.578167,2.662841 -1.578167,2.642199 3.088698,0.04128 3.088699,0.04128 -0.9469,-1.672017 12.039161,-6.749993 c 0.426007,0.340749 0.967678,0.536697 1.555622,0.536697 0.97078,0 1.798652,-0.551924 2.209435,-1.362384 l 14.6995,0.206422 -0.02255,2.146787 2.863246,-1.610091 2.863246,-1.61009 -2.818155,-1.672016 -2.818156,-1.692659 -0.02255,2.167429 -14.744591,-0.18578 c -0.276375,-0.539009 -0.738838,-0.954624 -1.307625,-1.176604 l 0,-14.883013 2.164344,0 -1.645803,-2.848621 -1.645803,-2.84862 z" id="rect3039-1" inkscape:connector-curvature="0" />
<rect y="15.941667" x="31.545361" height="19.048214" width="2.271805" id="rect3039" style="fill:#729fcf;fill-rule:evenodd;stroke:none" />
<path transform="matrix(0.96114836,0,0,0.96114836,0.26435064,8.6019885)" inkscape:transform-center-y="-0.94840389" d="m 37.145445,9.6098442 -3.418169,0 -3.418169,0 1.709084,-2.960221 1.709085,-2.9602211 1.709084,2.960221 z" inkscape:randomized="0" inkscape:rounded="0" inkscape:flatsided="false" sodipodi:arg2="1.5707963" sodipodi:arg1="0.52359878" sodipodi:r2="1.9734807" sodipodi:r1="3.9469614" sodipodi:cy="7.6363635" sodipodi:cx="33.727276" sodipodi:sides="3" id="path3043" style="fill:#729fcf;fill-rule:evenodd;stroke:none" sodipodi:type="star" />
<rect transform="matrix(-0.0130695,0.99991459,-0.99991459,-0.0130695,0,0)" y="-52.183987" x="33.423866" height="19.048214" width="2.271805" id="rect3039-3" style="fill:#ef2929;fill-rule:evenodd;stroke:none" />
<path inkscape:transform-center-x="-0.92685398" inkscape:transform-center-y="-0.024790177" d="m 37.145445,9.6098442 -3.418169,0 -3.418169,0 1.709084,-2.960221 1.709085,-2.9602211 1.709084,2.960221 z" inkscape:randomized="0" inkscape:rounded="0" inkscape:flatsided="false" sodipodi:arg2="1.5707963" sodipodi:arg1="0.52359878" sodipodi:r2="1.9734807" sodipodi:r1="3.9469614" sodipodi:cy="7.6363635" sodipodi:cx="33.727276" sodipodi:sides="3" id="path3043-6" style="fill:#ef2929;fill-rule:evenodd;stroke:none" sodipodi:type="star" transform="matrix(-0.01256173,0.96106627,-0.96106627,-0.01256173,59.490575,2.9206132)" />
<rect transform="matrix(-0.48864025,-0.87248536,0.87248701,-0.4886373,0,0)" y="-7.3576851" x="-47.582092" height="18.921833" width="2.2567275" id="rect3039-3-7" style="fill:#8ae234;fill-rule:evenodd;stroke:none" />
<path inkscape:transform-center-x="0.0233072" inkscape:transform-center-y="-0.87140186" d="m 37.145445,9.6098442 -3.418169,0 -3.418169,0 1.709084,-2.960221 1.709085,-2.9602211 1.709084,2.960221 z" inkscape:randomized="0" inkscape:rounded="0" inkscape:flatsided="false" sodipodi:arg2="1.5707963" sodipodi:arg1="0.52359878" sodipodi:r2="1.9734807" sodipodi:r1="3.9469614" sodipodi:cy="7.6363635" sodipodi:cx="33.727276" sodipodi:sides="3" id="path3043-6-5" style="fill:#8ae234;fill-rule:evenodd;stroke:none" sodipodi:type="star" transform="matrix(-0.44155795,-0.78841815,0.78842129,-0.4415562,26.06505,73.540728)" />
<path transform="matrix(0.96114836,0,0,0.96114836,-1.6579462,-1.0968723)" d="m 38.545456,37.590908 c 0,1.43092 -1.159989,2.590909 -2.590908,2.590909 -1.430919,0 -2.590908,-1.159989 -2.590908,-2.590909 0,-1.430919 1.159989,-2.590909 2.590908,-2.590909 1.430919,0 2.590908,1.15999 2.590908,2.590909 z" sodipodi:ry="2.590909" sodipodi:rx="2.5909083" sodipodi:cy="37.590908" sodipodi:cx="35.954548" id="path4366" style="fill:#fce94f;stroke:none" sodipodi:type="arc" />
</g>
<g id="g8668">
<g transform="translate(0.3044802,0.12123813)" id="g8732-1" style="fill:none;stroke:#000000;stroke-width:7.7;stroke-miterlimit:4;stroke-dasharray:none;stroke-linecap:round;stroke-linejoin:round">
<text xml:space="preserve" style="font-size:30.92953299999999928px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:none;stroke:#000000;font-family:Sans;stroke-width:7.7;stroke-miterlimit:4;stroke-dasharray:none;stroke-linecap:round;stroke-linejoin:round" x="4.7745667" y="44.87561" id="text8146-1" sodipodi:linespacing="125%"><tspan sodipodi:role="line" id="tspan8148-0" x="4.7745667" y="44.87561">ALL</tspan></text>
</g>
<g id="g8732">
<text xml:space="preserve" style="font-size:30.929533px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#34e0e2;fill-opacity:1;stroke:none;font-family:Sans" x="4.7745667" y="44.87561" id="text8146" sodipodi:linespacing="125%"><tspan sodipodi:role="line" id="tspan8148" x="4.7745667" y="44.87561">ALL</tspan></text>
</g>
<path inkscape:connector-curvature="0" id="path8658" d="M 15.04209,25.301974 10.799449,36.358553" style="fill:none;stroke:#16d0d2;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" />
<path inkscape:connector-curvature="0" id="path8660" d="M 9.9680966,38.989814 7.9667027,44.462459" style="fill:none;stroke:#16d0d2;stroke-width:0.99136168px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" />
<path inkscape:connector-curvature="0" id="path8662" d="m 10.092342,38.608438 10.02806,0.06428" style="fill:#06989a;stroke:#16d0d2;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" />
<path inkscape:connector-curvature="0" id="path8664" d="m 29.423219,44.45814 13.06747,-0.128565" style="fill:none;stroke:#16d0d2;stroke-width:0.99580127px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" />
<path inkscape:connector-curvature="0" id="path8666" d="m 46.669048,44.329575 13.131626,0.06428" style="fill:none;stroke:#16d0d2;stroke-width:0.99581689px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" />
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 10 KiB

View file

@ -1,141 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="64px" height="64px" id="svg2985" version="1.1" inkscape:version="0.48.4 r9939" sodipodi:docname="New document 2">
<defs id="defs2987">
<radialGradient inkscape:collect="always" xlink:href="#linearGradient1789" id="radialGradient159" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.015635,0,0.103105,1.000512,0,-0.08369458)" cx="26.106777" cy="38.195114" fx="26.106777" fy="38.195114" r="32.259769" />
<linearGradient id="linearGradient1789">
<stop style="stop-color:#a0a0a0;stop-opacity:1;" offset="0" id="stop1790" />
<stop style="stop-color:#a8a8a8;stop-opacity:1;" offset="1" id="stop1791" />
</linearGradient>
<linearGradient inkscape:collect="always" xlink:href="#linearGradient5048" id="linearGradient5027" gradientUnits="userSpaceOnUse" gradientTransform="matrix(2.774389,0,0,1.969706,-1892.179,-872.8854)" x1="302.85715" y1="366.64789" x2="302.85715" y2="609.50507" />
<linearGradient id="linearGradient5048">
<stop style="stop-color:black;stop-opacity:0;" offset="0" id="stop5050" />
<stop id="stop5056" offset="0.5" style="stop-color:black;stop-opacity:1;" />
<stop style="stop-color:black;stop-opacity:0;" offset="1" id="stop5052" />
</linearGradient>
<radialGradient inkscape:collect="always" xlink:href="#linearGradient5060" id="radialGradient5029" gradientUnits="userSpaceOnUse" gradientTransform="matrix(2.774389,0,0,1.969706,-1891.633,-872.8854)" cx="605.71429" cy="486.64789" fx="605.71429" fy="486.64789" r="117.14286" />
<linearGradient inkscape:collect="always" id="linearGradient5060">
<stop style="stop-color:black;stop-opacity:1;" offset="0" id="stop5062" />
<stop style="stop-color:black;stop-opacity:0;" offset="1" id="stop5064" />
</linearGradient>
<radialGradient inkscape:collect="always" xlink:href="#linearGradient5060" id="radialGradient5031" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-2.774389,0,0,1.969706,112.7623,-872.8854)" cx="605.71429" cy="486.64789" fx="605.71429" fy="486.64789" r="117.14286" />
<linearGradient inkscape:collect="always" xlink:href="#linearGradient137" id="linearGradient158" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.462696,0,0.06907908,0.683669,7.6420233,9.9623265)" x1="5.2657914" y1="18.725863" x2="8.212224" y2="52.625851" />
<linearGradient id="linearGradient137">
<stop style="stop-color:#ffffff;stop-opacity:0.70059878;" offset="0.0000000" id="stop138" />
<stop style="stop-color:#ffffff;stop-opacity:0.0000000;" offset="1.0000000" id="stop139" />
</linearGradient>
<linearGradient gradientTransform="translate(7.6420233,9.9623265)" inkscape:collect="always" xlink:href="#linearGradient13842" id="linearGradient13848" x1="22.25" y1="37.625" x2="19.75" y2="14.875" gradientUnits="userSpaceOnUse" />
<linearGradient inkscape:collect="always" id="linearGradient13842">
<stop style="stop-color:#000000;stop-opacity:1;" offset="0" id="stop13844" />
<stop style="stop-color:#000000;stop-opacity:0;" offset="1" id="stop13846" />
</linearGradient>
<linearGradient id="linearGradient259">
<stop id="stop260" offset="0.0000000" style="stop-color:#fafafa;stop-opacity:1.0000000;" />
<stop style="stop-color:#a8a8a8;stop-opacity:1;" offset="0.5" id="stop8238" />
<stop id="stop261" offset="1" style="stop-color:#cdcdcd;stop-opacity:1;" />
</linearGradient>
<linearGradient id="linearGradient269">
<stop id="stop270" offset="0.0000000" style="stop-color:#a3a3a3;stop-opacity:1.0000000;" />
<stop id="stop271" offset="1.0000000" style="stop-color:#4c4c4c;stop-opacity:1.0000000;" />
</linearGradient>
<linearGradient inkscape:collect="always" xlink:href="#linearGradient9766" id="linearGradient13162" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1,0,0,1.022118,59.698963,8.6393005)" x1="22.175976" y1="36.987999" x2="22.065331" y2="32.050499" />
<linearGradient id="linearGradient9766">
<stop style="stop-color:#6194cb;stop-opacity:1;" offset="0" id="stop9768" />
<stop style="stop-color:#729fcf;stop-opacity:1;" offset="1" id="stop9770" />
</linearGradient>
<linearGradient inkscape:collect="always" xlink:href="#linearGradient148" id="linearGradient156" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.535299,0,0,0.651339,11.093441,12.410326)" x1="14.899379" y1="27.059643" x2="22.715446" y2="41.836895" />
<linearGradient id="linearGradient148">
<stop style="stop-color:#ffffff;stop-opacity:0.13402061;" offset="0.0000000" id="stop149" />
<stop style="stop-color:#ffffff;stop-opacity:0.051546391;" offset="1.0000000" id="stop150" />
</linearGradient>
<linearGradient inkscape:collect="always" xlink:href="#linearGradient335" id="linearGradient155" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.421537,0,0,0.703464,7.6420233,9.9623265)" x1="19.116116" y1="28.946041" x2="19.426924" y2="51.912693" />
<linearGradient id="linearGradient335">
<stop style="stop-color:#ffffff;stop-opacity:1.0000000;" offset="0.0000000" id="stop336" />
<stop style="stop-color:#ffffff;stop-opacity:0.0000000;" offset="1.0000000" id="stop337" />
</linearGradient>
<radialGradient r="32.259769" fy="38.195114" fx="26.106777" cy="38.195114" cx="26.106777" gradientTransform="matrix(1.015635,0,0.103105,1.000512,7.6420233,9.8786325)" gradientUnits="userSpaceOnUse" id="radialGradient3407" xlink:href="#linearGradient1789" inkscape:collect="always" />
</defs>
<sodipodi:namedview id="base" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="5.5" inkscape:cx="32" inkscape:cy="32" inkscape:current-layer="layer1" showgrid="true" inkscape:document-units="px" inkscape:grid-bbox="true" inkscape:window-width="809" inkscape:window-height="698" inkscape:window-x="65" inkscape:window-y="24" inkscape:window-maximized="0" />
<metadata id="metadata2990">
<rdf:RDF>
<cc:Work rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g id="layer1" inkscape:label="Layer 1" inkscape:groupmode="layer">
<path inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccssssccc" style="color:#000000;fill:url(#radialGradient3407);fill-opacity:1;fill-rule:nonzero;stroke:#5a5a5a;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" id="path2375" d="m 12.262052,48.613342 c 0.04181,0.420455 0.497385,0.840909 0.911155,0.840909 l 31.136162,0 c 0.41377,0 0.785732,-0.420454 0.743924,-0.840909 L 42.356676,21.494054 C 42.314866,21.0736 41.85929,20.653146 41.445521,20.653146 l -12.723416,0 c -0.590546,0 -1.209083,-0.379552 -1.402861,-0.960335 L 26.216242,16.386935 C 26.04699,15.879657 25.669092,15.65114 24.901769,15.65114 l -14.9373267,0 c -0.413769,0 -0.785731,0.420454 -0.743923,0.840908 l 3.0415327,32.121294 z" />
<path inkscape:connector-curvature="0" style="opacity:0.11363633;color:#000000;fill:#729fcf;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.00000036;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" d="m 10.980625,27.495814 31.149859,0" id="path13113" sodipodi:nodetypes="cc" />
<path inkscape:connector-curvature="0" style="opacity:0.11363633;color:#000000;fill:#729fcf;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" d="m 12.972176,47.495814 29.987754,0" id="path13160" sodipodi:nodetypes="cc" />
<path inkscape:connector-curvature="0" sodipodi:nodetypes="cc" id="path13139" d="m 12.972176,45.495814 29.987754,0" style="opacity:0.11363633;color:#000000;fill:#729fcf;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" />
<g style="display:inline" id="g5022" transform="matrix(0.02165152,0,0,0.01903841,50.057403,46.896047)">
<rect y="-150.69685" x="-1559.2523" height="478.35718" width="1339.6335" id="rect4173" style="opacity:0.40206185;color:#000000;fill:url(#linearGradient5027);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible" />
<path inkscape:connector-curvature="0" sodipodi:nodetypes="cccc" id="path5058" d="m -219.61876,-150.68038 c 0,0 0,478.33079 0,478.33079 142.874166,0.90045 345.40022,-107.16966 345.40014,-239.196175 0,-132.026537 -159.436816,-239.134595 -345.40014,-239.134615 z" style="opacity:0.40206185;color:#000000;fill:url(#radialGradient5029);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible" />
<path inkscape:connector-curvature="0" style="opacity:0.40206185;color:#000000;fill:url(#radialGradient5031);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible" d="m -1559.2523,-150.68038 c 0,0 0,478.33079 0,478.33079 -142.8742,0.90045 -345.4002,-107.16966 -345.4002,-239.196175 0,-132.026537 159.4368,-239.134595 345.4002,-239.134615 z" id="path5018" sodipodi:nodetypes="cccc" />
</g>
<path inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccsscsscccc" id="path2380" d="m 13.813775,48.381001 c 0.03136,0.310327 -0.154625,0.517212 -0.475404,0.413769 l 0,0 C 13.017592,48.691328 12.789803,48.484443 12.758447,48.174116 L 9.7288813,16.806921 c -0.03136,-0.310328 0.156594,-0.497723 0.4669207,-0.497723 l 14.749752,-0.09145 c 0.531284,-0.0033 0.739429,0.05331 0.879799,0.517212 0,0 1.085374,3.112797 1.246234,3.698104 l -1.555596,-2.917035 c -0.26518,-0.497263 -0.598744,-0.41377 -0.97279,-0.41377 l -13.1294,0 c -0.310327,0 -0.496308,0.206885 -0.464952,0.517212 l 2.978821,30.864968 -0.113895,-0.103442 z" style="color:#000000;fill:url(#linearGradient158);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.17341149;marker:none;visibility:visible;display:block;overflow:visible" />
<path inkscape:connector-curvature="0" sodipodi:nodetypes="cc" id="path13145" d="m 9.9472573,17.495813 14.7837327,0" style="opacity:0.11363633;color:#000000;fill:#729fcf;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.99999982;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" />
<path inkscape:connector-curvature="0" sodipodi:nodetypes="cc" id="path13115" d="m 10.399357,21.495813 30.73888,0" style="opacity:0.11363633;color:#000000;fill:#729fcf;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" />
<g inkscape:export-ydpi="74.800003" inkscape:export-xdpi="74.800003" inkscape:export-filename="/home/jimmac/ximian_art/icons/nautilus/suse93/gnome-fs-directory.png" transform="matrix(1.034424,0,0.10452,1.034424,-2.3904566,12.59424)" id="g2381" style="fill:#ffffff;fill-opacity:0.5803109;fill-rule:nonzero;stroke:#000000;stroke-miterlimit:4;display:block">
<path inkscape:connector-curvature="0" sodipodi:nodetypes="cscscs" id="path2382" d="m 41.785743,9.0363862 c 0.0096,-0.4745828 0.01519,-0.7245056 -0.423393,-0.7242032 l -12.55582,0.00866 c -0.3,0 -0.324614,-0.1432061 0,0 0.324614,0.1432061 1.247098,0.6582712 2.182697,0.7009947 0,0 10.796477,0.016463 10.796516,0.014551 z" style="stroke:none" />
</g>
<path inkscape:connector-curvature="0" sodipodi:nodetypes="cc" id="path13123" d="m 10.804919,25.495814 30.830556,0" style="opacity:0.11363633;color:#000000;fill:#729fcf;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" />
<path inkscape:connector-curvature="0" style="opacity:0.11363633;color:#000000;fill:#729fcf;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" d="m 12.801495,43.495814 29.987754,0" id="path13121" sodipodi:nodetypes="cc" />
<path inkscape:connector-curvature="0" sodipodi:nodetypes="cc" id="path13119" d="m 12.507832,41.495814 30.108724,0" style="opacity:0.11363633;color:#000000;fill:#729fcf;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.00000036;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" />
<path inkscape:connector-curvature="0" style="opacity:0.11363633;color:#000000;fill:#729fcf;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.00000036;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" d="m 12.27566,39.495814 30.16921,0" id="path13135" sodipodi:nodetypes="cc" />
<path inkscape:connector-curvature="0" sodipodi:nodetypes="cc" id="path13137" d="m 12.104979,37.495814 30.16921,0" style="opacity:0.11363633;color:#000000;fill:#729fcf;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.00000036;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" />
<path inkscape:connector-curvature="0" style="opacity:0.11363633;color:#000000;fill:#729fcf;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" d="m 11.897695,35.495814 30.205121,0" id="path13143" sodipodi:nodetypes="cc" />
<path inkscape:connector-curvature="0" sodipodi:nodetypes="cc" id="path13133" d="m 11.665543,33.495814 30.265581,0" style="opacity:0.11363633;color:#000000;fill:#729fcf;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" />
<path inkscape:connector-curvature="0" style="opacity:0.11363633;color:#000000;fill:#729fcf;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" d="m 11.494862,31.495814 30.265581,0" id="path13117" sodipodi:nodetypes="cc" />
<g inkscape:export-ydpi="74.800003" inkscape:export-xdpi="74.800003" inkscape:export-filename="/home/jimmac/ximian_art/icons/nautilus/suse93/gnome-fs-directory.png" transform="matrix(1.034424,0,0.10452,1.034424,-2.3904566,12.59424)" id="g1853" style="fill:#ffffff;fill-opacity:0.5803109;fill-rule:nonzero;stroke:#000000;stroke-miterlimit:4;display:block">
<path inkscape:connector-curvature="0" sodipodi:nodetypes="cscscs" id="path1855" d="m 41.785743,9.0363862 c 0.0096,-0.4745828 0.01519,-0.7245056 -0.423393,-0.7242032 l -12.55582,0.00866 c -0.3,0 -0.324614,-0.1432061 0,0 0.324614,0.1432061 1.247098,0.6582712 2.182697,0.7009947 0,0 10.796477,0.016463 10.796516,0.014551 z" style="stroke:none" />
</g>
<path inkscape:connector-curvature="0" style="opacity:0.11363633;color:#000000;fill:#729fcf;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.00000036;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" d="m 10.606255,23.495814 31.026503,0" id="path13127" sodipodi:nodetypes="cc" />
<path inkscape:connector-curvature="0" sodipodi:nodetypes="cc" id="path13125" d="m 11.293442,29.495814 30.295796,0" style="opacity:0.11363633;color:#000000;fill:#729fcf;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" />
<path inkscape:connector-curvature="0" style="opacity:0.11363633;color:#000000;fill:#729fcf;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" d="m 10.166281,19.495814 15.280815,0" id="path13147" sodipodi:nodetypes="cc" />
<path inkscape:connector-curvature="0" style="opacity:0.39204544;color:#000000;fill:url(#linearGradient13848);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:block;overflow:visible" d="m 42.017023,24.087327 2.625,24.625 -31,0.125 c 0,0 -1.875,-24.75 -1.875,-24.75 0,0 30.375,0 30.25,0 z" id="path13840" sodipodi:nodetypes="cccsc" />
<g id="g4526" transform="translate(-31.454545,22.181819)">
<path sodipodi:nodetypes="ccccc" inkscape:connector-curvature="0" id="path3150-7" d="m 82.727274,-7.4545432 0,19.9999972 -12.000001,8 0,-19.99999998 z" style="fill:#204a87;stroke:none" />
<path inkscape:connector-curvature="0" id="path3930" d="m 70.727273,18.545454 12.000001,-8" style="fill:none;stroke:#3465a4;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<path inkscape:connector-curvature="0" id="path3932" d="m 80.727271,14.545454 0,-19.999999" style="fill:none;stroke:#3465a4;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<path inkscape:connector-curvature="0" id="path3934" d="m 82.727274,-5.454545 -12.000001,8" style="fill:none;stroke:#3465a4;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<path inkscape:connector-curvature="0" id="path3936" d="m 72.72727,-1.454545 0,19.999999" style="fill:none;stroke:#3465a4;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<path inkscape:connector-curvature="0" id="path3152-1" d="m 70.727273,20.545454 -16.000001,-8 0,-19.9999988 16.000001,7.99999882 z" style="fill:#3465a4;stroke:none" />
<path inkscape:connector-curvature="0" id="path3938" d="m 68.72727,0.54545502 0,17.99999898" style="fill:none;stroke:#729fcf;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<path inkscape:connector-curvature="0" id="path3940" d="m 54.727272,10.545454 16.000001,8" style="fill:none;stroke:#729fcf;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<path inkscape:connector-curvature="0" id="path3942" d="m 56.727275,12.545454 0,-17.999999" style="fill:none;stroke:#729fcf;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<path sodipodi:nodetypes="ccccc" inkscape:connector-curvature="0" id="path3150" d="m 82.727274,-7.4545448 0,19.9999988 -12.000001,8 0,-19.99999898 z" style="fill:none;stroke:#0b1521;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<path inkscape:connector-curvature="0" id="path3944" d="m 70.727273,2.545455 -16.000001,-8" style="fill:none;stroke:#729fcf;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<path inkscape:connector-curvature="0" id="path3152" d="m 70.727273,20.545454 -16.000001,-8 0,-19.9999988 16.000001,7.99999982 z" style="fill:none;stroke:#0b1521;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<path inkscape:connector-curvature="0" id="path3156" d="M 82.727274,-7.4545448 70.727273,0.54545502 54.727272,-7.4545448 66.727273,-15.454545 82.727274,-7.4545448" style="fill:#729fcf;stroke:#0b1521;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
</g>
<g id="g4792-3" style="stroke-width:1.60000002;stroke-miterlimit:4;stroke-dasharray:none" transform="matrix(0.31467961,0,0,0.34369088,28.536609,10.383837)">
<path style="fill:#729fcf;fill-rule:evenodd;stroke:#000000;stroke-width:2.34711409;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" d="m 32.679504,12.145359 -1.645803,2.84862 -1.645803,2.848621 2.164344,0 0,15.110077 c -0.652792,0.422664 -1.086869,1.135456 -1.127263,1.961007 l -12.219523,6.832562 -0.969446,-1.733943 -1.578167,2.662841 -1.578167,2.642199 3.088698,0.04128 3.088699,0.04128 -0.9469,-1.672017 12.039161,-6.749993 c 0.426007,0.340749 0.967678,0.536697 1.555622,0.536697 0.97078,0 1.798652,-0.551924 2.209435,-1.362384 l 14.6995,0.206422 -0.02255,2.146787 2.863246,-1.610091 2.863246,-1.61009 -2.818155,-1.672016 -2.818156,-1.692659 -0.02255,2.167429 -14.744591,-0.18578 c -0.276375,-0.539009 -0.738838,-0.954624 -1.307625,-1.176604 l 0,-14.883013 2.164344,0 -1.645803,-2.848621 -1.645803,-2.84862 z" id="rect3039-1-6" inkscape:connector-curvature="0" />
<rect y="15.941667" x="31.545361" height="19.048214" width="2.271805" id="rect3039-7" style="fill:#729fcf;fill-rule:evenodd;stroke:none" />
<path transform="matrix(0.96114836,0,0,0.96114836,0.26435064,8.6019885)" inkscape:transform-center-y="-0.94840389" d="m 37.145445,9.6098442 -3.418169,0 -3.418169,0 1.709084,-2.960221 1.709085,-2.9602211 1.709084,2.960221 z" inkscape:randomized="0" inkscape:rounded="0" inkscape:flatsided="false" sodipodi:arg2="1.5707963" sodipodi:arg1="0.52359878" sodipodi:r2="1.9734807" sodipodi:r1="3.9469614" sodipodi:cy="7.6363635" sodipodi:cx="33.727276" sodipodi:sides="3" id="path3043-5" style="fill:#729fcf;fill-rule:evenodd;stroke:none" sodipodi:type="star" />
<rect transform="matrix(-0.0130695,0.99991459,-0.99991459,-0.0130695,0,0)" y="-52.183987" x="33.423866" height="19.048214" width="2.271805" id="rect3039-3-3" style="fill:#ef2929;fill-rule:evenodd;stroke:none" />
<path inkscape:transform-center-x="-0.92685398" inkscape:transform-center-y="-0.024790177" d="m 37.145445,9.6098442 -3.418169,0 -3.418169,0 1.709084,-2.960221 1.709085,-2.9602211 1.709084,2.960221 z" inkscape:randomized="0" inkscape:rounded="0" inkscape:flatsided="false" sodipodi:arg2="1.5707963" sodipodi:arg1="0.52359878" sodipodi:r2="1.9734807" sodipodi:r1="3.9469614" sodipodi:cy="7.6363635" sodipodi:cx="33.727276" sodipodi:sides="3" id="path3043-6-56" style="fill:#ef2929;fill-rule:evenodd;stroke:none" sodipodi:type="star" transform="matrix(-0.01256173,0.96106627,-0.96106627,-0.01256173,59.490575,2.9206132)" />
<rect transform="matrix(-0.48864025,-0.87248536,0.87248701,-0.4886373,0,0)" y="-7.3576851" x="-47.582092" height="18.921833" width="2.2567275" id="rect3039-3-7-2" style="fill:#8ae234;fill-rule:evenodd;stroke:none" />
<path inkscape:transform-center-x="0.0233072" inkscape:transform-center-y="-0.87140186" d="m 37.145445,9.6098442 -3.418169,0 -3.418169,0 1.709084,-2.960221 1.709085,-2.9602211 1.709084,2.960221 z" inkscape:randomized="0" inkscape:rounded="0" inkscape:flatsided="false" sodipodi:arg2="1.5707963" sodipodi:arg1="0.52359878" sodipodi:r2="1.9734807" sodipodi:r1="3.9469614" sodipodi:cy="7.6363635" sodipodi:cx="33.727276" sodipodi:sides="3" id="path3043-6-5-9" style="fill:#8ae234;fill-rule:evenodd;stroke:none" sodipodi:type="star" transform="matrix(-0.44155795,-0.78841815,0.78842129,-0.4415562,26.06505,73.540728)" />
<path transform="matrix(0.96114836,0,0,0.96114836,-1.6579462,-1.0968723)" d="m 38.545456,37.590908 c 0,1.43092 -1.159989,2.590909 -2.590908,2.590909 -1.430919,0 -2.590908,-1.159989 -2.590908,-2.590909 0,-1.430919 1.159989,-2.590909 2.590908,-2.590909 1.430919,0 2.590908,1.15999 2.590908,2.590909 z" sodipodi:ry="2.590909" sodipodi:rx="2.5909083" sodipodi:cy="37.590908" sodipodi:cx="35.954548" id="path4366-1" style="fill:#fce94f;stroke:none" sodipodi:type="arc" />
</g>
<path inkscape:connector-curvature="0" inkscape:export-ydpi="74.800003" inkscape:export-xdpi="74.800003" inkscape:export-filename="/home/jimmac/ximian_art/icons/nautilus/suse93/gnome-fs-directory.png" sodipodi:nodetypes="cccsscccscc" id="path2401" d="m 13.420589,49.028324 c 0.103442,0.211469 0.310326,0.422928 0.620652,0.422928 l 33.308452,0 c 0.206892,0 0.521164,-0.126305 0.708174,-0.264351 0.530402,-0.391535 0.65486,-0.612385 0.892782,-0.973467 2.448126,-3.71546 5.805141,-19.276893 5.805141,-19.276893 0.103442,-0.21146 -0.103441,-0.42292 -0.413767,-0.42292 l -34.923642,0 c -0.310326,0 -1.655965,16.10733 -4.862998,19.287023 l -1.238236,1.22768 0.103442,0 z" style="color:#000000;fill:url(#linearGradient13162);fill-opacity:1;fill-rule:nonzero;stroke:#3465a4;stroke-width:0.99999982;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:block;overflow:visible" />
<path inkscape:connector-curvature="0" id="path323" d="m 20.776499,30.100968 c -0.772747,4.990757 -1.501301,9.009243 -2.71599,13.513864 2.386485,-0.707107 7.116116,-3.204505 17.116116,-3.204505 10,0 16.723573,-9.248699 17.651651,-10.353553 l -32.051777,0.04419 z" style="fill:url(#linearGradient156);fill-opacity:1;fill-rule:evenodd;stroke:none" sodipodi:nodetypes="ccccc" />
<path inkscape:connector-curvature="0" style="opacity:0.52272728;color:#000000;fill:none;stroke:url(#linearGradient155);stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" d="m 53.462106,29.649827 -33.158471,0 c 0,0 -2.147748,16.019607 -4.722272,18.240578 8.121077,0 31.571171,-0.04864 31.59099,-0.04864 1.751659,0 4.907641,-12.636194 6.289753,-18.191942 z" id="path324" sodipodi:nodetypes="cccsc" />
<g id="g5258" transform="matrix(0.28930544,0,0,0.28930544,12.974584,4.0161761)">
<g transform="matrix(1.3322492,0,0,1.4550733,-6.5424305,-12.411736)" style="stroke-width:1.60000002;stroke-miterlimit:4;stroke-dasharray:none" id="g4792">
<path inkscape:connector-curvature="0" id="rect3039-1" d="m 32.679504,12.145359 -1.645803,2.84862 -1.645803,2.848621 2.164344,0 0,15.110077 c -0.652792,0.422664 -1.086869,1.135456 -1.127263,1.961007 l -12.219523,6.832562 -0.969446,-1.733943 -1.578167,2.662841 -1.578167,2.642199 3.088698,0.04128 3.088699,0.04128 -0.9469,-1.672017 12.039161,-6.749993 c 0.426007,0.340749 0.967678,0.536697 1.555622,0.536697 0.97078,0 1.798652,-0.551924 2.209435,-1.362384 l 14.6995,0.206422 -0.02255,2.146787 2.863246,-1.610091 2.863246,-1.61009 -2.818155,-1.672016 -2.818156,-1.692659 -0.02255,2.167429 -14.744591,-0.18578 c -0.276375,-0.539009 -0.738838,-0.954624 -1.307625,-1.176604 l 0,-14.883013 2.164344,0 -1.645803,-2.848621 -1.645803,-2.84862 z" style="fill:#729fcf;fill-rule:evenodd;stroke:#000000;stroke-width:2.34711409;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<rect style="fill:#729fcf;fill-rule:evenodd;stroke:none" id="rect3039" width="2.271805" height="19.048214" x="31.545361" y="15.941667" />
<path sodipodi:type="star" style="fill:#729fcf;fill-rule:evenodd;stroke:none" id="path3043" sodipodi:sides="3" sodipodi:cx="33.727276" sodipodi:cy="7.6363635" sodipodi:r1="3.9469614" sodipodi:r2="1.9734807" sodipodi:arg1="0.52359878" sodipodi:arg2="1.5707963" inkscape:flatsided="false" inkscape:rounded="0" inkscape:randomized="0" d="m 37.145445,9.6098442 -3.418169,0 -3.418169,0 1.709084,-2.960221 1.709085,-2.9602211 1.709084,2.960221 z" inkscape:transform-center-y="-0.94840389" transform="matrix(0.96114836,0,0,0.96114836,0.26435064,8.6019885)" />
<rect style="fill:#ef2929;fill-rule:evenodd;stroke:none" id="rect3039-3" width="2.271805" height="19.048214" x="33.423866" y="-52.183987" transform="matrix(-0.0130695,0.99991459,-0.99991459,-0.0130695,0,0)" />
<path transform="matrix(-0.01256173,0.96106627,-0.96106627,-0.01256173,59.490575,2.9206132)" sodipodi:type="star" style="fill:#ef2929;fill-rule:evenodd;stroke:none" id="path3043-6" sodipodi:sides="3" sodipodi:cx="33.727276" sodipodi:cy="7.6363635" sodipodi:r1="3.9469614" sodipodi:r2="1.9734807" sodipodi:arg1="0.52359878" sodipodi:arg2="1.5707963" inkscape:flatsided="false" inkscape:rounded="0" inkscape:randomized="0" d="m 37.145445,9.6098442 -3.418169,0 -3.418169,0 1.709084,-2.960221 1.709085,-2.9602211 1.709084,2.960221 z" inkscape:transform-center-y="-0.024790177" inkscape:transform-center-x="-0.92685398" />
<rect style="fill:#8ae234;fill-rule:evenodd;stroke:none" id="rect3039-3-7" width="2.2567275" height="18.921833" x="-47.582092" y="-7.3576851" transform="matrix(-0.48864025,-0.87248536,0.87248701,-0.4886373,0,0)" />
<path transform="matrix(-0.44155795,-0.78841815,0.78842129,-0.4415562,26.06505,73.540728)" sodipodi:type="star" style="fill:#8ae234;fill-rule:evenodd;stroke:none" id="path3043-6-5" sodipodi:sides="3" sodipodi:cx="33.727276" sodipodi:cy="7.6363635" sodipodi:r1="3.9469614" sodipodi:r2="1.9734807" sodipodi:arg1="0.52359878" sodipodi:arg2="1.5707963" inkscape:flatsided="false" inkscape:rounded="0" inkscape:randomized="0" d="m 37.145445,9.6098442 -3.418169,0 -3.418169,0 1.709084,-2.960221 1.709085,-2.9602211 1.709084,2.960221 z" inkscape:transform-center-y="-0.87140186" inkscape:transform-center-x="0.0233072" />
<path sodipodi:type="arc" style="fill:#fce94f;stroke:none" id="path4366" sodipodi:cx="35.954548" sodipodi:cy="37.590908" sodipodi:rx="2.5909083" sodipodi:ry="2.590909" d="m 38.545456,37.590908 c 0,1.43092 -1.159989,2.590909 -2.590908,2.590909 -1.430919,0 -2.590908,-1.159989 -2.590908,-2.590909 0,-1.430919 1.159989,-2.590909 2.590908,-2.590909 1.430919,0 2.590908,1.15999 2.590908,2.590909 z" transform="matrix(0.96114836,0,0,0.96114836,-1.6579462,-1.0968723)" />
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 31 KiB

View file

@ -1,254 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="64px"
height="64px"
id="svg7430"
version="1.1"
inkscape:version="0.48.4 r9939"
sodipodi:docname="New document 55">
<defs
id="defs7432">
<radialGradient
r="22"
fy="91.956673"
fx="225.93762"
cy="91.956673"
cx="225.93762"
gradientTransform="matrix(-1.4090915,3.8636359,-0.97565325,-0.35582669,693.7938,-749.33348)"
gradientUnits="userSpaceOnUse"
id="radialGradient3061"
xlink:href="#linearGradient3084"
inkscape:collect="always" />
<linearGradient
inkscape:collect="always"
id="linearGradient3084">
<stop
style="stop-color:#729fcf;stop-opacity:1"
offset="0"
id="stop3086" />
<stop
style="stop-color:#204a87;stop-opacity:1"
offset="1"
id="stop3088" />
</linearGradient>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3857"
id="radialGradient3863"
cx="43.783218"
cy="41.446495"
fx="43.783218"
fy="41.446495"
r="12.458333"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.38461542,0.38461546,-0.84615388,0.84615382,61.897077,-11.243146)" />
<linearGradient
inkscape:collect="always"
id="linearGradient3857">
<stop
style="stop-color:#ffffff;stop-opacity:1"
offset="0"
id="stop3859" />
<stop
style="stop-color:#d3d7cf;stop-opacity:0.4"
offset="1"
id="stop3861" />
</linearGradient>
<radialGradient
r="22"
fy="91.956673"
fx="225.93762"
cy="91.956673"
cx="225.93762"
gradientTransform="matrix(-1.4090915,3.8636359,-0.97565325,-0.35582669,439.26643,-814.94734)"
gradientUnits="userSpaceOnUse"
id="radialGradient7462"
xlink:href="#linearGradient3084"
inkscape:collect="always" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="5.5"
inkscape:cx="31.272727"
inkscape:cy="32"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:document-units="px"
inkscape:grid-bbox="true"
inkscape:window-width="885"
inkscape:window-height="635"
inkscape:window-x="65"
inkscape:window-y="24"
inkscape:window-maximized="0" />
<metadata
id="metadata7435">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer">
<path
style="fill:url(#radialGradient7462);fill-opacity:1;stroke:#0b1521;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
d="m 34.181818,4.2727238 -21,52.0000072 c 0,8 42,8 42,0 z"
id="path3039"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccc" />
<path
style="fill:none;stroke:#729fcf;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 34.181818,9.2727238 -19,47.0000072 c 3,6 35,6 38,0 z"
id="path3817"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccc" />
<path
style="fill:#c17d11;fill-opacity:1;stroke:#271903;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:2.04"
d="m 39.181818,26.272729 4,-4 10,10.000013 -4,3.999989 z"
id="rect3057"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
<path
style="fill:none;stroke:#e9b96e;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 51.081828,32.972732 -10,-9.999997"
id="path3865"
inkscape:connector-curvature="0" />
<g
id="g4792"
style="stroke-width:1.60000002;stroke-miterlimit:4;stroke-dasharray:none"
transform="matrix(0.62901767,-0.34747949,0.37951469,0.68700873,-3.3397857,6.0535633)">
<path
style="fill:#729fcf;fill-rule:evenodd;stroke:#000000;stroke-width:2.34711409;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 32.679504,12.145359 -1.645803,2.84862 -1.645803,2.848621 2.164344,0 0,15.110077 c -0.652792,0.422664 -1.086869,1.135456 -1.127263,1.961007 l -12.219523,6.832562 -0.969446,-1.733943 -1.578167,2.662841 -1.578167,2.642199 3.088698,0.04128 3.088699,0.04128 -0.9469,-1.672017 12.039161,-6.749993 c 0.426007,0.340749 0.967678,0.536697 1.555622,0.536697 0.97078,0 1.798652,-0.551924 2.209435,-1.362384 l 14.6995,0.206422 -0.02255,2.146787 2.863246,-1.610091 2.863246,-1.61009 -2.818155,-1.672016 -2.818156,-1.692659 -0.02255,2.167429 -14.744591,-0.18578 c -0.276375,-0.539009 -0.738838,-0.954624 -1.307625,-1.176604 l 0,-14.883013 2.164344,0 -1.645803,-2.848621 -1.645803,-2.84862 z"
id="rect3039-1"
inkscape:connector-curvature="0" />
<rect
y="15.941667"
x="31.545361"
height="19.048214"
width="2.271805"
id="rect3039"
style="fill:#729fcf;fill-rule:evenodd;stroke:none" />
<path
transform="matrix(0.96114836,0,0,0.96114836,0.26435064,8.6019885)"
inkscape:transform-center-y="-0.94840389"
d="m 37.145445,9.6098442 -3.418169,0 -3.418169,0 1.709084,-2.960221 1.709085,-2.9602211 1.709084,2.960221 z"
inkscape:randomized="0"
inkscape:rounded="0"
inkscape:flatsided="false"
sodipodi:arg2="1.5707963"
sodipodi:arg1="0.52359878"
sodipodi:r2="1.9734807"
sodipodi:r1="3.9469614"
sodipodi:cy="7.6363635"
sodipodi:cx="33.727276"
sodipodi:sides="3"
id="path3043"
style="fill:#729fcf;fill-rule:evenodd;stroke:none"
sodipodi:type="star" />
<rect
transform="matrix(-0.0130695,0.99991459,-0.99991459,-0.0130695,0,0)"
y="-52.183987"
x="33.423866"
height="19.048214"
width="2.271805"
id="rect3039-3"
style="fill:#ef2929;fill-rule:evenodd;stroke:none" />
<path
inkscape:transform-center-x="-0.92685398"
inkscape:transform-center-y="-0.024790177"
d="m 37.145445,9.6098442 -3.418169,0 -3.418169,0 1.709084,-2.960221 1.709085,-2.9602211 1.709084,2.960221 z"
inkscape:randomized="0"
inkscape:rounded="0"
inkscape:flatsided="false"
sodipodi:arg2="1.5707963"
sodipodi:arg1="0.52359878"
sodipodi:r2="1.9734807"
sodipodi:r1="3.9469614"
sodipodi:cy="7.6363635"
sodipodi:cx="33.727276"
sodipodi:sides="3"
id="path3043-6"
style="fill:#ef2929;fill-rule:evenodd;stroke:none"
sodipodi:type="star"
transform="matrix(-0.01256173,0.96106627,-0.96106627,-0.01256173,59.490575,2.9206132)" />
<rect
transform="matrix(-0.48864025,-0.87248536,0.87248701,-0.4886373,0,0)"
y="-7.3576851"
x="-47.582092"
height="18.921833"
width="2.2567275"
id="rect3039-3-7"
style="fill:#8ae234;fill-rule:evenodd;stroke:none" />
<path
inkscape:transform-center-x="0.0233072"
inkscape:transform-center-y="-0.87140186"
d="m 37.145445,9.6098442 -3.418169,0 -3.418169,0 1.709084,-2.960221 1.709085,-2.9602211 1.709084,2.960221 z"
inkscape:randomized="0"
inkscape:rounded="0"
inkscape:flatsided="false"
sodipodi:arg2="1.5707963"
sodipodi:arg1="0.52359878"
sodipodi:r2="1.9734807"
sodipodi:r1="3.9469614"
sodipodi:cy="7.6363635"
sodipodi:cx="33.727276"
sodipodi:sides="3"
id="path3043-6-5"
style="fill:#8ae234;fill-rule:evenodd;stroke:none"
sodipodi:type="star"
transform="matrix(-0.44155795,-0.78841815,0.78842129,-0.4415562,26.06505,73.540728)" />
<path
transform="matrix(0.96114836,0,0,0.96114836,-1.6579462,-1.0968723)"
d="m 38.545456,37.590908 c 0,1.43092 -1.159989,2.590909 -2.590908,2.590909 -1.430919,0 -2.590908,-1.159989 -2.590908,-2.590909 0,-1.430919 1.159989,-2.590909 2.590908,-2.590909 1.430919,0 2.590908,1.15999 2.590908,2.590909 z"
sodipodi:ry="2.590909"
sodipodi:rx="2.5909083"
sodipodi:cy="37.590908"
sodipodi:cx="35.954548"
id="path4366"
style="fill:#fce94f;stroke:none"
sodipodi:type="arc" />
</g>
<path
sodipodi:type="arc"
style="fill:url(#radialGradient3863);fill-opacity:1;stroke:#2e3436;stroke-width:1.91666663;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:2.04"
id="path3055"
sodipodi:cx="47.5"
sodipodi:cy="44.5"
sodipodi:rx="11.5"
sodipodi:ry="11.5"
d="m 59,44.5 a 11.5,11.5 0 1 1 -23,0 11.5,11.5 0 1 1 23,0 z"
transform="matrix(1.0434783,0,0,1.0434783,-16.383402,-30.162054)" />
<path
sodipodi:type="arc"
style="fill:none;stroke:#d3d7cf;stroke-width:2.29999995;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:2.04"
id="path3055-1"
sodipodi:cx="47.5"
sodipodi:cy="44.5"
sodipodi:rx="11.5"
sodipodi:ry="11.5"
d="m 59,44.5 a 11.5,11.5 0 1 1 -23,0 11.5,11.5 0 1 1 23,0 z"
transform="matrix(0.86956525,0,0,0.86956521,-8.1225322,-22.422923)" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 10 KiB

View file

@ -1,152 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="64px"
height="64px"
id="svg6384"
version="1.1"
inkscape:version="0.48.4 r9939"
sodipodi:docname="New document 37">
<defs
id="defs6386" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.9445436"
inkscape:cx="33.122262"
inkscape:cy="42.611518"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:document-units="px"
inkscape:grid-bbox="true"
inkscape:window-width="472"
inkscape:window-height="383"
inkscape:window-x="968"
inkscape:window-y="24"
inkscape:window-maximized="0" />
<metadata
id="metadata6389">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer">
<g
id="g4792"
style="stroke-width:1.60000002;stroke-miterlimit:4;stroke-dasharray:none"
transform="matrix(1.3322492,0,0,1.4550733,-13.530887,-8.9206423)">
<path
style="fill:#729fcf;fill-rule:evenodd;stroke:#000000;stroke-width:2.34711409;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 32.679504,12.145359 -1.645803,2.84862 -1.645803,2.848621 2.164344,0 0,15.110077 c -0.652792,0.422664 -1.086869,1.135456 -1.127263,1.961007 l -12.219523,6.832562 -0.969446,-1.733943 -1.578167,2.662841 -1.578167,2.642199 3.088698,0.04128 3.088699,0.04128 -0.9469,-1.672017 12.039161,-6.749993 c 0.426007,0.340749 0.967678,0.536697 1.555622,0.536697 0.97078,0 1.798652,-0.551924 2.209435,-1.362384 l 14.6995,0.206422 -0.02255,2.146787 2.863246,-1.610091 2.863246,-1.61009 -2.818155,-1.672016 -2.818156,-1.692659 -0.02255,2.167429 -14.744591,-0.18578 c -0.276375,-0.539009 -0.738838,-0.954624 -1.307625,-1.176604 l 0,-14.883013 2.164344,0 -1.645803,-2.848621 -1.645803,-2.84862 z"
id="rect3039-1"
inkscape:connector-curvature="0" />
<rect
y="15.941667"
x="31.545361"
height="19.048214"
width="2.271805"
id="rect3039"
style="fill:#729fcf;fill-rule:evenodd;stroke:none" />
<path
transform="matrix(0.96114836,0,0,0.96114836,0.26435064,8.6019885)"
inkscape:transform-center-y="-0.94840389"
d="m 37.145445,9.6098442 -3.418169,0 -3.418169,0 1.709084,-2.960221 1.709085,-2.9602211 1.709084,2.960221 z"
inkscape:randomized="0"
inkscape:rounded="0"
inkscape:flatsided="false"
sodipodi:arg2="1.5707963"
sodipodi:arg1="0.52359878"
sodipodi:r2="1.9734807"
sodipodi:r1="3.9469614"
sodipodi:cy="7.6363635"
sodipodi:cx="33.727276"
sodipodi:sides="3"
id="path3043"
style="fill:#729fcf;fill-rule:evenodd;stroke:none"
sodipodi:type="star" />
<rect
transform="matrix(-0.0130695,0.99991459,-0.99991459,-0.0130695,0,0)"
y="-52.183987"
x="33.423866"
height="19.048214"
width="2.271805"
id="rect3039-3"
style="fill:#ef2929;fill-rule:evenodd;stroke:none" />
<path
inkscape:transform-center-x="-0.92685398"
inkscape:transform-center-y="-0.024790177"
d="m 37.145445,9.6098442 -3.418169,0 -3.418169,0 1.709084,-2.960221 1.709085,-2.9602211 1.709084,2.960221 z"
inkscape:randomized="0"
inkscape:rounded="0"
inkscape:flatsided="false"
sodipodi:arg2="1.5707963"
sodipodi:arg1="0.52359878"
sodipodi:r2="1.9734807"
sodipodi:r1="3.9469614"
sodipodi:cy="7.6363635"
sodipodi:cx="33.727276"
sodipodi:sides="3"
id="path3043-6"
style="fill:#ef2929;fill-rule:evenodd;stroke:none"
sodipodi:type="star"
transform="matrix(-0.01256173,0.96106627,-0.96106627,-0.01256173,59.490575,2.9206132)" />
<rect
transform="matrix(-0.48864025,-0.87248536,0.87248701,-0.4886373,0,0)"
y="-7.3576851"
x="-47.582092"
height="18.921833"
width="2.2567275"
id="rect3039-3-7"
style="fill:#8ae234;fill-rule:evenodd;stroke:none" />
<path
inkscape:transform-center-x="0.0233072"
inkscape:transform-center-y="-0.87140186"
d="m 37.145445,9.6098442 -3.418169,0 -3.418169,0 1.709084,-2.960221 1.709085,-2.9602211 1.709084,2.960221 z"
inkscape:randomized="0"
inkscape:rounded="0"
inkscape:flatsided="false"
sodipodi:arg2="1.5707963"
sodipodi:arg1="0.52359878"
sodipodi:r2="1.9734807"
sodipodi:r1="3.9469614"
sodipodi:cy="7.6363635"
sodipodi:cx="33.727276"
sodipodi:sides="3"
id="path3043-6-5"
style="fill:#8ae234;fill-rule:evenodd;stroke:none"
sodipodi:type="star"
transform="matrix(-0.44155795,-0.78841815,0.78842129,-0.4415562,26.06505,73.540728)" />
<path
transform="matrix(0.96114836,0,0,0.96114836,-1.6579462,-1.0968723)"
d="m 38.545456,37.590908 c 0,1.43092 -1.159989,2.590909 -2.590908,2.590909 -1.430919,0 -2.590908,-1.159989 -2.590908,-2.590909 0,-1.430919 1.159989,-2.590909 2.590908,-2.590909 1.430919,0 2.590908,1.15999 2.590908,2.590909 z"
sodipodi:ry="2.590909"
sodipodi:rx="2.5909083"
sodipodi:cy="37.590908"
sodipodi:cx="35.954548"
id="path4366"
style="fill:#fce94f;stroke:none"
sodipodi:type="arc" />
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 101 KiB

View file

@ -1,49 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="64px" height="64px" id="svg4339" version="1.1" inkscape:version="0.48.4 r9939" sodipodi:docname="inserttask.svg">
<defs id="defs4341">
<linearGradient inkscape:collect="always" xlink:href="#linearGradient3801" id="linearGradient3807" x1="110" y1="35" x2="85" y2="35" gradientUnits="userSpaceOnUse" spreadMethod="reflect" gradientTransform="translate(-61,23.272727)" />
<linearGradient inkscape:collect="always" id="linearGradient3801">
<stop style="stop-color:#c4a000;stop-opacity:1" offset="0" id="stop3803" />
<stop style="stop-color:#fce94f;stop-opacity:1" offset="1" id="stop3805" />
</linearGradient>
<linearGradient inkscape:collect="always" xlink:href="#linearGradient3801-5" id="linearGradient3807-7" x1="110" y1="35" x2="85" y2="35" gradientUnits="userSpaceOnUse" spreadMethod="reflect" gradientTransform="matrix(0.67526107,0,0,0.67526107,-31.705858,16.546964)" />
<linearGradient inkscape:collect="always" id="linearGradient3801-5">
<stop style="stop-color:#204a87;stop-opacity:1" offset="0" id="stop3803-9" />
<stop style="stop-color:#729fcf;stop-opacity:1" offset="1" id="stop3805-2" />
</linearGradient>
<linearGradient inkscape:collect="always" xlink:href="#linearGradient3801-5-7" id="linearGradient3807-7-9" x1="110" y1="35" x2="85" y2="35" gradientUnits="userSpaceOnUse" spreadMethod="reflect" gradientTransform="matrix(0.72727273,0,0,0.72727273,-36.272728,10.363637)" />
<linearGradient inkscape:collect="always" id="linearGradient3801-5-7">
<stop style="stop-color:#204a87;stop-opacity:1" offset="0" id="stop3803-9-3" />
<stop style="stop-color:#729fcf;stop-opacity:1" offset="1" id="stop3805-2-6" />
</linearGradient>
<linearGradient inkscape:collect="always" xlink:href="#linearGradient3801-5" id="linearGradient9363" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.25185691,0,0,0.33739682,10.761638,12.267711)" spreadMethod="reflect" x1="110" y1="35" x2="85" y2="35" />
</defs>
<sodipodi:namedview id="base" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="7.8520325" inkscape:cx="27.226073" inkscape:cy="45.767531" inkscape:current-layer="layer1" showgrid="true" inkscape:document-units="px" inkscape:grid-bbox="true" inkscape:snap-global="true" inkscape:snap-object-midpoints="false" inkscape:window-width="1375" inkscape:window-height="811" inkscape:window-x="65" inkscape:window-y="24" inkscape:window-maximized="1">
<inkscape:grid type="xygrid" id="grid9407" empspacing="5" visible="true" enabled="true" snapvisiblegridlinesonly="true" spacingx="0.8px" spacingy="0.8px" />
</sodipodi:namedview>
<metadata id="metadata4344">
<rdf:RDF>
<cc:Work rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g id="layer1" inkscape:label="Layer 1" inkscape:groupmode="layer">
<path style="fill:#729fcf;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" d="m 8,32 12,0 c 0,0 0,-4 12,-4 12,0 12,4 12,4 l 12,0 4,-8 -48,0 z" id="path9453" inkscape:connector-curvature="0" />
<path style="fill:#729fcf;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" d="m 56,32 0,16 -12,0 c 0,0 0,4 -12,4 C 20,52 20,48 20,48 L 8,48 8,32 20,32 c 0,0 0,4 12,4 12,0 12,-4 12,-4 z" id="path9459" inkscape:connector-curvature="0" />
<path style="fill:#ef2929;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:1, 1;stroke-dashoffset:0" d="m 20,32 0,16 c 0,0 0,-4 12,-4 12,0 12,4 12,4 l 0,-16 c 0,0 0,-4 -12,-4 -12,0 -12,4 -12,4 z" id="path9461" inkscape:connector-curvature="0" />
<path style="fill:#729fcf;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;opacity:0.75" d="M 4,56 4,40 8,32 8,48 z" id="path9477" inkscape:connector-curvature="0" />
<path style="fill:#729fcf;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1;opacity:0.75000000000000000" d="m 4,40 0,16 48,0 0,-16 z" id="path9457" inkscape:connector-curvature="0" />
<path style="fill:#729fcf;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" d="m 56,48 4,-8 0,-16 -4,8 z" id="path9465" inkscape:connector-curvature="0" />
<path style="fill:#729fcf;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1;opacity:0.75000000000000000" d="m 8,32 -4,8 48,0 4,-8 -12,0 c 0,0 0,4 -12,4 -12,0 -12,-4 -12,-4 z" id="path9471" inkscape:connector-curvature="0" />
<path style="fill:#729fcf;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;opacity:0.75" d="m 52,56 4,-8 0,-16 -4,8 z" id="path9475" inkscape:connector-curvature="0" />
<g id="g9521" transform="translate(0.59307628,-0.76413336)">
<path inkscape:connector-curvature="0" id="path9461-5" d="m 43.268756,23.699378 0,-15.4239998 c 0,0 0,3.8559998 -11.568,3.8559998 -11.568,0 -11.568,-3.8559998 -11.568,-3.8559998 l 0,15.4239998 c 0,0 0,3.856 11.568,3.856 11.568,0 11.568,-3.856 11.568,-3.856 z" style="fill:#ef2929;stroke:#000000;stroke-width:0.96399993;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
<path inkscape:connector-curvature="0" id="path9519" d="m 20.132756,8.2753782 c 0,0 0,-3.8559999 11.568,-3.8559999 11.568,0 11.568,3.8559999 11.568,3.8559999 0,0 0,3.8559998 -11.568,3.8559998 -11.568,0 -11.568,-3.8559998 -11.568,-3.8559998 z" style="fill:#729fcf;stroke:#000000;stroke-width:0.96399993px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 6.3 KiB

View file

@ -1,384 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="64px"
height="64px"
id="svg2860"
sodipodi:version="0.32"
inkscape:version="0.48.4 r9939"
sodipodi:docname="Part_ShapeInfo.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
version="1.1"
inkscape:export-filename="/home/user/Downloads/cad/freecad1_oce/mystuff/stuffchanged/newicons/JimsPartIcons/Part_ShapeInfo64.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90">
<defs
id="defs2862">
<inkscape:path-effect
is_visible="true"
id="path-effect3075"
effect="spiro" />
<linearGradient
id="linearGradient3775">
<stop
style="stop-color:#faff2b;stop-opacity:1;"
offset="0"
id="stop3777" />
<stop
style="stop-color:#ffaa00;stop-opacity:1;"
offset="1"
id="stop3779" />
</linearGradient>
<inkscape:path-effect
effect="spiro"
id="path-effect3076"
is_visible="true" />
<linearGradient
id="linearGradient3377">
<stop
id="stop3379"
offset="0"
style="stop-color:#faff2b;stop-opacity:1;" />
<stop
id="stop3381"
offset="1"
style="stop-color:#ffaa00;stop-opacity:1;" />
</linearGradient>
<inkscape:path-effect
effect="spiro"
id="path-effect3076-2"
is_visible="true" />
<inkscape:path-effect
effect="spiro"
id="path-effect3808"
is_visible="true" />
<inkscape:path-effect
effect="spiro"
id="path-effect3076-9"
is_visible="true" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3011-6"
id="radialGradient3174-3"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(-1.4090915,3.8636359,-0.97565325,-0.35582669,355.44592,-815.80833)"
cx="225.93762"
cy="91.956673"
fx="225.93762"
fy="91.956673"
r="22" />
<linearGradient
id="linearGradient3011-6"
inkscape:collect="always">
<stop
id="stop3013-7"
offset="0"
style="stop-color:#fce94f;stop-opacity:1" />
<stop
id="stop3015-5"
offset="1"
style="stop-color:#c4a000;stop-opacity:1" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3777"
id="linearGradient3220"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.79109028,0,0,0.78516507,69.03755,5.1139279)"
x1="53.896763"
y1="51.179787"
x2="47.502235"
y2="21.83742" />
<linearGradient
inkscape:collect="always"
id="linearGradient3777">
<stop
style="stop-color:#c4a000;stop-opacity:1"
offset="0"
id="stop3779-3" />
<stop
style="stop-color:#edd400;stop-opacity:1"
offset="1"
id="stop3781" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3767"
id="linearGradient3222"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.82352937,0,0,0.77272731,68.529413,5.8636358)"
x1="22.116516"
y1="55.717518"
x2="17.328547"
y2="21.31134" />
<linearGradient
inkscape:collect="always"
id="linearGradient3767">
<stop
style="stop-color:#edd400;stop-opacity:1"
offset="0"
id="stop3769" />
<stop
style="stop-color:#fce94f;stop-opacity:1"
offset="1"
id="stop3771" />
</linearGradient>
<inkscape:path-effect
is_visible="true"
id="path-effect3075-6"
effect="spiro" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="10.672523"
inkscape:cx="32.760661"
inkscape:cy="34.286167"
inkscape:current-layer="g3163"
showgrid="true"
inkscape:document-units="px"
inkscape:grid-bbox="true"
inkscape:window-width="1375"
inkscape:window-height="811"
inkscape:window-x="65"
inkscape:window-y="24"
inkscape:window-maximized="1"
inkscape:snap-global="true"
inkscape:snap-bbox="true"
inkscape:snap-nodes="false">
<inkscape:grid
type="xygrid"
id="grid3073"
empspacing="2"
visible="true"
enabled="true"
snapvisiblegridlinesonly="true" />
</sodipodi:namedview>
<metadata
id="metadata2865">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
<dc:creator>
<cc:Agent>
<dc:title>[wmayer]</dc:title>
</cc:Agent>
</dc:creator>
<dc:title>Part_ShapeInfo</dc:title>
<dc:date>2011-10-21</dc:date>
<dc:relation>http://www.freecadweb.org/wiki/index.php?title=Artwork</dc:relation>
<dc:publisher>
<cc:Agent>
<dc:title>FreeCAD</dc:title>
</cc:Agent>
</dc:publisher>
<dc:identifier>FreeCAD/src/Mod/Part/Gui/Resources/icons/Part_ShapeInfo.svg</dc:identifier>
<dc:rights>
<cc:Agent>
<dc:title>FreeCAD LGPL2+</dc:title>
</cc:Agent>
</dc:rights>
<cc:license>https://www.gnu.org/copyleft/lesser.html</cc:license>
<dc:contributor>
<cc:Agent>
<dc:title>[agryson] Alexander Gryson</dc:title>
</cc:Agent>
</dc:contributor>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer">
<g
id="g3618"
transform="translate(-129.7515,-68.681262)">
<g
id="g3163"
transform="translate(71.7515,76.68126)">
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="path2993"
d="m 71,19 28,5 18,-7 -23.84947,-3.42198 z"
style="fill:#fce94f;stroke:#302b00;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" />
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="path2995"
d="m 117,17 0,28 -18,8 0,-30 z"
style="fill:url(#linearGradient3220);fill-opacity:1;stroke:#302b00;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" />
<path
style="fill:url(#linearGradient3222);fill-opacity:1;fill-rule:evenodd;stroke:#302b00;stroke-width:1.99999988;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 71,19 28,4 0,30.000002 -28,-4.636365 z"
id="path3825"
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0" />
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="path3765"
d="M 72.993,21.368254 73,46.6 l 24,4 -0.007,-25.843 z"
style="fill:none;stroke:#fce94f;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="path3775"
d="m 101,24.5 0,25.6 14,-6.4 0,-23.8 z"
style="fill:none;stroke:#edd400;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
</g>
<g
id="g4792"
style="stroke-width:1.60000002;stroke-miterlimit:4;stroke-dasharray:none"
transform="matrix(0.67056429,0,0,0.73238565,125.13259,64.608603)">
<path
style="fill:#729fcf;fill-rule:evenodd;stroke:#000000;stroke-width:2.34711409;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 32.679504,12.145359 -1.645803,2.84862 -1.645803,2.848621 2.164344,0 0,15.110077 c -0.652792,0.422664 -1.086869,1.135456 -1.127263,1.961007 l -12.219523,6.832562 -0.969446,-1.733943 -1.578167,2.662841 -1.578167,2.642199 3.088698,0.04128 3.088699,0.04128 -0.9469,-1.672017 12.039161,-6.749993 c 0.426007,0.340749 0.967678,0.536697 1.555622,0.536697 0.97078,0 1.798652,-0.551924 2.209435,-1.362384 l 14.6995,0.206422 -0.02255,2.146787 2.863246,-1.610091 2.863246,-1.61009 -2.818155,-1.672016 -2.818156,-1.692659 -0.02255,2.167429 -14.744591,-0.18578 c -0.276375,-0.539009 -0.738838,-0.954624 -1.307625,-1.176604 l 0,-14.883013 2.164344,0 -1.645803,-2.848621 -1.645803,-2.84862 z"
id="rect3039-1"
inkscape:connector-curvature="0" />
<rect
y="15.941667"
x="31.545361"
height="19.048214"
width="2.271805"
id="rect3039"
style="fill:#729fcf;fill-rule:evenodd;stroke:none" />
<path
transform="matrix(0.96114836,0,0,0.96114836,0.26435064,8.6019885)"
inkscape:transform-center-y="-0.94840389"
d="m 37.145445,9.6098442 -3.418169,0 -3.418169,0 1.709084,-2.960221 1.709085,-2.9602211 1.709084,2.960221 z"
inkscape:randomized="0"
inkscape:rounded="0"
inkscape:flatsided="false"
sodipodi:arg2="1.5707963"
sodipodi:arg1="0.52359878"
sodipodi:r2="1.9734807"
sodipodi:r1="3.9469614"
sodipodi:cy="7.6363635"
sodipodi:cx="33.727276"
sodipodi:sides="3"
id="path3043"
style="fill:#729fcf;fill-rule:evenodd;stroke:none"
sodipodi:type="star" />
<rect
transform="matrix(-0.0130695,0.99991459,-0.99991459,-0.0130695,0,0)"
y="-52.183987"
x="33.423866"
height="19.048214"
width="2.271805"
id="rect3039-3"
style="fill:#ef2929;fill-rule:evenodd;stroke:none" />
<path
inkscape:transform-center-x="-0.92685398"
inkscape:transform-center-y="-0.024790177"
d="m 37.145445,9.6098442 -3.418169,0 -3.418169,0 1.709084,-2.960221 1.709085,-2.9602211 1.709084,2.960221 z"
inkscape:randomized="0"
inkscape:rounded="0"
inkscape:flatsided="false"
sodipodi:arg2="1.5707963"
sodipodi:arg1="0.52359878"
sodipodi:r2="1.9734807"
sodipodi:r1="3.9469614"
sodipodi:cy="7.6363635"
sodipodi:cx="33.727276"
sodipodi:sides="3"
id="path3043-6"
style="fill:#ef2929;fill-rule:evenodd;stroke:none"
sodipodi:type="star"
transform="matrix(-0.01256173,0.96106627,-0.96106627,-0.01256173,59.490575,2.9206132)" />
<rect
transform="matrix(-0.48864025,-0.87248536,0.87248701,-0.4886373,0,0)"
y="-7.3576851"
x="-47.582092"
height="18.921833"
width="2.2567275"
id="rect3039-3-7"
style="fill:#8ae234;fill-rule:evenodd;stroke:none" />
<path
inkscape:transform-center-x="0.0233072"
inkscape:transform-center-y="-0.87140186"
d="m 37.145445,9.6098442 -3.418169,0 -3.418169,0 1.709084,-2.960221 1.709085,-2.9602211 1.709084,2.960221 z"
inkscape:randomized="0"
inkscape:rounded="0"
inkscape:flatsided="false"
sodipodi:arg2="1.5707963"
sodipodi:arg1="0.52359878"
sodipodi:r2="1.9734807"
sodipodi:r1="3.9469614"
sodipodi:cy="7.6363635"
sodipodi:cx="33.727276"
sodipodi:sides="3"
id="path3043-6-5"
style="fill:#8ae234;fill-rule:evenodd;stroke:none"
sodipodi:type="star"
transform="matrix(-0.44155795,-0.78841815,0.78842129,-0.4415562,26.06505,73.540728)" />
<path
transform="matrix(0.96114836,0,0,0.96114836,-1.6579462,-1.0968723)"
d="m 38.545456,37.590908 c 0,1.43092 -1.159989,2.590909 -2.590908,2.590909 -1.430919,0 -2.590908,-1.159989 -2.590908,-2.590909 0,-1.430919 1.159989,-2.590909 2.590908,-2.590909 1.430919,0 2.590908,1.15999 2.590908,2.590909 z"
sodipodi:ry="2.590909"
sodipodi:rx="2.5909083"
sodipodi:cy="37.590908"
sodipodi:cx="35.954548"
id="path4366"
style="fill:#fce94f;stroke:none"
sodipodi:type="arc" />
</g>
<g
id="g3866"
transform="translate(-0.18097,2.2293053)">
<path
sodipodi:nodetypes="csssc"
inkscape:connector-curvature="0"
inkscape:original-d="m 147.93247,83.778883 c 3.4411,-8.506183 27.00312,1.297037 21.85148,11.450722 -1.85745,3.660955 -8.83783,6.411525 -11.92001,9.448945 -3.48475,3.43417 -1.11244,-2.0533 -1.11244,4.00271 0,3 0,2 0,4"
inkscape:path-effect="#path-effect3076"
id="path3074"
d="m 147.93247,83.778883 c 0.81237,-3.858821 3.51206,-7.273515 7.07935,-8.954275 3.56728,-1.68076 7.91929,-1.588544 11.41217,0.241814 3.49288,1.830359 6.04551,5.356345 6.6937,9.246114 0.64818,3.889769 -0.62313,8.052971 -3.33374,10.917069 -1.75374,1.853043 -4.00899,3.134652 -6.17494,4.482987 -2.16596,1.348338 -4.32985,2.843108 -5.74507,4.965958 -0.39126,0.5869 -0.71613,1.22352 -0.90052,1.90436 -0.18438,0.68083 -0.21192,1.39299 -0.21192,2.09835 l 0,4"
style="fill:none;stroke:#042a2a;stroke-width:8;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<path
id="path3011"
style="fill:none;stroke:#16d0d2;stroke-width:4;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 147.93247,84.054862 c 0.6406,-4.041309 3.31501,-7.707217 6.96781,-9.551011 3.65281,-1.843794 8.19051,-1.818285 11.82235,0.06646 3.63184,1.884746 6.26487,5.580491 6.85999,9.628746 0.59512,4.048256 -0.8629,8.345412 -3.79867,11.19564 -1.82858,1.775297 -4.12759,2.967137 -6.30722,4.287969 -2.17963,1.320833 -4.33592,2.863803 -5.61279,5.069473 -0.70845,1.22379 -1.1158,2.61098 -1.26025,4.01764 -0.12007,1.16922 -0.0614,2.35663 0.17343,3.5083"
inkscape:path-effect="#path-effect3075"
inkscape:original-d="m 147.93247,84.054862 c 3.4411,-8.423811 27.00312,1.284477 21.85148,11.339836 -1.85745,3.625503 -8.83783,6.349442 -11.92001,9.357442 -3.48475,3.40092 0.22192,-0.32188 -1.26025,4.01764 -0.99163,2.9033 -0.76327,1.22292 0.17343,3.5083"
inkscape:connector-curvature="0"
sodipodi:nodetypes="csssc" />
<path
id="path3011-7"
style="fill:none;stroke:#34e0e2;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 147.44781,82.697555 c 0.86224,-3.821346 3.5811,-7.178164 7.14,-8.815345 3.5589,-1.637181 7.87702,-1.517542 11.33981,0.314185 3.46279,1.831728 5.99161,5.33394 6.64094,9.197166 0.64932,3.863227 -0.59559,7.999725 -3.26927,10.862865 -1.74762,1.871459 -4.00446,3.170044 -6.17223,4.532874 -2.16777,1.36283 -4.33397,2.87044 -5.74778,5.00531 -0.80384,1.2138 -1.33911,2.60623 -1.54135,4.04795 -0.16676,1.18883 -0.10759,2.40896 0.17343,3.57607"
inkscape:path-effect="#path-effect3075-6"
inkscape:original-d="m 147.44781,82.697555 c 3.4411,-8.586521 27.00312,1.309287 21.85148,11.558871 -1.85745,3.695532 -8.83783,6.472084 -11.92001,9.538184 -3.48475,3.46661 -0.0592,-0.37539 -1.54135,4.04795 -0.99163,2.95938 -0.76327,1.24654 0.17343,3.57607"
inkscape:connector-curvature="0"
sodipodi:nodetypes="csssc" />
</g>
<path
sodipodi:type="arc"
style="fill:#34e0e2;fill-opacity:1;stroke:#042a2a;stroke-width:1.49073517;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:20.4"
id="path3871"
sodipodi:cx="26.932613"
sodipodi:cy="59.130264"
sodipodi:rx="2.9814701"
sodipodi:ry="2.9814701"
d="m 29.914083,59.130264 c 0,1.646621 -1.334849,2.98147 -2.98147,2.98147 -1.64662,0 -2.98147,-1.334849 -2.98147,-2.98147 0,-1.64662 1.33485,-2.98147 2.98147,-2.98147 1.646621,0 2.98147,1.33485 2.98147,2.98147 z"
transform="matrix(1.3416199,0,0,1.3416199,120.61817,46.350924)" />
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 17 KiB

View file

@ -1,262 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="64px"
height="64px"
id="svg6752"
version="1.1"
inkscape:version="0.48.4 r9939"
sodipodi:docname="New document 44">
<defs
id="defs6754">
<linearGradient
id="linearGradient4081">
<stop
style="stop-color:#ef2929;stop-opacity:1"
offset="0"
id="stop4083" />
<stop
style="stop-color:#a40000;stop-opacity:1"
offset="1"
id="stop4085" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4081"
id="linearGradient7020"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.83065033,0.55679442,-0.55679442,0.83065033,34.6951,-1.2386055)"
x1="14.824193"
y1="50.468616"
x2="20.93985"
y2="56.000233" />
<linearGradient
y2="60"
x2="16"
y1="48"
x1="12"
gradientTransform="matrix(-1,0,0,1,3.7546294,-19.78136)"
gradientUnits="userSpaceOnUse"
id="linearGradient3049"
xlink:href="#linearGradient4081-6"
inkscape:collect="always" />
<linearGradient
id="linearGradient4081-6">
<stop
style="stop-color:#8ae234;stop-opacity:1"
offset="0"
id="stop4083-7" />
<stop
style="stop-color:#4e9a06;stop-opacity:1"
offset="1"
id="stop4085-53" />
</linearGradient>
<linearGradient
y2="60"
x2="16"
y1="48"
x1="12"
gradientTransform="translate(3.1909099,-2.1818172)"
gradientUnits="userSpaceOnUse"
id="linearGradient7125"
xlink:href="#linearGradient4081-6"
inkscape:collect="always" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="5.5"
inkscape:cx="32"
inkscape:cy="32"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:document-units="px"
inkscape:grid-bbox="true"
inkscape:snap-object-midpoints="true"
inkscape:window-width="687"
inkscape:window-height="783"
inkscape:window-x="752"
inkscape:window-y="24"
inkscape:window-maximized="0" />
<metadata
id="metadata6757">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer">
<path
style="fill:#204a87;stroke:none"
d="m 31.000001,11.545457 0,19.999997 -12.000001,8 0,-19.999999 z"
id="path3150-7"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
<path
style="fill:none;stroke:#3465a4;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="M 19,37.545454 31.000001,29.545455"
id="path3930"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#3465a4;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 28.999998,33.545454 0,-19.999999"
id="path3932"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#3465a4;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="M 31.000001,13.545455 19,21.545455"
id="path3934"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#3465a4;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 20.999997,17.545455 0,19.999999"
id="path3936"
inkscape:connector-curvature="0" />
<path
style="fill:#3465a4;stroke:none"
d="m 19,39.545454 -16.0000006,-8 0,-19.999998 L 19,19.545454 z"
id="path3152-1"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#729fcf;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 16.999997,19.545455 0,17.999999"
id="path3938"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#729fcf;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="M 2.9999994,29.545454 19,37.545454"
id="path3940"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#729fcf;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 5.0000031,31.545454 0,-17.999999"
id="path3942"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#0b1521;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 31.000001,11.545456 0,19.999999 L 19,39.545454 19,19.545456 z"
id="path3150"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
<path
style="fill:none;stroke:#729fcf;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 19,21.545455 -16.0000006,-8"
id="path3944"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#0b1521;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 19,39.545454 -16.0000006,-8 0,-19.999998 L 19,19.545455 z"
id="path3152"
inkscape:connector-curvature="0" />
<path
style="fill:#729fcf;stroke:#0b1521;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="M 31.000001,11.545456 19,19.545455 2.9999994,11.545456 15.000001,3.5454545 l 16,8.0000015"
id="path3156"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:none;display:inline"
d="m 35.090876,17.81818 0,35.999998 24,0 0,-27.999998 -8,-8 z"
id="path4219"
inkscape:connector-curvature="0" />
<path
style="fill:#ffffff;stroke:none;display:inline"
d="m 35.090909,17.818182 0,35.999998 24,0 0,-27.999998 -8,-8 z"
id="path4219-6"
inkscape:connector-curvature="0" />
<path
style="fill:#888a85;stroke:none;display:inline"
d="m 51.090909,17.818182 0,8 8,0 z"
id="path4245"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#2e3436;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1;display:inline"
d="m 51.090909,17.818182 0,8 8,0"
id="path4221"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#2e3436;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1;display:inline"
d="m 39.090836,21.81818 8,0"
id="path4247"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#2e3436;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1;display:inline"
d="m 39.090836,31.81818 16,0"
id="path4251"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#2e3436;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1;display:inline"
d="m 39.090804,25.81818 8,0"
id="path4247-3"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#2e3436;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1;display:inline"
d="m 35.09091,17.818182 0,35.999998 23.999999,0 0,-27.999998 -8,-8 z"
id="path4219-6-6"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#2e3436;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1;display:inline"
d="m 39.090836,35.81818 16,0"
id="path4251-4"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#2e3436;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1;display:inline"
d="m 39.090836,39.81818 16,0"
id="path4251-7"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#2e3436;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1;display:inline"
d="m 39.090836,43.81818 16,0"
id="path4251-4-4"
inkscape:connector-curvature="0" />
<path
style="fill:url(#linearGradient7125);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.20000005;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 19.190911,57.818182 12,-8 -12,-8 0,4 -12.0000011,0 0,8 12.0000011,0 z"
id="rect3165"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccc" />
<path
style="fill:none;stroke:#8ae234;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1;display:inline"
d="m 21.190911,53.818182 0,-2 -12.0000015,0 0,-4"
id="path4087"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccc" />
<path
style="fill:none;stroke:#8ae234;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
d="M 19.009093,55.409091 29.054548,48.681819"
id="path4089"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#8ae234;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
d="m 19.190911,51.818182 2,2"
id="path4091"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#172a04;stroke-width:2.20000005;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 19.09091,57.818182 12,-8 -12,-8 0,4 -12.0000019,0 0,8 12.0000019,0 z"
id="rect3165-1"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccc" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 11 KiB

View file

@ -1,66 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" version="1.1" id="svg2816" height="64px" width="64px" inkscape:version="0.48.4 r9939" sodipodi:docname="plasetask.svg">
<sodipodi:namedview pagecolor="#ffffff" bordercolor="#666666" borderopacity="1" objecttolerance="10" gridtolerance="10" guidetolerance="10" inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:window-width="1375" inkscape:window-height="811" id="namedview8" showgrid="true" inkscape:snap-global="true" inkscape:zoom="7.375" inkscape:cx="13.685213" inkscape:cy="39.431348" inkscape:window-x="65" inkscape:window-y="24" inkscape:window-maximized="1" inkscape:current-layer="svg2816">
<inkscape:grid type="xygrid" id="grid2985" empspacing="1" visible="true" enabled="true" snapvisiblegridlinesonly="true" spacingx="0.8px" spacingy="0.8px" />
</sodipodi:namedview>
<defs id="defs2818">
<linearGradient inkscape:collect="always" id="linearGradient3799">
<stop style="stop-color:#204a87;stop-opacity:1" offset="0" id="stop3801" />
<stop style="stop-color:#3465a4;stop-opacity:1" offset="1" id="stop3803" />
</linearGradient>
<linearGradient inkscape:collect="always" id="linearGradient3773">
<stop style="stop-color:#3465a4;stop-opacity:1" offset="0" id="stop3775" />
<stop style="stop-color:#729fcf;stop-opacity:1" offset="1" id="stop3777" />
</linearGradient>
<linearGradient inkscape:collect="always" xlink:href="#linearGradient3773" id="linearGradient3779" x1="21.38983" y1="54.203388" x2="19.118645" y2="38" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.74237288,0,0,0.74237288,8.1084746,15.186441)" />
<linearGradient inkscape:collect="always" xlink:href="#linearGradient3799" id="linearGradient3805" x1="54.40678" y1="40.631996" x2="47.966103" y2="32.76759" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.74237288,0,0,0.74237288,8.1084746,15.186441)" />
<linearGradient inkscape:collect="always" xlink:href="#linearGradient3799-9" id="linearGradient3805-1" x1="54.40678" y1="40.631996" x2="47.966103" y2="32.76759" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.52090396,0,0,0.52090396,-10.567231,-6.7288135)" />
<linearGradient inkscape:collect="always" id="linearGradient3799-9">
<stop style="stop-color:#204a87;stop-opacity:1" offset="0" id="stop3801-7" />
<stop style="stop-color:#3465a4;stop-opacity:1" offset="1" id="stop3803-1" />
</linearGradient>
<linearGradient inkscape:collect="always" xlink:href="#linearGradient3773-1" id="linearGradient3779-3" x1="21.38983" y1="54.203388" x2="19.118645" y2="38" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.52090396,0,0,0.52090396,-10.567231,-6.7288135)" />
<linearGradient inkscape:collect="always" id="linearGradient3773-1">
<stop style="stop-color:#3465a4;stop-opacity:1" offset="0" id="stop3775-2" />
<stop style="stop-color:#729fcf;stop-opacity:1" offset="1" id="stop3777-0" />
</linearGradient>
</defs>
<metadata id="metadata2821">
<rdf:RDF>
<cc:Work rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
<dc:title>Path-BaseGeometry</dc:title>
<dc:date>2016-05-15</dc:date>
<dc:relation>http://www.freecadweb.org/wiki/index.php?title=Artwork</dc:relation>
<dc:publisher>
<cc:Agent>
<dc:title>FreeCAD</dc:title>
</cc:Agent>
</dc:publisher>
<dc:identifier>FreeCAD/src/Mod/Path/Gui/Resources/icons/Path-BaseGeometry.svg</dc:identifier>
<dc:rights>
<cc:Agent>
<dc:title>FreeCAD LGPL2+</dc:title>
</cc:Agent>
</dc:rights>
<cc:license>https://www.gnu.org/copyleft/lesser.html</cc:license>
<dc:contributor>
<cc:Agent>
<dc:title>[agryson] Alexander Gryson</dc:title>
</cc:Agent>
</dc:contributor>
</cc:Work>
</rdf:RDF>
</metadata>
<path style="fill:#729fcf;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" d="m 8,40 0,16 44,0 0,-16 z" id="path9885" inkscape:connector-curvature="0" />
<path style="fill:#729fcf;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" d="m 8,40 8,-16 44,0 -8,16 z" id="path9887" inkscape:connector-curvature="0" />
<path style="fill:#729fcf;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" d="m 60,40 0,-16 -8,16 0,16 z" id="path9891" inkscape:connector-curvature="0" />
<path style="fill:#ef2929;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:1,1;stroke-dashoffset:0" d="m 24.033899,35.864407 4,-8 16,0 -4,8 z" id="path10413-2" inkscape:connector-curvature="0" />
<g id="g10441" transform="translate(-2.0338983,1.7627119)">
<path inkscape:connector-curvature="0" id="path10405" d="m 25.898305,27.050847 16,0 0,-12 -16,0 z" style="fill:#729fcf;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" />
<path inkscape:connector-curvature="0" id="path10411" d="m 41.898305,27.050847 4,-8 0,-11.9999995 -4,7.9999995 z" style="fill:#729fcf;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" />
<path inkscape:connector-curvature="0" id="path10409" d="m 25.898305,15.050847 4,-7.9999995 16,0 -4,7.9999995 z" style="fill:#729fcf;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 5.9 KiB

View file

@ -1,66 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" version="1.1" id="svg2816" height="64px" width="64px" inkscape:version="0.48.4 r9939" sodipodi:docname="Path-BaseGeometry.svg">
<sodipodi:namedview pagecolor="#ffffff" bordercolor="#666666" borderopacity="1" objecttolerance="10" gridtolerance="10" guidetolerance="10" inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:window-width="1375" inkscape:window-height="811" id="namedview8" showgrid="true" inkscape:snap-global="true" inkscape:zoom="7.375" inkscape:cx="13.685213" inkscape:cy="39.431348" inkscape:window-x="65" inkscape:window-y="24" inkscape:window-maximized="1" inkscape:current-layer="svg2816">
<inkscape:grid type="xygrid" id="grid2985" empspacing="1" visible="true" enabled="true" snapvisiblegridlinesonly="true" spacingx="0.8px" spacingy="0.8px" />
</sodipodi:namedview>
<defs id="defs2818">
<linearGradient inkscape:collect="always" id="linearGradient3799">
<stop style="stop-color:#204a87;stop-opacity:1" offset="0" id="stop3801" />
<stop style="stop-color:#3465a4;stop-opacity:1" offset="1" id="stop3803" />
</linearGradient>
<linearGradient inkscape:collect="always" id="linearGradient3773">
<stop style="stop-color:#3465a4;stop-opacity:1" offset="0" id="stop3775" />
<stop style="stop-color:#729fcf;stop-opacity:1" offset="1" id="stop3777" />
</linearGradient>
<linearGradient inkscape:collect="always" xlink:href="#linearGradient3773" id="linearGradient3779" x1="21.38983" y1="54.203388" x2="19.118645" y2="38" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.74237288,0,0,0.74237288,8.1084746,15.186441)" />
<linearGradient inkscape:collect="always" xlink:href="#linearGradient3799" id="linearGradient3805" x1="54.40678" y1="40.631996" x2="47.966103" y2="32.76759" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.74237288,0,0,0.74237288,8.1084746,15.186441)" />
<linearGradient inkscape:collect="always" xlink:href="#linearGradient3799-9" id="linearGradient3805-1" x1="54.40678" y1="40.631996" x2="47.966103" y2="32.76759" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.52090396,0,0,0.52090396,-10.567231,-6.7288135)" />
<linearGradient inkscape:collect="always" id="linearGradient3799-9">
<stop style="stop-color:#204a87;stop-opacity:1" offset="0" id="stop3801-7" />
<stop style="stop-color:#3465a4;stop-opacity:1" offset="1" id="stop3803-1" />
</linearGradient>
<linearGradient inkscape:collect="always" xlink:href="#linearGradient3773-1" id="linearGradient3779-3" x1="21.38983" y1="54.203388" x2="19.118645" y2="38" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.52090396,0,0,0.52090396,-10.567231,-6.7288135)" />
<linearGradient inkscape:collect="always" id="linearGradient3773-1">
<stop style="stop-color:#3465a4;stop-opacity:1" offset="0" id="stop3775-2" />
<stop style="stop-color:#729fcf;stop-opacity:1" offset="1" id="stop3777-0" />
</linearGradient>
</defs>
<metadata id="metadata2821">
<rdf:RDF>
<cc:Work rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
<dc:title>Path-BaseGeometry</dc:title>
<dc:date>2016-05-15</dc:date>
<dc:relation>http://www.freecadweb.org/wiki/index.php?title=Artwork</dc:relation>
<dc:publisher>
<cc:Agent>
<dc:title>FreeCAD</dc:title>
</cc:Agent>
</dc:publisher>
<dc:identifier>FreeCAD/src/Mod/Path/Gui/Resources/icons/Path-BaseGeometry.svg</dc:identifier>
<dc:rights>
<cc:Agent>
<dc:title>FreeCAD LGPL2+</dc:title>
</cc:Agent>
</dc:rights>
<cc:license>https://www.gnu.org/copyleft/lesser.html</cc:license>
<dc:contributor>
<cc:Agent>
<dc:title>[agryson] Alexander Gryson</dc:title>
</cc:Agent>
</dc:contributor>
</cc:Work>
</rdf:RDF>
</metadata>
<path style="fill:#729fcf;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" d="m 8,40 0,16 44,0 0,-16 z" id="path9885" inkscape:connector-curvature="0" />
<path style="fill:#729fcf;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" d="m 8,40 8,-16 44,0 -8,16 z" id="path9887" inkscape:connector-curvature="0" />
<path style="fill:#729fcf;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" d="m 60,40 0,-16 -8,16 0,16 z" id="path9891" inkscape:connector-curvature="0" />
<path style="fill:#ef2929;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:1,1;stroke-dashoffset:0" d="m 24.033899,35.864407 4,-8 16,0 -4,8 z" id="path10413-2" inkscape:connector-curvature="0" />
<g id="g10441" transform="translate(-2.0338983,1.7627119)">
<path inkscape:connector-curvature="0" id="path10405" d="m 25.898305,27.050847 16,0 0,-12 -16,0 z" style="fill:#729fcf;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" />
<path inkscape:connector-curvature="0" id="path10411" d="m 41.898305,27.050847 4,-8 0,-11.9999995 -4,7.9999995 z" style="fill:#729fcf;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" />
<path inkscape:connector-curvature="0" id="path10409" d="m 25.898305,15.050847 4,-7.9999995 16,0 -4,7.9999995 z" style="fill:#729fcf;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 5.9 KiB

View file

@ -1,48 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" version="1.1" id="svg2816" height="64px" width="64px" inkscape:version="0.48.4 r9939" sodipodi:docname="screwtask.svg">
<sodipodi:namedview pagecolor="#ffffff" bordercolor="#666666" borderopacity="1" objecttolerance="10" gridtolerance="10" guidetolerance="10" inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:window-width="1375" inkscape:window-height="811" id="namedview8" showgrid="true" inkscape:snap-global="true" inkscape:zoom="2.6074563" inkscape:cx="13.761741" inkscape:cy="7.0890204" inkscape:window-x="65" inkscape:window-y="24" inkscape:window-maximized="1" inkscape:current-layer="svg2816">
<inkscape:grid type="xygrid" id="grid2985" empspacing="1" visible="true" enabled="true" snapvisiblegridlinesonly="true" spacingx="0.8px" spacingy="0.8px" />
</sodipodi:namedview>
<defs id="defs2818" />
<metadata id="metadata2821">
<rdf:RDF>
<cc:Work rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
<dc:title>Path-BaseGeometry</dc:title>
<dc:date>2016-05-15</dc:date>
<dc:relation>http://www.freecadweb.org/wiki/index.php?title=Artwork</dc:relation>
<dc:publisher>
<cc:Agent>
<dc:title>FreeCAD</dc:title>
</cc:Agent>
</dc:publisher>
<dc:identifier>FreeCAD/src/Mod/Path/Gui/Resources/icons/Path-BaseGeometry.svg</dc:identifier>
<dc:rights>
<cc:Agent>
<dc:title>FreeCAD LGPL2+</dc:title>
</cc:Agent>
</dc:rights>
<cc:license>https://www.gnu.org/copyleft/lesser.html</cc:license>
<dc:contributor>
<cc:Agent>
<dc:title>[agryson] Alexander Gryson</dc:title>
</cc:Agent>
</dc:contributor>
</cc:Work>
</rdf:RDF>
</metadata>
<path style="fill:#729fcf;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" d="m 8,40 0,16 44,0 0,-16 z" id="path9885" inkscape:connector-curvature="0" />
<path style="fill:#729fcf;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" d="m 8,40 8,-16 44,0 -8,16 z" id="path9887" inkscape:connector-curvature="0" />
<path style="fill:#729fcf;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" d="m 60,40 0,-16 -8,16 0,16 z" id="path9891" inkscape:connector-curvature="0" />
<g id="g11337" transform="matrix(1.6407747,0,0,1.6407747,72.077665,-1.9550749)">
<path inkscape:connector-curvature="0" id="path11317" d="m -28,12 0,9.6 c 0,0 0,1.6 4,1.6 4,0 4,-1.6 4,-1.6 l 0,-9.6" style="fill:#ef2929;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path inkscape:connector-curvature="0" id="path11190-46-2" d="m -19.946244,11.494715 c 0,0 -1.423729,1.898305 -4,1.898305 -2.576271,0 -4,-0.40678 -4,-0.40678" style="fill:none;stroke:#000000;stroke-width:1.60000002;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<path inkscape:connector-curvature="0" id="path11048" d="m -32,8 c 0,0 0,-4 8,-4 8,0 8,4 8,4 0,0 0,4 -8,4 -8,0 -8,-4 -8,-4 z" style="fill:#729fcf;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path inkscape:connector-curvature="0" id="path11190" d="m -19.898305,16.079095 c 0,0 -1.423729,1.898305 -4,1.898305 -2.576271,0 -4,-0.40678 -4,-0.40678" style="fill:none;stroke:#000000;stroke-width:1.60000002;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<path inkscape:connector-curvature="0" id="path11190-46" d="m -19.898305,18.327684 c 0,0 -1.423729,1.898305 -4,1.898305 -2.576271,0 -4,-0.40678 -4,-0.40678" style="fill:none;stroke:#000000;stroke-width:1.60000002;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<path inkscape:connector-curvature="0" id="path11190-3" d="m -19.898305,13.830509 c 0,0 -1.423729,1.898305 -4,1.898305 -2.576271,0 -4,-0.40678 -4,-0.40678" style="fill:none;stroke:#000000;stroke-width:1.60000002;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<path transform="matrix(1.0318786,0,0,0.41149652,4.8926008,12.937958)" d="m -24,-8.0000001 -3.267949,-1.2679492 -2.196153,2.7320508 L -30,-10 l -3.464102,-0.535898 2.732051,-2.196153 L -32,-16 l 3.267949,1.267949 2.196153,-2.732051 L -26,-14 l 3.464102,0.535898 -2.732051,2.196153 z" inkscape:randomized="0" inkscape:rounded="0" inkscape:flatsided="false" sodipodi:arg2="1.3089969" sodipodi:arg1="0.78539816" sodipodi:r2="2.8284271" sodipodi:r1="5.6568542" sodipodi:cy="-12" sodipodi:cx="-28" sodipodi:sides="6" id="path11272" style="fill:#729fcf;fill-opacity:0.29223747;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" sodipodi:type="star" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 5.4 KiB

View file

@ -1,49 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" version="1.1" id="svg2816" height="64px" width="64px" inkscape:version="0.48.4 r9939" sodipodi:docname="Path-BaseGeometry.svg">
<sodipodi:namedview pagecolor="#ffffff" bordercolor="#666666" borderopacity="1" objecttolerance="10" gridtolerance="10" guidetolerance="10" inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:window-width="1375" inkscape:window-height="811" id="namedview8" showgrid="true" inkscape:snap-global="false" inkscape:zoom="7.375" inkscape:cx="35.651266" inkscape:cy="31.713387" inkscape:window-x="65" inkscape:window-y="24" inkscape:window-maximized="1" inkscape:current-layer="svg2816">
<inkscape:grid type="xygrid" id="grid2985" empspacing="2" visible="true" enabled="true" snapvisiblegridlinesonly="true" />
</sodipodi:namedview>
<defs id="defs2818">
<linearGradient inkscape:collect="always" id="linearGradient3799">
<stop style="stop-color:#204a87;stop-opacity:1" offset="0" id="stop3801" />
<stop style="stop-color:#3465a4;stop-opacity:1" offset="1" id="stop3803" />
</linearGradient>
<linearGradient inkscape:collect="always" id="linearGradient3773">
<stop style="stop-color:#3465a4;stop-opacity:1" offset="0" id="stop3775" />
<stop style="stop-color:#729fcf;stop-opacity:1" offset="1" id="stop3777" />
</linearGradient>
<linearGradient inkscape:collect="always" xlink:href="#linearGradient3773" id="linearGradient3779" x1="21.38983" y1="54.203388" x2="19.118645" y2="38" gradientUnits="userSpaceOnUse" />
<linearGradient inkscape:collect="always" xlink:href="#linearGradient3799" id="linearGradient3805" x1="54.40678" y1="40.631996" x2="47.966103" y2="32.76759" gradientUnits="userSpaceOnUse" />
</defs>
<metadata id="metadata2821">
<rdf:RDF>
<cc:Work rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
<dc:title>Path-BaseGeometry</dc:title>
<dc:date>2016-05-15</dc:date>
<dc:relation>http://www.freecadweb.org/wiki/index.php?title=Artwork</dc:relation>
<dc:publisher>
<cc:Agent>
<dc:title>FreeCAD</dc:title>
</cc:Agent>
</dc:publisher>
<dc:identifier>FreeCAD/src/Mod/Path/Gui/Resources/icons/Path-BaseGeometry.svg</dc:identifier>
<dc:rights>
<cc:Agent>
<dc:title>FreeCAD LGPL2+</dc:title>
</cc:Agent>
</dc:rights>
<cc:license>https://www.gnu.org/copyleft/lesser.html</cc:license>
<dc:contributor>
<cc:Agent>
<dc:title>[agryson] Alexander Gryson</dc:title>
</cc:Agent>
</dc:contributor>
</cc:Work>
</rdf:RDF>
</metadata>
<text xml:space="preserve" style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans" x="9.7627115" y="27.118645" id="text10484" sodipodi:linespacing="125%"><tspan sodipodi:role="line" id="tspan10486" x="9.7627115" y="27.118645" /></text>
<text xml:space="preserve" style="font-size:72px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#ef2929;fill-opacity:1;stroke:#000000;font-family:Sans;stroke-opacity:1;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none" x="33.084747" y="57.355934" id="text11000" sodipodi:linespacing="125%"><tspan sodipodi:role="line" id="tspan11002" x="33.084747" y="57.355934">T</tspan></text>
</svg>

Before

Width:  |  Height:  |  Size: 3.9 KiB

View file

@ -0,0 +1,15 @@
## Скрипт генерации датасета
Скрипт используется в составе web-сервиса для генерации датасетов с использованием заданной пользователем конфигурации.
Должен быть установлен пакет [BlenderProc](https://github.com/DLR-RM/BlenderProc).
Команда для вызова:
```bash
blenderproc run renderBOPdataset.py --cfg CFG
options:
--cfg CFG строка json с параметрами конфигурации датасета / путь к json-файлу с конфигурацией
```
[Пример файла конфигурации датасета.](dataset_cfg.json)

View file

@ -0,0 +1,41 @@
{
"dataSetObjects": ["fork"],
"datasetType": "Object Detection - YOLOv8",
"name": "123123e",
"formBuilder": {
"output": {
"typedataset": "ObjectDetection",
"dataset_path": "eqwfeadszxz",
"models": [{"id": 1, "name": "fork"}],
"models_randomization": { "loc_range_low": [-1, -1, 0.0], "loc_range_high": [1, 1, 2] },
"scene": {
"objects": [
{"name": "floor", "collision_shape": "BOX", "loc_xyz":[0,0,0], "rot_euler":[0, 0, 0],
"material_randomization": {"specular":[0,1], "roughness":[0,1], "metallic":[0,1], "base_color":[[0,0,0,1],[1,1,1,1]]}
}
],
"lights": [
{"id": 1, "type": "POINT", "loc_xyz":[5,5,5], "rot_euler":[-0.06, 0.61, -0.19],
"color_range_low":[0.5, 0.5, 0.5], "color_range_high":[1, 1, 1],
"energy_range":[400,900]
},
{"id": 2, "type": "SUN", "loc_xyz":[0,0,0], "rot_euler":[-0.01, 0.01, -0.01],
"color_range_low":[1, 1, 1], "color_range_high":[1, 1, 1],
"energy_range":[2,9]
}
]
},
"camera_position": { "center_shell": [0, 0, 0], "radius_range": [0.4, 1.4], "elevation_range": [10, 90] },
"generation": {
"n_cam_pose": 3,
"n_sample_on_pose": 1,
"n_series": 3,
"image_format": "JPEG",
"image_size_wh": [640, 480]
}
}
},
"processStatus": "exec",
"local_path": "/home/user/5f4e161b-82d1-41fa-a11c-15d485b01600",
"projectId": "660aaddbf98957a186f9c546"
}

View file

@ -0,0 +1,361 @@
import blenderproc as bproc
"""
renderBOPdataset
Общая задача: common pipeline
Реализуемая функция: создание датасета в формате BOP с заданными параметрами рандомизации
Используется модуль blenderproc
26.04.2024 @shalenikol release 0.1
"""
import numpy as np
import argparse
import random
import os
import shutil
import json
VHACD_PATH = "blenderproc_resources/vhacd"
DIR_MODELS = "models"
FILE_LOG_SCENE = "res.txt"
FILE_RBS_INFO = "rbs_info.json"
FILE_GT_COCO = "scene_gt_coco.json"
Not_Categories_Name = True # наименование категории в COCO-аннотации отсутствует
def _get_path_model(name_model: str) -> str:
# TODO on name_model find path for mesh (model.fbx)
# local_path/assets/mesh/
return os.path.join(rnd_par.output_dir, "assets/mesh/"+name_model+".fbx")
def _get_path_object(name_obj: str) -> str:
# TODO on name_obj find path for scene object (object.fbx)
return os.path.join(rnd_par.output_dir, "assets/mesh/"+name_obj+".fbx")
def convert2relative(height, width, bbox):
"""
YOLO format use relative coordinates for annotation
"""
x, y, w, h = bbox
x += w/2
y += h/2
return x/width, y/height, w/width, h/height
def render() -> int:
for obj in all_meshs:
# Make the object actively participate in the physics simulation
obj.enable_rigidbody(active=True, collision_shape="COMPOUND")
# Also use convex decomposition as collision shapes
obj.build_convex_decomposition_collision_shape(VHACD_PATH)
objs = all_meshs + rnd_par.scene.objs
log_txt = os.path.join(rnd_par.output_dir, FILE_LOG_SCENE)
with open(log_txt, "w") as fh:
for i,o in enumerate(objs):
loc = o.get_location()
euler = o.get_rotation_euler()
fh.write(f"{i} : {o.get_name()} {loc} {euler} category_id = {o.get_cp('category_id')}\n")
# define a light and set its location and energy level
ls = []
for l in rnd_par.scene.light_data:
light = bproc.types.Light(name=f"l{l['id']}")
light.set_type(l["type"])
light.set_location(l["loc_xyz"]) #[5, -5, 5])
light.set_rotation_euler(l["rot_euler"]) #[-0.063, 0.6177, -0.1985])
ls += [light]
# define the camera intrinsics
bproc.camera.set_intrinsics_from_blender_params(1,
rnd_par.image_size_wh[0],
rnd_par.image_size_wh[1],
lens_unit="FOV")
# add segmentation masks (per class and per instance)
bproc.renderer.enable_segmentation_output(map_by=["category_id", "instance", "name"])
# activate depth rendering
bproc.renderer.enable_depth_output(activate_antialiasing=False)
res_dir = os.path.join(rnd_par.output_dir, rnd_par.ds_name)
if os.path.isdir(res_dir):
shutil.rmtree(res_dir)
# Цикл рендеринга
# Do multiple times: Position the shapenet objects using the physics simulator and render X images with random camera poses
for r in range(rnd_par.n_series):
# один случайный объект в кадре / все заданные объекты
random_obj = random.choice(range(rnd_par.scene.n_obj))
meshs = []
for i,o in enumerate(all_meshs): #objs
if rnd_par.single_object and i != random_obj:
continue
meshs += [o]
rnd_mat = rnd_par.scene.obj_data[i]["material_randomization"]
mats = o.get_materials() #[0]
for mat in mats:
val = rnd_mat["specular"]
mat.set_principled_shader_value("Specular", random.uniform(val[0], val[1]))
val = rnd_mat["roughness"]
mat.set_principled_shader_value("Roughness", random.uniform(val[0], val[1]))
val = rnd_mat["base_color"]
mat.set_principled_shader_value("Base Color", np.random.uniform(val[0], val[1]))
val = rnd_mat["metallic"]
mat.set_principled_shader_value("Metallic", random.uniform(val[0], val[1]))
# Randomly set the color and energy
for i,l in enumerate(ls):
current = rnd_par.scene.light_data[i]
l.set_color(np.random.uniform(current["color_range_low"], current["color_range_high"]))
energy = current["energy_range"]
l.set_energy(random.uniform(energy[0], energy[1]))
# Clear all key frames from the previous run
bproc.utility.reset_keyframes()
# Define a function that samples 6-DoF poses
def sample_pose(obj: bproc.types.MeshObject):
obj.set_location(np.random.uniform(rnd_par.loc_range_low, rnd_par.loc_range_high)) #[-1, -1, 0], [1, 1, 2]))
obj.set_rotation_euler(bproc.sampler.uniformSO3())
# Sample the poses of all shapenet objects above the ground without any collisions in-between
bproc.object.sample_poses(meshs,
objects_to_check_collisions = meshs + rnd_par.scene.collision_objects,
sample_pose_func = sample_pose)
# Run the simulation and fix the poses of the shapenet objects at the end
bproc.object.simulate_physics_and_fix_final_poses(min_simulation_time=4, max_simulation_time=20, check_object_interval=1)
# Find point of interest, all cam poses should look towards it
poi = bproc.object.compute_poi(meshs)
coord_max = [0.1, 0.1, 0.1]
coord_min = [0., 0., 0.]
with open(log_txt, "a") as fh:
fh.write("*****************\n")
fh.write(f"{r}) poi = {poi}\n")
i = 0
for o in meshs:
i += 1
loc = o.get_location()
euler = o.get_rotation_euler()
fh.write(f" {i} : {o.get_name()} {loc} {euler}\n")
for j in range(3):
if loc[j] < coord_min[j]:
coord_min[j] = loc[j]
if loc[j] > coord_max[j]:
coord_max[j] = loc[j]
# Sample up to X camera poses
#an = np.random.uniform(0.78, 1.2) #1. #0.35
for i in range(rnd_par.n_cam_pose):
# Sample location
location = bproc.sampler.shell(center=rnd_par.center_shell,
radius_min=rnd_par.radius_range[0],
radius_max=rnd_par.radius_range[1],
elevation_min=rnd_par.elevation_range[0],
elevation_max=rnd_par.elevation_range[1])
# координата, по которой будем сэмплировать положение камеры
j = random.randint(0, 2)
# разовый сдвиг по случайной координате
d = (coord_max[j] - coord_min[j]) / rnd_par.n_sample_on_pose
if location[j] < 0:
d = -d
for _ in range(rnd_par.n_sample_on_pose):
# Compute rotation based on vector going from location towards poi
rotation_matrix = bproc.camera.rotation_from_forward_vec(poi - location, inplane_rot=np.random.uniform(-0.7854, 0.7854))
# Add homog cam pose based on location an rotation
cam2world_matrix = bproc.math.build_transformation_mat(location, rotation_matrix)
bproc.camera.add_camera_pose(cam2world_matrix)
location[j] -= d
# render the whole pipeline
data = bproc.renderer.render()
# Write data to bop format
bproc.writer.write_bop(res_dir,
target_objects = all_meshs, # Optional[List[MeshObject]] = None
depths = data["depth"],
depth_scale = 1.0,
colors = data["colors"],
color_file_format=rnd_par.image_format,
append_to_existing_output = (r>0),
save_world2cam = False) # world coords are arbitrary in most real BOP datasets
# dataset="robo_ds",
models_dir = os.path.join(res_dir, DIR_MODELS)
os.mkdir(models_dir)
data = []
for i,objn in enumerate(rnd_par.models.names):
rec = {}
rec["id"] = i+1
rec["name"] = objn
rec["model"] = os.path.join(DIR_MODELS, os.path.split(rnd_par.models.filenames[i])[1]) # путь относительный
t = [obj.get_bound_box(local_coords=True).tolist() for obj in all_meshs if obj.get_name() == objn]
rec["cuboid"] = t[0]
data.append(rec)
shutil.copy2(rnd_par.models.filenames[i], models_dir)
f = (os.path.splitext(rnd_par.models.filenames[i]))[0] + ".mtl" # файл материала
if os.path.isfile(f):
shutil.copy2(f, models_dir)
with open(os.path.join(res_dir, FILE_RBS_INFO), "w") as fh:
json.dump(data, fh, indent=2)
"""
!!! categories -> name берётся из category_id !!!
см.ниже
blenderproc.python.writer : BopWriterUtility.py
class _BopWriterUtility
def calc_gt_coco
...
CATEGORIES = [{'id': obj.get_cp('category_id'), 'name': str(obj.get_cp('category_id')), 'supercategory':
dataset_name} for obj in dataset_objects]
поэтому заменим наименование категории в аннотации
"""
def change_categories_name(dir: str):
coco_file = os.path.join(dir,FILE_GT_COCO)
with open(coco_file, "r") as fh:
data = json.load(fh)
cats = data["categories"]
for i,cat in enumerate(cats):
cat["name"] = rnd_par.models.names[i] #obj_names[i]
with open(coco_file, "w") as fh:
json.dump(data, fh, indent=0)
def explore(path: str):
if not os.path.isdir(path):
return
folders = [
os.path.join(path, o)
for o in os.listdir(path)
if os.path.isdir(os.path.join(path, o))
]
for path_entry in folders:
print(path_entry)
if os.path.isfile(os.path.join(path_entry,FILE_GT_COCO)):
change_categories_name(path_entry)
else:
explore(path_entry)
if Not_Categories_Name:
explore(res_dir)
return 0 # success
def _get_models(par, data) -> int:
global all_meshs
par.models = lambda: None
par.models.n_item = len(data)
if par.models.n_item == 0:
return 0 # no models
# загрузим объекты
par.models.names = [] # obj_names
par.models.filenames = [] # obj_filenames
i = 1
for f in data:
nam = f
par.models.names.append(nam)
ff = _get_path_model(nam)
par.models.filenames.append(ff)
if not os.path.isfile(ff):
print(f"Error: no such file '{ff}'")
return -1
obj = bproc.loader.load_obj(ff)
all_meshs += obj
obj[0].set_cp("category_id", i) # начиная с 1
i += 1
return par.models.n_item
def _get_scene(par, data) -> int:
# load scene
par.scene = lambda: None
objs = data["objects"]
par.scene.n_obj = len(objs)
if par.scene.n_obj == 0:
return 0 # empty scene
lights = data["lights"]
par.scene.n_light = len(lights)
if par.scene.n_light == 0:
return 0 # no lighting
par.scene.objs = []
par.scene.collision_objects = []
for f in objs:
ff = _get_path_object(f["name"])
if not os.path.isfile(ff):
print(f"Error: no such file '{ff}'")
return -1
obj = bproc.loader.load_obj(ff)
obj[0].set_cp("category_id", 999)
coll = f["collision_shape"]
if len(coll) > 0:
obj[0].enable_rigidbody(False, collision_shape=coll)
par.scene.collision_objects += obj
par.scene.objs += obj
if not par.scene.collision_objects:
print("Collision objects not found in the scene")
return 0
par.scene.obj_data = objs
par.scene.light_data = lights
return par.scene.n_obj
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--cfg", required=True, help="Json-string with dataset parameters")
args = parser.parse_args()
if args.cfg[-5:] == ".json":
if not os.path.isfile(args.cfg):
print(f"Error: no such file '{args.cfg}'")
exit(-1)
with open(args.cfg, "r") as f:
j_data = f.read()
else:
j_data = args.cfg
try:
cfg = json.loads(j_data)
except json.JSONDecodeError as e:
print(f"JSon error: {e}")
exit(-2)
ds_cfg = cfg["formBuilder"]["output"] # dataset config
generation = ds_cfg["generation"]
cam_pos = ds_cfg["camera_position"]
models_randomization = ds_cfg["models_randomization"]
rnd_par = lambda: None
rnd_par.single_object = True
rnd_par.ds_name = cfg["name"]
rnd_par.output_dir = cfg["local_path"]
rnd_par.dataset_objs = cfg["dataSetObjects"]
rnd_par.n_cam_pose = generation["n_cam_pose"]
rnd_par.n_sample_on_pose = generation["n_sample_on_pose"]
rnd_par.n_series = generation["n_series"]
rnd_par.image_format = generation["image_format"]
rnd_par.image_size_wh = generation["image_size_wh"]
rnd_par.center_shell = cam_pos["center_shell"]
rnd_par.radius_range = cam_pos["radius_range"]
rnd_par.elevation_range = cam_pos["elevation_range"]
rnd_par.loc_range_low = models_randomization["loc_range_low"]
rnd_par.loc_range_high = models_randomization["loc_range_high"]
if not os.path.isdir(rnd_par.output_dir):
print(f"Error: invalid path '{rnd_par.output_dir}'")
exit(-3)
bproc.init()
all_meshs = []
ret = _get_models(rnd_par, rnd_par.dataset_objs)
if ret <= 0:
print("Error: no models in config")
exit(-4)
if _get_scene(rnd_par, ds_cfg["scene"]) == 0:
print("Error: empty scene in config")
exit(-5)
exit(render())

View file

@ -0,0 +1,412 @@
import blenderproc as bproc
"""
renderBOPdataset2
Общая задача: common pipeline
Реализуемая функция: создание датасета в формате BOP с заданными параметрами рандомизации
Используется модуль blenderproc
02.05.2024 @shalenikol release 0.1
02.07.2024 @shalenikol release 0.2
28.10.2024 @shalenikol release 0.3
"""
import numpy as np
import argparse
import random
import os
import shutil
import json
from pathlib import Path
import bpy
VHACD_PATH = "blenderproc_resources/vhacd"
DIR_MODELS = "models"
DIR_MESH = "assets/libs/objects/"
FILE_LOG_SCENE = "res.txt"
FILE_RBS_INFO = "rbs_info.json"
FILE_GT_COCO = "scene_gt_coco.json"
EXT_MODELS = ".fbx"
TEXTURE_TMPL = "*.jpg"
Not_Categories_Name = True # наименование категории в COCO-аннотации отсутствует
def _get_list_texture(rel_path: str) -> list:
# local_path/texture/
loc = os.path.dirname(os.path.dirname(rnd_par.output_dir))
path = os.path.join(loc, rel_path)
return list(Path(path).absolute().rglob(TEXTURE_TMPL))
# def _get_path_model(name_model: str) -> str:
# # TODO on name_model find path for mesh (model.fbx)
# # local_path/assets/libs/objects # assets/mesh/
# loc = os.path.dirname(os.path.dirname(rnd_par.output_dir))
# return os.path.join(loc, DIR_MESH + name_model + EXT_MODELS)
def _get_path_object(name_obj: str) -> str:
# TODO on name_obj find path for scene object (object.fbx)
# loc = os.path.dirname(os.path.dirname(rnd_par.output_dir))
# return os.path.join(loc, DIR_MESH + name_obj + EXT_MODELS)
return os.path.join(rnd_par.details_dir, name_obj + EXT_MODELS)
def convert2relative(height, width, bbox):
"""
YOLO format use relative coordinates for annotation
"""
x, y, w, h = bbox
x += w/2
y += h/2
return x/width, y/height, w/width, h/height
def render() -> int:
i = 0
for obj in all_meshs:
# Make the object actively participate in the physics simulation
obj.enable_rigidbody(active=True, collision_shape="COMPOUND")
# Also use convex decomposition as collision shapes
obj.build_convex_decomposition_collision_shape(VHACD_PATH)
i += 1
# print(f"{i} : {obj.get_name()}")
objs = all_meshs + rnd_par.scene.objs
log_txt = os.path.join(os.path.dirname(rnd_par.output_dir), FILE_LOG_SCENE)
with open(log_txt, "w") as fh:
for i,o in enumerate(objs):
loc = o.get_location()
euler = o.get_rotation_euler()
fh.write(f"{i} : {o.get_name()} {loc} {euler} category_id = {o.get_cp('category_id')}\n")
# define a light and set its location and energy level
ls = []
for l in rnd_par.scene.light_data:
light = bproc.types.Light(name=f"l{l['id']}")
light.set_type(l["type"])
light.set_location(l["loc_xyz"]) #[5, -5, 5])
light.set_rotation_euler(l["rot_euler"]) #[-0.063, 0.6177, -0.1985])
ls += [light]
# define the camera intrinsics
bproc.camera.set_intrinsics_from_blender_params(1,
rnd_par.image_size_wh[0],
rnd_par.image_size_wh[1],
lens_unit="FOV")
# add segmentation masks (per class and per instance)
bproc.renderer.enable_segmentation_output(map_by=["category_id", "instance", "name"])
# activate depth rendering
bproc.renderer.enable_depth_output(activate_antialiasing=False)
# res_dir = os.path.join(rnd_par.output_dir, rnd_par.ds_name)
res_dir = rnd_par.output_dir
if os.path.isdir(res_dir):
shutil.rmtree(res_dir)
# Цикл рендеринга
# Do multiple times: Position the shapenet objects using the physics simulator and render X images with random camera poses
for r in range(rnd_par.n_series):
print(f"********** Series : {r+1}")
is_texture = True if "texture_path" in rnd_par.models_randomization else False
if is_texture:
val = rnd_par.models_randomization["texture_path"]
l_texture = _get_list_texture(val)
image = bpy.data.images.load(filepath=str(l_texture[r % len(l_texture)]))
# один случайный объект в кадре / все заданные объекты
random_obj = random.choice(range(rnd_par.models.n_item))
meshs = []
for i,o in enumerate(all_meshs): # активные модели
if rnd_par.single_object and i != random_obj:
continue
meshs += [o]
if is_texture:
mats = o.get_materials()
for mat in mats:
# image = bpy.data.images.load(filepath=str(random.choice(l_texture)))
mat.set_principled_shader_value("Base Color", image)
for i,o in enumerate(rnd_par.scene.objs): # объекты сцены
rnd_mat = rnd_par.scene.obj_data[i]["material_randomization"]
mats = o.get_materials() #[0]
for mat in mats:
val = rnd_mat["specular"]
mat.set_principled_shader_value("Specular", random.uniform(val[0], val[1]))
val = rnd_mat["roughness"]
mat.set_principled_shader_value("Roughness", random.uniform(val[0], val[1]))
val = rnd_mat["metallic"]
mat.set_principled_shader_value("Metallic", random.uniform(val[0], val[1]))
if "texture_path" in rnd_mat: # путь к текстурам (*.jpg)
val = rnd_mat["texture_path"]
val = _get_list_texture(val)
image = bpy.data.images.load(filepath=str(random.choice(val)))
mat.set_principled_shader_value("Base Color", image)
else:
val = rnd_mat["base_color"]
mat.set_principled_shader_value("Base Color", np.random.uniform(val[0], val[1]))
# mat.set_principled_shader_value("Base Color", image)
# Randomly set the color and energy
for i,l in enumerate(ls):
current = rnd_par.scene.light_data[i]
l.set_color(np.random.uniform(current["color_range_low"], current["color_range_high"]))
energy = current["energy_range"]
l.set_energy(random.uniform(energy[0], energy[1]))
# Clear all key frames from the previous run
bproc.utility.reset_keyframes()
# Define a function that samples 6-DoF poses
def sample_pose(obj: bproc.types.MeshObject):
obj.set_location(np.random.uniform(rnd_par.loc_range_low, rnd_par.loc_range_high)) #[-1, -1, 0], [1, 1, 2]))
obj.set_rotation_euler(bproc.sampler.uniformSO3())
# Sample the poses of all shapenet objects above the ground without any collisions in-between
bproc.object.sample_poses(meshs,
objects_to_check_collisions = meshs + rnd_par.scene.collision_objects,
sample_pose_func = sample_pose)
# Run the simulation and fix the poses of the shapenet objects at the end
bproc.object.simulate_physics_and_fix_final_poses(min_simulation_time=4, max_simulation_time=20, check_object_interval=1)
# Find point of interest, all cam poses should look towards it
poi = bproc.object.compute_poi(meshs)
coord_max = [0.1, 0.1, 0.1]
coord_min = [0., 0., 0.]
with open(log_txt, "a") as fh:
fh.write("*****************\n")
fh.write(f"{r}) poi = {poi}\n")
i = 0
for o in meshs:
i += 1
loc = o.get_location()
euler = o.get_rotation_euler()
fh.write(f" {i} : {o.get_name()} {loc} {euler}\n")
for j in range(3):
if loc[j] < coord_min[j]:
coord_min[j] = loc[j]
if loc[j] > coord_max[j]:
coord_max[j] = loc[j]
# Sample up to X camera poses
#an = np.random.uniform(0.78, 1.2) #1. #0.35
for i in range(rnd_par.n_cam_pose):
# Sample location
location = bproc.sampler.shell(center=rnd_par.center_shell,
radius_min=rnd_par.radius_range[0],
radius_max=rnd_par.radius_range[1],
elevation_min=rnd_par.elevation_range[0],
elevation_max=rnd_par.elevation_range[1])
# координата, по которой будем сэмплировать положение камеры
j = random.randint(0, 2)
# разовый сдвиг по случайной координате
d = (coord_max[j] - coord_min[j]) / rnd_par.n_sample_on_pose
if location[j] < 0:
d = -d
for _ in range(rnd_par.n_sample_on_pose):
# Compute rotation based on vector going from location towards poi
rotation_matrix = bproc.camera.rotation_from_forward_vec(poi - location, inplane_rot=np.random.uniform(-0.7854, 0.7854))
# Add homog cam pose based on location an rotation
cam2world_matrix = bproc.math.build_transformation_mat(location, rotation_matrix)
bproc.camera.add_camera_pose(cam2world_matrix)
location[j] -= d
# render the whole pipeline
data = bproc.renderer.render()
# Write data to bop format
bproc.writer.write_bop(res_dir,
target_objects = all_meshs, # Optional[List[MeshObject]] = None
depths = data["depth"],
depth_scale = 1.0,
colors = data["colors"],
color_file_format=rnd_par.image_format,
append_to_existing_output = (r>0),
save_world2cam = False) # world coords are arbitrary in most real BOP datasets
# dataset="robo_ds",
models_dir = os.path.join(res_dir, DIR_MODELS)
os.mkdir(models_dir)
data = []
for i,objn in enumerate(rnd_par.models.names):
rec = {}
rec["id"] = i+1
rec["name"] = objn
rec["model"] = os.path.join(DIR_MODELS, os.path.split(rnd_par.models.filenames[i])[1]) # путь относительный
t = [obj.get_bound_box(local_coords=True).tolist() for obj in all_meshs if obj.get_name() == objn]
rec["cuboid"] = t[0]
data.append(rec)
shutil.copy2(rnd_par.models.filenames[i], models_dir)
f = (os.path.splitext(rnd_par.models.filenames[i]))[0] + ".mtl" # файл материала
if os.path.isfile(f):
shutil.copy2(f, models_dir)
with open(os.path.join(res_dir, FILE_RBS_INFO), "w") as fh:
json.dump(data, fh, indent=2)
"""
!!! categories -> name берётся из category_id !!!
см.ниже
blenderproc.python.writer : BopWriterUtility.py
class _BopWriterUtility
def calc_gt_coco
...
CATEGORIES = [{'id': obj.get_cp('category_id'), 'name': str(obj.get_cp('category_id')), 'supercategory':
dataset_name} for obj in dataset_objects]
поэтому заменим наименование категории в аннотации
"""
def change_categories_name(dir: str):
coco_file = os.path.join(dir,FILE_GT_COCO)
with open(coco_file, "r") as fh:
data = json.load(fh)
cats = data["categories"]
for i,cat in enumerate(cats):
cat["name"] = rnd_par.models.names[i] #obj_names[i]
with open(coco_file, "w") as fh:
json.dump(data, fh, indent=1)
def explore(path: str):
if not os.path.isdir(path):
return
folders = [
os.path.join(path, o)
for o in os.listdir(path)
if os.path.isdir(os.path.join(path, o))
]
for path_entry in folders:
print(path_entry)
if os.path.isfile(os.path.join(path_entry,FILE_GT_COCO)):
change_categories_name(path_entry)
else:
explore(path_entry)
if Not_Categories_Name:
explore(res_dir)
return 0 # success
def _get_models(par, data) -> int:
global all_meshs
par.models = lambda: None
par.models.n_item = len(data)
if par.models.n_item == 0:
return 0 # no models
# загрузим объекты
par.models.names = [] # obj_names
par.models.filenames = [] # obj_filenames
i = 1
for f in data:
nam = f["name"]
par.models.names.append(nam)
ff = f["fbx"] # _get_path_model(nam)
par.models.filenames.append(ff)
if not os.path.isfile(ff):
print(f"Error: no such file '{ff}'")
return -1
# !!! dir with meshs
par.details_dir = os.path.split(ff)[0]
obj = bproc.loader.load_obj(ff)
all_meshs += obj
obj[0].set_cp("category_id", i) # начиная с 1
i += 1
return par.models.n_item
def _get_scene(par, data) -> int:
# load scene
par.scene = lambda: None
objs = data["objects"]
par.scene.n_obj = len(objs)
if par.scene.n_obj == 0:
return 0 # empty scene
lights = data["lights"]
par.scene.n_light = len(lights)
if par.scene.n_light == 0:
return 0 # no lighting
if len(rnd_par.details_dir) == 0:
return 0 # no path to details
par.scene.objs = []
par.scene.collision_objects = []
for f in objs:
ff = _get_path_object(f["name"])
if not os.path.isfile(ff):
print(f"Error: no such file '{ff}'")
return -1
obj = bproc.loader.load_obj(ff)
obj[0].set_cp("category_id", 999)
coll = f["collision_shape"]
if len(coll) > 0:
obj[0].enable_rigidbody(False, collision_shape=coll)
par.scene.collision_objects += obj
par.scene.objs += obj
if not par.scene.collision_objects:
print("Collision objects not found in the scene")
return 0
par.scene.obj_data = objs
par.scene.light_data = lights
return par.scene.n_obj
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--form", required=True, help="Json-string with dataset parameters")
parser.add_argument("--path", required=True, help="Output path")
args = parser.parse_args()
if args.form[-5:] == ".json":
if not os.path.isfile(args.form):
print(f"Error: no such file '{args.form}'")
exit(-1)
with open(args.form, "r") as f:
j_data = f.read()
else:
j_data = args.form
try:
cfg = json.loads(j_data)
except json.JSONDecodeError as e:
print(f"JSon error: {e}")
exit(-2)
# output_dir = args.path
ds_cfg = cfg["output"] # dataset config
generation = ds_cfg["generation"]
cam_pos = ds_cfg["camera_position"]
models_randomization = ds_cfg["models_randomization"]
rnd_par = lambda: None
rnd_par.output_dir = args.path # cfg["local_path"]
if not os.path.isdir(rnd_par.output_dir):
print(f"Error: invalid path '{rnd_par.output_dir}'")
exit(-3)
rnd_par.single_object = False # True
rnd_par.details_dir = ""
# rnd_par.ds_name = os.path.split(rnd_par.output_dir)[1] # cfg["name"]
rnd_par.dataset_objs = ds_cfg["datasetObjects"]["details"] # ["knight"]
rnd_par.n_cam_pose = generation["n_cam_pose"]
rnd_par.n_sample_on_pose = generation["n_sample_on_pose"]
rnd_par.n_series = generation["n_series"]
rnd_par.image_format = generation["image_format"]
rnd_par.image_size_wh = generation["image_size_wh"]
rnd_par.center_shell = cam_pos["center_shell"]
rnd_par.radius_range = cam_pos["radius_range"]
rnd_par.elevation_range = cam_pos["elevation_range"]
rnd_par.models_randomization = models_randomization
rnd_par.loc_range_low = models_randomization["loc_range_low"]
rnd_par.loc_range_high = models_randomization["loc_range_high"]
bproc.init()
all_meshs = []
if _get_models(rnd_par, rnd_par.dataset_objs) <= 0:
print("Error: no models in config")
exit(-4)
if _get_scene(rnd_par, ds_cfg["scene"]) <= 0:
print("Error: empty scene in config")
exit(-5)
exit(render())

View file

@ -0,0 +1,17 @@
# Фреймворк: отладка.
После того как был отлажен механизм обнаружения объектов на основе метода YoloV4 и в результате его испытаний, нами было принято решение имплементировать более совершенный и современный метод Yolo 8-ой версии ([YoloV8](https://github.com/ultralytics/ultralytics)).
На основе предыдущего опыта был взят за основу lifecycle-узел ROS2, который управлялся бы исполнением действий деревьев поведения (Behavior Tree). В ходе работы над этим модулем и дальнейшей отладки выявились преимущества метода YoloV8 в сравнении с YoloV4: файл весов модели 8-й версии по размеру составил около 6 МБ, в 4-й - около 244 МБ. Также на реальных изображениях распечатанных нами моделей улучшилась их точность распознавания (рис.1). В качестве моделей мы использовали набор шахматных фигур, распечатанных на 3D-принтере.
![pic1](img/P_curve.png)
Рис.1
Когда отлаживался модуль распознавания объектов (Object Detection), выявилась сложность проектирования и отладки этого навыка. Необходимо было кроме основной логики ROS-узла создавать и отлаживать передачу параметров в дереве поведения. И была предложена схема обобщения интерфейса для любых навыков.
![Схема1](img/scheme1.jpg)
В ней предположено использовать отдельный интерфейсный узел (Interface Node), который будет реализовывать взаимодействие системы исполнения дерева поведения (BT Engine Node) c библиотекой навыков. А сами навыки предложено упаковывать в отдельные ROS-пакеты с json-файлом описания, который позволит декларативно описывать элементы интерфейса, а также схему запуска навыков.
Такой интерфейсный узел был реализован и позволил упростить как составление и выполнение дерева поведения, так и облегчить создание самой библиотеки навыков.
Первым навыком, который использовал интерфейсный узел, стала имплементация метода оценки 6D-позы объекта [DOPE](https://github.com/NVlabs/Deep_Object_Pose).

BIN
docs/img/P_curve.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 KiB

BIN
docs/img/qXX7sBMbsvA.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

BIN
docs/img/scheme1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

File diff suppressed because one or more lines are too long

123
docs/randomization.md Normal file
View file

@ -0,0 +1,123 @@
# Рандомизация
### При обучении робота (Илья Ураев)
- Гравитация
- Положение камеры
- Конфигурацию робота (положение джоинтов так называется)
- Положение объекта или точки куда надо дотянутся
- Текстуру поверхности размещения
- Ну и я думаю чтобы с robot_builder смотрелось, то можно рандомизировать число степеней свободы робота.
- Можно рандомизировать позиции спавна робота
### При создании датасета (Александр Шушпанов)
- Зона локации (спавна) активных объектов
- Позиция камеры: радиус сферы размещения и наклон, центр этой сферы
- Источники света: количество, тип, локализация в пространстве, цветность, сила света
- Свойства материала по отражению света: зеркальность, шероховатость, металлизация, цвет
Гиперпараметры.
- количество серий (спавна активных объектов)
- количество позиций камеры на одну серию
- количество сдвигов камеры на 1 позу
### Общий список параметров рандомизации
- Положение искомого(активного) объекта(-ов) в рабочей зоне
- Позиция камеры: радиус сферы размещения и наклон, центр этой сферы
- Текстуры повехностей объектов и/или свойства материала по отражению света: зеркальность, шероховатость, металлизация, цвет
- Источники света: количество, тип, локализация в пространстве, цветность, сила света
- Конфигурация робота (положение джоинтов), число степеней свободы и его начальное расположение
- Гравитация
## Web-сервис для генерации датасетов
Для реализации пользовательского интерфейса web-сервиса нами была разработана схема описания параметров рандомизации. Её использование позволяет изменять конфигурацию параметров в зависимости от задачи. Предполагается в дальнейшем использовать модуль ввода параметров в том числе и в задачах обучения с подкреплением.
Пример такой схемы:
```
ENUM T = "ObjectDetection","PoseEstimation"
ENUM C = "","BOX","SPHERE","CAPSULE","CYLINDER","CONE","CONVEX_HULL","MESH","COMPOUND"
ENUM L = "POINT","SUN"
ENUM F = "JPEG","PNG"
MODELS = {
"id": ${ID:number:1},
"name": ${NAME:string:""},
"model": ${MODEL:string:"models/1.fbx"}
}
OBJECTS_SCENE = {
"name": ${NAME:string:""},
"collision_shape": ${enum:C:"BOX"},
"loc_xyz": [${LOC_XYZ_1:number:0}, ${LOC_XYZ_2:number:0}, ${LOC_XYZ_3:number:0}],
"rot_euler": [${ROT_EULER_1:number:0}, ${ROT_EULER_2:number:0}, ${ROT_EULER_3:number:0}],
"material_randomization": {
"specular": [${SPECULAR_1:number:0}, ${SPECULAR_2:number:1}],
"roughness": [${ROUGHNESS_1:number:0}, ${ROUGHNESS_2:number:1}],
"metallic": [${METALLIC_1:number:0}, ${METALLIC_2:number:1}],
"base_color": [
[
${BASE_COLOR_1:number:0},
${BASE_COLOR_2:number:0},
${BASE_COLOR_3:number:0},
${BASE_COLOR_4:number:1}
],
[
${BASE_COLOR_5:number:1},
${BASE_COLOR_6:number:1},
${BASE_COLOR_7:number:1},
${BASE_COLOR_8:number:1}
]
]
}
}
LIGHTS = {
"id": ${ID:number:1},
"type": ${enum:L:"POINT"},
"loc_xyz": [${LOC_XYZ_1:number:5}, ${LOC_XYZ_2:number:5}, ${LOC_XYZ_3:number:5}],
"rot_euler": [${ROT_EULER_1:number:-0.06}, ${ROT_EULER_2:number:0.61}, ${ROT_EULER_3:number:-0.19}],
"color_range_low": [${COLOR_RANGE_LOW_1:number:0.5}, ${COLOR_RANGE_LOW_2:number:0.5}, ${COLOR_RANGE_LOW_3:number:0.5}],
"color_range_high":[${COLOR_RANGE_HIGH_1:number:1}, ${COLOR_RANGE_HIGH_2:number:1}, ${COLOR_RANGE_HIGH_3:number:1}],
"energy_range":[${ENERGY_RANGE_1:number:400},${ENERGY_RANGE_2:number:900}]
}
{
"typedataset": ${enum:T:"ObjectDetection"},
"dataset_path": ${DATASET_PATH:string},
"models":${ARRAY:MODELS:[]},
"models_randomization":{
"loc_range_low": [${LOC_RANGE_LOW_1:number:-1}, ${LOC_RANGE_LOW_2:number:-1}, ${LOC_RANGE_LOW_3:number:0}],
"loc_range_high": [${LOC_RANGE_HIGH_1:number:1}, ${LOC_RANGE_HIGH_2:number:1}, ${LOC_RANGE_HIGH_3:number:2}]
},
"scene":{
"objects": ${ARRAY:OBJECTS_SCENE:[]},
"lights": ${ARRAY:LIGHTS:[]},
},
"camera_position":{
"center_shell": [${CENTER_SHELL_1:number:0}, ${CENTER_SHELL_2:number:0}, ${CENTER_SHELL_3:number:0}],
"radius_range": [${RADIUS_RANGE_1:number:0.4}, ${RADIUS_RANGE_2:number:1.4}],
"elevation_range": [${ELEVATION_RANGE_1:number:10}, ${ELEVATION_RANGE_2:number:90}]
},
"generation":{
"n_cam_pose": ${N_CAM_POSE:number:5},
"n_sample_on_pose": ${N_SAMPLE_ON_POSE:number:3},
"n_series": ${N_SERIES:number:100},
"image_format": ${enum:F:"jpg"},
"image_size_wh": [${IMAGE_SIZE_WH_1:number:640}, ${IMAGE_SIZE_WH_2:number:480}]
}
}
```
Вначале описываются перечисления - ENUM, которым присваиваются имена и список возможных значений. Затем описываются составные именованные объекты, а затем основной блок описания параметров. Этот блок представляет из себя JSON-словарь параметров, который будет подготовлен на выходе модуля ввода параметров. Каждый ключ этого словаря дополняется мини-схемой описания вводимого значения.
Формат:
```
${<имя_переменной>:<тип>:<значение_по_умолчанию>}
```
либо массив объектов
```
${ARRAY:<имя_объекта>:[]}
```
В нашем алгоритме формирования датасета для задач компьютерного зрения (ObjectDetection, PoseEstimation) выбран формат [BOP: Benchmark for 6D Object Pose Estimation](https://bop.felk.cvut.cz/home/), в его [BOP-Classic](https://bop.felk.cvut.cz/datasets/) версии.
Он содержит в своей аннотации все необходимые данные (ground truth) для обучения нейросетевых моделей поиску объектов на изображении, а также распознавания поз искомых объектов.

435
docs/scene_generator.md Normal file
View file

@ -0,0 +1,435 @@
## Мета-модель фреймворка
## Соответствие Digital Twin Definition Language и мета-модели Robossembler
Слои абстракции
1. DTDL - BASETYPES, COMPLEXTYPES (Array, Map, ...), DT_TYPES
2. ROBOSSEMBLER_CONTEXT (Represents)
3. USE_CASE_CONTEXT (Entities)
4. USE_CASE_INSTANCE (Product)
## Сравнение мета-моделей Digital Twin Definition Language и ROS 2
| Сущность | DTDL | ROS | Robonomics |
| - | - | - | - |
| Описывает всё содержимое двойника, включая ниже приведённые сущности | **Interface** | **Interface Spec** | - |
| Передаваемые данные и их тип | **Telemetry** | **Topic** | **Datalog Hash** |
| Свойство, описывающее какое-то состояние двойника, может быть read-only или read/write; также описывает синхронизацию состояния между компонентами (например, показание датчика записано в облако) | **Property** | **Parameters** | **Launch Param** |
| Функция или операция, которая может быть осуществлена над двойником (например, `reboot`) | **Command** | **Service** / **Action** | **Launch** |
| Структура из примитивных типов (Array, Enum, Map, Object) данных для сериализации (в JSON, Avro, Protobuf) | **Schema** | **IDL** | - |
| Часть интерфейса (отношение part-of с каким-то другим двойником) | **Component** | - | - |
| Связь с другим цифровым двойником. Связи могут представлять различные семантические значения. Например, `contains` ("этаж содержит комнату"), `cools` ("hvac cools room"), `isBilledTo` ("счёт выставляется пользователю") | **Relationship** | - | - |
```json
# базовые типы значений (из JSON Schema)
"string","number", "boolean", "array", "object";
{
"type": "object",
"properties": {
"REPRESENT": {
"type": {
"enum": [ "OBJECT_LINK", "KEY", "FILEPATH", "VALUE", "TREE", "ARRAY", "SEQUENCE" ]
}
}
}
}
# представления
ENUM REPRESENT = "OBJECT_LINK", # строка-ссылка на объект (ENTITY)
"KEY", # уникальный ключ в виде строки (используется как идентификатор записи)
"FILEPATH", # строка - путь к файлу
"VALUE", # непосредственное значение
"TREE", # представление в виде дерева
"ARRAY", # массив значений
"SEQUENCE"; # массив ссылок на объект определённого типа
# сущности
ENUM ENTITY = "MESH", "PART", "ASSET", "BTREE", "BTACTION", "SKILL", "DATASET", "INTERFACE", "WEIGHTS", "DEVICE";
ENUM DEVICE = "ROBOT", "SENSOR";
type SCENE = {
"objects": [ { ref: "1", type: "PART" }; { ref: "2", type: "PART" }; ]
};
type PARAM = {
"sid": \${KEY:string:""},
"name": \${NAME:string:""},
"represent": \${REPRESENT:Enum<REPRESENT>:"VALUE"},
"link": \${LINK:Enum<LINK>:"topic"}
};
### тип поверхность детали
type MESH/SURFACE = {
"sid": \${KEY:string:""};
"path": { "stl": "PATH/*.stl", "brep": "PATH/*.brep", "fbx": "PATH/*.fbx", }
};
type PART = {
"sid": \${NAME:string:""},
"name": \${NAME:string:""},
"pose6d": { "loc_xyz": \${XYZ:Array<number>3:[0.0,0.0,0.0] }, "rot_xyzw": \${XYZW:Array<number>4:[0.0,0.0,0.0,1.0]} },
"attributes": [
"Robossembler_NonSolid": True
],
"surface": { "stl": "PATH/*.stl", "brep": "PATH/*.brep", },
"material": "/path/to/robossembler/materials/mmm.FCMat",
"unit_scale": \${UNIT_SCALE:number:1.0},
"dimensions": \${Array<number>3:[0.0,0.0,0.0]},
"assets": { "fbx": "PATH/*.fbx", "blend": "PATH/*.blend", }
};
type DATASET = {
"sid": \${NAME:string:""},
"name": \${NAME:string:""},
"objects": \${SEQUENCE:PART},
"environment": \${SEQUENCE:PART},
"randomisation": \${FILE}
};
type WEIGHTS = {
"sid": \${NAME:string:""},
"name": \${NAME:string:""},
"file": \${FILE:string:"*.pth"},
"epoch": \${EPOCH:number:""},
"dataset": \${OBJECT_LINK:DATASET}
};
type TOPIC = {
"sid": ...,
"name": "topic_name",
"msg": "sensor_msgs/Image",
};
DEVICE = {
"sid": 1235,
"name": "dev",
"topics": \${SEQUENCE:TOPIC},
}
// DEVICE -> TOPIC LIST -> {DEVICE: {TOPIC LIST}}
type POSE_ESTIMATION = {
"object_name": \${OBJECT_LINK:PART},
"weights": \${OBJECT_LINK:WEIGHTS},
"topic_name": \${OBJECT_LINK:TOPIC}
};
type SKILL = {
"sid": \${NAME:string:""},
"name": \${NAME:string:""},
"interface": \${INTERFACE}
};
command_LifeCycle = "run", "stop"
type ASSEMBLY_SEQUENCE = \{SEQUENCE:TASK};
# task1 = { source_state = []; target_state = [ p1 ] }
# task2 = { source_state = [ p1 ]; target_state = [ p1 p2 ] }
# task3 = { source_state = [ p1 p2 ]; target_state = [ p1 p2 p3 ] }
task = { source_state = \${TREE:PART}; target_state = \${TREE:PART} }
type TASK = {
"sid": ...
"action": \${BT_TREE}
"source_state": \${TREE:PART} // PART
"target_state": \${TREE:PART} // PRODUCT
};
type DOMAIN = {
"objects": \{SEQUENCE:PART}
"predicates": \{OBJECT_LINK:CONDITION}
"actions": \${OBJECT_LINK:BT_ACTION}
};
type BTREE = {
"sid": \${NAME:string:""},
"name": \${NAME:string:""},
};
```
## Device Package
### Camera
```json
{
"DevicePackage": { "name": "Robossembler", "version": "1.0", "format": "1" },
"Module": { "name": "RealSense Dxx", "description": "ROS Wrapper for Intel(R) RealSense(TM) Cameras" },
"Launch": { "package": "realsense2_camera", "executable": "rs_launch.py" },
"DTwin": [
{ "interface": {
"input": [
{ "name": "camera_namespace", "type": "STRING" }, // -- /robot_drawer/455_1/camera_info
{ "name": "camera_name", "type": "STRING" },
{ "name": "serial_port", "type": "STRING" },
],
"output": [
{ "name": "camera_info", "type": "TOPIC", "topic_name": "/${camera_namespace}/${camera_name}/camera_info" },
{ "name": "pose", "type": "TOPIC", "msg": "Pose" }
]
},
}
],
"Settings": [
{ "name": "camera_config", "description": "Camera Config", "type":"file", "defaultValue": "{ rgb_camera.profile: 1280x720x15 }" }
]
}
```
### Robot RBS
```json
{
"DevicePackage": { "name": "Robossembler", "version": "1.0", "format": "1" },
"Module": { "name": "RBS", "description": "Main Robot" },
"Launch": { "package": "rbs_bringup", "executable": "single_robot.launch.py" },
"DTwin": [
{ "interface": {
"input": [
{ "name": "robot_namespace", "type": "STRING", "defaultValue": "rbs_arm" },
{ "name": "dof", "type": "INT", "defaultValue": 6 }
]
}
}
],
"Settings": [
{ "name": "robot_type", "description": "Type of robot by name", "defaultValue": "rbs_arm" }
]
}
```
### Robot UR5
```json
{
"DevicePackage": { "name": "Robossembler", "version": "1.0", "format": "1" },
"Module": { "name": "UR", "description": "..." },
"Launch": { "package": "ur_package", "executable": "ur5_single_arm.py" },
"DTwin": [
{ "interface": {
"input": [
{ "robot_namespace": "robot1" },
],
},
}
],
"Settings": [
{ "name": "", "description": "Config", "type":"file", "defaultValue": "{}" }
]
}
```
```json
{
"SkillPackage": { "name": "Robossembler", "version": "1.0", "format": "1" },
"Module": { "name": "PoseEstimation", "description": "Pose Estimation skill with DOPE" },
"Launch": { "package": "rbs_perception", "executable": "pe_dope_lc.py", "name": "lc_dope" },
"BTAction": [
{ "name": "peConfigure",
"type": "run",
"interface": {
"input": [
{ "name": "image_raw", "type": "TOPIC", "msg": "Image" },
{ "name": "camera_info", "type": "TOPIC", "msg": "CameraInfo" },
{ "name": "object_name", "type": "PART", "msgs": "Part" }, // string
{ "name": "weights", "type": "WEIGHTS", "msgs": "" },
],
"output": [
{ "name": "pose_estimation", "type": "TOPIC" },
]
},
},
{ "name": "peStop", "type": "stop", "interface": { "input": [], "output": [] } }
],
"Settings": [
{ "name": "publishDelay", "description": "Publish Delay", "type":"float", "defaultValue": 0.5 },
{ "name": "tf2_send_pose", "description": "Transform Pose", "type":"int", "defaultValue": 1 },
{ "name": "mesh_scale", "description": "Part Mesh Scale", "type":"float", "defaultValue": 0.001 }
]
}
```
## Атомарные навыки
```xml
<TreeNodesModel>
<SubTree ID="GraspObject">
<input_port default="false" name="__shared_blackboard"></input_port>
<input_port name="pose_vec"/>
<input_port name="robot_name"/>
</SubTree>
<Action ID="GripperAction">
<input_port name="action">Open or close</input_port>
<input_port name="gripper_name"/>
</Action>
<SubTree ID="InspectWorkspace">
<input_port default="true" name="__shared_blackboard">
<input_port name="pose_vec"/>
<input_port name="robot_name"/>
</SubTree>
<Condition ID="IsObjectInWorkspace">
<input_port name="topic_name"/>
</Condition>
<Condition ID="IsObjectVisible"/>
<Action ID="MoveToPose">
<input_port name="cancel_timeout"/>
<input_port name="pose"/>
<input_port name="robot_name"/>
<input_port name="server_name"/>
<input_port name="server_timeout"/>
</Action>
<Action ID="MoveToPoseArray">
<input_port name="cancel_timeout"/>
<input_port name="pose_vec_in"/>
<output_port name="pose_vec_out"/>
<input_port name="robot_name"/>
<input_port name="server_name"/>
<input_port name="server_timeout"/>
</Action>
<SubTree ID="PlaceObject">
<input_port default="true" name="__shared_blackboard"></input_port>
<input_port name="pose_vec"/>
<input_port name="robot_name"/>
</SubTree>
<Action ID="PoseEstimationCleanup"/>
<Action ID="PoseEstimationConfigure">
<input_port name="object_name"/>
<output_port name="topic_name"/>
<input_port name="weight_file"/>
</Action>
<Action ID="RbsBtAction">
<input_port name="command"/>
<input_port name="do"/>
<input_port name="server_name"/>
<input_port name="server_timeout"/>
</Action>
</TreeNodesModel>
```
## Пример интерфейса в DTDL
```json
{
"@context": "...;3",
"@id": "robossember_assembly;1",
"@type": "Interface",
"displayName": "Bolt",
"contents": [
{
"@type": "Property",
"name": "Label",
"schema": "string"
},
{
"@type": "Property",
"name": "mesh",
"writable": true,
"schema": "string"
},
{
"@type": "Telemetry",
"name": "Pose6D",
"writable": true,
"schema": {
"@type": "Object",
"fields": [
{
"name": "x",
"schema": "double"
},
{
"name": "y",
"schema": "double"
},
{
"name": "z",
"schema": "double"
}
]
}
},
{
"@type": "Relationship",
"name": "contains",
"target": "dtmi:com:robossember_assembly:Bolt;1"
},
{
"@type": "Component",
"name": "frontCamera",
"schema": "dtmi:com:example:Camera;3"
},
]
}
```
## Пример файла описания сцены из Blender
TODO: рассписать потребность в основных элементах, что и для чего
```json
{
"assets": [
{
"name": "robo-arm",
"id": "629b29d7-fe15-428b-9014-6c3dde045af8",
"model_path": "../model.urdf"
}
],
"instances": [
// измненная URDF модель
{
"id": "0e29084f-1190-45d0-bd59-8f4ce2591gb1",
"name": "robo-arm-1",
//assetId указывает на родительский ассет
"assetId": "629b29d7-fe15-428b-9014-6c3dde045af8",
"pose": {
"x": 12.0,
"y": 1.0,
"z": 4.0,
"roll": 1.0,
"pitch": 4.0,
"yaw": 5.0
},
//если изменено внутренее состояние URDF модели
"tags": [
"<joint name=\"robotiq_85_right_finger_joint\" type=\"fixed\"><parent link=\"robotiq_85_right_knuckle_link\"/><child link=\"robotiq_85_right_finger_link\"/><origin rpy=\"0 0 0\" xyz=\"-0.03152616 0.0 -0.00376347\"/></joint>"
]
},
{
"id": "0e27984f-8890-4d90-bd59-8f4ce29920f9",
"name": "robo-arm-2",
//assetId указывает на родительский ассет
"assetId": "629b29d7-fe15-428b-9014-6c3dde045af8",
//если дефолтные позиции модели
"pose": null,
//если не изменено внутренее состояние URDF модели
"tags": null
},
{
"type": "LIGHT",
"light_type": "SPOT",
"power": 10.0,
"spot_angle": 45.0,
"name": null,
"pose": {
"x": 0.0,
"y": 0.0,
"z": 0.0,
"roll": 0.0,
"pitch": 0.0,
"yaw": 0.0
}
}
]
}
```

View file

@ -0,0 +1,60 @@
# Модуль технологической подготовки
На вход: - step-модель описываемого оборудования.
1. Описание имеющихся сущностей:
- Мы можем создать описание действий со станком и его состояниями для связи с окружающим миром нужен некий обобщенный объект
его свойством будет возможность воздействовать на состояния, но сам он будет любым. Думаю, нужно описать сами рычаги, а не того, кто будет их нажимать.
- Описать объекты можно созданием зон вокруг них и/или созданием призрака геометрии оборудования (может быть сложно и избыточно).
- Для этого возможно создать параллелепипед/цилиндр, сопоставимый по габаритам с рассматриваемой зоной. С помощью инструментов верстака Part создается объект, имеющий желаемое название (Станок, рабочая зона, etc). Эта зона с помощью отношений parent привязана к геометрии станка.
2. Описание действий
- Создается папка actions, в которую сохраняются создаваемые действия
- Интерфейс создания действий аналогичен интерфейсу задания других сущностей. Через него мы задаем ссылки на существующие действия и элементы и указываем их тип: триггеры, рабочие органы, конечные состояния, начальные состояния. Указываем их статус (выбор "да/нет")
- Указываем ссылки на привязываемую к этим действиям геометрию. (катушки, статоры, расходники и тд) Для этого их геометрия должна быть импортирована в модель. Ссылка будет указывать на конкретный импортированный файл. Если существует идентификатор детали, можно ссылаться на него.
3. Задание состояний и переменных
- Переменные задаются средствами параметризации FreeCAD, инструменты для этого можно взять из ASM4, используя функционал переменных (Variables) и панели конфигураций.
- Для состояний переменных аналогично создается (в ASM4 уже имеется при создании модели) отдельная директория.
4. Результатом описания будет модель, имеющая дерево объектов, в свойствах которых мы имеем всю необходимую информацию. Геометрические характеристики мы сохраняем как json и отправляем в среды, работающие с геометрией и физикой. Действия и геометрия подставляются в шаблон pddl в соответствующие абзацы.
## Пример описания объекта
Action - "Заправка 3д-принтера пластиком"
- |- Объекты:
- - 3d-принтер [printer_id] /прямоугольная зона по габаритам принтера. Зона привязана к геометрии оборудования
- Workzone [printer_id] / прямоугольная зона. Указание на объект workzone, который содержит в себе габариты и позиционирование рабочей зоны относительно 3d-принтера.
- Wirenest [printer_id] /цилиндрическая зона. Указание на объект wirenest (цилиндр), хранящий информацию об ориентации и положении гнезда для катушки с пластиком
- Filament [filament_id] /катушка с пластиком требуемой модели, формы и габаритов.
- Observer [observer_id] / некая сущность(манипулятор, человек, камера), к которой обращается станок, чтобы с ним провели внешние манипуляции
- |- Длительность действия, с
- |- Стартовые состояния:
- Пластика достаточно (нет)
- Наблюдатель свободен (да)
- |- Во время действия:
- Наблюдатель[observer_id] свободен (нет)
- Катушка пластика установлена (нет)
- |- После окончания:
- Катушка пластика установлена (да)
- Наблюдатель [observer_id] свободен (да)
- Пластика достаточно (да)
--В раздел Variables мы можем (должны ли?) полуавтоматически/автоматически указать подобные состояния, привязанные к значениям да/нет.-- (Указывать стартовые значения по умолчанию?)
Указанные отдельно состояния пригодились бы, чтобы ссылаться на них при задавании действий, поскольку действия сообщаются между собой не напрямую, а через выполнение определенного набора состояний.
Пример размеченной модели:
![Разметка](img/qXX7sBMbsvA.jpg)

1
freecad_workbench Submodule

@ -0,0 +1 @@
Subproject commit 08db6583ce94895103c94b1b70b4846ef581e624

1
rcg_pipeline Submodule

@ -0,0 +1 @@
Subproject commit 605d45e85ae0ca1076553f0e496442b0f358700c

1
simulation/asp/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
out

View file

@ -0,0 +1,37 @@
import os
import json
import typing
class FS:
def readJSON(path: str):
return json.loads((open(path)).read())
def writeFile(data, filePath, fileName):
file_to_open = filePath + fileName
f = open(file_to_open, "w", encoding="utf-8", errors="ignore")
f.write(data)
f.close()
def readFile(path: str):
return open(path).read()
def readFilesTypeFolder(pathFolder: str, fileType=".json"):
filesJson = list(
filter(
lambda x: x[-fileType.__len__() :] == fileType, os.listdir(pathFolder)
)
)
return filesJson
def listGetFirstValue(iterable, default=False, pred=None):
return next(filter(pred, iterable), default)
def filterModels(filterModels, filterModelsDescription: list[str]):
models = []
for el in filterModelsDescription:
models.append(listGetFirstValue(filterModels, None, lambda x: x.name == el))
return models

View file

@ -0,0 +1,877 @@
"""
Format and compress XML documents
"""
import getopt
import re
import sys
import xml.parsers.expat
__version__ = "0.2.4"
DEFAULT_BLANKS = False
DEFAULT_COMPRESS = False
DEFAULT_SELFCLOSE = False
DEFAULT_CORRECT = True
DEFAULT_INDENT = 2
DEFAULT_INDENT_CHAR = " "
DEFAULT_INLINE = True
DEFAULT_ENCODING_INPUT = None
DEFAULT_ENCODING_OUTPUT = None
DEFAULT_EOF_NEWLINE = False
class Formatter:
# Use internal encoding:
encoding_internal = None
def __init__(
self,
indent=DEFAULT_INDENT,
preserve=[],
blanks=DEFAULT_BLANKS,
compress=DEFAULT_COMPRESS,
selfclose=DEFAULT_SELFCLOSE,
indent_char=DEFAULT_INDENT_CHAR,
encoding_input=DEFAULT_ENCODING_INPUT,
encoding_output=DEFAULT_ENCODING_OUTPUT,
inline=DEFAULT_INLINE,
correct=DEFAULT_CORRECT,
eof_newline=DEFAULT_EOF_NEWLINE,
):
# Minify the XML document:
self.compress = compress
# Use self-closing tags
self.selfclose = selfclose
# Correct text nodes
self.correct = correct
# Decode the XML document:
self.encoding_input = self.enc_normalize(encoding_input)
# Encode ouput by:
self.encoding_output = self.enc_normalize(encoding_output)
# Insert indent = indent*level*indent_char:
self.indent = int(indent)
# Indent by char:
self.indent_char = indent_char
# Format inline objects:
self.inline = inline
# Don't compress this elements and their descendants:
self.preserve = preserve
# Preserve blanks lines (collapse multiple into one)
self.blanks = blanks
# Always add a newline character at EOF
self.eof_newline = eof_newline
@property
def encoding_effective(self, enc=None):
if self.encoding_output:
return self.encoding_output
elif self.encoding_internal:
return self.encoding_internal
elif self.encoding_input:
return self.encoding_input
else:
return "UTF-8"
def enc_normalize(self, string):
""" Format an Encoding identifier to upper case. """
if isinstance(string, str):
return string.upper()
return None
def enc_encode(self, strg):
""" Encode a formatted XML document in target"""
if sys.version_info > (3, 0):
return strg.encode(self.encoding_effective) # v3
return strg.decode("utf-8").encode(self.encoding_effective) # v2
def enc_output(self, path, strg):
""" Output according to encoding """
fh = sys.stdout
if strg is not None:
if path is not None:
open(path, "w+b").write(strg)
elif sys.version_info > (3, 0):
fh.buffer.write(strg)
else:
fh.write(strg)
def format_string(self, xmldoc=""):
""" Format a XML document given by xmldoc """
token_list = Formatter.TokenList(self)
token_list.parser.Parse(xmldoc)
return self.enc_encode(str(token_list))
def format_file(self, file):
""" Format a XML document given by path name """
fh = open(file, "rb")
token_list = Formatter.TokenList(self)
token_list.parser.ParseFile(fh)
fh.close()
return self.enc_encode(str(token_list))
class TokenList:
# Being in a cdata section:
cdata_section = False
# Lock deletion of leading whitespace:
desc_mixed_level = None
# Lock indenting:
indent_level = None
# Reference the Formatter:
formatter = None
# Count levels:
level_counter = 0
# Lock deletion of whitespaces:
preserve_level = None
def __init__(self, formatter):
# Keep tokens in a list:
self._list = []
self.formatter = formatter
self.parser = xml.parsers.expat.ParserCreate(
encoding=self.formatter.encoding_input
)
self.parser.specified_attributes = 1
self.parser.buffer_text = True
# Push tokens to buffer:
for pattern in [
"XmlDecl%s",
"ElementDecl%s",
"AttlistDecl%s",
"EntityDecl%s",
"StartElement%s",
"EndElement%s",
"ProcessingInstruction%s",
"CharacterData%s",
"Comment%s",
"Default%s",
"StartDoctypeDecl%s",
"EndDoctypeDecl%s",
"StartCdataSection%s",
"EndCdataSection%s",
"NotationDecl%s",
]:
setattr(
self.parser, pattern % "Handler", self.xml_handler(pattern % "")
)
def __iter__(self):
return iter(self._list)
def __len__(self):
return len(self._list)
def __getitem__(self, pos):
if 0 <= pos < len(self._list):
return self._list[pos]
else:
raise IndexError
def __setitem__(self, pos, value):
if 0 <= pos < len(self._list):
self._list[pos] = value
else:
raise IndexError
def __str__(self):
""" Returns the formatted XML document in UTF-8. """
for step in ["configure", "pre_operate", "post_operate"]:
for tk in iter(self):
getattr(tk, step)()
result = ""
for tk in iter(self):
result += str(tk)
if self.formatter.eof_newline and not result.endswith("\n"):
result += "\n"
return result
def append(self, tk):
""" Add token to tokenlist. """
tk.pos = len(self._list)
self._list.append(tk)
def level_increment(self):
""" Increment level counter. """
self.level_counter += 1
def level_decrement(self):
""" Decrement level counter. """
self.level_counter -= 1
def token_descendant_mixed(self, tk):
""" Mark descendants of mixed content. """
if tk.name == "StartElement":
# Mark every descendant:
if tk.content_model in [2, 3] and self.desc_mixed_level is None:
self.desc_mixed_level = tk.level
return False
return self.desc_mixed_level is not None
elif tk.name == "EndElement":
# Stop marking every descendant:
if tk.level is self.desc_mixed_level:
self.desc_mixed_level = None
elif self.desc_mixed_level is not None:
return True
return False
elif self.desc_mixed_level is None:
return False
return self.desc_mixed_level >= tk.level - 1
def sequence(self, tk, scheme=None):
"""Returns sublist of token list.
None: next to last
EndElement: first to previous"""
if scheme == "EndElement" or (scheme is None and tk.end):
return reversed(self._list[: tk.pos])
return self._list[(tk.pos + 1) :]
def token_indent(self, tk):
if self.formatter.inline:
return self.token_indent_inline(tk)
""" Indent outside of text of mixed content. """
if tk.name == "StartElement":
# Block indenting for descendants of text and mixed content:
if tk.content_model in [2, 3] and self.indent_level is None:
self.indent_level = tk.level
elif self.indent_level is not None:
return False
return True
elif tk.name == "EndElement":
# Unblock indenting for descendants of text and mixed content:
if tk.level == self.indent_level:
self.indent_level = None
elif self.indent_level is None:
return True
return False
return self.indent_level is None
def token_indent_inline(self, tk):
""" Indent every element content - no matter enclosed by text or mixed content. """
for itk in iter(self.sequence(tk, "EndElement")):
if itk.level < tk.level and itk.name == "StartElement":
if itk.content_model == 1:
return True
return False
if (
itk.level == tk.level
and tk.name == "EndElement"
and itk.name == "StartElement"
):
if itk.content_model == 1:
return True
return False
return True
def token_model(self, tk):
"""Returns code for content model.
0: empty
1: element
2: text
3: mixed"""
eflag = tflag = 0
for itk in iter(self.sequence(tk)):
# Element boundary found:
if itk.level <= tk.level:
break
# Direct child found:
elif (itk.level - 1) == tk.level:
if itk.start:
eflag = 1
elif itk.not_empty:
tflag = 2
return eflag + tflag
def token_preserve(self, tk):
"""Preseve eyery descendant of an preserved element.
0: not locked
1: just (un)locked
2: locked"""
# Lock perserving for StartElements:
if tk.name == "StartElement":
if self.preserve_level is not None:
return 2
if tk.arg[0] in self.formatter.preserve:
self.preserve_level = tk.level
return 1
return 0
# Unlock preserving for EndElements:
elif tk.name == "EndElement":
if (
tk.arg[0] in self.formatter.preserve
and tk.level == self.preserve_level
):
self.preserve_level = None
return 1
elif self.preserve_level is None:
return 0
return 2
return self.preserve_level is not None
def whitespace_append_trailing(self, tk):
""" Add a trailing whitespace to previous character data. """
if self.formatter.correct and tk.leading and tk.not_empty:
self.whitespace_append(tk, "EndElement", "StartElement", True)
def whitespace_append_leading(self, tk):
""" Add a leading whitespace to previous character data. """
if self.formatter.correct and tk.trailing and tk.not_empty:
self.whitespace_append(tk)
def whitespace_append(
self, tk, start="StartElement", stop="EndElement", direct=False
):
""" Add a whitspace to token list. """
for itk in self.sequence(tk, start):
if (
itk.empty
or (itk.name == stop and itk.descendant_mixed is False)
or (itk.name == start and abs(tk - itk) == 1)
):
break
elif itk.not_empty or (itk.name == start and itk.descendant_mixed):
self.insert_empty(itk, direct)
break
def whitespace_delete_leading(self, tk):
""" Returns True, if no next token or all empty (up to next end element)"""
if (
self.formatter.correct
and tk.leading
and not tk.preserve
and not tk.cdata_section
):
for itk in self.sequence(tk, "EndElement"):
if itk.trailing:
return True
elif itk.name in ["EndElement", "CharacterData", "EndCdataSection"]:
return False
return True
return False
def whitespace_delete_trailing(self, tk):
"""Returns True, if no next token or all empty (up to next end element)"""
if (
self.formatter.correct
and tk.trailing
and not tk.preserve
and not tk.cdata_section
):
for itk in self.sequence(tk, "StartElement"):
if itk.end:
return True
elif (
itk.name in ["StartElement", "StartCdataSection"]
or itk.not_empty
):
return False
return True
return False
def insert_empty(self, tk, before=True):
""" Insert an Empty Token into token list - before or after tk. """
if not (0 < tk.pos < (len(self) - 1)):
return False
ptk = self[tk.pos - 1]
ntk = self.formatter.CharacterData(self, [" "])
ntk.level = max(ptk.level, tk.level)
ntk.descendant_mixed = tk.descendant_mixed
ntk.preserve = ptk.preserve * tk.preserve
ntk.cdata_section = ptk.cdata_section or tk.cdata_section
if before:
self._list.insert(tk.pos + 1, ntk)
else:
self._list.insert(tk.pos, ntk)
for i in range((tk.pos - 1), len(self._list)):
self._list[i].pos = i
def xml_handler(self, key):
""" Returns lambda function which adds token to token list"""
return lambda *arg: self.append(getattr(self.formatter, key)(self, arg))
class Token(object):
def __init__(self, tklist, arg):
# Reference Token List:
self.list = tklist
# Token datas:
self.arg = list(arg)
# Token is placed in an CDATA section:
self.cdata_section = False
# Token has content model:
self.content_model = None
# Remove trailing wihtespaces:
self.delete_trailing = False
# Remove leading whitespaces:
self.delete_leading = False
# Token is descendant of text or mixed content element:
self.descendant_mixed = False
# Reference to formatter:
self.formatter = tklist.formatter
# Insert indenting white spaces:
self.indent = False
# N-th generation of roots descendants:
self.level = self.list.level_counter
# Token class:
self.name = self.__class__.__name__
# Preserve white spaces within enclosed tokens:
self.preserve = False
# Position in token list:
self.pos = None
def __sub__(self, other):
return self.pos - other.pos
def __unicode__(self):
return ""
# Workaround, see http://lucumr.pocoo.org/2011/1/22/forwards-compatible-python/:
if sys.version_info > (3, 0):
__str__ = lambda x: x.__unicode__()
else:
__str__ = lambda x: unicode(x).encode("utf-8")
@property
def end(self):
return self.name == "EndElement"
@property
def empty(self):
return self.name == "CharacterData" and re.match(
r"^[\t\s\n]*$", self.arg[0]
)
@property
def leading(self):
return self.name == "CharacterData" and re.search(
r"^[\t\s\n]+", self.arg[0]
)
@property
def not_empty(self):
return (
self.name == "CharacterData"
and not self.cdata_section
and not re.match(r"^[\t\s\n]+$", self.arg[0])
)
@property
def trailing(self):
return self.name == "CharacterData" and re.search(
r"[\t\s\n]+$", self.arg[0]
)
@property
def start(self):
return self.name == "StartElement"
@property
def correct(self):
return self.formatter.correct
def attribute(self, key, value):
if key and value:
return ' %s="%s"' % (key, value)
elif key:
return ' %s=""' % (key)
return ""
def indent_insert(self):
""" Indent token. """
# Child of root and no empty node
if (
self.level > 0 and not (self.end and self.list[self.pos - 1].start)
) or ( # not empty node:
self.end and not self.list[self.pos - 1].start
):
return self.indent_create(self.level)
return ""
def indent_create(self, times=1):
""" Returns indent string. """
if not self.formatter.compress and self.formatter.indent:
return "\n%s" % (
(times * self.formatter.indent) * self.formatter.indent_char
)
return ""
def identifier(self, systemid, publicid):
# TODO add base parameter:
if publicid and systemid:
return ' PUBLIC "%s" "%s"' % (publicid, systemid)
elif publicid:
return ' PUBLIC "%s"' % publicid
elif systemid:
return ' SYSTEM "%s"' % systemid
return ""
def configure(self):
""" Set token properties. """
self.descendant_mixed = self.list.token_descendant_mixed(self)
self.preserve = self.list.token_preserve(self)
self.cdata_section = self.list.cdata_section
def pre_operate(self):
pass
def post_operate(self):
pass
class AttlistDecl(Token):
def __unicode__(self):
str = self.indent_create()
str += "<!ATTLIST %s %s" % (self.arg[0], self.arg[1])
if self.arg[2] is not None:
str += " %s" % self.arg[2]
if self.arg[4] and not self.arg[3]:
str += " #REQUIRED"
elif self.arg[3] and self.arg[4]:
str += " #FIXED"
elif not self.arg[4] and not self.arg[3]:
str += " #IMPLIED"
if self.arg[3]:
str += ' "%s"' % self.arg[3]
str += ">"
return str
class CharacterData(Token):
def __unicode__(self):
str = self.arg[0]
if not self.preserve and not self.cdata_section:
# remove empty tokens always in element content!
if self.empty and not self.descendant_mixed:
if self.formatter.blanks and not self.formatter.compress and re.match(r"\s*\n\s*\n\s*", str):
str = "\n"
else:
str = ""
else:
if self.correct:
str = re.sub(r"\r\n", "\n", str)
str = re.sub(r"\r|\n|\t", " ", str)
str = re.sub(r"\s+", " ", str)
if self.delete_leading:
str = re.sub(r"^\s", "", str)
if self.delete_trailing:
str = re.sub(r"\s$", "", str)
if not self.cdata_section:
str = re.sub(r"&", "&amp;", str)
str = re.sub(r"<", "&lt;", str)
return str
def pre_operate(self):
self.list.whitespace_append_trailing(self)
self.list.whitespace_append_leading(self)
def post_operate(self):
self.delete_leading = self.list.whitespace_delete_leading(self)
self.delete_trailing = self.list.whitespace_delete_trailing(self)
class Comment(Token):
def __unicode__(self):
str = ""
if self.preserve in [0, 1] and self.indent:
str += self.indent_insert()
str += "<!--%s-->" % re.sub(
r"^[\r\n]+$", "\n", re.sub(r"^[\r\n]+", "\n", self.arg[0])
)
return str
def configure(self):
super(Formatter.Comment, self).configure()
self.indent = self.list.token_indent(self)
class Default(Token):
pass
class EndCdataSection(Token):
def __unicode__(self):
return "]]>"
def configure(self):
self.list.cdata_section = False
class ElementDecl(Token):
def __unicode__(self):
str = self.indent_create()
str += "<!ELEMENT %s%s>" % (self.arg[0], self.evaluate_model(self.arg[1]))
return str
def evaluate_model(self, model, modelStr="", concatStr=""):
childSeq = []
mixed = model[0] == xml.parsers.expat.model.XML_CTYPE_MIXED
hasChilds = len(model[3]) or mixed
if model[0] == xml.parsers.expat.model.XML_CTYPE_EMPTY: # 1
modelStr += " EMPTY"
elif model[0] == xml.parsers.expat.model.XML_CTYPE_ANY: # 2
modelStr += " ANY"
elif model[0] == xml.parsers.expat.model.XML_CTYPE_NAME: # 4
modelStr = "%s" % model[2] # new start
elif model[0] in (
xml.parsers.expat.model.XML_CTYPE_CHOICE,
xml.parsers.expat.model.XML_CTYPE_MIXED,
): # 5
concatStr = "|"
elif model[0] == xml.parsers.expat.model.XML_CTYPE_SEQ: # 6
concatStr = ","
if hasChilds:
modelStr += " ("
if mixed:
childSeq.append("#PCDATA")
for child in model[3]:
childSeq.append(self.evaluate_model(child))
modelStr += concatStr.join(childSeq)
if hasChilds:
modelStr += ")"
modelStr += {
xml.parsers.expat.model.XML_CQUANT_NONE: "",
xml.parsers.expat.model.XML_CQUANT_OPT: "?",
xml.parsers.expat.model.XML_CQUANT_PLUS: "+",
xml.parsers.expat.model.XML_CQUANT_REP: "*",
}[model[1]]
return modelStr
class EndDoctypeDecl(Token):
def __unicode__(self):
str = ""
if self.list[self.pos - 1].name != "StartDoctypeDecl":
str += self.indent_create(0)
str += "]"
str += ">"
str += self.indent_create(0)
return str
class EndElement(Token):
def __init__(self, list, arg):
list.level_decrement()
super(Formatter.EndElement, self).__init__(list, arg)
def __unicode__(self):
str = ""
# Don't close empty nodes on compression mode:
if (
not (self.formatter.compress or self.formatter.selfclose)
or self.list[self.pos - 1].name != "StartElement"
):
if self.preserve in [0] and self.indent:
str += self.indent_insert()
str += "</%s>" % self.arg[0]
return str
def configure(self):
self.descendant_mixed = self.list.token_descendant_mixed(self)
self.preserve = self.list.token_preserve(self)
self.indent = self.list.token_indent(self)
class EntityDecl(Token):
def __unicode__(self):
str = self.indent_create()
str += "<!ENTITY "
if self.arg[1]:
str += "% "
str += "%s " % self.arg[0]
if self.arg[2]:
str += '"%s"' % self.arg[2]
else:
str += "%s " % self.identifier(self.arg[4], self.arg[5])
if self.arg[6]:
str += "NDATA %s" % self.arg[6]
str += ">"
return str
class NotationDecl(Token):
def __unicode__(self):
str = self.indent_create()
str += "<!NOTATION %s%s>" % (
self.arg[0],
self.identifier(self.arg[2], self.arg[3]),
)
return str
class ProcessingInstruction(Token):
def __unicode__(self):
str = ""
if self.preserve in [0, 1] and self.indent:
str += self.indent_insert()
str += "<?%s %s?>" % (self.arg[0], self.arg[1])
return str
def configure(self):
super(Formatter.ProcessingInstruction, self).configure()
self.indent = self.list.token_indent(self)
class StartCdataSection(Token):
def __unicode__(self):
return "<![CDATA["
def configure(self):
self.list.cdata_section = True
class StartDoctypeDecl(Token):
def __unicode__(self):
str = "<!DOCTYPE %s" % (self.arg[0])
if self.arg[1]:
str += self.identifier(self.arg[1], self.arg[2])
if self.arg[3]:
str += " ["
return str
class StartElement(Token):
def __init__(self, list, arg):
super(Formatter.StartElement, self).__init__(list, arg)
self.list.level_increment()
def __unicode__(self):
str = ""
if self.preserve in [0, 1] and self.indent:
str += self.indent_insert()
str += "<%s" % self.arg[0]
for attr in sorted(self.arg[1].keys()):
str += self.attribute(attr, self.arg[1][attr])
if self.list[self.pos + 1].end and (self.formatter.compress or self.formatter.selfclose):
str += "/>"
else:
str += ">"
return str
def configure(self):
self.content_model = self.list.token_model(self)
self.descendant_mixed = self.list.token_descendant_mixed(self)
self.preserve = self.list.token_preserve(self)
self.indent = self.list.token_indent(self)
class XmlDecl(Token):
def __init__(self, list, arg):
super(Formatter.XmlDecl, self).__init__(list, arg)
if len(self.arg) > 1:
self.formatter.encoding_internal = self.arg[1]
def __unicode__(self):
str = "<?xml%s%s" % (
self.attribute("version", self.arg[0]),
self.attribute("encoding", self.formatter.encoding_effective),
)
if self.arg[2] > -1:
str += self.attribute("standalone", "yes")
str += "?>\n"
return str
def cli_usage(msg=""):
""" Output usage for command line tool. """
sys.stderr.write(msg + "\n")
sys.stderr.write(
'Usage: xmlformat [--preserve "pre,literal"] [--blanks]\
[--compress] [--selfclose] [--indent num] [--indent-char char]\
[--outfile file] [--encoding enc] [--outencoding enc]\
[--disable-inlineformatting] [--overwrite] [--disable-correction]\
[--eof-newline]\
[--help] <--infile file | file | - >\n'
)
sys.exit(2)
def cli():
""" Launch xmlformatter from command line. """
res = None
indent = DEFAULT_INDENT
indent_char = DEFAULT_INDENT_CHAR
outfile = None
overwrite = False
preserve = []
blanks = False
compress = DEFAULT_COMPRESS
selfclose = DEFAULT_SELFCLOSE
infile = None
encoding = DEFAULT_ENCODING_INPUT
outencoding = DEFAULT_ENCODING_OUTPUT
inline = DEFAULT_INLINE
correct = DEFAULT_CORRECT
eof_newline = DEFAULT_EOF_NEWLINE
try:
opts, args = getopt.getopt(
sys.argv[1:],
"",
[
"compress",
"selfclose",
"disable-correction",
"disable-inlineformatting",
"encoding=",
"help",
"infile=",
"indent=",
"indent-char=",
"outfile=",
"outencoding=",
"overwrite",
"preserve=",
"blanks",
"eof-newline"
],
)
except getopt.GetoptError as err:
cli_usage(str(err))
for key, value in opts:
if key in ["--indent"]:
indent = value
elif key in ["--preserve"]:
preserve = value.replace(",", " ").split()
elif key in ["--blanks"]:
blanks = True
elif key in ["--help"]:
cli_usage()
elif key in ["--compress"]:
compress = True
elif key in ["--selfclose"]:
selfclose = True
elif key in ["--outfile"]:
outfile = value
elif key in ["--infile"]:
infile = value
elif key in ["--encoding"]:
encoding = value
elif key in ["--outencoding"]:
outencoding = value
elif key in ["--indent-char"]:
indent_char = value
elif key in ["--disable-inlineformatting"]:
inline = False
elif key in ["--disable-correction"]:
correct = False
elif key in ["--overwrite"]:
overwrite = True
elif key in ["--eof-newline"]:
eof_newline = True
try:
formatter = Formatter(
indent=indent,
preserve=preserve,
blanks=blanks,
compress=compress,
selfclose=selfclose,
encoding_input=encoding,
encoding_output=outencoding,
indent_char=indent_char,
inline=inline,
correct=correct,
eof_newline=eof_newline,
)
input_file = None
if infile:
input_file = infile
res = formatter.format_file(input_file)
elif len(args) > 0:
if args[0] == "-":
res = formatter.format_string("".join(sys.stdin.readlines()))
else:
input_file = args[0]
res = formatter.format_file(input_file)
except xml.parsers.expat.ExpatError as err:
cli_usage("XML error: %s" % err)
except IOError as err:
cli_usage("IO error: %s" % err)
except:
cli_usage("Unkonwn error")
if overwrite:
formatter.enc_output(input_file, res)
else:
formatter.enc_output(outfile, res)

53
simulation/asp/main.py Normal file
View file

@ -0,0 +1,53 @@
import argparse
import shutil
from src.model.enum import Enum
from helper.fs import FS
from src.usecases.urdf_sub_assembly_usecase import UrdfSubAssemblyUseCase
from src.model.sdf_geometry import GeometryModel
from src.usecases.sdf_sub_assembly_usecase import SdfSubAssemblyUseCase
import os
from pathlib import Path
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--generationFolder", help="FreeCad generation folder")
parser.add_argument("--outPath", help="save SDF path")
parser.add_argument("--world", help="adding sdf world")
parser.add_argument("--format", help="urdf,sdf,mujoco")
args = parser.parse_args()
if args.generationFolder == None or args.outPath == None:
parser.print_help()
outPath = args.outPath
geometryFiles = FS.readFilesTypeFolder(args.generationFolder + "/assets/")
assemblyStructure = FS.readJSON(args.generationFolder + "/step-structure.json")
geometryModels: list[GeometryModel] = []
for el in geometryFiles:
geometryModels.append(
GeometryModel.from_dict(
FS.readJSON(args.generationFolder + "/assets/" + el)
)
)
if os.path.exists(outPath + Enum.folderPath):
shutil.rmtree(outPath + Enum.folderPath)
Path(outPath + Enum.folderPath).mkdir(parents=True, exist_ok=True)
if args.format == "sdf":
SdfSubAssemblyUseCase().call(
geometryModels=geometryModels,
assembly=assemblyStructure,
world=args.world,
generationFolder=args.generationFolder,
outPath=args.outPath,
)
if args.format == "urdf":
UrdfSubAssemblyUseCase().call(
geometryModels=geometryModels,
assembly=assemblyStructure,
world=args.world,
generationFolder=args.generationFolder,
outPath=args.outPath,
)

View file

@ -0,0 +1,18 @@
{
"name": "Cube1",
"ixx": "16.66666666666667",
"ixy": "0.0",
"ixz": "0.0",
"iyy": "16.66666666666667",
"izz": "16.66666666666667",
"massSDF": "0.9999999999999998",
"posX": "0.0",
"posY": "-0.015",
"posZ": "0.0",
"eulerX": "0.0",
"eulerY": "0.0",
"eulerZ": "0.0",
"iyz": "0.0",
"stl": "/meshes/Cube1.stl",
"link": "1554"
}

View file

@ -0,0 +1,18 @@
{
"name": "Cube2",
"ixx": "16.66666666666667",
"ixy": "0.0",
"ixz": "-3.637978807091713e-15",
"iyy": "16.66666666666667",
"izz": "16.66666666666667",
"massSDF": "0.9999999999999998",
"posX": "0.0",
"posY": "-0.009",
"posZ": "0.01",
"eulerX": "0.0",
"eulerY": "0.0",
"eulerZ": "0.0",
"iyz": "-3.637978807091713e-15",
"stl": "/meshes/Cube2.stl",
"link": "8838"
}

View file

@ -0,0 +1,4 @@
<include>
<name>{name}</name>
<uri>{uri}</uri>
</include>

View file

@ -0,0 +1,5 @@
<include>
<name>{name}</name>
<uri>{uri}</uri>
<pose>{posX} {posY} {posZ} {eulerX} {eulerY} {eulerZ}</pose>
</include>

View file

@ -0,0 +1,7 @@
<joint name="{name}" type="fixed">
<parent>base_link</parent>
<child>{child}::{child}</child>
<pose>{posX} {posY} {posZ} {eulerX} {eulerY} {eulerZ}</pose>
</joint>

View file

@ -0,0 +1,36 @@
<link name="{name}">
<pose>{posX} {posY} {posZ} {eulerX} {eulerY} {eulerZ}</pose>
<inertial>
<pose>{posX} {posY} {posZ} {eulerX} {eulerY} {eulerZ}</pose>
<inertia>
<ixx>{ixx}</ixx>
<ixy>{ixy}</ixy>
<ixz>{ixz}</ixz>
<iyy>{iyy}</iyy>
<iyz>{iyz}</iyz>
<izz>{izz}</izz>
</inertia>
<mass>{massSDF}</mass>
</inertial>
<collision name="collision">
<geometry>
<mesh>
<uri>model:/{stl}</uri>
</mesh>
</geometry>
</collision>
<visual name="visual">
<geometry>
<mesh>
<uri>model:/{stl}</uri>
</mesh>
</geometry>
<surface>
<friction>
<ode>
<mu>{friction}</mu>
</ode>
</friction>
</surface>
</visual>
</link>

View file

@ -0,0 +1,5 @@
<?xml version="1.0" ?>
<model>
<sdf version="1.5">model.sdf</sdf>
</model>

View file

@ -0,0 +1,27 @@
<?xml version='1.0'?>
<sdf version="1.4">
<model name="{name}">
<link name="{name}">
<gravity>0</gravity>
<collision name="collision">
<mesh>
<uri>model:/{stl}</uri>
</mesh>
</collision>
<visual name="visual">
<geometry>
<mesh>
<uri>model:/{stl}</uri>
</mesh>
</geometry>
<surface>
<friction>
<ode>
<mu>{friction}</mu>
</ode>
</friction>
</surface>
</visual>
</link>
</model>
</sdf>

View file

@ -0,0 +1,64 @@
<sdf version='1.7'>
<world name='empty'>
<gravity>0 0 -9.8</gravity>
<magnetic_field>6e-06 2.3e-05 -4.2e-05</magnetic_field>
<atmosphere type='adiabatic'/>
<scene>
<ambient>0.4 0.4 0.4 1</ambient>
<background>0.7 0.7 0.7 1</background>
<shadows>true</shadows>
</scene>
<model name='ground_plane'>
<static>true</static>
<link name='link'>
<collision name='collision'>
<geometry>
<plane>
<normal>0 0 1</normal>
<size>100 100</size>
</plane>
</geometry>
<surface>
<friction>
<ode/>
</friction>
<bounce/>
<contact/>
</surface>
</collision>
<visual name='visual'>
<geometry>
<plane>
<normal>0 0 1</normal>
<size>100 100</size>
</plane>
</geometry>
<material>
<ambient>0.8 0.8 0.8 1</ambient>
<diffuse>0.8 0.8 0.8 1</diffuse>
<specular>0.8 0.8 0.8 1</specular>
</material>
</visual>
<pose>0 0 0 0 -0 0</pose>
<inertial>
<pose>0 0 0 0 -0 0</pose>
<mass>1</mass>
<inertia>
<ixx>1</ixx>
<ixy>0</ixy>
<ixz>0</ixz>
<iyy>1</iyy>
<iyz>0</iyz>
<izz>1</izz>
</inertia>
</inertial>
<enable_wind>false</enable_wind>
</link>
<pose>0 0 0 0 -0 0</pose>
<self_collide>false</self_collide>
</model>
</world>
</sdf>

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<robossembler
name="{name}">
</robossembler>

View file

@ -0,0 +1,13 @@
<joint
name="{joint_name}"
type="{joint_type}">
<origin
xyz="{joint_location}"
rpy="{joint_rotation}" />
<parent
link="{parent_part}" />
<child
link="{child_part}" />
<axis
xyz="0 0 1" />
</joint>

View file

@ -0,0 +1,31 @@
<link
name="{part_name}">
<inertial>
<origin
xyz="0 0 0"
rpy="0 0 0" />
<mass
value="{mass}" />
<inertia
ixx="0.0"
ixy="0.0"
ixz="0.0"
iyy="0.0"
iyz="0.0"
izz="0.0" />
</inertial>
<visual>
<geometry>
<mesh
filename="{visual_file}"
scale="1.0 1.0 1.0" />
</geometry>
</visual>
<collision>
<geometry>
<mesh
filename="{collision_file}"
scale="1.0 1.0 1.0" />
</geometry>
</collision>
</link>

View file

@ -0,0 +1,37 @@
<?xml version="1.0"?>
<robot name="{name}">
<link name="baseLink">
<contact>
<friction_anchor />
<lateral_friction value="0.3" />
<rolling_friction value="0.0" />
<contact_cfm value="0.0" />
<contact_erp value="1.0" />
</contact>
<inertial>
<origin xyz="{centerMassX} {centerMassY} {centerMassZ}" />
<mass value="{massSDF}" />
<inertia ixx="{ixx}" ixy="{ixy}" ixz="{ixz}" iyy="{iyy}" iyz="{iyz}" izz="{izz}" />
</inertial>
<visual>
<geometry>
<mesh filename="{stl}" scale="0.001 0.001 0.001" />
</geometry>
<material name="white">
<color rgba="1. 1. 1. 1." />
</material>
</visual>
<collision>
<geometry>
<mesh filename="{stl}" scale="0.001 0.001 0.001" />
</geometry>
</collision>
<friction>
<ode>
<mu>0.2</mu>
<mu2>0.1</mu2>
<fdir1>1 0 0</fdir1>
</ode>
</friction>
</link>
</robot>

View file

@ -0,0 +1,5 @@
argparse
matplotlib
pybullet
argparse
xmlformatter

View file

@ -0,0 +1,16 @@
from distutils.dir_util import copy_tree
from src.model.enum import Enum
class Assembly:
def generateSubAssembly(self, assembly: list[str]):
asm = {}
inc = 0
for el in assembly:
asm[str("asm" + str(inc))] = {
"part": el,
"assembly": assembly[0:inc],
}
inc += 1
return asm
def copy(self,generationFolder,format,outPath ):
copy_tree(generationFolder + format, outPath + Enum.folderPath)

View file

@ -0,0 +1,2 @@
class Enum:
folderPath = "generation/"

View file

@ -0,0 +1,327 @@
import os
from helper.fs import FS
from src.model.sdf_join import SdfJoin
import typing
import uuid
def from_str(x):
assert isinstance(x, str)
return x
def from_none(x):
assert x is None
return x
def from_union(fs, x):
for f in fs:
try:
return f(x)
except:
pass
assert False
def to_class(c, x):
assert isinstance(x, c)
return x.to_dict()
DELIMITER_SCALE = 10000
class GeometryModel:
def __init__(
self,
name,
ixx,
ixy,
ixz,
iyy,
izz,
massSDF,
posX,
posY,
posZ,
eulerX,
eulerY,
eulerZ,
iyz,
stl,
link,
friction,
centerMassX,
centerMassY,
centerMassZ,
):
self.name = name
self.ixx = ixx
self.ixy = ixy
self.ixz = ixz
self.iyy = iyy
self.izz = izz
self.massSDF = massSDF
self.posX = posX
self.posY = posY
self.posZ = posZ
self.eulerX = eulerX
self.eulerY = eulerY
self.eulerZ = eulerZ
self.iyz = iyz
self.stl = stl
self.link = link
self.friction = friction
self.centerMassX = centerMassX
self.centerMassY = centerMassY
self.centerMassZ = centerMassZ
@staticmethod
def from_dict(obj):
assert isinstance(obj, dict)
name = from_union([from_str, from_none], obj.get("name"))
ixx = from_union([from_str, from_none], obj.get("ixx"))
ixy = from_union([from_str, from_none], obj.get("ixy"))
ixz = from_union([from_str, from_none], obj.get("ixz"))
iyy = from_union([from_str, from_none], obj.get("iyy"))
izz = from_union([from_str, from_none], obj.get("izz"))
massSDF = from_union([from_str, from_none], obj.get("massSDF"))
posX = from_union([from_str, from_none], obj.get("posX"))
posY = from_union([from_str, from_none], obj.get("posY"))
posZ = from_union([from_str, from_none], obj.get("posZ"))
eulerX = from_union([from_str, from_none], obj.get("eulerX"))
eulerY = from_union([from_str, from_none], obj.get("eulerY"))
eulerZ = from_union([from_str, from_none], obj.get("eulerZ"))
iyz = from_union([from_str, from_none], obj.get("iyz"))
stl = from_union([from_str, from_none], obj.get("stl"))
link = from_union([from_str, from_none], obj.get("link"))
friction = from_union([from_str, from_none], obj.get("friction"))
centerMassX = from_union([from_str, from_none], obj.get("centerMassX"))
centerMassY = from_union([from_str, from_none], obj.get("centerMassY"))
centerMassZ = from_union([from_str, from_none], obj.get("centerMassZ"))
return GeometryModel(
name,
ixx,
ixy,
ixz,
iyy,
izz,
massSDF,
posX,
posY,
posZ,
eulerX,
eulerY,
eulerZ,
iyz,
stl,
link,
friction,
centerMassX,
centerMassY,
centerMassZ,
)
def to_dict(self):
result = {}
if self.name is not None:
result["name"] = from_union([from_str, from_none], self.name)
if self.ixx is not None:
result["ixx"] = from_union([from_str, from_none], self.ixx)
if self.ixy is not None:
result["ixy"] = from_union([from_str, from_none], self.ixy)
if self.ixz is not None:
result["ixz"] = from_union([from_str, from_none], self.ixz)
if self.iyy is not None:
result["iyy"] = from_union([from_str, from_none], self.iyy)
if self.izz is not None:
result["izz"] = from_union([from_str, from_none], self.izz)
if self.massSDF is not None:
result["massSDF"] = from_union([from_str, from_none], self.massSDF)
if self.posX is not None:
result["posX"] = from_union([from_str, from_none], self.posX)
if self.posY is not None:
result["posY"] = from_union([from_str, from_none], self.posY)
if self.posZ is not None:
result["posZ"] = from_union([from_str, from_none], self.posZ)
if self.eulerX is not None:
result["eulerX"] = from_union([from_str, from_none], self.eulerX)
if self.eulerY is not None:
result["eulerY"] = from_union([from_str, from_none], self.eulerY)
if self.eulerZ is not None:
result["eulerZ"] = from_union([from_str, from_none], self.eulerZ)
if self.iyz is not None:
result["iyz"] = from_union([from_str, from_none], self.iyz)
if self.stl is not None:
result["stl"] = from_union([from_str, from_none], self.stl)
if self.link is not None:
result["link"] = from_union([from_str, from_none], self.link)
if self.friction is not None:
result["friction"] = from_union([from_str, from_none], self.eulerZ)
if self.centerMassX is not None:
result["centerMassX"] = from_union([from_str, from_none], self.centerMassX)
if self.centerMassY is not None:
result["centerMassY"] = from_union([from_str, from_none], self.centerMassY)
if self.centerMassZ is not None:
result["centerMassZ"] = from_union([from_str, from_none], self.centerMassZ)
return result
def toJSON(self) -> str:
return str(self.to_dict()).replace("'", '"')
def toSDF(self):
return (
FS.readFile(
os.path.dirname(os.path.realpath(__file__))
+ "/../../mocks/sdf/model.sdf"
)
.replace(
"{name}",
self.name,
)
.replace("{posX}", self.posX)
.replace("{posY}", self.posY)
.replace("{posZ}", self.posZ)
.replace("{eulerX}", self.eulerX)
.replace("{eulerY}", self.eulerY)
.replace("{eulerZ}", self.eulerZ)
.replace("{ixx}", self.ixx)
.replace("{ixy}", self.ixy)
.replace("{ixz}", self.ixz)
.replace("{iyy}", self.iyy)
.replace("{iyz}", self.iyz)
.replace("{izz}", self.izz)
.replace(
"{massSDF}",
self.massSDF,
)
.replace("{stl}", self.stl)
.replace("{friction}", self.friction)
)
def toSdfLink(self):
return (
FS.readFile(
os.path.dirname(os.path.realpath(__file__))
+ "/../../mocks/sdf/link.sdf"
)
.replace(
"{name}",
self.name,
)
.replace("{posX}", self.posX)
.replace("{posY}", self.posY)
.replace("{posZ}", self.posZ)
.replace("{eulerX}", self.eulerX)
.replace("{eulerY}", self.eulerY)
.replace("{eulerZ}", self.eulerZ)
.replace("{ixx}", self.ixx)
.replace("{ixy}", self.ixy)
.replace("{ixz}", self.ixz)
.replace("{iyy}", self.iyy)
.replace("{iyz}", self.iyz)
.replace("{izz}", self.izz)
.replace(
"{massSDF}",
self.massSDF,
)
.replace("{stl}", self.stl)
.replace("{friction}", self.friction)
)
def includeLink(self, pose=False):
if pose == False:
return (
FS.readFile(
os.path.dirname(os.path.realpath(__file__))
+ "/../../mocks/sdf/include.sdf"
)
.replace("{name}", self.name)
.replace("{uri}", "/" + self.name)
)
return (
FS.readFile(
os.path.dirname(os.path.realpath(__file__))
+ "/../../mocks/sdf/include_pose.sdf"
)
.replace("{name}", self.name)
.replace("{uri}", "/" + self.name)
.replace("{posX}", self.posX)
.replace("{posY}", self.posY)
.replace("{posZ}", self.posZ)
.replace("{eulerX}", self.eulerX)
.replace("{eulerY}", self.eulerY)
.replace("{eulerZ}", self.eulerZ)
.replace("{ixx}", self.ixx)
.replace("{ixy}", self.ixy)
.replace("{ixz}", self.ixz)
.replace("{iyy}", self.iyy)
.replace("{iyz}", self.iyz)
.replace("{izz}", self.izz)
)
def generateSDFatJoinFixed(self, sdfModels: list["GeometryModel"]):
sdf = '\n<model name="assembly">\n'
sdf += ' <link name="base_link">\n'
sdf += " <pose>0 0 0 0 0 0</pose>\n"
sdf += " </link>\n"
link = sdf + self.includeLink(pose=True)
if sdfModels.__len__() == 0:
return link
endTagLinkInc = link.__len__()
beginSDF = link[0:endTagLinkInc]
sdfJoin = beginSDF + "\n"
for el in sdfModels:
if el.name != self.name:
sdfJoin += el.includeLink(pose=True) + "\n"
endSDF = link[endTagLinkInc : link.__len__()]
for el in sdfModels:
if el.name != self.name:
sdfJoin += (
SdfJoin(
name=str(uuid.uuid4()),
parent=self.name,
child=el.name,
modelAt=el,
).toSDF()
+ "\n"
)
sdfJoin += endSDF
sdfJoin += "</model>"
return sdfJoin
def toUrdf(self):
return (
FS.readFile(
os.path.dirname(os.path.realpath(__file__))
+ "/../../mocks/urdf/model.urdf"
)
.replace("{name}", self.name)
.replace("{name}", self.name)
.replace("{uri}", "/" + self.name)
.replace("{posX}", self.posX)
.replace("{posY}", self.posY)
.replace("{posZ}", self.posZ)
.replace("{eulerX}", self.eulerX)
.replace("{eulerY}", self.eulerY)
.replace("{eulerZ}", self.eulerZ)
.replace("{ixx}", self.ixx)
.replace("{ixy}", self.ixy)
.replace("{ixz}", self.ixz)
.replace("{iyy}", self.iyy)
.replace("{iyz}", self.iyz)
.replace("{izz}", self.izz)
.replace("{stl}", self.stl)
.replace("{massSDF}", self.massSDF)
.replace("{centerMassX}", self.centerMassX)
.replace("{centerMassY}", self.centerMassY)
.replace("{centerMassZ}", self.centerMassZ)
)

View file

@ -0,0 +1,16 @@
from helper.fs import FS
import os
class SdfJoin:
def __init__(self, name, parent, modelAt, child) -> None:
self.name = name
self.parent = parent
self.child = child
self.modelAt = modelAt
pass
def toSDF(self):
return (FS.readFile(os.path.dirname(os.path.realpath(__file__)) + '/../../mocks/sdf/joint_fixed.sdf')).replace('{name}', self.name,).replace('{parent}', self.parent).replace('{child}', self.child).replace('{posX}', self.modelAt.posX).replace('{posY}', self.modelAt.posY).replace('{posZ}', self.modelAt.posZ).replace('{eulerX}', self.modelAt.eulerX).replace('{eulerY}', self.modelAt.eulerY).replace('{eulerZ}', self.modelAt.eulerZ).replace('{ixx}', self.modelAt.ixx).replace('{ixy}', self.modelAt.ixy).replace('{ixz}', self.modelAt.ixz).replace('{iyy}', self.modelAt.iyy).replace('{iyz}', self.modelAt.iyz).replace('{izz}', self.modelAt.izz)

View file

@ -0,0 +1,14 @@
from helper.xmlformatter import Formatter
from src.model.enum import Enum
from helper.fs import FS
class FormatterUseCase:
def call(outPath: str, format: str):
formatter = Formatter(
indent="1", indent_char="\t", encoding_output="ISO-8859-1", preserve=["literal"])
files = FS.readFilesTypeFolder(
outPath + Enum.folderPath, fileType=format)
for el in files:
FS.writeFile(data=str(formatter.format_file(outPath + Enum.folderPath + el),
'utf-8'), filePath=outPath + Enum.folderPath, fileName=el)

View file

@ -0,0 +1,18 @@
import os
from helper.fs import FS
class SdfGenerateWorldUseCase:
def call(assembly: str) -> str:
world = FS.readFile(
os.path.dirname(os.path.realpath(__file__)) + "/../../mocks/sdf/world.sdf"
)
beginWorld = world[0 : world.find("</world") - 1]
endWorld = world[world.find("</world") - 1 : world.__len__()]
return beginWorld + assembly + endWorld
class GeometryValidateUseCase:
def call(geometry) -> str:
return

View file

@ -0,0 +1,12 @@
import os
from helper.fs import FS
class SdfGenerateWorldUseCase:
def call(assembly:str) -> str:
world = FS.readFile(os.path.dirname(os.path.realpath(__file__))
+ '/../../mocks/sdf/world.sdf')
beginWorld = world[0:world.find('</world') - 1]
endWorld = world[world.find('</world') - 1: world.__len__()]
return beginWorld + assembly + endWorld

View file

@ -0,0 +1,78 @@
import os
from typing import Optional
from helper.fs import FS
from helper.fs import filterModels, listGetFirstValue
from src.model.asm import Assembly
from src.model.enum import Enum
from src.usecases.formatter_usecase import FormatterUseCase
from src.usecases.sdf_generate_world_usecase import SdfGenerateWorldUseCase
from src.model.sdf_geometry import GeometryModel
from distutils.dir_util import copy_tree
SDF_FILE_FORMAT = ".sdf"
CONFIG_PATH = (
os.path.dirname(os.path.realpath(__file__)) + "/../../mocks/sdf/model.config"
)
class SdfSubAssemblyUseCase(Assembly):
def call(
self,
geometryModels: list[GeometryModel],
assembly: list[str],
outPath: str,
generationFolder: str,
world: bool,
):
asm = {}
generateSubAssemblyModels = self.generateSubAssembly(assembly)
inc = 0
for key, value in generateSubAssemblyModels.items():
inc += 1
if value["assembly"].__len__() != 0:
model: Optional[GeometryModel] = listGetFirstValue(
geometryModels, None, lambda x: x.name == value["assembly"][0]
)
if model != None:
asm[key] = {
"assembly": model.generateSDFatJoinFixed(
filterModels(geometryModels, value["assembly"])
),
"part": (
listGetFirstValue(
geometryModels, None, lambda x: x.name == value["part"]
)
).includeLink(),
}
self.copy(generationFolder=generationFolder, format="/sdf", outPath=outPath)
dirPath = outPath + Enum.folderPath
for el in geometryModels:
path = dirPath + el.name + "/"
os.makedirs(path)
FS.writeFile(
data=el.toSDF(), filePath=path, fileName="/model" + SDF_FILE_FORMAT
)
FS.writeFile(
data=FS.readFile(CONFIG_PATH),
filePath=path,
fileName="/model" + ".config",
)
for key, v in asm.items():
FS.writeFile(
data=v["assembly"],
filePath=dirPath,
fileName="/" + key + SDF_FILE_FORMAT,
)
else:
for key, v in asm.items():
FS.writeFile(
data=SdfGenerateWorldUseCase.call(v["assembly"]),
filePath=dirPath,
fileName="/" + key + SDF_FILE_FORMAT,
)
FormatterUseCase.call(outPath=outPath, format=SDF_FILE_FORMAT)

View file

@ -0,0 +1,30 @@
from helper.fs import FS
from src.model.enum import Enum
from src.model.asm import Assembly
from src.model.sdf_geometry import GeometryModel
import json
import re
URDF_FILE_FORMAT = ".urdf"
URDF_GENERATOR_FILE = "urdf-generation" + ".json"
class UrdfSubAssemblyUseCase(Assembly):
def call(
self,
geometryModels: list[GeometryModel],
assembly: list[str],
outPath: str,
generationFolder: str,
world: bool,
):
dirPath = generationFolder + Enum.folderPath
asm = {}
for el in geometryModels:
asm[el.name] = el.toUrdf()
FS.writeFile(
data=json.dumps(asm, indent=4),
fileName=URDF_GENERATOR_FILE,
filePath=dirPath,
)

View file

@ -0,0 +1,116 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# pyenv
.python-version
# celery beat schedule file
celerybeat-schedule
# SageMath parsed files
*.sage.py
# dotenv
.env
# virtualenv
.venv
venv/
ENV/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
# blender backup files
*.blend1
install_plugin_cad.sh
.vscode
.DS_Store
# emacs backup files
~*
*~
*#
.#*
\#*\#
out/
/env.json

View file

@ -0,0 +1,31 @@
# Start dev
create env.json
```json
{
"cadDoc":"CAD_DOC_PATH_REPLACE",
"sequences":"SEQUENCES_PATH_REPLACE",
"aspDir":"ASP_DIR_REPLACE"
}
```
# Command generation assets
freecad generate.py
# Command generation insertion vectors
Загрузка субмодуля git
```
git submodule update --init
```
Создание и активация виртуального окружения
```
conda env create -f assembly/environment.yml
conda activate assembly
```
Запуск программы
```
python3 main.py
```

@ -0,0 +1 @@
Subproject commit 29db7df4d7f2e6055f3f26fc5c11a424954f7308

View file

@ -0,0 +1,205 @@
from typing import List
import FreeCAD as App
import Part
import Mesh
import Part
import MeshPart
import os
import json
import FreeCADGui as Gui
class FS:
def readJSON(path: str):
return json.loads((open(path)).read())
def writeFile(data, filePath, fileName):
file_to_open = filePath + fileName
f = open(file_to_open, 'w', encoding='utf-8',
errors='ignore')
f.write(data)
f.close()
def createFolder(path: str):
if (not os.path.exists(path)):
return os.mkdir(path)
class SimpleCopyPartModel:
id = None
copyLink = None
label = None
part = None
def getPart(self):
return self.part
def __init__(self, part) -> None:
try:
from random import randrange
self.id = str(randrange(1000000))
childObj = part
print(part)
__shape = Part.getShape(
childObj, '', needSubElement=False, refine=False)
obj = App.ActiveDocument.addObject('Part::Feature', self.id)
obj.Shape = __shape
self.part = obj
self.label = obj.Label
App.ActiveDocument.recompute()
except Exception as e:
print(e)
def remove(self):
App.ActiveDocument.removeObject(self.label)
class MeshPartModel:
id = None
mesh = None
def __init__(self, part) -> None:
try:
from random import randrange
self.id = 'mesh' + str(randrange(1000000))
document = App.ActiveDocument
mesh = document.addObject("Mesh::Feature", self.id)
shape = Part.getShape(part, "")
mesh.Mesh = MeshPart.meshFromShape(
Shape=shape, LinearDeflection=20, AngularDeflection=0.1, Relative=False)
mesh.Label = self.id
self.mesh = mesh
except Exception as e:
print(e)
pass
def remove(self):
try:
App.ActiveDocument.removeObject(self.mesh.Label)
except Exception as e:
print(e)
class JoinMeshModel:
id = None
mesh = None
def __init__(self, meshesPartModels: list['MeshPartModel']) -> None:
meshes = []
from random import randrange
for el in meshesPartModels:
meshes.append(el.mesh.Mesh)
self.id = 'MergedMesh' + str(randrange(1000000))
doc = App.ActiveDocument
merged_mesh = Mesh.Mesh()
for el in meshes:
merged_mesh.addMesh(el)
new_obj = doc.addObject("Mesh::Feature", self.id)
new_obj.Mesh = merged_mesh
new_obj.ViewObject.DisplayMode = "Flat Lines"
self.mesh = new_obj
def remove(self):
try:
App.ActiveDocument.removeObject(self.id)
except Exception as e:
print(e)
class ExportAssemblyThemAllUseCase:
def call(self, path:str, assemblys:list[str]):
assembly = assemblys
asmStructure = {}
inc = 0
for el in assembly:
if (inc != 0):
asmStructure[inc] = {
"child": el,
"parents": assembly[0:inc]
}
inc += 1
objectsFreeCad = App.ActiveDocument.Objects
asmSolids = {}
for k, v in asmStructure.items():
assemblyParentList = v['parents']
assemblyChild = v['child']
for el in assemblyParentList:
for solid in objectsFreeCad:
if (el == solid.Label):
if (asmSolids.get(k) is None):
asmSolids[k] = {'parents': [], 'child': list(
filter(lambda x: x.Label == assemblyChild, objectsFreeCad))[0]}
asmSolids[k]['parents'].append(solid)
inc = 0
for k, v in asmSolids.items():
geometry = {"0": [], "1": []}
if (k != 0):
App.activeDocument().addObject("Part::Compound", "Compound")
copyLinks = list(
map(lambda el: SimpleCopyPartModel(el), v['parents']))
if copyLinks != None:
App.activeDocument().Compound.Links = list(
map(lambda el: el.getPart(), copyLinks))
object = App.activeDocument().getObject('Compound')
boundBox = object.Shape.BoundBox
geometry['0'].append(boundBox.XMax)
geometry['0'].append(boundBox.YMax)
geometry['0'].append(boundBox.ZMax)
boundBoxChild = v['child'].Shape.BoundBox
geometry['1'].append(boundBoxChild.XMax)
geometry['1'].append(boundBoxChild.YMax)
geometry['1'].append(boundBoxChild.ZMax)
meshParents = []
for el in v['parents']:
meshParents.append(MeshPartModel(el))
joinMesh = JoinMeshModel(meshParents)
for el in meshParents:
el.remove()
import importOBJ
importOBJ.export(joinMesh.mesh, path + str(1) + '.obj')
joinMesh.remove()
importOBJ.export(v['child'], path + str(0) + '.obj')
FS.writeFile(json.dumps(geometry), path, 'translation.json')
App.ActiveDocument.removeObject("Compound")
for el in copyLinks:
el.remove()
App.activeDocument().recompute()
inc += 1
def main():
env = FS.readJSON('./env.json')
env.get('cadDoc')
aspDir = env.get('aspDir')
sequences = FS.readJSON(env.get('sequences')).get('sequences')
App.openDocument(env.get('cadDoc'))
for sequencyNumber in range(len(sequences)):
FS.createFolder(aspDir + 'assemblys/')
mainFolder = aspDir + 'assemblys/' + str(sequencyNumber) + '/'
FS.createFolder(mainFolder)
for subSequenceNumber in range(len(sequences[sequencyNumber])):
if(subSequenceNumber != 0):
subFolder = aspDir + 'assemblys/' + \
str(sequencyNumber) + '/' + str(subSequenceNumber) + '/'
FS.createFolder(subFolder)
ExportAssemblyThemAllUseCase().call(path=subFolder,assemblys=sequences[sequencyNumber][0:subSequenceNumber+1])
App.closeDocument(App.ActiveDocument.Name)
freecadQTWindow = Gui.getMainWindow()
freecadQTWindow.close()
main()

View file

@ -0,0 +1,174 @@
import os
import sys
project_base_dir = os.path.abspath(os.path.join(
os.path.dirname(os.path.abspath(__file__)), './')) + '/assembly/'
sys.path.append(project_base_dir)
sys.path.append(project_base_dir + '/baselines/')
sys.path.append(project_base_dir + '/assets/')
from scipy.spatial.transform import Rotation
import shutil
from spatialmath import *
from spatialmath.base import *
from assembly.assets.process_mesh import process_mesh
from assembly.examples.run_joint_plan import get_planner
from assembly.baselines.run_joint_plan import PyPlanner
from assembly.assets.subdivide import subdivide_to_size
import numpy as np
import json
import trimesh
import re
def merge_meshes(meshes):
# Создание пустого меша
merged_mesh = trimesh.Trimesh()
# Объединение каждого меша в один
for mesh in meshes:
merged_mesh = trimesh.util.concatenate(
[merged_mesh, trimesh.load(mesh)])
i = True
while i:
if merged_mesh.fill_holes():
i = False
return merged_mesh
os.environ['OMP_NUM_THREADS'] = '1'
class FS:
def readJSON(path: str):
return json.loads((open(path)).read())
def writeFile(data, filePath, fileName):
file_to_open = filePath + fileName
f = open(file_to_open, 'w', )
f.write(data)
def readFile(path: str):
return open(path).read()
def readFilesTypeFolder(pathFolder: str, fileType='.json'):
return os.listdir(pathFolder)
def readFolder(pathFolder: str):
return list(map(lambda el: pathFolder + '/' + el, os.listdir(pathFolder)))
def createFolder(path: str):
if (not os.path.exists(path)):
return os.mkdir(path)
def listGetFirstValue(iterable, default=False, pred=None):
return next(filter(pred, iterable), default)
def filterModels(filterModels, filterModelsDescription):
models = []
for el in filterModelsDescription:
models.append(listGetFirstValue(
filterModels, None, lambda x: x.name == el))
return models
# mesh1 = trimesh.load('/Users/idontsudo/framework/asp/out/sdf-generation/meshes/Cube.obj')
# mesh2 = trimesh.load('/Users/idontsudo/framework/asp/out/sdf-generation/meshes/Cube001.obj')
# # Объединение мешей
# merged_mesh = merge_meshes([mesh1, mesh2])
# # Сохранение объединенного меша в файл
# merged_mesh.export('merged.obj')
def main():
# from argparse import ArgumentParser
# parser = ArgumentParser()
# parser.add_argument('--asp-path', type=str, required=True)
# args = parser.parse_args()
# aspDir = args.asp_dir
# # Коректировка пути до папки с генерацией ASP
# if (aspDir == None):
# args.print_helper()
# if (aspDir[aspDir.__len__() - 1] != '/'):
# aspDir += '/'
aspDir = '/home/idontsudo/framework/asp/out/'
sequences = FS.readJSON(aspDir + 'sequences.json').get('sequences')
assemblyDirNormalize = []
for el in FS.readFolder(aspDir + 'assemblys'):
for e in FS.readFolder(el):
try:
# Пост обработка .obj обьектов
process_mesh(source_dir=e, target_dir=e +
'/process/', subdivide=e, verbose=True)
assemblyDirNormalize.append(e + '/process/')
except Exception as e:
print('ERRROR:')
print(e)
print(assemblyDirNormalize)
for el in assemblyDirNormalize:
asset_folder = os.path.join(project_base_dir, aspDir)
assembly_dir = os.path.join(asset_folder, el)
planner = get_planner('bfs')(assembly_dir, assembly_dir, 0, [
1], False, 'sdf', 0.05, 0.01, 100, 100, True)
# Планирование пути
status, t_plan, path = planner.plan(
120, seed=1, return_path=True, render=False, record_path=None
)
coords = []
for k in path:
seMatrix = SE3(k)
euler = seMatrix.eul()
coord = seMatrix.A[0:3, 3]
rot = Rotation.from_euler('xyz', euler, degrees=True).as_quat()
coords.append({'quadrelion': [rot[0], rot[1], rot[2], rot[3]], 'xyz': [
coord[0], coord[1], coord[2]], 'euler': [euler[0], euler[1], euler[2]]})
# Запись пути в кортеж
planingObject = {
"time": t_plan,
"insertion_path": coords,
"status": status,
}
# Запись результата планирования
FS.writeFile(json.dumps(planingObject),
el[0:el.__len__() - 8], 'insertion_path.json')
try:
planner = PyPlanner(assembly_dir, 'process', still_ids=[1],)
status, t_plan, path = planner.plan(
planner_name='rrt',
step_size=None,
max_time=None,
seed=1,
return_path=True,
simplify=False,
render=False
)
print(f'Status: {status}, planning time: {t_plan}')
if args.save_dir is not None:
planner.save_path(path, args.save_dir, args.n_save_state)
except Exception as e:
print(e)
main()

View file

@ -0,0 +1,3 @@
spatialmath
scipy
uuid

View file

@ -0,0 +1,37 @@
# Intersection Geometry Predicate
Осуществляется проверка геометрических вершин пересечения файлов .obj на соответствие допустимой погрешности глубины.
### CLI аргументы:
--aspPath путь до папки с асетами сборки
### вывод
на выходе делает файл intersection_geometry.json
в котором записан результат работы предиката в виде ключа status и результат в виде ключа recalculations.
В ключе recalculations, записан объект в который записываются результаты расчета пересечения.
Они состоят из объекта.
- names имена пересекающеюся деталей
- depth глубина пересечения
- point геометрические вершины
```JSON
{
"status": false,
"recalculations": {
"disk_bottom bolt ": [
{
"names": "disk_bottom bolt ",
"depth": 0.5127948565443177,
"point": [
-1.972554,
16.442781,
-9.208569
]
}
]
}
}
```

View file

@ -0,0 +1,86 @@
import trimesh
import os
import json
import argparse
class FS:
def readJSON(path: str):
return json.loads((open(path)).read())
def writeFile(data, filePath, fileName):
file_to_open = filePath + fileName
f = open(file_to_open, 'w')
f.write(data)
f.close()
def readFile(path: str):
return open(path).read()
def readFilesTypeFolder(pathFolder: str, fileType='.json'):
filesJson = list(
filter(lambda x: x[-fileType.__len__():] == fileType, os.listdir(pathFolder)))
return list(map(lambda x: pathFolder + x, filesJson))
def main():
parser = argparse.ArgumentParser()
parser.add_argument('--aspPath', help='asp generation folder')
args = parser.parse_args()
if args.aspPath == None:
parser.print_help()
aspPath = args.aspPath
pathMeshes = 'sdf/meshes/'
permissibleDepth = 0.5
trimeshObjects = []
meshes = FS.readFilesTypeFolder(aspPath + pathMeshes, '.obj')
for el in meshes:
trimeshObjects.append(trimesh.load(el))
manager = trimesh.collision.CollisionManager()
for el in range(len(trimeshObjects)):
manager.add_object(str(meshes[el]), trimeshObjects[el])
def set_to_dict(s):
keys = list(s)
values = [None] * len(s)
return {k: v for k, v in zip(keys, values)}
collisions = manager.in_collision_internal(True, True)
recalculations = {}
for el in collisions[collisions.__len__() - 1]:
if (el.depth > permissibleDepth):
labels = ''
for key in set_to_dict(el.names).keys():
label = key[key.rfind('/') + 1:key.__len__() - 4]
labels+=label + " "
message = {
'names': labels,
'depth': el.depth,
'point': el.point.tolist()
}
if(recalculations.get(labels) != None):
recalculations[labels].append(message)
else:
recalculations[labels] = [message]
if(len(list(recalculations.keys())) >= 1):
messageError = {
'status':False,
'recalculations':recalculations
}
FS.writeFile(json.dumps(messageError, ensure_ascii=False, indent=4), aspPath,'intersection_geometry.json')
else:
message = {
'status':True,
'recalculations': None
}
FS.writeFile(json.dumps(messageError, ensure_ascii=False, indent=4), aspPath,'intersection_geometry.json')
main()

View file

@ -0,0 +1,2 @@
argparse
trimesh

View file

@ -0,0 +1,97 @@
from types import LambdaType, UnionType
from returns.pipeline import is_successful
from typing import List, TypeVar
from returns.result import Result, Success, Failure
import os
from model.robossembler_assets import (
MappingInstanceAtModel,
RobossemblerAssets,
Instance,
)
import re
import pathlib
from repository.file_system import FileSystemRepository
from model.robossembler_assets import Physics
from argparse import ArgumentParser
T = TypeVar("T")
class JsonReaderAndModelMapperUseCase:
def call(path: str, model: T) -> Result[T, str]:
try:
if not re.search("^(.+)\/([^\/]+)$", path):
return Failure("path not valid")
if model.from_dict == None:
return Failure("Model is not have mapping method from_dict")
return Success(model.from_dict(FileSystemRepository.readJSON(path=path)))
except:
return Failure("JsonReaderAndModelMapperUseCase unknown error")
class MappingInstanceAtModelToSdfUseCase:
def call(instances: List[MappingInstanceAtModel]) -> Result[List[str], str]:
try:
return Success(list(map(lambda el: el.toSDF(), instances)))
except:
return Failure("MappingInstanceAtModelToSdfUseCase unknown error")
class MappingSdfWorldToPhysicsModelUseCase:
def call(physicModel: Physics) -> Result[List[str], str]:
try:
return Success(Physics.toSDF(physicModel))
except:
return Failure("MappingInstanceAtModelToSdfUseCase unknown error")
class FormationOfTheSDFUseCase:
def call(worldTag: str, modelsTags: List[str], path: str) -> Result[bool, str]:
path = str(pathlib.Path(path).parent.resolve()) + "/"
if modelsTags == None:
return Failure("FormationOfTheSDFUseCase modelsTags is None")
if worldTag == None:
return Failure("FormationOfTheSDFUseCase worldTag is None")
FileSystemRepository.writeFile(
data=worldTag.replace("{models}", "\n".join(modelsTags)),
filePath=path,
fileName="world.sdf",
)
return Success(True)
def main():
parser = ArgumentParser()
parser.add_argument("--path", help="need path .json")
args = parser.parse_args()
if args.path == None:
parser.print_help()
return
path = args.path
jsonReaderAndModelMapperUseCase = JsonReaderAndModelMapperUseCase.call(
path=path, model=RobossemblerAssets
)
if not is_successful(jsonReaderAndModelMapperUseCase):
return
robossemblerAssets = jsonReaderAndModelMapperUseCase.value_or(None)
instanceSdfModel = MappingInstanceAtModelToSdfUseCase.call(
instances=robossemblerAssets.getAllAssetsInstanceAtModel()
)
sdfWorld = MappingSdfWorldToPhysicsModelUseCase.call(
physicModel=robossemblerAssets.physics
)
FormationOfTheSDFUseCase.call(
worldTag=sdfWorld.value_or(None),
modelsTags=instanceSdfModel.value_or(None),
path=path,
)
main()

View file

@ -0,0 +1,12 @@
<light type="{type_light}" name="{name_light}">
<pose>{x} {y} {z} {roll} {pitch} {yaw}</pose>
<diffuse>{r} {g} {b} {a}</diffuse>
<specular>.1 .1 .1 1</specular>
<attenuation>
<range>20</range>
<linear>0.2</linear>
<constant>0.8</constant>
<quadratic>0.01</quadratic>
</attenuation>
<cast_shadows>false</cast_shadows>
</light>

View file

@ -0,0 +1,7 @@
<model name="{name}">
<pose>{x} {y} {z} {roll} {pitch} {yaw}</pose>
<include>
<name>{name}</name>
<uri>model://{uri}</uri>
</include>
</model>

View file

@ -0,0 +1,105 @@
<?xml version="1.0"?>
<sdf version='1.9'>
<world name='mir'>
<physics name='1ms' type='{engine_type}'>
<max_step_size>0.001</max_step_size>
<real_time_factor>1.0</real_time_factor>
<real_time_update_rate>1000</real_time_update_rate>
</physics>
<plugin
name='ignition::gazebo::systems::Physics' filename='ignition-gazebo-physics-system' />
<plugin
name='ignition::gazebo::systems::UserCommands'
filename='ignition-gazebo-user-commands-system' />
<plugin
name='ignition::gazebo::systems::SceneBroadcaster'
filename='ignition-gazebo-scene-broadcaster-system' />
<plugin
name='ignition::gazebo::systems::Contact' filename='ignition-gazebo-contact-system' />
<plugin
name="ignition::gazebo::systems::Sensors" filename="ignition-gazebo-sensors-system">
<render_engine>ogre2</render_engine>
</plugin>
<gravity>{gravity_x} {gravity_y} {gravity_z}</gravity>
<magnetic_field>6e-06
2.3e-05 -4.2e-05</magnetic_field>
<atmosphere type='adiabatic' />
<scene>
<ambient>0.4 0.4 0.4 1</ambient>
<background>0.7 0.7 0.7 1</background>
<shadows>false</shadows>
</scene>
<gui fullscreen="0">
<plugin filename="GzScene3D" name="3D View">
<ignition-gui>
<title>3D View</title>
<property type="bool" key="showTitleBar">false</property>
<property type="string" key="state">docked</property>
</ignition-gui>
<engine>ogre2</engine>
<scene>scene</scene>
<ambient_light>1.0 1.0 1.0</ambient_light>
<background_color>0.4 0.6 1.0</background_color>
<camera_pose>3.3 2.8 2.8 0 0.5 -2.4</camera_pose>
</plugin>
<plugin filename="WorldStats" name="World stats">
<ignition-gui>
<title>World stats</title>
<property type="bool" key="showTitleBar">false</property>
<property type="bool" key="resizable">false</property>
<property type="double" key="height">110</property>
<property type="double" key="width">290</property>
<property type="double" key="z">1</property>
<property type="string" key="state">floating</property>
<anchors target="3D View">
<line own="right" target="right" />
<line own="bottom" target="bottom" />
</anchors>
</ignition-gui>
<sim_time>true</sim_time>
<real_time>true</real_time>
<real_time_factor>true</real_time_factor>
<iterations>true</iterations>
</plugin>
</gui>
<light type="directional" name="sun">
<cast_shadows>true</cast_shadows>
<pose>0 0 10 0 0 0</pose>
<diffuse>0.8 0.8 0.8 1</diffuse>
<specular>0.2 0.2 0.2 1</specular>
<attenuation>
<range>1000</range>
<constant>0.9</constant>
<linear>0.01</linear>
<quadratic>0.001</quadratic>
</attenuation>
<direction>-0.5 0.1 -0.9</direction>
</light>
<model name='ground'>
<static>true</static>
<link name="link">
<collision name="collision">
<geometry>
<plane>
<normal>0 0 1</normal>
</plane>
</geometry>
</collision>
<visual name="visual">
<geometry>
<plane>
<normal>0 0 1</normal>
<size>100 100</size>
</plane>
</geometry>
<material>
<ambient>0.8 0.8 0.8 1</ambient>
<diffuse>0.8 0.8 0.8 1</diffuse>
<specular>0.8 0.8 0.8 1</specular>
</material>
</visual>
</link>
</model>
{models} </world>
</sdf>

View file

@ -0,0 +1,394 @@
from dataclasses import dataclass
import os
from returns.result import Result, Success, Failure
from typing import Optional, Any, List, TypeVar, Callable, Type, cast
from enum import Enum
from repository.file_system import FileSystemRepository
T = TypeVar("T")
EnumT = TypeVar("EnumT", bound=Enum)
def from_float(x: Any) -> float:
assert isinstance(x, (float, int)) and not isinstance(x, bool)
return float(x)
def from_none(x: Any) -> Any:
return x
def from_union(fs, x):
for f in fs:
try:
return f(x)
except:
pass
assert False
def to_float(x: Any) -> float:
assert isinstance(x, float)
return x
def from_str(x: Any) -> str:
assert isinstance(x, str)
return x
def from_int(x: Any) -> int:
assert isinstance(x, int) and not isinstance(x, bool)
return x
def from_list(f: Callable[[Any], T], x: Any) -> List[T]:
assert isinstance(x, list)
return [f(y) for y in x]
def to_class(c: Type[T], x: Any) -> dict:
assert isinstance(x, c)
return cast(Any, x).to_dict()
def to_enum(c: Type[EnumT], x: Any) -> EnumT:
assert isinstance(x, c)
return x.value
@dataclass
class Model:
name: Optional[str] = None
id: Optional[str] = None
path: Optional[str] = None
@staticmethod
def from_dict(obj: Any) -> "Model":
assert isinstance(obj, dict)
name = from_union([from_str, from_none], obj.get("name"))
id = from_union([from_str, from_none], obj.get("id"))
path = from_union([from_str, from_none], obj.get("path"))
return Model(name, id, path)
def to_dict(self) -> dict:
result: dict = {}
if self.name is not None:
result["name"] = from_union([from_str, from_none], self.name)
if self.id is not None:
result["id"] = from_union([from_str, from_none], self.id)
if self.path is not None:
result["path"] = from_union([from_str, from_none], self.path)
return result
@dataclass
class Pose:
x: Optional[float] = None
y: Optional[float] = None
z: Optional[float] = None
roll: Optional[float] = None
pitch: Optional[float] = None
yaw: Optional[float] = None
@staticmethod
def from_dict(obj: Any) -> "Pose":
assert isinstance(obj, dict)
x = from_union([from_float, from_none], obj.get("x"))
y = from_union([from_float, from_none], obj.get("y"))
z = from_union([from_float, from_none], obj.get("z"))
roll = from_union([from_float, from_none], obj.get("roll"))
pitch = from_union([from_float, from_none], obj.get("pitch"))
yaw = from_union([from_float, from_none], obj.get("yaw"))
return Pose(x, y, z, roll, pitch, yaw)
def to_dict(self) -> dict:
result: dict = {}
if self.x is not None:
result["x"] = from_union([to_float, from_none], self.x)
if self.y is not None:
result["y"] = from_union([to_float, from_none], self.y)
if self.z is not None:
result["z"] = from_union([to_float, from_none], self.z)
if self.roll is not None:
result["roll"] = from_union([to_float, from_none], self.roll)
if self.pitch is not None:
result["pitch"] = from_union([to_float, from_none], self.pitch)
if self.yaw is not None:
result["yaw"] = from_union([to_float, from_none], self.yaw)
return result
class TypeEnum(Enum):
ASSET = "asset"
LIGHT = "light"
@dataclass
class Instance:
model_name: Optional[str] = None
model_id: Optional[str] = None
id: Optional[str] = None
pose: Optional[Pose] = None
scale: Optional[int] = None
type: Optional[TypeEnum] = None
parent: Optional[str] = None
light_type: Optional[str] = None
intencity: Optional[int] = None
diffuse: Optional[List[float]] = None
spot_angle: Optional[int] = None
@staticmethod
def from_dict(obj: Any) -> "Instance":
assert isinstance(obj, dict)
model_name = from_union([from_str, from_none], obj.get("model_name"))
model_id = from_union([from_str, from_none], obj.get("model_id"))
id = from_union([from_str, from_none], obj.get("id"))
pose = from_union([Pose.from_dict, from_none], obj.get("pose"))
scale = from_union([from_int, from_none], obj.get("scale"))
type = from_union([TypeEnum, from_none], obj.get("type"))
parent = from_union([from_str, from_none], obj.get("parent"))
light_type = from_union([from_str, from_none], obj.get("light_type"))
intencity = from_union([from_int, from_none], obj.get("intencity"))
diffuse = from_union(
[lambda x: from_list(from_float, x), from_none], obj.get("diffuse")
)
spot_angle = from_union([from_int, from_none], obj.get("spot_angle"))
return Instance(
model_name,
model_id,
id,
pose,
scale,
type,
parent,
light_type,
intencity,
diffuse,
spot_angle,
)
def fromMappingInstanceAtModel(
self, models: List[Model]
) -> "MappingInstanceAtModel":
for el in models:
if el.id == self.model_id:
return MappingInstanceAtModel(instance=self, model=el)
return Failure("not found model at {self.model_id} ")
def to_dict(self) -> dict:
result: dict = {}
if self.model_name is not None:
result["model_name"] = from_union([from_str, from_none], self.model_name)
if self.model_id is not None:
result["model_id"] = from_union([from_str, from_none], self.model_id)
if self.id is not None:
result["id"] = from_union([from_str, from_none], self.id)
if self.pose is not None:
result["pose"] = from_union(
[lambda x: to_class(Pose, x), from_none], self.pose
)
if self.scale is not None:
result["scale"] = from_union([from_int, from_none], self.scale)
if self.type is not None:
result["type"] = from_union(
[lambda x: to_enum(TypeEnum, x), from_none], self.type
)
if self.parent is not None:
result["parent"] = from_union([from_str, from_none], self.parent)
if self.light_type is not None:
result["light_type"] = from_union([from_str, from_none], self.light_type)
if self.intencity is not None:
result["intencity"] = from_union([from_int, from_none], self.intencity)
if self.diffuse is not None:
result["diffuse"] = from_union(
[lambda x: from_list(to_float, x), from_none], self.diffuse
)
if self.spot_angle is not None:
result["spot_angle"] = from_union([from_int, from_none], self.spot_angle)
return result
class BasePose:
def __init__(self, x: float, y: float, z: float, **kwargs):
self.x = x
self.y = y
self.z = z
def toPose(self, sdfXmlMock: str):
return (
sdfXmlMock.replace("{x}", str(self.x))
.replace("{y}", str(self.y))
.replace("{z}", str(self.z))
)
class MappingInstanceAtModel(BasePose):
instance: Instance
model: Model
def __init__(self, instance: Instance, model: Model) -> None:
self.instance = instance
self.model = model
pass
def toSDF(self):
pose = self.instance.pose
match self.instance.type:
case TypeEnum.ASSET:
mock = FileSystemRepository.readFile(
os.path.dirname(os.path.realpath(__file__))
+ "/../mocks/model_include_sdf.xml"
)
# mockPose = self.toPose(mock)
return (
mock.replace("{name}", str(self.model.name))
.replace("{x}", str(pose.x))
.replace("{y}", str(pose.y))
.replace("{z}", str(pose.z))
.replace("{pitch}", str(pose.pitch))
.replace("{yaw}", str(pose.yaw))
.replace("{roll}", str(pose.roll))
.replace("{uri}", str(self.model.path))
)
case TypeEnum.LIGHT:
pathMock = (
os.path.dirname(os.path.realpath(__file__))
+ "/../mocks/light_sdf.xml"
)
return (
FileSystemRepository.readFile(pathMock)
.replace("{x}", str(pose.x))
.replace("{y}", str(pose.y))
.replace("{z}", str(pose.z))
.replace("{pitch}", str(pose.pitch))
.replace("{yaw}", str(pose.yaw))
.replace("{roll}", str(pose.roll))
.replace("{type_light}", str(self.instance.light_type))
.replace("{name_light}", str("132"))
.replace("{r}", self.instance.diffuse[0])
.replace("{g}", self.instance.diffuse[1])
.replace("{b}", self.instance.diffuse[2])
.replace("{a}", self.instance.diffuse[3])
)
@dataclass
class Gravity:
x: Optional[int] = None
y: Optional[int] = None
z: Optional[float] = None
@staticmethod
def from_dict(obj: Any) -> "Gravity":
assert isinstance(obj, dict)
x = from_union([from_int, from_none], obj.get("x"))
y = from_union([from_int, from_none], obj.get("y"))
z = from_union([from_float, from_none], obj.get("z"))
return Gravity(x, y, z)
def to_dict(self) -> dict:
result: dict = {}
if self.x is not None:
result["x"] = from_union([from_int, from_none], self.x)
if self.y is not None:
result["y"] = from_union([from_int, from_none], self.y)
if self.z is not None:
result["z"] = from_union([to_float, from_none], self.z)
return result
@dataclass
class Physics:
engine_name: Optional[str] = None
gravity: Optional[Gravity] = None
@staticmethod
def from_dict(obj: Any) -> "Physics":
assert isinstance(obj, dict)
engine_name = from_union([from_str, from_none], obj.get("engine_name"))
gravity = from_union([Gravity.from_dict, from_none], obj.get("gravity"))
return Physics(engine_name, gravity)
def to_dict(self) -> dict:
result: dict = {}
if self.engine_name is not None:
result["engine_name"] = from_union([from_str, from_none], self.engine_name)
if self.gravity is not None:
result["gravity"] = from_union(
[lambda x: to_class(Gravity, x), from_none], self.gravity
)
return result
def toSDF(self) -> str:
pathMock = os.path.dirname(os.path.realpath(__file__)) + "/../mocks/world.xml"
gravity = self.gravity
return (
FileSystemRepository.readFile(pathMock)
.replace("{gravity_x}", str(gravity.x))
.replace("{gravity_y}", str(gravity.y))
.replace("{gravity_z}", str(gravity.z))
.replace("{engine_type}", str(self.engine_name))
)
@dataclass
class RobossemblerAssets:
models: Optional[List[Model]] = None
instances: Optional[List[Instance]] = None
physics: Optional[Physics] = None
@staticmethod
def from_dict(obj: Any) -> "RobossemblerAssets":
assert isinstance(obj, dict)
models = from_union(
[lambda x: from_list(Model.from_dict, x), from_none], obj.get("models")
)
instances = from_union(
[lambda x: from_list(Instance.from_dict, x), from_none],
obj.get("instances"),
)
physics = from_union([Physics.from_dict, from_none], obj.get("physics"))
return RobossemblerAssets(models, instances, physics)
def to_dict(self) -> dict:
result: dict = {}
if self.models is not None:
result["models"] = from_union(
[lambda x: from_list(lambda x: to_class(Model, x), x), from_none],
self.models,
)
if self.instances is not None:
result["instances"] = from_union(
[lambda x: from_list(lambda x: to_class(Instance, x), x), from_none],
self.instances,
)
if self.physics is not None:
result["physics"] = from_union(
[lambda x: to_class(Physics, x), from_none], self.physics
)
return result
def _getAllAtType(self, type: TypeEnum) -> List[Instance]:
return list(filter(lambda x: x.type == type, self.instances))
def getAllLightInstances(self) -> List[Instance]:
return list(
map(
lambda el: el.fromMappingInstanceAtModel(self.models),
self._getAllAtType(type=TypeEnum.LIGHT),
)
)
def getAllAssetsInstanceAtModel(self) -> List[MappingInstanceAtModel]:
return list(
map(
lambda el: el.fromMappingInstanceAtModel(self.models),
self._getAllAtType(type=TypeEnum.ASSET),
)
)

View file

@ -0,0 +1,25 @@
import json
import os
class FileSystemRepository:
def readJSON(path: str):
return json.loads((open(path)).read())
def writeFile(data, filePath, fileName):
file_to_open = filePath + fileName
f = open(file_to_open, "w", encoding="utf-8", errors="ignore")
f.write(data)
f.close()
def readFile(path: str):
return open(path).read()
def readFilesTypeFolder(pathFolder: str, fileType=".json"):
filesJson = list(
filter(
lambda x: x[-fileType.__len__() :] == fileType, os.listdir(pathFolder)
)
)
return filesJson

View file

@ -0,0 +1,14 @@
import argparse
from usecases.stability_check_usecase import StabilityCheckUseCase
# python3 main.py --aspPath /Users/idontsudo/Desktop/asp-example/
def main():
parser = argparse.ArgumentParser()
parser.add_argument("--aspPath", help="asp folder generation path")
args = parser.parse_args()
StabilityCheckUseCase().call(args.aspPath)
main()

View file

@ -0,0 +1,229 @@
from typing import Any, List, TypeVar, Type, cast, Callable
import numpy as np
import pybullet as p
import time
import pybullet_data
import os
import json
from time import sleep
T = TypeVar("T")
def from_str(x):
assert isinstance(x, str)
return x
def from_float(x: Any) -> float:
assert isinstance(x, (float, int)) and not isinstance(x, bool)
return float(x)
def to_float(x: Any) -> float:
assert isinstance(x, float)
return x
def from_int(x: Any) -> int:
assert isinstance(x, int) and not isinstance(x, bool)
return x
def to_class(c: Type[T], x: Any) -> dict:
assert isinstance(x, c)
return cast(Any, x).to_dict()
def from_list(f: Callable[[Any], T], x: Any) -> List[T]:
assert isinstance(x, list)
return [f(y) for y in x]
class Coords:
x: float
y: float
z: float
def __init__(self, x: float, y: float, z: float) -> None:
self.x = x
self.y = y
self.z = z
@staticmethod
def from_dict(obj: Any) -> "Coords":
assert isinstance(obj, dict)
x = from_float(obj.get("x"))
y = from_float(obj.get("y"))
z = from_float(obj.get("z"))
return Coords(x, y, z)
def to_dict(self) -> dict:
result: dict = {}
result["x"] = to_float(self.x)
result["y"] = to_float(self.y)
result["z"] = to_float(self.z)
return result
class SimulatorStabilityResultModel:
id: str
quaternion: Coords
position: Coords
def __init__(self, id: int, quaternion: Coords, position: Coords) -> None:
self.id = id
self.quaternion = quaternion
self.position = position
@staticmethod
def from_dict(obj: Any) -> "SimulatorStabilityResultModel":
assert isinstance(obj, dict)
id = from_str(obj.get("id"))
quaternion = Coords.from_dict(obj.get("quaternion"))
position = Coords.from_dict(obj.get("position"))
return SimulatorStabilityResultModel(id, quaternion, position)
def to_dict(self) -> dict:
result: dict = {}
result["id"] = from_str(self.id)
result["quaternion"] = to_class(Coords, self.quaternion)
result["position"] = to_class(Coords, self.position)
return result
def SimulatorStabilityModelfromdict(s: Any) -> List[SimulatorStabilityResultModel]:
return from_list(SimulatorStabilityResultModel.from_dict, s)
def SimulatorStabilityModeltodict(x: List[SimulatorStabilityResultModel]) -> Any:
return from_list(lambda x: to_class(SimulatorStabilityResultModel, x), x)
class StabilityCheckUseCase:
def urdfLoader(
self, assembly: list[str], outPath: str, urdfGeneration: dict[str:str]
):
urdfs = []
for assemblyCount in range(len(assembly)):
urdf = urdfGeneration.get(assembly[assemblyCount])
file_to_open = outPath + "/generation/" + str(assemblyCount) + ".urdf"
f = open(file_to_open, "w", encoding="utf-8", errors="ignore")
f.write(urdf)
f.close()
urdfs.append(os.path.abspath(f.name))
return urdfs
def executeSimulation(
self,
assembly: list[str],
outPath: str,
urdfGeneration: dict[str:str],
duration: int,
) -> list["SimulatorStabilityResultModel"]:
p.connect(p.DIRECT)
p.setGravity(0, 0, -10)
p.setAdditionalSearchPath(pybullet_data.getDataPath())
p.loadURDF("plane.urdf")
resultCoords = []
urdfs = self.urdfLoader(
assembly=assembly, urdfGeneration=urdfGeneration, outPath=outPath
)
bulletIds = []
for el in urdfs:
id = p.loadURDF(el)
bulletIds.append(id)
for i in range(duration):
if i + 200 == duration:
inc = 0
for bulletUUID in bulletIds:
pos, rot = p.getBasePositionAndOrientation(bulletUUID)
resultCoords.append(
SimulatorStabilityResultModel(
id=assembly[inc],
quaternion=Coords(x=rot[0], y=rot[1], z=rot[2]),
position=Coords(x=pos[0], y=pos[1], z=pos[2]),
)
)
p.removeBody(bulletUUID)
inc += 1
p.stepSimulation()
time.sleep(1.0 / 240.0)
return resultCoords
def call(self, aspPath: str):
try:
assemblyFolder = aspPath
assemblesStructures = json.loads(
(open(assemblyFolder + "sequences.json")).read()
).get("sequences")
tasks = len(assemblesStructures) * len(assemblesStructures[0])
taskCounter = 0
urdfGeneration = json.loads(
(open(assemblyFolder + "generation/urdf-generation.json")).read()
)
for activeAssemblyNumber in range(len(assemblesStructures)):
pathSaveResultAssemblyFolder = (
aspPath + "stability" + "/" + str(activeAssemblyNumber + 1) + "/"
)
if not os.path.exists(pathSaveResultAssemblyFolder):
os.makedirs(pathSaveResultAssemblyFolder)
for subAssemblyNumber in range(
len(assemblesStructures[activeAssemblyNumber])
):
taskCounter += 1
subAssembly = assemblesStructures[activeAssemblyNumber][
0 : subAssemblyNumber + 1
]
print(subAssembly)
if subAssembly == [
"disk_top",
"disk_middel",
]:
asm = []
for el in subAssembly:
asm.append(el)
resultSimulationStates = self.executeSimulation(
assembly=asm,
outPath=aspPath,
urdfGeneration=urdfGeneration,
duration=1000,
)
pathSaveResultSubAssemblyFolder = (
aspPath
+ "stability"
+ "/"
+ str(activeAssemblyNumber + 1)
+ "/"
+ str(subAssemblyNumber)
+ "/"
)
if not os.path.exists(pathSaveResultSubAssemblyFolder):
os.makedirs(pathSaveResultSubAssemblyFolder)
results = {}
for state in resultSimulationStates:
results[state.id] = state.to_dict()
f = open(
pathSaveResultSubAssemblyFolder
+ "/"
+ "motion_result.json",
"w",
encoding="utf-8",
errors="ignore",
)
f.write(json.dumps(results, ensure_ascii=False, indent=4))
f.close()
percentageOfCompletion = taskCounter / tasks * 100
print("process complete: " + str(percentageOfCompletion) + "%")
except Exception as e:
print(e)

Binary file not shown.

View file

@ -0,0 +1,34 @@
[
{
"Name": "Fastener_Set",
"Type": "fastener_set",
"Parent": "body_down",
"Child": "body_up",
"Fasteners": [
"bolt4",
"bolt",
"bolt2",
"bolt3"
]
},
{
"Name": "Assembly_Sequence",
"Type": "asm_sequence",
"Parent": "body_down",
"Child": "sol_gear"
},
{
"Name": "Clearance_Constraint",
"Type": "clearance",
"PartName": [
"planet_gear002",
"planet_gear005",
"planet_gear004",
"planet_gear003",
"planet_gear",
"output_shaft",
"sol_gear"
],
"MaxClearance": 1.0
}
]

View file

@ -0,0 +1,34 @@
[
{
"Name": "Fastener_Set",
"Type": "fastener_set",
"Parent": "body_down",
"Child": "body_up",
"Fasteners": [
"bolt4",
"bolt",
"bolt2",
"bolt3"
]
},
{
"Name": "Assembly_Sequence",
"Type": "asm_sequence",
"Parent": "body_down",
"Child": "sol_gear"
},
{
"Name": "Clearance_Constraint",
"Type": "clearance",
"PartName": [
"planet_gear002",
"planet_gear005",
"planet_gear004",
"planet_gear003",
"planet_gear",
"output_shaft",
"sol_gear"
],
"MaxClearance": 1.0
}
]

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,10 @@
{
"sequences": [
"body_down",
"sol_gear",
"output_shaft",
"planet_gear",
"planet_gear002"
]
}

BIN
test_models/table_pc.FCStd Normal file

Binary file not shown.

Binary file not shown.

196
train_models/models_dope.py Executable file
View file

@ -0,0 +1,196 @@
"""
NVIDIA from jtremblay@gmail.com
"""
# Networks
import torch
import torch
import torch.nn as nn
import torch.nn.parallel
import torch.utils.data
import torchvision.models as models
class DopeNetwork(nn.Module):
def __init__(
self,
pretrained=False,
numBeliefMap=9,
numAffinity=16,
stop_at_stage=6, # number of stages to process (if less than total number of stages)
):
super(DopeNetwork, self).__init__()
self.stop_at_stage = stop_at_stage
vgg_full = models.vgg19(pretrained=False).features
self.vgg = nn.Sequential()
for i_layer in range(24):
self.vgg.add_module(str(i_layer), vgg_full[i_layer])
# Add some layers
i_layer = 23
self.vgg.add_module(
str(i_layer), nn.Conv2d(512, 256, kernel_size=3, stride=1, padding=1)
)
self.vgg.add_module(str(i_layer + 1), nn.ReLU(inplace=True))
self.vgg.add_module(
str(i_layer + 2), nn.Conv2d(256, 128, kernel_size=3, stride=1, padding=1)
)
self.vgg.add_module(str(i_layer + 3), nn.ReLU(inplace=True))
# print('---Belief------------------------------------------------')
# _2 are the belief map stages
self.m1_2 = DopeNetwork.create_stage(128, numBeliefMap, True)
self.m2_2 = DopeNetwork.create_stage(
128 + numBeliefMap + numAffinity, numBeliefMap, False
)
self.m3_2 = DopeNetwork.create_stage(
128 + numBeliefMap + numAffinity, numBeliefMap, False
)
self.m4_2 = DopeNetwork.create_stage(
128 + numBeliefMap + numAffinity, numBeliefMap, False
)
self.m5_2 = DopeNetwork.create_stage(
128 + numBeliefMap + numAffinity, numBeliefMap, False
)
self.m6_2 = DopeNetwork.create_stage(
128 + numBeliefMap + numAffinity, numBeliefMap, False
)
# print('---Affinity----------------------------------------------')
# _1 are the affinity map stages
self.m1_1 = DopeNetwork.create_stage(128, numAffinity, True)
self.m2_1 = DopeNetwork.create_stage(
128 + numBeliefMap + numAffinity, numAffinity, False
)
self.m3_1 = DopeNetwork.create_stage(
128 + numBeliefMap + numAffinity, numAffinity, False
)
self.m4_1 = DopeNetwork.create_stage(
128 + numBeliefMap + numAffinity, numAffinity, False
)
self.m5_1 = DopeNetwork.create_stage(
128 + numBeliefMap + numAffinity, numAffinity, False
)
self.m6_1 = DopeNetwork.create_stage(
128 + numBeliefMap + numAffinity, numAffinity, False
)
def forward(self, x):
"""Runs inference on the neural network"""
out1 = self.vgg(x)
out1_2 = self.m1_2(out1)
out1_1 = self.m1_1(out1)
if self.stop_at_stage == 1:
return [out1_2], [out1_1]
out2 = torch.cat([out1_2, out1_1, out1], 1)
out2_2 = self.m2_2(out2)
out2_1 = self.m2_1(out2)
if self.stop_at_stage == 2:
return [out1_2, out2_2], [out1_1, out2_1]
out3 = torch.cat([out2_2, out2_1, out1], 1)
out3_2 = self.m3_2(out3)
out3_1 = self.m3_1(out3)
if self.stop_at_stage == 3:
return [out1_2, out2_2, out3_2], [out1_1, out2_1, out3_1]
out4 = torch.cat([out3_2, out3_1, out1], 1)
out4_2 = self.m4_2(out4)
out4_1 = self.m4_1(out4)
if self.stop_at_stage == 4:
return [out1_2, out2_2, out3_2, out4_2], [out1_1, out2_1, out3_1, out4_1]
out5 = torch.cat([out4_2, out4_1, out1], 1)
out5_2 = self.m5_2(out5)
out5_1 = self.m5_1(out5)
if self.stop_at_stage == 5:
return [out1_2, out2_2, out3_2, out4_2, out5_2], [
out1_1,
out2_1,
out3_1,
out4_1,
out5_1,
]
out6 = torch.cat([out5_2, out5_1, out1], 1)
out6_2 = self.m6_2(out6)
out6_1 = self.m6_1(out6)
return [out1_2, out2_2, out3_2, out4_2, out5_2, out6_2], [
out1_1,
out2_1,
out3_1,
out4_1,
out5_1,
out6_1,
]
@staticmethod
def create_stage(in_channels, out_channels, first=False):
"""Create the neural network layers for a single stage."""
model = nn.Sequential()
mid_channels = 128
if first:
padding = 1
kernel = 3
count = 6
final_channels = 512
else:
padding = 3
kernel = 7
count = 10
final_channels = mid_channels
# First convolution
model.add_module(
"0",
nn.Conv2d(
in_channels, mid_channels, kernel_size=kernel, stride=1, padding=padding
),
)
# Middle convolutions
i = 1
while i < count - 1:
model.add_module(str(i), nn.ReLU(inplace=True))
i += 1
model.add_module(
str(i),
nn.Conv2d(
mid_channels,
mid_channels,
kernel_size=kernel,
stride=1,
padding=padding,
),
)
i += 1
# Penultimate convolution
model.add_module(str(i), nn.ReLU(inplace=True))
i += 1
model.add_module(
str(i), nn.Conv2d(mid_channels, final_channels, kernel_size=1, stride=1)
)
i += 1
# Last convolution
model.add_module(str(i), nn.ReLU(inplace=True))
i += 1
model.add_module(
str(i), nn.Conv2d(final_channels, out_channels, kernel_size=1, stride=1)
)
i += 1
return model

29
train_models/rbs_train.py Normal file
View file

@ -0,0 +1,29 @@
"""
rbs_train
Общая задача: web-service pipeline
Реализуемая функция: обучение нейросетевой модели по заданному BOP-датасету
python3 $PYTHON_EDUCATION --path /Users/idontsudo/webservice/server/build/public/7065d6b6-c8a3-48c5-9679-bb8f3a690296 \
--name test1234 --datasetName 32123213
27.04.2024 @shalenikol release 0.1
"""
import argparse
from train_Yolo import train_YoloV8
from train_Dope import train_Dope_i
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--path", required=True, help="Path for dataset")
parser.add_argument("--name", required=True, help="String with result weights name")
parser.add_argument("--datasetName", required=True, help="String with dataset name")
parser.add_argument("--outpath", default="weights", help="Output path for weights")
parser.add_argument("--type", default="ObjectDetection", help="Type of implementation")
parser.add_argument("--epoch", default=3, type=int, help="How many training epochs")
parser.add_argument('--pretrain', action="store_true", help="Use pretraining")
args = parser.parse_args()
if args.type == "ObjectDetection":
train_YoloV8(args.path, args.name, args.datasetName, args.outpath, args.epoch, args.pretrain)
else:
train_Dope_i(args.path, args.name, args.datasetName, args.outpath, args.epoch, args.pretrain)

542
train_models/train_Dope.py Normal file
View file

@ -0,0 +1,542 @@
"""
train_Dope
Общая задача: оценка позиции объекта (Pose estimation)
Реализуемая функция: обучение нейросетевой модели DOPE по заданному BOP-датасету
python3 $PYTHON_EDUCATION --path /Users/user/webservice/server/build/public/7065d6b6-c8a3-48c5-9679-bb8f3a690296 \
--name test1234 --datasetName 32123213
08.05.2024 @shalenikol release 0.1
"""
import os
import json
import shutil
import numpy as np
import transforms3d as t3d
FILE_RBS_INFO = "rbs_info.json"
FILE_CAMERA = "camera.json"
FILE_GT = "scene_gt.json"
FILE_GT_COCO = "scene_gt_coco.json"
FILE_GT_INFO = "scene_gt_info.json"
FILE_MODEL = "epoch"
EXT_MODEL = ".pth"
EXT_RGB = "jpg"
DIR_ROOT_DS = "dataset_dope"
DIR_TRAIN_OUT = "out_weights"
MODEL_SCALE = 1000 # исходная модель в метрах, преобразуем в мм (для DOPE)
# Own_Numbering_Files = True # наименование image-файлов: собственная нумерация
nn_image = 0
K_intrinsic = []
model_info = []
camera_data = {}
im_width = 0
nb_update_network = 0
# [
# [min(x), min(y), min(z)],
# [min(x), max(y), min(z)],
# [min(x), max(y), max(z)],
# [min(x), min(y), max(z)],
# [max(x), min(y), max(z)],
# [max(x), max(y), min(z)],
# [max(x), max(y), max(z)],
# [max(x), min(y), max(z)],
# [xc, yc, zc] # min + (max - min) / 2
# ]
def trans_3Dto2D_point_in_camera(xyz, K_m, R_m2c, t_m2c):
"""
xyz : 3D-координаты точки
K_m : внутренняя матрица камеры 3х3
R_m2c : матрица поворота 3х3
t_m2c : вектор перемещения 3х1
return [u,v]
"""
K = np.array(K_m)
r = np.array(R_m2c)
r.shape = (3, 3)
t = np.array(t_m2c)
t.shape = (3, 1)
T = np.concatenate((r, t), axis=1)
P_m = np.array(xyz)
P_m.resize(4)
P_m[-1] = 1.0
P_m.shape = (4, 1)
# Project (X, Y, Z, 1) into cameras coordinate system
P_c = T @ P_m # 4x1
# Apply camera intrinsics to map (Xc, Yc, Zc) to p=(x, y, z)
p = K @ P_c
# Normalize by z to get (u,v,1)
uv = (p / p[2][0])[:-1]
return uv.flatten().tolist()
def gt_parse(path: str, out_dir: str):
global nn_image
with open(os.path.join(path, FILE_GT_COCO), "r") as fh:
coco_data = json.load(fh)
with open(os.path.join(path, FILE_GT), "r") as fh:
gt_data = json.load(fh)
with open(os.path.join(path, FILE_GT_INFO), "r") as fh:
gt_info = json.load(fh)
for img in coco_data["images"]:
rgb_file = os.path.join(path, img["file_name"])
if os.path.isfile(rgb_file):
# if Own_Numbering_Files:
ext = os.path.splitext(rgb_file)[1] # only ext
f = f"{nn_image:06}"
out_img = os.path.join(out_dir, f + ext)
# else:
# f = os.path.split(rgb_file)[1] # filename with extension
# f = os.path.splitext(f)[0] # only filename
# out_img = out_dir
shutil.copy2(rgb_file, out_img)
out_file = os.path.join(out_dir,f+".json")
nn_image += 1
# full annotation of the one image
all_data = camera_data.copy()
cat_names = {obj["id"]: obj["name"] for obj in coco_data["categories"]}
id_img = img["id"] # 0, 1, 2 ...
sid_img = str(id_img) # "0", "1", "2" ...
img_info = gt_info[sid_img]
img_gt = gt_data[sid_img]
img_idx = 0 # object index on the image
objs = []
for ann in coco_data["annotations"]:
if ann["image_id"] == id_img:
item = ann["category_id"]
obj_data = {}
obj_data["class"] = cat_names[item]
x, y, width, height = ann["bbox"]
obj_data["bounding_box"] = {"top_left":[x,y], "bottom_right":[x+width,y+height]}
# visibility from FILE_GT_INFO
item_info = img_info[img_idx]
obj_data["visibility"] = item_info["visib_fract"]
# location from FILE_GT
item_gt = img_gt[img_idx]
obj_id = item_gt["obj_id"] - 1 # index with 0
cam_R_m2c = item_gt["cam_R_m2c"]
cam_t_m2c = item_gt["cam_t_m2c"]
obj_data["location"] = cam_t_m2c
q = t3d.quaternions.mat2quat(np.array(cam_R_m2c))
obj_data["quaternion_xyzw"] = [q[1], q[2], q[3], q[0]]
cuboid_xyz = model_info[obj_id]
obj_data["projected_cuboid"] = [
trans_3Dto2D_point_in_camera(cub, K_intrinsic, cam_R_m2c, cam_t_m2c)
for cub in cuboid_xyz
]
objs.append(obj_data)
img_idx += 1
all_data["objects"] = objs
with open(out_file, "w") as fh:
json.dump(all_data, fh, indent=2)
def explore(path: str, res_dir: str):
if not os.path.isdir(path):
return
folders = [
os.path.join(path, o)
for o in os.listdir(path)
if os.path.isdir(os.path.join(path, o))
]
for path_entry in folders:
if os.path.isfile(os.path.join(path_entry,FILE_GT_COCO)) and \
os.path.isfile(os.path.join(path_entry,FILE_GT_INFO)) and \
os.path.isfile(os.path.join(path_entry,FILE_GT)):
gt_parse(path_entry, res_dir)
else:
explore(path_entry, res_dir)
def BOP2DOPE_dataset(dpath: str, out_dir: str) -> str:
""" Convert BOP-dataset to YOLO format for train """
res_dir = os.path.join(out_dir, DIR_ROOT_DS)
if os.path.isdir(res_dir):
shutil.rmtree(res_dir)
os.mkdir(res_dir)
explore(dpath, res_dir)
return out_dir
def train(dopepath:str, wname:str, epochs:int, pretrain: bool, lname: list):
import random
# try:
import configparser as configparser
# except ImportError:
# import ConfigParser as configparser
import torch
# import torch.nn.parallel
import torch.optim as optim
import torch.utils.data
import torchvision.transforms as transforms
from torch.autograd import Variable
import datetime
from tensorboardX import SummaryWriter
from models_dope import DopeNetwork
from utils_dope import CleanVisiiDopeLoader #, VisualizeBeliefMap, save_image
import warnings
warnings.filterwarnings("ignore")
os.environ["CUDA_VISIBLE_DEVICES"] = "0,1,2,3,4,5,6,7"
torch.autograd.set_detect_anomaly(False)
torch.autograd.profiler.profile(False)
torch.autograd.gradcheck = False
torch.backends.cudnn.benchmark = True
start_time = datetime.datetime.now()
print("start:", start_time.strftime("%m/%d/%Y, %H:%M:%S"))
res_model = os.path.join(dopepath, wname + EXT_MODEL)
local_rank = 0
opt = lambda: None
opt.use_s3 = False
opt.train_buckets = []
opt.endpoint = None
opt.lr=0.0001
opt.loginterval=100
opt.sigma=0.5 # 4
opt.nbupdates=None
# opt.save=False
# opt.option="default"
# opt.gpuids=[0]
opt.namefile=FILE_MODEL
opt.workers=8
opt.batchsize=16
opt.data = [os.path.join(dopepath, DIR_ROOT_DS)]
opt.outf = os.path.join(dopepath, DIR_TRAIN_OUT)
opt.object = lname #["fork"]
opt.exts = [EXT_RGB]
# opt.imagesize = im_width
opt.epochs = epochs
opt.pretrained = pretrain
opt.net_path = res_model if pretrain else None
opt.manualseed = random.randint(1, 10000)
# # Validate Arguments
# if opt.use_s3 and (opt.train_buckets is None or opt.endpoint is None):
# raise ValueError(
# "--train_buckets and --endpoint must be specified if training with data from s3 bucket."
# )
# if not opt.use_s3 and opt.data is None:
# raise ValueError("--data field must be specified.")
os.makedirs(opt.outf, exist_ok=True)
# if local_rank == 0:
# writer = SummaryWriter(opt.outf + "/runs/")
random.seed(opt.manualseed)
torch.cuda.set_device(local_rank)
# torch.distributed.init_process_group(backend="nccl", init_method="env://")
torch.manual_seed(opt.manualseed)
torch.cuda.manual_seed_all(opt.manualseed)
# # Data Augmentation
# if not opt.save:
# contrast = 0.2
# brightness = 0.2
# noise = 0.1
# normal_imgs = [0.59, 0.25]
# transform = transforms.Compose(
# [
# AddRandomContrast(0.2),
# AddRandomBrightness(0.2),
# transforms.Resize(opt.imagesize),
# ]
# )
# else:
# contrast = 0.00001
# brightness = 0.00001
# noise = 0.00001
# normal_imgs = None
# transform = transforms.Compose(
# [transforms.Resize(opt.imagesize), transforms.ToTensor()]
# )
# Load Model
net = DopeNetwork()
output_size = 50
# opt.sigma = 0.5
train_dataset = CleanVisiiDopeLoader(
opt.data,
sigma=opt.sigma,
output_size=output_size,
extensions=opt.exts,
objects=opt.object,
use_s3=opt.use_s3,
buckets=opt.train_buckets,
endpoint_url=opt.endpoint,
)
trainingdata = torch.utils.data.DataLoader(
train_dataset,
batch_size=opt.batchsize,
shuffle=True,
num_workers=opt.workers,
pin_memory=True,
)
if not trainingdata is None:
print(f"training data: {len(trainingdata)} batches")
print("Loading Model...")
net = net.cuda()
# net = torch.nn.parallel.DistributedDataParallel(
# net.cuda(), device_ids=[local_rank], output_device=local_rank
# )
if opt.pretrained:
if opt.net_path is not None:
net.load_state_dict(torch.load(opt.net_path))
else:
print("Error: Did not specify path to pretrained weights.")
quit()
parameters = filter(lambda p: p.requires_grad, net.parameters())
optimizer = optim.Adam(parameters, lr=opt.lr)
print("ready to train!")
global nb_update_network
nb_update_network = 0
# best_results = {"epoch": None, "passed": None, "add_mean": None, "add_std": None}
scaler = torch.cuda.amp.GradScaler()
def _runnetwork(epoch, train_loader): #, syn=False
global nb_update_network
# net
net.train()
loss_avg_to_log = {}
loss_avg_to_log["loss"] = []
loss_avg_to_log["loss_affinities"] = []
loss_avg_to_log["loss_belief"] = []
loss_avg_to_log["loss_class"] = []
for batch_idx, targets in enumerate(train_loader):
optimizer.zero_grad()
data = Variable(targets["img"].cuda())
target_belief = Variable(targets["beliefs"].cuda())
target_affinities = Variable(targets["affinities"].cuda())
output_belief, output_aff = net(data)
loss = None
loss_belief = torch.tensor(0).float().cuda()
loss_affinities = torch.tensor(0).float().cuda()
loss_class = torch.tensor(0).float().cuda()
for stage in range(len(output_aff)): # output, each belief map layers.
loss_affinities += (
(output_aff[stage] - target_affinities)
* (output_aff[stage] - target_affinities)
).mean()
loss_belief += (
(output_belief[stage] - target_belief)
* (output_belief[stage] - target_belief)
).mean()
loss = loss_affinities + loss_belief
# if batch_idx == 0:
# post = "train"
# if local_rank == 0:
# for i_output in range(1):
# # input images
# writer.add_image(
# f"{post}_input_{i_output}",
# targets["img_original"][i_output],
# epoch,
# dataformats="CWH",
# )
# # belief maps gt
# imgs = VisualizeBeliefMap(target_belief[i_output])
# img, grid = save_image(
# imgs, "some_img.png", mean=0, std=1, nrow=3, save=False
# )
# writer.add_image(
# f"{post}_belief_ground_truth_{i_output}",
# grid,
# epoch,
# dataformats="CWH",
# )
# # belief maps guess
# imgs = VisualizeBeliefMap(output_belief[-1][i_output])
# img, grid = save_image(
# imgs, "some_img.png", mean=0, std=1, nrow=3, save=False
# )
# writer.add_image(
# f"{post}_belief_guess_{i_output}",
# grid,
# epoch,
# dataformats="CWH",
# )
loss.backward()
optimizer.step()
nb_update_network += 1
# log the loss
loss_avg_to_log["loss"].append(loss.item())
loss_avg_to_log["loss_class"].append(loss_class.item())
loss_avg_to_log["loss_affinities"].append(loss_affinities.item())
loss_avg_to_log["loss_belief"].append(loss_belief.item())
if batch_idx % opt.loginterval == 0:
print(
"Train Epoch: {} [{}/{} ({:.0f}%)] \tLoss: {:.15f} \tLocal Rank: {}".format(
epoch,
batch_idx * len(data),
len(train_loader.dataset),
100.0 * batch_idx / len(train_loader),
loss.item(),
local_rank,
)
)
# # log the loss values
# if local_rank == 0:
# writer.add_scalar("loss/train_loss", np.mean(loss_avg_to_log["loss"]), epoch)
# writer.add_scalar("loss/train_cls", np.mean(loss_avg_to_log["loss_class"]), epoch)
# writer.add_scalar("loss/train_aff", np.mean(loss_avg_to_log["loss_affinities"]), epoch)
# writer.add_scalar("loss/train_bel", np.mean(loss_avg_to_log["loss_belief"]), epoch)
for epoch in range(1, opt.epochs + 1):
_runnetwork(epoch, trainingdata)
try:
if local_rank == 0:
torch.save(
net.state_dict(),
f"{opt.outf}/{opt.namefile}_{str(epoch).zfill(3)}.pth",
)
except Exception as e:
print(f"Encountered Exception: {e}")
if not opt.nbupdates is None and nb_update_network > int(opt.nbupdates):
break
# if local_rank == 0:
# save result model
torch.save(net.state_dict(), res_model) #os.path.join(dopepath, wname + EXT_MODEL))
# else:
# torch.save(
# net.state_dict(),
# f"{opt.outf}/{opt.namefile}_{str(epoch).zfill(3)}_rank_{local_rank}.pth",
# )
print("end:", datetime.datetime.now().strftime("%m/%d/%Y, %H:%M:%S"))
print("Total time taken: ", str(datetime.datetime.now() - start_time).split(".")[0])
def train_Dope_i(path:str, wname:str, dname:str, outpath:str, epochs:int, pretrain: bool):
""" Main procedure for train DOPE model """
global K_intrinsic, model_info, camera_data, im_width
if not os.path.isdir(outpath):
print(f"Invalid output path '{outpath}'")
exit(-1)
out_dir = os.path.join(outpath, wname)
ds_path = os.path.join(path, dname)
if not os.path.isdir(ds_path):
print(f"{ds_path} : no BOP directory")
return ""
camera_json = os.path.join(ds_path, FILE_CAMERA)
if not os.path.isfile(camera_json):
print(f"{camera_json} : no intrinsic camera file")
return ""
rbs_info = os.path.join(ds_path, FILE_RBS_INFO)
if not os.path.isfile(rbs_info):
print(f"{rbs_info} : no dataset info file")
return ""
camera_data = {}
with open(camera_json, "r") as fh:
data = json.load(fh)
keys = ["cx","cy","fx","fy"]
intrinsic = {k: data[k] for k in keys}
im_height = data["height"]
im_width = data["width"]
camera_data["camera_data"] = dict(intrinsic=intrinsic, height=im_height, width=im_width)
K_intrinsic = [
[data["fx"], 0.0, data["cx"]],
[0.0, data["fy"], data["cy"]],
[0.0, 0.0, 1.0]
]
# calc cuboid + center
with open(rbs_info, "r") as fh:
info = json.load(fh)
# список имён объектов
list_name = list(map(lambda x: x["name"], info))
# in FILE_RBS_INFO model numbering from smallest to largest
model_info = []
for m_info in info:
cub = np.array(m_info["cuboid"]) * MODEL_SCALE
xyz_min = cub.min(axis=0)
xyz_max = cub.max(axis=0)
# [xc, yc, zc] # min + (max - min) / 2
center = []
for i in range(3):
center.append(xyz_min[i] + (xyz_max[i]- xyz_min[i]) / 2)
c = np.array(center, ndmin=2)
model_info.append(np.append(cub, c, axis=0))
if pretrain:
# продолжить обучение
if not os.path.isdir(out_dir):
print(f"No dir '{out_dir}'")
exit(-2)
dpath = out_dir
# model_path = os.path.join(dpath, wname + ".pt")
else:
# обучение сначала
if not os.path.isdir(out_dir):
os.mkdir(out_dir)
dpath = BOP2DOPE_dataset(ds_path, out_dir)
if len(dpath) == 0:
print(f"Error in convert dataset '{ds_path}' to '{outpath}'")
exit(-4)
# model_path = os.path.join(dpath, FILE_BASEMODEL)
# results = f"python train.py --local_rank 0 --data {dpath} --object fork" \
# + f" -e {epochs} --batchsize 16 --exts jpg --imagesize 640 --pretrained" \
# + " --net_path /home/shalenikol/fork_work/dope_training/output/weights_2996/net_epoch_47.pth"
# print(results)
train(dpath, wname, epochs, pretrain, list_name)
import argparse
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--path", required=True, help="Path for dataset")
parser.add_argument("--name", required=True, help="String with result weights name")
parser.add_argument("--datasetName", required=True, help="String with dataset name")
parser.add_argument("--outpath", default="weights", help="Output path for weights")
parser.add_argument("--epoch", default=3, help="How many training epochs")
parser.add_argument('--pretrain', action="store_true", help="Use pretraining")
args = parser.parse_args()
train_Dope_i(args.path, args.name, args.datasetName, args.outpath, args.epoch, args.pretrain)

Some files were not shown because too many files have changed in this diff Show more