Commit 0b0cddbf authored by Andrey Filippov's avatar Andrey Filippov

Debugging, bug fixing

parent b57ed3ac
...@@ -28,6 +28,7 @@ from __future__ import print_function ...@@ -28,6 +28,7 @@ from __future__ import print_function
@contact: andrey@elphel.coml @contact: andrey@elphel.coml
@deffield updated: Updated @deffield updated: Updated
''' '''
from email import Errors
__author__ = "Andrey Filippov" __author__ = "Andrey Filippov"
__copyright__ = "Copyright 2015, Elphel, Inc." __copyright__ = "Copyright 2015, Elphel, Inc."
__license__ = "GPL" __license__ = "GPL"
...@@ -37,7 +38,7 @@ __email__ = "andrey@elphel.com" ...@@ -37,7 +38,7 @@ __email__ = "andrey@elphel.com"
__status__ = "Development" __status__ = "Development"
import FreeCAD import FreeCAD
import FreeCADGui # just to update cosole output (change to threads later?) import FreeCADGui # just to update console output (change to threads later?) - does not seem to work
import Part import Part
import os import os
import time import time
...@@ -57,6 +58,10 @@ X3D_DIR = "x3d" ...@@ -57,6 +58,10 @@ X3D_DIR = "x3d"
X3D_EXT = ".x3d" X3D_EXT = ".x3d"
INFO_EXT = ".pickle" INFO_EXT = ".pickle"
PRECISION = 0.0001 PRECISION = 0.0001
PRECISION_AREA = 0.001
PRECISION_VOLUME = 0.001
PRECISION_GYRATION = 0.001
PRECISION_INSIDE = 0.03 PRECISION_INSIDE = 0.03
COLOR_PER_VERTEX = True COLOR_PER_VERTEX = True
if ROOT_DIR[0] == "~": if ROOT_DIR[0] == "~":
...@@ -333,6 +338,8 @@ def findPartsTransformations(solids, objects, candidates, info_dict, insidePreci ...@@ -333,6 +338,8 @@ def findPartsTransformations(solids, objects, candidates, info_dict, insidePreci
containing list of colors (tuples) for which there is an area match between assembly element and a part. containing list of colors (tuples) for which there is an area match between assembly element and a part.
Build element part frame from colors first, then (if not enough) use inertial directions Build element part frame from colors first, then (if not enough) use inertial directions
""" """
progress_bar = Base.ProgressIndicator()
progress_bar.start("Finding transformations for library parts to match assembly elements ...", len(objects))
transformations=[] transformations=[]
for i,s in enumerate(solids): for i,s in enumerate(solids):
tolerance = insidePrecision * s.BoundBox.DiagonalLength # Or should it be fraction of the translation distance? tolerance = insidePrecision * s.BoundBox.DiagonalLength # Or should it be fraction of the translation distance?
...@@ -397,10 +404,12 @@ def findPartsTransformations(solids, objects, candidates, info_dict, insidePreci ...@@ -397,10 +404,12 @@ def findPartsTransformations(solids, objects, candidates, info_dict, insidePreci
trans.append(None) # so Transformations have same structure as candidates trans.append(None) # so Transformations have same structure as candidates
print("*** Could not find match for part %s"%(cand_name)) print("*** Could not find match for part %s"%(cand_name))
transformations.append(trans) transformations.append(trans)
progress_bar.next() # True) # True - enable ESC to abort
progress_bar.stop()
return transformations return transformations
def colorMatchCandidate(assy_object, candidates, info_dict, precision = PRECISION): def colorMatchCandidate(assy_object, candidates, info_dict, precision = PRECISION_AREA):
""" """
@return dictionary partName -> list of colors (as 3-tuples) @return dictionary partName -> list of colors (as 3-tuples)
""" """
...@@ -428,11 +437,27 @@ def colorMatchCandidate(assy_object, candidates, info_dict, precision = PRECISIO ...@@ -428,11 +437,27 @@ def colorMatchCandidate(assy_object, candidates, info_dict, precision = PRECISIO
if len(colors) == max_match: if len(colors) == max_match:
colored_candidates[candidate]=colors colored_candidates[candidate]=colors
return colored_candidates return colored_candidates
"""
PRECISION_AREA = 0.02
PRECISION_VOLUME = 0.03
PRECISION_INSIDE = 0.03
"""
#components=scan_step_parts.findComponents("/home/andrey/parts/0393/export/nc393_07_flat_noassy.stp") #components=scan_step_parts.findComponents("/home/andrey/parts/0393/export/nc393_07_flat_noassy.stp")
def findComponents(assembly, precision_inside = PRECISION_INSIDE, precision = PRECISION): def findComponents(assembly,
precision_area = PRECISION_AREA,
precision_volume = PRECISION_VOLUME,
precision_gyration = PRECISION_GYRATION,
precision_inside = PRECISION_INSIDE,
precision = PRECISION,
show_best = True):
""" """
@param assembly - may be file path (different treatment for Gui/no-Gui, Shape or doc.Objects @param assembly - may be file path (different treatment for Gui/no-Gui, Shape or doc.Objects
@param precision_area = PRECISION_AREA - relative precision in surface area calculations
@param precision_volume = PRECISION_VOLUME - relative precision in volume calculations
@param precision_gyration = PRECISION_GYRATION - relative precision in radius of gyration calculations
@param precision_inside = PRECISION_INSIDE - relative precision in calculations of point inside/outside of a solid
@param precision = PRECISION - precision in vector calculation
@param show_best - calculate and show the best relative match for each parameter
""" """
start_time=time.time() start_time=time.time()
print("Getting parts database") print("Getting parts database")
...@@ -458,39 +483,70 @@ def findComponents(assembly, precision_inside = PRECISION_INSIDE, precision = PR ...@@ -458,39 +483,70 @@ def findComponents(assembly, precision_inside = PRECISION_INSIDE, precision = PR
else: else:
objects,solids = create_file_info(assembly, aname) objects,solids = create_file_info(assembly, aname)
# print (objects) # print (objects)
progress_bar = Base.ProgressIndicator()
progress_bar.start("Looking for matching parts for each of the assembly element ...", len(objects))
candidates=[] candidates=[]
for i,o in enumerate(objects): for i,o in enumerate(objects):
# try: # try:
# FreeCADGui.updateGui() # FreeCADGui.updateGui()
# except: # except:
# pass # pass
# print (i,o) print (i,o)
this_candidates = [] this_candidates = []
list_errors=[]
rg=o['principal']['RadiusOfGyration'] rg=o['principal']['RadiusOfGyration']
rgp = precision*math.sqrt(rg[0]**2 + rg[1]**2 + rg[2]**2) rg_av = math.sqrt(rg[0]**2 + rg[1]**2 + rg[2]**2)
vp = o['volume']*precision rgp = precision_gyration * rg_av
ap = o['area']*precision vp = o['volume']*precision_volume
ap = o['area']*precision_area
for n in info_dict: for n in info_dict:
co = info_dict[n][0] co = info_dict[n][0]
if ((abs(o['volume'] - co['volume']) < vp) and errors = (abs(o['volume'] - co['volume']),
(abs(o['area'] - co['area']) < ap) and abs(o['area'] - co['area']),
(abs(rg[0] - co['principal']['RadiusOfGyration'][0]) < ap) and abs(rg[0] - co['principal']['RadiusOfGyration'][0]),
(abs(rg[1] - co['principal']['RadiusOfGyration'][1]) < ap) and abs(rg[1] - co['principal']['RadiusOfGyration'][1]),
(abs(rg[2] - co['principal']['RadiusOfGyration'][2]) < ap)): abs(rg[2] - co['principal']['RadiusOfGyration'][2]),
)
if show_best:
list_errors.append(errors)
# if ((abs(o['volume'] - co['volume']) < vp) and
# (abs(o['area'] - co['area']) < ap) and
# (abs(rg[0] - co['principal']['RadiusOfGyration'][0]) < rgp) and
# (abs(rg[1] - co['principal']['RadiusOfGyration'][1]) < rgp) and
# (abs(rg[2] - co['principal']['RadiusOfGyration'][2]) < rgp)):
if ((errors[0] < vp) and
(errors[1] < ap) and
(errors[2] < rgp) and
(errors[3] < rgp) and
(errors[4] < rgp)):
this_candidates.append(n) this_candidates.append(n)
if show_best:
weighted_errors = [errors[0]/vp + errors[1]/ap + (errors[2] + errors[3] + errors[4])/rgp for errors in list_errors]
best_index = weighted_errors.index(min(weighted_errors))
errors = list_errors[best_index]
print ("Best match with %s, relative errors: dV=%f, dS=%f, dRG1=%f, dRG2=%f, dRG3=%f"%(
info_dict.keys()[best_index],
errors[0]/o['volume'],
errors[1]/o['area'],
errors[2]/rg_av,
errors[3]/rg_av,
errors[4]/rg_av))
# Filter candidates by number of color areas matched # Filter candidates by number of color areas matched
colored_candidates=colorMatchCandidate(o, this_candidates, info_dict, precision) colored_candidates=colorMatchCandidate(o, this_candidates, info_dict, precision_area)
try: try:
num_ass_obj_colors = len(o["colorCenters"]) num_ass_obj_colors = len(o["colorCenters"])
except: except:
num_ass_obj_colors = 0 num_ass_obj_colors = 0
# print ("%d :colors: %d candidates: %s, colored_candidates: %s"%(i,num_ass_obj_colors, str(this_candidates), str(colored_candidates))) print ("%d :colors: %d candidates: %s, colored_candidates: %s"%(i,num_ass_obj_colors, str(this_candidates), str(colored_candidates)))
candidates.append(colored_candidates) candidates.append(colored_candidates)
progress_bar.next() # True) # True - enable ESC to abort
progress_bar.stop()
transformations = findPartsTransformations(solids, objects, candidates, info_dict, precision_inside, precision) transformations = findPartsTransformations(solids, objects, candidates, info_dict, precision_inside, precision)
#Each part can be in two orientations - check overlap after loading actual parts #Each part can be in two orientations - check overlap after loading actual parts
return {"Solids":solids,"objects":objects,"candidates":candidates,"transformations":transformations} return {"solids":solids,"objects":objects,"candidates":candidates,"transformations":transformations}
def ortho3(v0,v1): def ortho3(v0,v1):
v0.normalize() v0.normalize()
...@@ -527,7 +583,7 @@ def ppToMatrix(pp, ...@@ -527,7 +583,7 @@ def ppToMatrix(pp,
for color in colors: for color in colors:
## print ("colorCenters=", colorCenters[color]['center']," area=",colorCenters[color]['area']) ## print ("colorCenters=", colorCenters[color]['center']," area=",colorCenters[color]['area'])
color_vectors.append(FreeCAD.Vector(colorCenters[color]['center']) - t) color_vectors.append(FreeCAD.Vector(colorCenters[color]['center']) - t)
# print ("color_vectors=",color_vectors) print ("color_vectors=",color_vectors)
## print ("color_vectors=",color_vectors, "t=",t) ## print ("color_vectors=",color_vectors, "t=",t)
if color_vectors: # find the longest one if color_vectors: # find the longest one
lengths = [v.Length for v in color_vectors] lengths = [v.Length for v in color_vectors]
...@@ -536,7 +592,7 @@ def ppToMatrix(pp, ...@@ -536,7 +592,7 @@ def ppToMatrix(pp,
if l > eps: if l > eps:
vectors.append(v.normalize()) vectors.append(v.normalize())
if color_vectors: # now find the vector having maximal orthogonal component to v[0] if vectors and color_vectors: # now find the vector having maximal orthogonal component to v[0]
lengths = [v.cross(vectors[0]).Length for v in color_vectors] lengths = [v.cross(vectors[0]).Length for v in color_vectors]
l = max(lengths) l = max(lengths)
v = color_vectors.pop(lengths.index(l)) v = color_vectors.pop(lengths.index(l))
...@@ -610,11 +666,16 @@ def list_parts_offsets(): ...@@ -610,11 +666,16 @@ def list_parts_offsets():
for j,o in enumerate(info_files[name]): for j,o in enumerate(info_files[name]):
d = math.sqrt(o["center"][0]**2 + o["center"][1]**2 + o["center"][2]**2) d = math.sqrt(o["center"][0]**2 + o["center"][1]**2 + o["center"][2]**2)
if j == 0: if j == 0:
print("%3i:"%(i), end="") print("%4d:"%(i), end="")
else: else:
print(" ", end="") print(" ", end="")
print("%s offset = %6.1f"%(name, d)) print("%s offset = %6.1f"%(name, d))
def list_parts():
info_files = get_info_files()
for i, name in enumerate(info_files):
print ("%4d '%s': %d solids:%s"%(i,name,len(info_files[name]),str(info_files[name])))
# X3D Export # X3D Export
def getShapeNode(vertices, faces, diffuseColor = None, main_color_index = 0, colorPerVertex = True): def getShapeNode(vertices, faces, diffuseColor = None, main_color_index = 0, colorPerVertex = True):
...@@ -647,7 +708,7 @@ def getShapeNode(vertices, faces, diffuseColor = None, main_color_index = 0, col ...@@ -647,7 +708,7 @@ def getShapeNode(vertices, faces, diffuseColor = None, main_color_index = 0, col
materialNode.set('diffuseColor', "%f %f %f" % tuple(diffuseColor[main_color_index * 3: main_color_index * 3 + 3])) materialNode.set('diffuseColor', "%f %f %f" % tuple(diffuseColor[main_color_index * 3: main_color_index * 3 + 3]))
return shapeNode return shapeNode
def exportX3D(objects, filepath, colorPerVertex): def exportX3D(objects, filepath, id="part", colorPerVertex=False):
"""Export given list of objects to a X3D file. """Export given list of objects to a X3D file.
Each object is a dictionary in this form: Each object is a dictionary in this form:
...@@ -657,17 +718,19 @@ def exportX3D(objects, filepath, colorPerVertex): ...@@ -657,17 +718,19 @@ def exportX3D(objects, filepath, colorPerVertex):
color : [R, G, B,...] # number range is 0-1.0, exactly 3 elements for a single color, 3*N for per-vertex colors color : [R, G, B,...] # number range is 0-1.0, exactly 3 elements for a single color, 3*N for per-vertex colors
} }
""" """
progress_bar = Base.ProgressIndicator()
progress_bar.start("Saving objects to X3D file %s ..."%(filepath), len(objects))
x3dNode = et.Element('x3d') x3dNode = et.Element('x3d')
x3dNode.set('profile', 'Interchange') x3dNode.set('profile', 'Interchange')
x3dNode.set('version', '3.3') x3dNode.set('version', '3.3')
sceneNode = et.SubElement(x3dNode, 'Scene') sceneNode = et.SubElement(x3dNode, 'Scene')
progress_bar = Base.ProgressIndicator() groupNode = et.SubElement(sceneNode, 'Group')
progress_bar.start("Saving objects to X3D file %s ..."%(filepath), len(objects)) groupNode.set('id', id)
for o in objects: for o in objects:
shapeNode = getShapeNode(o["points"], o["faces"], o["color"], o["main_color_index"], colorPerVertex) shapeNode = getShapeNode(o["points"], o["faces"], o["color"], o["main_color_index"], colorPerVertex)
sceneNode.append(shapeNode) groupNode.append(shapeNode)
progress_bar.next() # True) # True - enable ESC to abort progress_bar.next() # True) # True - enable ESC to abort
oneliner= et.tostring(x3dNode) oneliner= et.tostring(x3dNode)
...@@ -744,10 +807,12 @@ def prepareX3dExport(freecadObjects, fname=""): ...@@ -744,10 +807,12 @@ def prepareX3dExport(freecadObjects, fname=""):
return objects return objects
def generatePartsX3d(dir_list = DIR_LIST, colorPerVertex = COLOR_PER_VERTEX): def generatePartsX3d(dir_list = DIR_LIST, colorPerVertex = COLOR_PER_VERTEX):
start_time=time.time()
info_dict= get_info_files(dir_list) # Will (re-) build info files if missing info_dict= get_info_files(dir_list) # Will (re-) build info files if missing
step_list = get_step_list(dir_list) #relative to ROOT_DIR step_list = get_step_list(dir_list) #relative to ROOT_DIR
if not X3D_DIR in os.listdir(ROOT_DIR): if not X3D_DIR in os.listdir(ROOT_DIR):
os.mkdir(os.path.join(ROOT_DIR,X3D_DIR)) os.mkdir(os.path.join(ROOT_DIR,X3D_DIR))
numExported=0
for step_file in step_list: for step_file in step_list:
partName,_ = os.path.splitext(os.path.basename(step_file)) partName,_ = os.path.splitext(os.path.basename(step_file))
x3dFile = os.path.join(ROOT_DIR,X3D_DIR,partName + X3D_EXT) x3dFile = os.path.join(ROOT_DIR,X3D_DIR,partName + X3D_EXT)
...@@ -757,9 +822,11 @@ def generatePartsX3d(dir_list = DIR_LIST, colorPerVertex = COLOR_PER_VERTEX): ...@@ -757,9 +822,11 @@ def generatePartsX3d(dir_list = DIR_LIST, colorPerVertex = COLOR_PER_VERTEX):
doc = FreeCAD.activeDocument() doc = FreeCAD.activeDocument()
doc.Label = partName doc.Label = partName
x3d_objects = prepareX3dExport(doc.Objects, step_file) # step_file needed just for progress bar x3d_objects = prepareX3dExport(doc.Objects, step_file) # step_file needed just for progress bar
exportX3D(x3d_objects, x3dFile, colorPerVertex) exportX3D(x3d_objects, x3dFile, id="part_"+partName, colorPerVertex=colorPerVertex)
FreeCAD.closeDocument(doc.Name) FreeCAD.closeDocument(doc.Name)
FreeCADGui.updateGui() FreeCADGui.updateGui()
numExported += 1
print("Exported %d files as X3D in @%f seconds, "%(numExported, time.time()-start_time))
def matrix4ToX3D(m, eps=0.000001): #assuming 3x3 matrix is pure rotational def matrix4ToX3D(m, eps=0.000001): #assuming 3x3 matrix is pure rotational
axis=FreeCAD.Vector(m.A32-m.A23, m.A13-m.A31, m.A21-m.A12) axis=FreeCAD.Vector(m.A32-m.A23, m.A13-m.A31, m.A21-m.A12)
...@@ -805,11 +872,27 @@ def matrix4ToX3D(m, eps=0.000001): #assuming 3x3 matrix is pure rotational ...@@ -805,11 +872,27 @@ def matrix4ToX3D(m, eps=0.000001): #assuming 3x3 matrix is pure rotational
def generateAssemblyX3d(assembly_path, components = None, dir_list = DIR_LIST, colorPerVertex = COLOR_PER_VERTEX): def generateAssemblyX3d(assembly_path,
components = None,
dir_list = DIR_LIST,
colorPerVertex = COLOR_PER_VERTEX,
precision_area = PRECISION_AREA,
precision_volume = PRECISION_VOLUME,
precision_gyration = PRECISION_GYRATION,
precision_inside = PRECISION_INSIDE,
precision = PRECISION
):
start_time=time.time()
info_dict = get_info_files(dir_list) # Will (re-) build info files if missing info_dict = get_info_files(dir_list) # Will (re-) build info files if missing
generatePartsX3d(dir_list = DIR_LIST, colorPerVertex = COLOR_PER_VERTEX) # Will only run if files are not there yet generatePartsX3d(dir_list = DIR_LIST, colorPerVertex = COLOR_PER_VERTEX) # Will only run if files are not there yet
if not components: if not components:
components = findComponents(assembly_path, precision_inside = PRECISION_INSIDE, precision = PRECISION) components = findComponents(assembly_path,
precision_area = precision_area,
precision_volume = precision_volume,
precision_gyration = precision_gyration,
precision_inside = precision_inside,
precision = precision,
show_best = False)
assName,_ = os.path.splitext(os.path.basename(assembly_path)) assName,_ = os.path.splitext(os.path.basename(assembly_path))
x3dFile = os.path.join(ROOT_DIR,X3D_DIR,assName + X3D_EXT) # currently in the same directory as parts x3dFile = os.path.join(ROOT_DIR,X3D_DIR,assName + X3D_EXT) # currently in the same directory as parts
x3dNode = et.Element('x3d') x3dNode = et.Element('x3d')
...@@ -880,6 +963,7 @@ def generateAssemblyX3d(assembly_path, components = None, dir_list = DIR_LIST, c ...@@ -880,6 +963,7 @@ def generateAssemblyX3d(assembly_path, components = None, dir_list = DIR_LIST, c
print ("Writing assembly to %s"%(x3dFile)) print ("Writing assembly to %s"%(x3dFile))
with open(x3dFile, "wr") as f: with open(x3dFile, "wr") as f:
f.write(reparsed.toprettyxml(indent=" ")) f.write(reparsed.toprettyxml(indent=" "))
print("Assembly %s exported as X3D file in @%f seconds, "%(x3dFile, time.time()-start_time))
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment