Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@ __pycache__
notes.txt
.vscode
test.py
out.xml
out.xml
fnrpl.sh
TODO.txt
4 changes: 2 additions & 2 deletions InitGui.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ def Initialize(self):
__dirname__ = os.path.join(FreeCAD.getUserAppDataDir(), "Mod", "RobotDescriptor")
#print("got dir:" + __dirname__);

from robot_descriptor import initialize
from robot_descriptor import initialize ,model_editor
from robot_descriptor.sdf_elements import world
self.list = ['RD_initialize','world_properties']
self.list = ['RD_initialize','world_properties','Model_Editor']
self.appendToolbar("RobotDescription",self.list) # creates a new toolbar with your commands
self.appendMenu("Robot Description",self.list) # creates a new menu
#self.appendMenu(["Robot Description","Tools"],self.list) # appends a submenu to an existing menu
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import xml.etree.ElementTree as ET
import os
from .. import RD_globals
from .. import common



Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

from .. import RD_globals
from .. import common

from . import RD_parse_sdf

Expand Down Expand Up @@ -63,7 +63,7 @@ def get_element(self)->ET.Element:
t=convdict_2_tree("world.sdf")
tree=t.get_tree
elm=t.get_elements
e_elem=RD_globals.set_xml_data('linear_velocity',elm,False,[12,9,8])
e_elem=common.set_xml_data('linear_velocity',elm,False,[12,9,8])
e_elem_t=ET.ElementTree(e_elem)
tree.write("out.xml",encoding='utf8',xml_declaration=True)
e_elem_t.write("out.xml",encoding='utf8',xml_declaration=True)
98 changes: 98 additions & 0 deletions robot_descriptor/RD_utils/parse_asm4_model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import FreeCAD
import FreeCADGui
import robot_descriptor.common as common
import os

'''
assembly4 Technical manual
https://github.com/Zolko-123/FreeCAD_Assembly4/blob/master/TECHMANUAL.md

'''

def read_assembly():
links=FreeCAD.ActiveDocument.findObjects("App::Link")

#get all objects of type part feature
objs=FreeCAD.ActiveDocument.findObjects("Part::Feature")
#get objects in the parts group
parts=FreeCAD.ActiveDocument.Parts.Group
#get fasteners since fasteners might not be accesed through links
#remove objects in parts , coordinate systems
#coordinate systems are removed by checking the MapMode attribute
#hopefully this is will get only fasteners
fasteners=[fast for fast in objs if fast not in parts and not hasattr(fast,'MapMode')]

#ensure that the link and the fastener are not the same object
#this might occur when the parts folder contains some parts that are used in the assembly
#get link documents
lnk_docs=[lnk.LinkedObject.Document for lnk in links]
for fastener in fasteners:
if fastener.Document not in lnk_docs:
links.append(fastener)

#links in Assembly4 are of type "App::Link"
#this is a list
#this will store a list of dictionaries
def create_structure(data,dest):
#check the parent objects
#since data is a list of dictionaries
#for every element int he list check if its parent is dest
children=[child for child in data if child["parent"]==dest["name"]]
#return of no children are found
if len (children)==0:
return
#append the children to the current item
for ch in children:
dest["children"].append(ch)
create_structure(data,ch)


link_data=[]
#create the root parent
structured_data={}

#links that have been iterated and not references
non_refs=[]
for child in links:

name=child.Label
#attachedTo returns a string of the format 'Parent Assembly#LCS_Origin' hence
#hence separating by the the '#' and taking the first element will be the parent
#the 2nd the coordinate system its attached to
parent,attachement=child.AttachedTo.split('#')
#returned type has '#' preceeding the coordinate remove it
attached_by=child.AttachedBy.replace('#','')
if hasattr(child,"LinkedObject") :
#get links which refer to the same document
ref=[r for r in non_refs if r.LinkedObject.Document ==child.LinkedObject.Document]
if len(ref)==1:
#set type as reference i.e its a copy of a link that already exists in the assembly
link_data.append({"ref_label":ref[0].Label,"type":"ref","link":child,"name":name,"parent":parent,"attached_to":attachement,"attached_by":attached_by,'children':[]})
elif len(ref)==0:
link_data.append({"ref_label":None,"type":"link","link":child,"name":name,"parent":parent,"attached_to":attachement,"attached_by":attached_by,'children':[]})
non_refs.append(child)
else:
FreeCAD.Console.PrintDeveloperError("parse_asm4:error getting refs no than 1 were found, this is a bug \n")
return
else:
#add fasterners and other too
link_data.append({"ref_label":None,"type":"link","link":child,"name":name,"parent":parent,"attached_to":attachement,"attached_by":attached_by,'children':[]})

