Compare commits
136 commits
Author | SHA1 | Date | |
---|---|---|---|
dc59211634 | |||
649a426c25 | |||
69b8512d6b | |||
82f7a7233d | |||
f4f56e53a8 | |||
03f8b86877 | |||
![]() |
045e157266 | ||
8d9f913cbc | |||
![]() |
05b1963a34 | ||
8fa9076f91 | |||
bd0a9865a1 | |||
9a7d6b9084 | |||
946e83fd15 | |||
![]() |
362e0f7a6f | ||
![]() |
e396b0c01e | ||
![]() |
a58dcdafb1 | ||
037827669a | |||
![]() |
31f5810bef | ||
![]() |
8aeb802ec8 | ||
![]() |
0ecf214e26 | ||
![]() |
3878990c4e | ||
![]() |
df0fb32592 | ||
![]() |
b80db52ea5 | ||
![]() |
8401cc51fa | ||
![]() |
cc538b719f | ||
![]() |
fe797ebeeb | ||
![]() |
871d9d735e | ||
![]() |
bce317a554 | ||
![]() |
6c7e8c46d6 | ||
![]() |
c27b99ff52 | ||
![]() |
e02bab244d | ||
![]() |
db3e0d1273 | ||
![]() |
fd59ab9e26 | ||
![]() |
d2ab856d64 | ||
![]() |
c64bbf4a70 | ||
![]() |
021e5862ff | ||
![]() |
e305d486f2 | ||
![]() |
b77687ea14 | ||
![]() |
679a52a041 | ||
![]() |
b3612d8655 | ||
![]() |
6538f70d54 | ||
![]() |
a1a961e7a7 | ||
![]() |
d9d07b33b1 | ||
![]() |
10d5ed451a | ||
![]() |
9222104a1a | ||
![]() |
25c9cbfbe9 | ||
90945c0430 | |||
![]() |
184ac7df88 | ||
![]() |
03bc34539c | ||
![]() |
78e31ea49c | ||
![]() |
80e3c58913 | ||
![]() |
64b80be028 | ||
![]() |
ea742b26d7 | ||
![]() |
c1e7882cbb | ||
![]() |
502e7a8d76 | ||
![]() |
70e268c455 | ||
![]() |
33dd320858 | ||
![]() |
12482ff40f | ||
![]() |
9eaf12a4fa | ||
![]() |
8dfbe38878 | ||
![]() |
5239e6d091 | ||
![]() |
247c84d718 | ||
![]() |
c1e4b0e0f0 | ||
23edfea360 | |||
![]() |
839ce36c70 | ||
![]() |
9fa936cfba | ||
![]() |
a38c3bec5a | ||
![]() |
47773be8d4 | ||
![]() |
1fb7077774 | ||
![]() |
6560a4359d | ||
![]() |
45e0d29ea0 | ||
![]() |
7cadf0741f | ||
![]() |
e65236aab6 | ||
![]() |
7f13c0056f | ||
![]() |
b744fe30a0 | ||
![]() |
5208577d86 | ||
![]() |
16f6f375b5 | ||
![]() |
b376c78e3b | ||
![]() |
37bdfcd5e9 | ||
![]() |
1ea7e50ecd | ||
![]() |
748fcd1351 | ||
![]() |
3d3a063a5d | ||
![]() |
6fcd2566b5 | ||
12f9caa69c | |||
35223a1af1 | |||
74f1a1493e | |||
![]() |
0c433c10d5 | ||
![]() |
95437a4527 | ||
![]() |
6af0f188a7 | ||
![]() |
d26698d1a6 | ||
![]() |
dada2d9dd5 | ||
![]() |
6e1a26504d | ||
db14ac643e | |||
fff6800d3b | |||
42762512c8 | |||
8bf8235add | |||
32e9b53fad | |||
b2543c3672 | |||
20900e4eba | |||
7f6e9c98aa | |||
3941c7aae6 | |||
8241627436 | |||
e2da384085 | |||
2111b33c75 | |||
b8f1ffc618 | |||
f221e5366e | |||
5a4daa42a2 | |||
2d704442c8 | |||
c410442b98 | |||
![]() |
cf43039dae | ||
![]() |
8547f5884c | ||
![]() |
04c866b60b | ||
![]() |
dd556e1a70 | ||
![]() |
cfd44313a3 | ||
![]() |
e28ff36674 | ||
![]() |
c407cd82b9 | ||
![]() |
06cd9fafb0 | ||
![]() |
d601655fca | ||
![]() |
e7c7796b6b | ||
![]() |
a3ba5dab37 | ||
![]() |
34d528afc5 | ||
![]() |
327955c231 | ||
![]() |
c94427f37c | ||
![]() |
17a91d11d3 | ||
![]() |
a78c3ef73a | ||
![]() |
b6dce011f4 | ||
![]() |
226dd4b34b | ||
![]() |
c1df40b3db | ||
![]() |
251d79e9f8 | ||
![]() |
d8aa4eb76e | ||
![]() |
26e6c96493 | ||
![]() |
4401848d8f | ||
![]() |
83bc0e922b | ||
![]() |
4fc65e3c80 | ||
![]() |
e610313349 | ||
![]() |
23905b1000 |
18
.gitignore
vendored
|
@ -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
|
@ -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
|
752
ARFrames.py
|
@ -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
|
520
ARTools.py
|
@ -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
|
1
Init.py
|
@ -1 +0,0 @@
|
|||
#I made this?
|
39
InitGui.py
|
@ -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())
|
53
README.md
|
@ -1,32 +1,31 @@
|
|||

