Can Spreadsheet WB make list of parts and sub-assemblies?
Forum rules
and Helpful information
and Helpful information
IMPORTANT: Please click here and read this first, before asking for help
Also, be nice to others! Read the FreeCAD code of conduct!
Also, be nice to others! Read the FreeCAD code of conduct!
Can Spreadsheet WB make list of parts and sub-assemblies?
Hi Forum,
I want to make a list of all Parts and/or Sub-Assemblies inside one Assembly.
Forum member Triplus guided me to Arch Schedule. That one is able to count all occurrences of individual Labels, such as 'window'. Thereby, the Label name is input, and the number of occurrences is output. It is not what I need. Because:
1/ A list of parts does not know before hand which Labels are to be expected.
2/ Not all Labels should be counted, only those that represent a Part or Sub-Assembly.
Any solutions available?
Greetz,
Roland
I want to make a list of all Parts and/or Sub-Assemblies inside one Assembly.
Forum member Triplus guided me to Arch Schedule. That one is able to count all occurrences of individual Labels, such as 'window'. Thereby, the Label name is input, and the number of occurrences is output. It is not what I need. Because:
1/ A list of parts does not know before hand which Labels are to be expected.
2/ Not all Labels should be counted, only those that represent a Part or Sub-Assembly.
Any solutions available?
Greetz,
Roland
Re: Can Spreadsheet WB make list of parts and sub-assemblies?
One attempt ...
A list of parts is created by Assembly2 WB as a drawing object, and also created as an object in the console. Can we use this to get there?
The attempt: Use Assembly2 WB, make new object of 2 parts. Create muxedAssembly (a new, invisible object, but needed for an assembly drawing). Then, inside spreadsheet read data from that Mux, e.g. Placement, Type, Label. That all works fine, indeed.
And then, there is one property that I want to be brought to the spreadsheet: muxedObjectList. It is 'seen' by the spreadsheet command list as soon as one types the first two characters (cell contents =muxedAssembly.muxedObjectList) , and then merely returns the command given as cell contents when executed. And the '=' sign gets deleted by FC. When '=' deliberately reinserted, FC returns ERR. So, it is sort of an empty command.
(By the way, such ObjectList is created by muxing in Assembly2, but rather not by Make Compound in Part WB.)
What can we do?
Roland
A list of parts is created by Assembly2 WB as a drawing object, and also created as an object in the console. Can we use this to get there?
The attempt: Use Assembly2 WB, make new object of 2 parts. Create muxedAssembly (a new, invisible object, but needed for an assembly drawing). Then, inside spreadsheet read data from that Mux, e.g. Placement, Type, Label. That all works fine, indeed.
And then, there is one property that I want to be brought to the spreadsheet: muxedObjectList. It is 'seen' by the spreadsheet command list as soon as one types the first two characters (cell contents =muxedAssembly.muxedObjectList) , and then merely returns the command given as cell contents when executed. And the '=' sign gets deleted by FC. When '=' deliberately reinserted, FC returns ERR. So, it is sort of an empty command.
(By the way, such ObjectList is created by muxing in Assembly2, but rather not by Make Compound in Part WB.)
What can we do?
Roland
Re: Can Spreadsheet WB make list of parts and sub-assemblies?
Hello !
I am facing the same issue. For now, i use Part List in Assembly2 to get a tab on a drawing with all the parts and the number of occurence. However i would like to have this tab in a spreadsheet, to be able to get some info on every part, such as length.
It looks like muxedObjectList would be the appropriate way to have that, but as you said it looks like an empty command.
I am facing the same issue. For now, i use Part List in Assembly2 to get a tab on a drawing with all the parts and the number of occurence. However i would like to have this tab in a spreadsheet, to be able to get some info on every part, such as length.
It looks like muxedObjectList would be the appropriate way to have that, but as you said it looks like an empty command.
L'Atelier Paysan, Coopérative d'autoconstruction de machines agricoles
Tous les plans des outils sont disponibles en opensource, sur https://www.latelierpaysan.org/Plans-et-Tutoriels
-
- Veteran
- Posts: 3157
- Joined: Sat May 20, 2017 12:06 pm
- Location: Germany
Re: Can Spreadsheet WB make list of parts and sub-assemblies?
Hello julieAP,julieAP wrote: ↑Fri Sep 15, 2017 12:33 pm Hello !
I am facing the same issue. For now, i use Part List in Assembly2 to get a tab on a drawing with all the parts and the number of occurence. However i would like to have this tab in a spreadsheet, to be able to get some info on every part, such as length.
It looks like muxedObjectList would be the appropriate way to have that, but as you said it looks like an empty command.
I had a look on your website here
https://www.latelierpaysan.org/Four-a-pain-2515
Very interesting!
Do you use FreeCAD for designing your projects?
(printing style looks like techdraw-workbench...)
regards Thomas
Re: Can Spreadsheet WB make list of parts and sub-assemblies?
Hi !
I'm happy you like it ! Right now we use SolidWorks, but we plan to make the transition to FreeCad it would be more in agreement with our values to use an open source software. I am here to work on that !
I will pretty soon post something on the forum to present us in more details.
Back to the topic, flachyjoe posted this macro on the french forum, it seems to work pretty fine to make a list in a spreadsheet of the visible objects of the document and extract their properties (length...)
If needed i can translate the comments inside the code
Julie
I'm happy you like it ! Right now we use SolidWorks, but we plan to make the transition to FreeCad it would be more in agreement with our values to use an open source software. I am here to work on that !
I will pretty soon post something on the forum to present us in more details.
Back to the topic, flachyjoe posted this macro on the french forum, it seems to work pretty fine to make a list in a spreadsheet of the visible objects of the document and extract their properties (length...)
Code: Select all
# -*- coding: utf-8 -*-
import re #support des expressions régulières
LABEL="Composant"
COUNT="Nombre"
DEBUG = False
def Debug(text):
if DEBUG :
Log(text+'\n')
def isAdditiveFunc(obj) :
'''L'objet corespond à un ajout de matière'''
return 'AddShape' in obj.PropertiesList
def isArray(obj) :
return 'ArrayType' in obj.PropertiesList
def isSketch(obj) :
return obj.TypeId=='Sketcher::SketchObject'
def getProperties(obj, prop={}) :
'''Extraits les informations sur un objet en parcourant récursivement son arbre de dépendence'''
Debug('get properties '+obj.Label)
if isAdditiveFunc(obj) :
if 'Length' in obj.PropertiesList and not prop.has_key('Length') :
prop['Length'] = obj.Length
if 'Angle' in obj.PropertiesList and not prop.has_key('Angle') :
prop['Angle'] = obj.Angle
if isArray(obj) :
if obj.ArrayType=='ortho' :
prop[COUNT] = obj.NumberX * obj.NumberY * obj.NumberZ
else :
prop[COUNT] = obj.NumberPolar
if isSketch(obj) :
#Extrait les valeurs des contraintes nommées
for c in obj.Constraints :
if c.Name :
prop[c.Name]= re.search('Value="([^"]*)', c.Content).group(1)
for child in obj.OutList :
prop = getProperties(child, prop)
return prop
def createDict(doc):
'''Crée un dictionnaire associant le nom de chaque objet à ses propriétés'''
objs = doc.Objects
#resultat
listObjects = {}
for obj in objs:
if not obj.ViewObject.Visibility :
#On ne liste pas les objets cachés
continue
prop = getProperties(obj, {})
if not prop.has_key(COUNT) :
prop[COUNT] = 1
lbl = obj.Label
if isArray(obj) :
lbl = obj.Base.Label
lbl = re.sub('_[^_]*$', '', lbl)
lbl = re.sub('^Clone of ', '', lbl)
count1 = prop[COUNT]
del prop[COUNT]
added = False
#si le nom existe deja dans le dictionnaire
while listObjects.has_key(lbl) and not added :
#recupere les infos sur l'objet stocké
objInfos = listObjects[lbl]
#On ne prend pas en compte la quantité d'objet pour comparer
count0 = listObjects[lbl][COUNT]
del listObjects[lbl][COUNT]
#On test si l'objet courant a les même prpriétés que celui déjà stocké
k0 = zip(objInfos.keys(), objInfos.values())
k0.sort(key=lambda x: x[0])
k1 = zip(prop.keys(), prop.values())
k1.sort(key=lambda x: x[0])
if k0 == k1 :
#Ils ont les mêmes propriétés, on additionne les quantités
listObjects[lbl][COUNT] = count0 + count1
added = True
else :
#ils n'ont pas les mêmes propriétés
#iteration du nombre final du nom
index = int('0'+re.search('[0-9]*$', lbl).group())
if index == 0 :
lbl = lbl + '_1'
else :
lbl = re.sub('[0-9]*$', str(index + 1), lbl)
if not added :
prop[COUNT] = count1
listObjects[lbl] = prop
return listObjects
def columnName(n) :
'''Renvoi le nom de la colone à partir de son indice 0->A, 27->AB ... 675->ZZ '''
if n < 26 :
return chr(ord('A')+n)
elif n < 26*26 :
return chr(ord('A')+int(n / 26)) + chr(ord('A')+(n % 26))
raise Exception('Out of range')
def fillSpreadsheet(listObjects, spreadsheet) :
'''Rempli le tableur à partir d'un dictionnaire'''
#Liste de toutes les propriétés parmi les objets
keys = []
for props in listObjects.values() :
keys.extend(props.keys())
#Compte les noms des propriétés
uniq_keys = {}
added = set()
nums = {}
for val in keys :
if not val in added:
uniq_keys[val] = 1
added.add(val)
else :
uniq_keys[val] += 1
#Tri par ordre d'utilisation
from collections import OrderedDict
from operator import itemgetter
header = OrderedDict(sorted(uniq_keys.items(), key=itemgetter(1))).keys()
header.reverse()
#Création de l'entête
spreadsheet.set('A1', LABEL)
x=1
for prop in header :
spreadsheet.set(columnName(x)+'1', prop)
x = x + 1
spreadsheet.setStyle('A1:ZZ1', 'bold', 'add')
#remplissage
y=2
for lbl in listObjects :
spreadsheet.set('A'+str(y), lbl.encode('utf-8'))
x=1
for prop in header :
if listObjects[lbl].has_key(prop) :
spreadsheet.set(columnName(x)+str(y), str(listObjects[lbl][prop]))
x = x + 1
y = y + 1
doc = FreeCAD.ActiveDocument
doc.openTransaction("Nomenclature")
fillSpreadsheet(createDict(doc), doc.addObject('Spreadsheet::Sheet','Nomenclature'))
doc.commitTransaction()
doc.recompute()
Julie
Last edited by julieAP on Wed Sep 20, 2017 1:27 pm, edited 1 time in total.
L'Atelier Paysan, Coopérative d'autoconstruction de machines agricoles
Tous les plans des outils sont disponibles en opensource, sur https://www.latelierpaysan.org/Plans-et-Tutoriels
Re: Can Spreadsheet WB make list of parts and sub-assemblies?
Deutsche FreeCAD Tutorials auf Youtube
My GrabCAD FreeCAD-Projects
FreeCAD lessons for beginners in english
Native german speaker - so apologies for my english, no offense intended
My GrabCAD FreeCAD-Projects
FreeCAD lessons for beginners in english
Native german speaker - so apologies for my english, no offense intended
Re: Can Spreadsheet WB make list of parts and sub-assemblies?
Here you are, i hope the translation is understandable:
Code: Select all
# -*- coding: utf-8 -*-
import re #support des expressions régulières
LABEL="Component"
COUNT="Number"
DEBUG = False
def Debug(text):
if DEBUG :
Log(text+'\n')
def isAdditiveFunc(obj) :
'''The object corresponds to an addition of matter'''
return 'AddShape' in obj.PropertiesList
def isArray(obj) :
return 'ArrayType' in obj.PropertiesList
def isSketch(obj) :
return obj.TypeId=='Sketcher::SketchObject'
def getProperties(obj, prop={}) :
'''Extracts the information of an object by travelling recursively its tree of dependence'''
Debug('get properties '+obj.Label)
if isAdditiveFunc(obj) :
if 'Length' in obj.PropertiesList and not prop.has_key('Length') :
prop['Length'] = obj.Length
if 'Angle' in obj.PropertiesList and not prop.has_key('Angle') :
prop['Angle'] = obj.Angle
if isArray(obj) :
if obj.ArrayType=='ortho' :
prop[COUNT] = obj.NumberX * obj.NumberY * obj.NumberZ
else :
prop[COUNT] = obj.NumberPolar
if isSketch(obj) :
#Extracts the values of the named constraints
for c in obj.Constraints :
if c.Name :
prop[c.Name]= re.search('Value="([^"]*)', c.Content).group(1)
for child in obj.OutList :
prop = getProperties(child, prop)
return prop
def createDict(doc):
'''Create a dictionary linking the name of each object to its properties'''
objs = doc.Objects
#resultat
listObjects = {}
for obj in objs:
if not obj.ViewObject.Visibility :
#On ne liste pas les objets cachés
continue
prop = getProperties(obj, {})
if not prop.has_key(COUNT) :
prop[COUNT] = 1
lbl = obj.Label
if isArray(obj) :
lbl = obj.Base.Label
lbl = re.sub('_[^_]*$', '', lbl)
lbl = re.sub('^Clone of ', '', lbl)
count1 = prop[COUNT]
del prop[COUNT]
added = False
#if the name already exists in the dictionary
while listObjects.has_key(lbl) and not added :
#retrieves the information of the stored object
objInfos = listObjects[lbl]
#We do not consider the amount of object to compare
count0 = listObjects[lbl][COUNT]
del listObjects[lbl][COUNT]
#We test if the current object has the same properties as the one already stored
k0 = zip(objInfos.keys(), objInfos.values())
k0.sort(key=lambda x: x[0])
k1 = zip(prop.keys(), prop.values())
k1.sort(key=lambda x: x[0])
if k0 == k1 :
#They have the same properties, so we add the quantities
listObjects[lbl][COUNT] = count0 + count1
added = True
else :
#they don't have the same properties
#Iteration of the final number of the name
index = int('0'+re.search('[0-9]*$', lbl).group())
if index == 0 :
lbl = lbl + '_1'
else :
lbl = re.sub('[0-9]*$', str(index + 1), lbl)
if not added :
prop[COUNT] = count1
listObjects[lbl] = prop
return listObjects
def columnName(n) :
'''Gives the name of the column using its index 0->A, 27->AB ... 675->ZZ '''
if n < 26 :
return chr(ord('A')+n)
elif n < 26*26 :
return chr(ord('A')+int(n / 26)) + chr(ord('A')+(n % 26))
raise Exception('Out of range')
def fillSpreadsheet(listObjects, spreadsheet) :
'''Files the spreadsheet from a dictionary'''
#Makes a list of every properties in the objects
keys = []
for props in listObjects.values() :
keys.extend(props.keys())
#Compute the names of the properties
uniq_keys = {}
added = set()
nums = {}
for val in keys :
if not val in added:
uniq_keys[val] = 1
added.add(val)
else :
uniq_keys[val] += 1
#Sorting by order of use
from collections import OrderedDict
from operator import itemgetter
header = OrderedDict(sorted(uniq_keys.items(), key=itemgetter(1))).keys()
header.reverse()
#Creation of the heading
spreadsheet.set('A1', LABEL)
x=1
for prop in header :
spreadsheet.set(columnName(x)+'1', prop)
x = x + 1
spreadsheet.setStyle('A1:ZZ1', 'bold', 'add')
#filling
y=2
for lbl in listObjects :
spreadsheet.set('A'+str(y), lbl.encode('utf-8'))
x=1
for prop in header :
if listObjects[lbl].has_key(prop) :
spreadsheet.set(columnName(x)+str(y), str(listObjects[lbl][prop]))
x = x + 1
y = y + 1
doc = FreeCAD.ActiveDocument
doc.openTransaction("Nomenclature")
fillSpreadsheet(createDict(doc), doc.addObject('Spreadsheet::Sheet','Nomenclature'))
doc.commitTransaction()
doc.recompute()
L'Atelier Paysan, Coopérative d'autoconstruction de machines agricoles
Tous les plans des outils sont disponibles en opensource, sur https://www.latelierpaysan.org/Plans-et-Tutoriels