#create a hierarchial data
if hasattr(child,"LinkedObject"):
if hasattr(child.LinkedObject.Document,"Assembly"):
FreeCAD.Console.PrintError("Sub assemblies not supported yet \n")
return None
root_lcs=FreeCAD.ActiveDocument.findObjects("PartDesign::CoordinateSystem")
structured_data={"ref_label":None,"type":"link","link":None,'name':"Parent Assembly","attachment":None,"coordinate_systems":root_lcs,"children":[]}

#this will just create a hierarchial data representation
create_structure(link_data,structured_data)
del link_data
del non_refs
return structured_data


def get_pose_info():
pass

39 changes: 25 additions & 14 deletions robot_descriptor/RD_globals.py → robot_descriptor/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@




import os
import FreeCAD
ICON_PATH=FreeCAD.getUserAppDataDir()+"Mod/RobotDescriptor/robot_descriptor/icons"
UI_PATH=FreeCAD.getUserAppDataDir()+"Mod/RobotDescriptor/robot_descriptor/forms"
ICON_PATH=os.path.join(FreeCAD.getUserAppDataDir()+"Mod","RobotDescriptor","robot_descriptor","icons")
UI_PATH=os.path.join(FreeCAD.getUserAppDataDir()+"Mod","RobotDescriptor","robot_descriptor","forms")
DOCUMENT=FreeCAD.ActiveDocument
import copy
import xml.etree.ElementTree as ET
Expand Down Expand Up @@ -78,7 +78,7 @@ def set_xml_data(element:ET.Element,tag:str,Is_Attribute:bool,value:Union[dict,f
#no need for a loop
try:
elem=elem_iter.__next__()
except:
except Exception:
return None
# ensure no dictionaries are sent for non attributes
if Is_Attribute is False and isinstance(value,dict) is False:
Expand All @@ -90,7 +90,7 @@ def set_xml_data(element:ET.Element,tag:str,Is_Attribute:bool,value:Union[dict,f
else:
#add/edit attributes
for key in value.keys():
elem.set(key,value[key])
elem.set(key,str(value[key]))
return element


Expand All @@ -114,9 +114,9 @@ def get_value(elem_data):
try:
try:
return int(elem_data)
except:
except Exception:
return float(elem_data)
except:
except Exception:
return elem_data

if Is_Attribute is not True:
Expand All @@ -126,7 +126,7 @@ def get_value(elem_data):
#only a single element exists no need to use a for loop
try:
elem=elem_iter.__next__()
except:
except Exception:
return None
if Is_Attribute is False:
txt=elem.text
Expand All @@ -138,9 +138,9 @@ def get_value(elem_data):
try:
try:
return int(elem.attrib[tag[1]])
except:
except Exception:
return float(elem.attrib[tag[1]])
except:
except Exception:
return elem.attrib[tag[1]]

#deleting attributes
Expand All @@ -165,14 +165,17 @@ def parse_dict(root_dict:dict,path:list):

# used to track the current index of the path list
current_idx=0
#if only one element is left return it
if len(path)==1:
if path[-1]=='sdf':
return root_dict[path[-1]]
#check if the element exists
elif path[-1] in list(root_dict.keys()):
return root_dict[path[-1]]
else:
return None
else:
#get the first item in the dictionary
parent_key=path[current_idx]
current_idx+=1
#child element tag
Expand Down Expand Up @@ -202,6 +205,7 @@ def update_dictionary(path:list,child_tag:Union[str,None],elem:Union[list,ET.Ele

parent_dict=parse_dict(elem_dict,path)
if parent_dict is not None:
#this allows update of an element not its children basically None means not the children
if child_tag is None:
if isinstance(elem,list):
parent_dict["elem_str"]=list(map(lambda e:ET.tostring(e,encoding="unicode"),elem))
Expand Down Expand Up @@ -245,21 +249,28 @@ def merge_elements(destination_el:ET.Element,source_el:ET.Element,recursive:bool
#implemtatation for all other elements
#the ones that are not recursive and not physics
else:
# Update attributes of destination_el with source_el
destination_el.attrib.update(source_el.attrib)
if source_el.text:
destination_el.text = source_el.text
# Merge child elements recursively
for child in source_el:
existing_el=destination_el.find(child.tag)
existing_el = destination_el.find(child.tag)
if existing_el is not None:
destination_el.remove(existing_el)
destination_el.append(child)
merge_elements(existing_el, child) # Recursively merge the existing element with the new one
else:
destination_el.append(child)
# If the element doesn't exist in destination, simply append it
# destination_el.append(child)
pass


import math
from PySide.QtGui import QColorDialog


class color_pickr:
'''class that implements color picker methods
'''
def __init__(self) -> None:
pass
#color picker
Expand Down
Loading