|
||||
# 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
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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 |
Before Width: | Height: | Size: 101 KiB |
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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 |
15
dataset_generation/cli/README.md
Normal 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)
|
||||
|
41
dataset_generation/cli/dataset_cfg.json
Normal 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"
|
||||
}
|
361
dataset_generation/cli/renderBOPdataset.py
Executable 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())
|
412
dataset_generation/renderBOPdataset2.py
Executable 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())
|
17
docs/framework_debug_3part.md
Normal 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-принтере.
|
||||
|
||||

|
||||
Рис.1
|
||||
|
||||
Когда отлаживался модуль распознавания объектов (Object Detection), выявилась сложность проектирования и отладки этого навыка. Необходимо было кроме основной логики ROS-узла создавать и отлаживать передачу параметров в дереве поведения. И была предложена схема обобщения интерфейса для любых навыков.
|
||||
|
||||

|
||||
|
||||
В ней предположено использовать отдельный интерфейсный узел (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
After Width: | Height: | Size: 166 KiB |
BIN
docs/img/qXX7sBMbsvA.jpg
Normal file
After Width: | Height: | Size: 86 KiB |
BIN
docs/img/scheme1.jpg
Normal file
After Width: | Height: | Size: 46 KiB |
1262
docs/obj_detection_use_case.drawio
Normal file
123
docs/randomization.md
Normal 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
|
@ -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
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
60
docs/Модуль технологической подготовки.md
Normal 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 мы можем (должны ли?) полуавтоматически/автоматически указать подобные состояния, привязанные к значениям да/нет.-- (Указывать стартовые значения по умолчанию?)
|
||||
|
||||
|
||||
Указанные отдельно состояния пригодились бы, чтобы ссылаться на них при задавании действий, поскольку действия сообщаются между собой не напрямую, а через выполнение определенного набора состояний.
|
||||
|
||||
|
||||
|
||||
|
||||
Пример размеченной модели:
|
||||
|
||||

|
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
|
@ -0,0 +1 @@
|
|||
out
|
37
simulation/asp/helper/fs.py
Normal 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
|
877
simulation/asp/helper/xmlformatter.py
Normal 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"&", "&", str)
|
||||
str = re.sub(r"<", "<", 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
|
@ -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,
|
||||
)
|
18
simulation/asp/mocks/Cube1.json
Normal 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"
|
||||
}
|
18
simulation/asp/mocks/Cube2.json
Normal 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"
|
||||
}
|
4
simulation/asp/mocks/sdf/include.sdf
Normal file
|
@ -0,0 +1,4 @@
|
|||
<include>
|
||||
<name>{name}</name>
|
||||
<uri>{uri}</uri>
|
||||
</include>
|
5
simulation/asp/mocks/sdf/include_pose.sdf
Normal file
|
@ -0,0 +1,5 @@
|
|||
<include>
|
||||
<name>{name}</name>
|
||||
<uri>{uri}</uri>
|
||||
<pose>{posX} {posY} {posZ} {eulerX} {eulerY} {eulerZ}</pose>
|
||||
</include>
|
7
simulation/asp/mocks/sdf/joint_fixed.sdf
Normal 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>
|
||||
|
||||
|
36
simulation/asp/mocks/sdf/link.sdf
Normal 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>
|
5
simulation/asp/mocks/sdf/model.config
Normal file
|
@ -0,0 +1,5 @@
|
|||
|
||||
<?xml version="1.0" ?>
|
||||
<model>
|
||||
<sdf version="1.5">model.sdf</sdf>
|
||||
</model>
|
27
simulation/asp/mocks/sdf/model.sdf
Normal 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>
|
64
simulation/asp/mocks/sdf/world.sdf
Normal 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>
|
4
simulation/asp/mocks/urdf/asm.urdf
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<robossembler
|
||||
name="{name}">
|
||||
</robossembler>
|
13
simulation/asp/mocks/urdf/joint.urdf
Normal 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>
|
31
simulation/asp/mocks/urdf/link.urdf
Normal 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>
|
37
simulation/asp/mocks/urdf/model.urdf
Normal 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>
|
5
simulation/asp/requirements.txt
Normal file
|
@ -0,0 +1,5 @@
|
|||
argparse
|
||||
matplotlib
|
||||
pybullet
|
||||
argparse
|
||||
xmlformatter
|
16
simulation/asp/src/model/asm.py
Normal 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)
|
2
simulation/asp/src/model/enum.py
Normal file
|
@ -0,0 +1,2 @@
|
|||
class Enum:
|
||||
folderPath = "generation/"
|
327
simulation/asp/src/model/sdf_geometry.py
Normal 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)
|
||||
)
|
16
simulation/asp/src/model/sdf_join.py
Normal 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)
|
14
simulation/asp/src/usecases/formatter_usecase.py
Normal 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)
|
18
simulation/asp/src/usecases/generate_world.py
Normal 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
|
12
simulation/asp/src/usecases/sdf_generate_world_usecase.py
Normal 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
|
78
simulation/asp/src/usecases/sdf_sub_assembly_usecase.py
Normal 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)
|
30
simulation/asp/src/usecases/urdf_sub_assembly_usecase.py
Normal 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,
|
||||
)
|
116
simulation/insertion_vector_predicate/.gitignore
vendored
Normal 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
|
31
simulation/insertion_vector_predicate/README.md
Normal 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
|
||||
```
|
1
simulation/insertion_vector_predicate/assembly
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit 29db7df4d7f2e6055f3f26fc5c11a424954f7308
|
205
simulation/insertion_vector_predicate/generate.py
Normal 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()
|
174
simulation/insertion_vector_predicate/main.py
Normal 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()
|
3
simulation/insertion_vector_predicate/requirements.txt
Normal file
|
@ -0,0 +1,3 @@
|
|||
spatialmath
|
||||
scipy
|
||||
uuid
|
37
simulation/intersection_geometry_predicate/README.md
Normal 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
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
```
|
86
simulation/intersection_geometry_predicate/main.py
Normal 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()
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
argparse
|
||||
trimesh
|
97
simulation/robossembler_scene_builder/main.py
Normal 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()
|
12
simulation/robossembler_scene_builder/mocks/light_sdf.xml
Normal 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>
|
|
@ -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>
|
105
simulation/robossembler_scene_builder/mocks/world.xml
Normal 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>
|
|
@ -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),
|
||||
)
|
||||
)
|
|
@ -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
|
14
simulation/stability_process_predicate/main.py
Normal 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()
|
|
@ -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)
|
BIN
test_models/asm_reductor.FCStd
Normal file
34
test_models/assembly_settings.json
Normal 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
|
||||
}
|
||||
]
|
34
test_models/assembly_settings_test_reductor.json
Normal 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
|
||||
}
|
||||
]
|
BIN
test_models/crux_hotend.FCStd
Normal file
BIN
test_models/desk_table.FCStd
Normal file
10
test_models/sequences.json
Normal file
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"sequences": [
|
||||
|
||||
"body_down",
|
||||
"sol_gear",
|
||||
"output_shaft",
|
||||
"planet_gear",
|
||||
"planet_gear002"
|
||||
]
|
||||
}
|
BIN
test_models/table_pc.FCStd
Normal file
BIN
test_models/test_reductor.FCStd
Normal file
196
train_models/models_dope.py
Executable 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
|
@ -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
|
@ -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)
|