FreeCAD: uber updating function in freecad_to_json WIP
This commit is contained in:
parent
cc538b719f
commit
8401cc51fa
2 changed files with 288 additions and 55 deletions
|
@ -31,8 +31,15 @@ Solid tools for FreeCAD's .FCStd scene.
|
|||
'''
|
||||
__version__ = '0.2'
|
||||
|
||||
import difflib
|
||||
import glob
|
||||
import logging
|
||||
import math
|
||||
import xml.dom.minidom
|
||||
|
||||
import FreeCAD
|
||||
import Part
|
||||
import MeshPart
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
@ -61,12 +68,13 @@ def collect_clones(doc=FreeCAD.getDocument(FreeCAD.ActiveDocument.Label)) -> lis
|
|||
:param doc: document, freecad opened scene (or current scene)
|
||||
:returns: list with clones sublists [['c0'], ['c1', 'c2', 'c4'],]
|
||||
'''
|
||||
doc_clones = []
|
||||
doc_clones = {}
|
||||
for item in doc.Objects:
|
||||
# for solid objects only
|
||||
if not is_object_solid(item):
|
||||
continue
|
||||
# collect clones lists
|
||||
item_clones = []
|
||||
item_clones.append(item.Label)
|
||||
for other in doc.Objects:
|
||||
if other == item:
|
||||
continue
|
||||
|
@ -74,7 +82,146 @@ def collect_clones(doc=FreeCAD.getDocument(FreeCAD.ActiveDocument.Label)) -> lis
|
|||
logger.info('%s and %s objects has equal Shapes',
|
||||
item.Label, other.Label)
|
||||
item_clones.append(other.Label)
|
||||
item_clones.sort()
|
||||
if item_clones not in doc_clones:
|
||||
doc_clones.append(item_clones)
|
||||
# if item has clones
|
||||
if item_clones:
|
||||
item_clones.append(item.Label)
|
||||
# find common basename for all clones
|
||||
idx = 0
|
||||
common_name = item_clones[0].lower()
|
||||
while idx < len(item_clones):
|
||||
match_data = difflib.SequenceMatcher(
|
||||
None, common_name, item_clones[idx].lower()
|
||||
).find_longest_match()
|
||||
common_name = common_name[match_data.a:match_data.a + match_data.size]
|
||||
idx += 1
|
||||
# if names has or hasn't common patterns
|
||||
item_base_name = common_name.strip(' .,_') or item_clones[0]
|
||||
# sort list names
|
||||
item_clones.sort()
|
||||
# add only unical list of clones
|
||||
if item_clones not in doc_clones.values():
|
||||
doc_clones[item_base_name] = item_clones
|
||||
return doc_clones
|
||||
|
||||
|
||||
def tesselation(obj,
|
||||
doc=FreeCAD.getDocument(FreeCAD.ActiveDocument.Label),
|
||||
linear_deflection=0.1, angular_deflection=20,
|
||||
tesselation_method='Standard', fem_size=50.0,
|
||||
adaptive=True) -> list::
|
||||
'''
|
||||
Perform shape tesselation.
|
||||
'''
|
||||
shape = obj.Shape.copy()
|
||||
shape.Placement = obj.Placement.inverse().multiply(shape.Placement)
|
||||
mesh_from_shape = doc.addObject('Mesh::Feature', 'mesh_from_shape')
|
||||
if tesselation_method == 'Standard':
|
||||
mesh_from_shape.Mesh = MeshPart.meshFromShape(
|
||||
Shape=shape,
|
||||
LinearDeflection=linear_deflection,
|
||||
AngularDeflection=math.radians(angular_deflection),
|
||||
Relative=False)
|
||||
elif tesselation_method == 'FEM':
|
||||
mesh_from_shape.Mesh = MeshPart.meshFromShape(
|
||||
Shape=shape,
|
||||
MaxLength=fem_size)
|
||||
else:
|
||||
raise TypeError('Wrong tesselation method! '
|
||||
'Standard and FEM methods are supported only!')
|
||||
|
||||
# for solids only
|
||||
volume = shape.Volume
|
||||
mesh_shape = Part.Shape()
|
||||
mesh_shape.makeShapeFromMesh(mesh_from_shape.Mesh.Topology, 0.100000, False)
|
||||
mesh_volume = mesh_shape.Volume
|
||||
|
||||
if adaptive:
|
||||
deviation = 100 * (volume - mesh_volume) / volume
|
||||
if deviation > 0.05:
|
||||
logger.info(
|
||||
'Percentage tesselation deviation for %s object is %s! '
|
||||
'Double increasing mesh detalisation!',
|
||||
obj.Label, deviation)
|
||||
linear_deflection = linear_deflection / 2
|
||||
angular_deflection = angular_deflection / 2
|
||||
doc.removeObject('mesh_from_shape')
|
||||
#doc.recompute()
|
||||
tesselation(
|
||||
obj, doc, linear_deflection, angular_deflection,
|
||||
tesselation_method, fem_size)
|
||||
|
||||
return mesh_from_shape
|
||||
|
||||
|
||||
def config_parser(comfig_path, param_path, param_name, param_type=None) -> str:
|
||||
'''
|
||||
Parse FreeCAD XML confings
|
||||
'''
|
||||
root_node = xml.dom.minidom.parse(comfig_path).childNodes[0]
|
||||
node_names = ['Root'] + param_path.split('/') + [param_name]
|
||||
|
||||
for node_name in node_names:
|
||||
for child in root_node.childNodes:
|
||||
if hasattr(child, 'getAttribute') and child.getAttribute('Name') == node_name:
|
||||
root_node = child
|
||||
break
|
||||
else:
|
||||
return None
|
||||
|
||||
tagname = root_node.tagName
|
||||
|
||||
if param_type is not None and tagname != param_type:
|
||||
return None
|
||||
|
||||
if tagname == 'FCText':
|
||||
if root_node.firstChild:
|
||||
return root_node.firstChild._get_data()
|
||||
return ''
|
||||
|
||||
if tagname == 'FCBool':
|
||||
return bool(root_node.getAttribute('Value'))
|
||||
|
||||
if tagname in ('FCInt', 'FCUInt'):
|
||||
return int(root_node.getAttribute('Value'))
|
||||
|
||||
if tagname == 'FCFloat':
|
||||
return float(root_node.getAttribute('Value'))
|
||||
|
||||
return root_node.getAttribute('Value')
|
||||
|
||||
|
||||
def get_material_paths() -> list:
|
||||
'''
|
||||
Collect all available material paths
|
||||
'''
|
||||
material_paths = []
|
||||
system_dir = os.path.join(
|
||||
FreeCAD.getResourceDir(),
|
||||
'Mod/Material')
|
||||
material_paths.extend(
|
||||
[item for item in glob.glob(f'{system_dir}/**', recursive=True)
|
||||
if item.endswith('.FCMat')]
|
||||
)
|
||||
user_dir = os.path.join(
|
||||
FreeCAD.getUserAppDataDir(),
|
||||
'Mod/Material')
|
||||
material_paths.extend(
|
||||
[item for item in glob.glob(f'{user_dir}/**', recursive=True)
|
||||
if item.endswith('.FCMat')]
|
||||
)
|
||||
custom_dir = []
|
||||
if config_parser(
|
||||
FreeCAD.ConfigGet("UserParameter"),
|
||||
'BaseApp/Preferences/Mod/Material/Resources',
|
||||
'UseMaterialsFromCustomDir', 'FCBool'
|
||||
):
|
||||
custom_dir = config_parser(
|
||||
FreeCAD.ConfigGet("UserParameter"),
|
||||
'BaseApp/Preferences/Mod/Material/Resources',
|
||||
'CustomMaterialsDir', 'FCText'
|
||||
)
|
||||
material_paths.extend(
|
||||
[item for item in glob.glob(f'{custom_dir}/**', recursive=True)
|
||||
if item.endswith('.FCMat')]
|
||||
)
|
||||
return material_paths
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue