Made LatticeTopoSeries expose the annotations of its inner shapes, added more instructions to scripting language
This commit is contained in:
parent
10e13dbbd0
commit
7cc7e5f55e
|
@ -22,10 +22,10 @@
|
||||||
#***************************************************************************
|
#***************************************************************************
|
||||||
|
|
||||||
from lattice2Common import *
|
from lattice2Common import *
|
||||||
|
from lattice2Utils import getAnnotatedShapes
|
||||||
import lattice2Markers as markers
|
import lattice2Markers as markers
|
||||||
import lattice2CompoundExplorer as LCE
|
import lattice2CompoundExplorer as LCE
|
||||||
from lattice2BaseFeature import assureProperty #assureProperty(self, selfobj, proptype, propname, defvalue, group, tooltip)
|
from lattice2BaseFeature import assureProperty #assureProperty(self, selfobj, proptype, propname, defvalue, group, tooltip)
|
||||||
import re
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
import math
|
import math
|
||||||
|
@ -87,6 +87,12 @@ example = """
|
||||||
# GT : ... t t : ... bool : pops two elements, pushes True if top > bot, False otherwise. Comparing elements of different types will always return False.
|
# GT : ... t t : ... bool : pops two elements, pushes True if top > bot, False otherwise. Comparing elements of different types will always return False.
|
||||||
# LE : ... t t : ... bool : pops two elements, pushes True if top <= bot, False otherwise. Comparing elements of different types will always return False.
|
# LE : ... t t : ... bool : pops two elements, pushes True if top <= bot, False otherwise. Comparing elements of different types will always return False.
|
||||||
# GE : ... t t : ... bool : pops two elements, pushes True if top >= bot, False otherwise. Comparing elements of different types will always return False.
|
# GE : ... t t : ... bool : pops two elements, pushes True if top >= bot, False otherwise. Comparing elements of different types will always return False.
|
||||||
|
# AND : ... bool bool : ... bool : pops two booleans, pushes (top and bot)
|
||||||
|
# OR : ... bool bool : ... bool : pops two booleans, pushes (top or bot)
|
||||||
|
# XOR : ... bool bool : ... bool : pops two booleans, pushes (top xor bot)
|
||||||
|
# NAND : ... bool bool : ... bool : pops two booleans, pushes (top nand bot)
|
||||||
|
# NOR : ... bool bool : ... bool : pops two booleans, pushes (top nor bot)
|
||||||
|
# NXOR : ... bool bool : ... bool : pops two booleans, pushes (top nxor bot)
|
||||||
# DROP : ... t : ... : pops the top of the stack and discards it
|
# DROP : ... t : ... : pops the top of the stack and discards it
|
||||||
# DUP : ... t : ... t t : pops the top of the stack, and pushes it back twice (duplication of the top of the stack)
|
# DUP : ... t : ... t t : pops the top of the stack, and pushes it back twice (duplication of the top of the stack)
|
||||||
# SWAP : ... t u : ... u t : pops two elements, and pushes them back in reverse order
|
# SWAP : ... t u : ... u t : pops two elements, and pushes them back in reverse order
|
||||||
|
@ -98,12 +104,13 @@ example = """
|
||||||
# NOP : ... : ... : No operation (NOOP is also accepted)
|
# NOP : ... : ... : No operation (NOOP is also accepted)
|
||||||
# SET xyz : ... t : ... : pops the top of the stack, and saves it as a global variable named xyz
|
# SET xyz : ... t : ... : pops the top of the stack, and saves it as a global variable named xyz
|
||||||
# GET xyz : ... : ... t : pushes the contents of the global variable xyz on top of the stack
|
# GET xyz : ... : ... t : pushes the contents of the global variable xyz on top of the stack
|
||||||
# .Annotation : ... geometry : ... string : gets the annotation from the given geometry element. Annotations are stored as dummy de-activated Block constraints named __theannotation.123 (where 123 is the constraint's ID). A separate macro allows setting these annotations.
|
# .Annotations.xyz : ... annotated_shape : ... string : gets the annotation from the given geometry element. Annotations are stored as dummy de-activated Block constraints named __theannotation.123 (where 123 is the constraint's ID) and some extra annotations are supplied by some Python objects (e.g. .Annotations.Geometry for sketches). A separate macro allows setting these annotations.
|
||||||
# .attribute : ... t : ... u : gets the attribute from the object on the top of the stack. Allowed attributes are {allowed_attributes}
|
# .attribute : ... geometry : ... u : gets the attribute from the object on the top of the stack. Allowed attributes are {allowed_attributes}
|
||||||
|
|
||||||
# The initial stack contains a list of sketch geometry elements.
|
# The initial stack contains a list of sketch geometry elements.
|
||||||
|
|
||||||
QUOTE
|
QUOTE
|
||||||
|
.Annotations.Geometry
|
||||||
.Construction
|
.Construction
|
||||||
NOT
|
NOT
|
||||||
END QUOTE
|
END QUOTE
|
||||||
|
@ -111,18 +118,18 @@ FILTER
|
||||||
"""
|
"""
|
||||||
example = example.format(allowed_attributes=",".join(sorted(["%s (%s)" % (k,v) for k,v in allowed_attributes.items()])))
|
example = example.format(allowed_attributes=",".join(sorted(["%s (%s)" % (k,v) for k,v in allowed_attributes.items()])))
|
||||||
|
|
||||||
def interpret_map(stack, env, closure, lst, edge_annotations):
|
def interpret_map(stack, env, closure, lst):
|
||||||
result = []
|
result = []
|
||||||
for elt in lst:
|
for elt in lst:
|
||||||
stack, env = interpret(stack + closure[1] + [elt], env, closure[0], edge_annotations)
|
stack, env = interpret(stack + closure[1] + [elt], env, closure[0])
|
||||||
result.append(stack[-1])
|
result.append(stack[-1])
|
||||||
stack = stack[:-1]
|
stack = stack[:-1]
|
||||||
return (stack + [('list', result)], env)
|
return (stack + [('list', result)], env)
|
||||||
|
|
||||||
def interpret_filter(stack, env, closure, lst, edge_annotations):
|
def interpret_filter(stack, env, closure, lst):
|
||||||
result = []
|
result = []
|
||||||
for elt in lst:
|
for elt in lst:
|
||||||
stack, env = interpret(stack + closure[1] + [elt], env, closure[0], edge_annotations)
|
stack, env = interpret(stack + closure[1] + [elt], env, closure[0])
|
||||||
if stack[-1][0] != 'bool':
|
if stack[-1][0] != 'bool':
|
||||||
raise ValueError("closure passed as an argument to filter should return a bool, but it returned a " + str(stack[-1][0]))
|
raise ValueError("closure passed as an argument to filter should return a bool, but it returned a " + str(stack[-1][0]))
|
||||||
if stack[-1][1] == True:
|
if stack[-1][1] == True:
|
||||||
|
@ -134,30 +141,44 @@ def interpret_filter(stack, env, closure, lst, edge_annotations):
|
||||||
stack = stack[:-1]
|
stack = stack[:-1]
|
||||||
return (stack + [('list', result)], env)
|
return (stack + [('list', result)], env)
|
||||||
|
|
||||||
def interpret(stack, env, program, edge_annotations):
|
boolOperations = {
|
||||||
quoting = False
|
'AND': (lambda x, y: x and y),
|
||||||
|
'OR': (lambda x, y: x or y),
|
||||||
|
'XOR': (lambda x, y: (x or y) and (not (x and y))),
|
||||||
|
'NAND': (lambda x, y: not (x and y)),
|
||||||
|
'NOR': (lambda x, y: not (x or y)),
|
||||||
|
'NXOR': (lambda x, y: (x and y) or (not (x or y)))
|
||||||
|
}
|
||||||
|
|
||||||
|
def interpret(stack, env, program):
|
||||||
|
quoting = 0
|
||||||
for line in program:
|
for line in program:
|
||||||
if line.strip() == '':
|
if line.strip() == '':
|
||||||
pass # no-op
|
pass # no-op
|
||||||
|
|
||||||
# quotations
|
# quotations
|
||||||
elif quoting and line == 'END QUOTE':
|
elif quoting > 0:
|
||||||
quoting = False
|
|
||||||
elif quoting and line == 'QUOTE':
|
|
||||||
raise ValueError("nested quotes are not allowed, use PARTIAL instead")
|
|
||||||
elif quoting:
|
|
||||||
if stack[-1][0] != 'closure':
|
if stack[-1][0] != 'closure':
|
||||||
raise ValueError("while in quote mode the top of the stack should be a closure")
|
raise ValueError("while in quote mode the top of the stack should be a closure")
|
||||||
|
if line == 'END QUOTE':
|
||||||
|
quoting = quoting - 1
|
||||||
|
elif line == 'QUOTE':
|
||||||
|
quoting = quoting + 1
|
||||||
|
|
||||||
|
if quoting > 0: # if this wasn't the last 'END QUOTE', i.e. after decrementing we're still quoting, then add the instruction to the closure
|
||||||
stack[-1] = ('closure', (stack[-1][1][0] + [line], stack[-1][1][1]))
|
stack[-1] = ('closure', (stack[-1][1][0] + [line], stack[-1][1][1]))
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
|
||||||
elif line == 'QUOTE':
|
elif line == 'QUOTE':
|
||||||
stack.append(('closure', ([],[])))
|
stack.append(('closure', ([],[])))
|
||||||
quoting = True
|
quoting = 1
|
||||||
|
|
||||||
# functions
|
# functions
|
||||||
elif line == 'CALL':
|
elif line == 'CALL':
|
||||||
if stack[-1][0] != "closure":
|
if stack[-1][0] != "closure":
|
||||||
raise ValueError("CALL expected a closure")
|
raise ValueError("CALL expected a closure")
|
||||||
stack, env = interpret(stack[:-1] + stack[-1][1][1], env, stack[-1][1][0], edge_annotations)
|
stack, env = interpret(stack[:-1] + stack[-1][1][1], env, stack[-1][1][0])
|
||||||
elif line == 'PARTIAL':
|
elif line == 'PARTIAL':
|
||||||
# push stack[-2] onto the closure's stack
|
# push stack[-2] onto the closure's stack
|
||||||
if stack[-1][0] != "closure":
|
if stack[-1][0] != "closure":
|
||||||
|
@ -169,14 +190,14 @@ def interpret(stack, env, program, edge_annotations):
|
||||||
if stack[-2][0] != "list":
|
if stack[-2][0] != "list":
|
||||||
raise ValueError("MAP expected a list as the second (deeper) element on the stack")
|
raise ValueError("MAP expected a list as the second (deeper) element on the stack")
|
||||||
closure = stack[-1][1]
|
closure = stack[-1][1]
|
||||||
stack, env = interpret_map(stack[:-2], env, stack[-1][1], stack[-2][1], edge_annotations)
|
stack, env = interpret_map(stack[:-2], env, stack[-1][1], stack[-2][1])
|
||||||
elif line == 'FILTER':
|
elif line == 'FILTER':
|
||||||
if stack[-1][0] != "closure":
|
if stack[-1][0] != "closure":
|
||||||
raise ValueError("FILTER expected a closure at the top of the stack")
|
raise ValueError("FILTER expected a closure at the top of the stack")
|
||||||
if stack[-2][0] != "list":
|
if stack[-2][0] != "list":
|
||||||
raise ValueError("FILTER expected a list as the second (deeper) element on the stack")
|
raise ValueError("FILTER expected a list as the second (deeper) element on the stack")
|
||||||
closure = stack[-1][1]
|
closure = stack[-1][1]
|
||||||
stack, env = interpret_filter(stack[:-2], env, stack[-1][1], stack[-2][1], edge_annotations)
|
stack, env = interpret_filter(stack[:-2], env, stack[-1][1], stack[-2][1])
|
||||||
|
|
||||||
elif line == 'DEBUG':
|
elif line == 'DEBUG':
|
||||||
print('stack:')
|
print('stack:')
|
||||||
|
@ -207,6 +228,12 @@ def interpret(stack, env, program, edge_annotations):
|
||||||
stack = stack[:-2] + [("bool", stack[-1] <= stack[-2])]
|
stack = stack[:-2] + [("bool", stack[-1] <= stack[-2])]
|
||||||
elif line == 'GE':
|
elif line == 'GE':
|
||||||
stack = stack[:-2] + [("bool", stack[-1] >= stack[-2])]
|
stack = stack[:-2] + [("bool", stack[-1] >= stack[-2])]
|
||||||
|
elif line in boolOperations:
|
||||||
|
if stack[-1][0] != "bool":
|
||||||
|
raise ValueError(line + " expected a boolean at the top of the stack")
|
||||||
|
if stack[-2][0] != "bool":
|
||||||
|
raise ValueError(line + " expected a boolean as the second (deeper) element on the stack")
|
||||||
|
stack = stack[:-2] + [("bool", boolOperations[line](stack[-1], stack[-2]))]
|
||||||
elif line == 'DROP':
|
elif line == 'DROP':
|
||||||
stack = stack[:-1]
|
stack = stack[:-1]
|
||||||
elif line == 'DUP':
|
elif line == 'DUP':
|
||||||
|
@ -236,33 +263,32 @@ def interpret(stack, env, program, edge_annotations):
|
||||||
stack = stack[:-1]
|
stack = stack[:-1]
|
||||||
elif line.startswith('GET '):
|
elif line.startswith('GET '):
|
||||||
stack.append(env[line[len('GET '):]])
|
stack.append(env[line[len('GET '):]])
|
||||||
elif line == '.Annotation':
|
elif line.startswith('.Annotations.'):
|
||||||
if stack[-1][0] != "geometry":
|
annotationName = line[len('.Annotations.'):]
|
||||||
raise ValueError(".Annotation expected a geometry elemnt")
|
if stack[-1][0] != "annotated_shape":
|
||||||
stack = stack[:-1] + [('string', edge_annotations.get(stack[-1][1][0], None))]
|
raise ValueError(".Annotations expected an annotated shape")
|
||||||
|
stack = stack[:-1] + [stack[-1][1][1].get(annotationName, ('none', None))]
|
||||||
elif line in allowed_attributes.keys():
|
elif line in allowed_attributes.keys():
|
||||||
if stack[-1][0] != "geometry":
|
if stack[-1][0] != "geometry":
|
||||||
raise ValueError(line + " expected a geometry elemnt")
|
raise ValueError(line + " expected a geometry elemnt")
|
||||||
stack = stack[:-1] + [(allowed_attributes[line], getattr(stack[-1][1][1], line[1:]))]
|
stack = stack[:-1] + [(allowed_attributes[line], getattr(stack[-1][1][1], line[1:]))]
|
||||||
else:
|
else:
|
||||||
raise ValueError('Unknown operation: "' + line + '"' + repr(line) + ". " + str(line.strip() == '') + "; " + str(len(line)))
|
raise ValueError('Unknown operation: "' + line + '", repr=' + repr(line) + ". empty after strip=" + str(line.strip() == '') + ", len=" + str(len(line)))
|
||||||
return stack, env
|
return stack, env
|
||||||
|
|
||||||
def user_filter(filter, sketch):
|
def user_filter(filter, sketch):
|
||||||
filter = [line.lstrip() for line in filter]
|
filter = [line.lstrip() for line in filter]
|
||||||
filter = [line for line in filter if not line.startswith('#')]
|
filter = [line for line in filter if not line.startswith('#')]
|
||||||
constraint_re_matches = [(c,re.match(r"^__(.*)\.[0-9]+$", c.Name)) for c in sketch.Constraints]
|
stack = [('list', [('annotated_shape', sh) for sh in getAnnotatedShapes(sketch)])]
|
||||||
edge_annotations = dict((c.First,match.group(1)) for c,match in constraint_re_matches if match)
|
stack, env = interpret(stack, {}, filter)
|
||||||
stack = [('list', [('geometry', (i, g)) for i, g in enumerate(sketch.Geometry)])]
|
|
||||||
stack, env = interpret(stack, {}, filter, edge_annotations)
|
|
||||||
if len(stack) != 1:
|
if len(stack) != 1:
|
||||||
raise ValueError("The stack should contain a single element after applying the filter's operations.")
|
raise ValueError("The stack should contain a single element after applying the filter's operations.")
|
||||||
if stack[0][0] != 'list':
|
if stack[0][0] != 'list':
|
||||||
raise ValueError("The stack should contain a list after applying the filter's operations.")
|
raise ValueError("The stack should contain a list after applying the filter's operations.")
|
||||||
for i, (type, g) in enumerate(stack[0][1]):
|
for i, (type, g) in enumerate(stack[0][1]):
|
||||||
if type != 'geometry':
|
if type != 'annotated_shape':
|
||||||
raise ValueError("The stack should contain a list of geometry elemnents after applying the filter's operations, wrong type for list element " + str(i) + " : " + str(type))
|
raise ValueError("The stack should contain a list of annotated shape elemnents after applying the filter's operations, wrong type for list element " + str(i) + " : " + str(type))
|
||||||
return [g for type,(id,g) in stack[0][1]]
|
return [shape for type,(shape,annotations) in stack[0][1]]
|
||||||
|
|
||||||
|
|
||||||
class _latticeDowngrade:
|
class _latticeDowngrade:
|
||||||
|
@ -318,7 +344,6 @@ class _latticeDowngrade:
|
||||||
rst = shp.Edges
|
rst = shp.Edges
|
||||||
elif obj.Mode == 'SketchEdges':
|
elif obj.Mode == 'SketchEdges':
|
||||||
rst = user_filter(obj.Filter, obj.Base)
|
rst = user_filter(obj.Filter, obj.Base)
|
||||||
rst = [g.toShape() for g in rst]
|
|
||||||
elif obj.Mode == 'Seam edges':
|
elif obj.Mode == 'Seam edges':
|
||||||
rst = getAllSeams(shp)
|
rst = getAllSeams(shp)
|
||||||
elif obj.Mode == 'Non-seam edges':
|
elif obj.Mode == 'Non-seam edges':
|
||||||
|
|
|
@ -32,10 +32,12 @@ import FreeCAD as App
|
||||||
import Part
|
import Part
|
||||||
|
|
||||||
from lattice2Common import *
|
from lattice2Common import *
|
||||||
|
from lattice2Utils import getAnnotatedShapes
|
||||||
import lattice2BaseFeature
|
import lattice2BaseFeature
|
||||||
import lattice2Executer as Executer
|
import lattice2Executer as Executer
|
||||||
import lattice2Markers as markers
|
import lattice2Markers as markers
|
||||||
import lattice2Subsequencer as Subsequencer
|
import lattice2Subsequencer as Subsequencer
|
||||||
|
from lattice2BaseFeature import assureProperty #assureProperty(self, selfobj, proptype, propname, defvalue, group, tooltip)
|
||||||
|
|
||||||
# --------------------------- general routines ------------------------------------------------
|
# --------------------------- general routines ------------------------------------------------
|
||||||
|
|
||||||
|
@ -93,6 +95,13 @@ class LatticeTopoSeries(lattice2BaseFeature.LatticeFeature):
|
||||||
obj.Recomputing = ["Disabled", "Recompute Once", "Enabled"]
|
obj.Recomputing = ["Disabled", "Recompute Once", "Enabled"]
|
||||||
obj.Recomputing = "Disabled" # recomputing TopoSeries can be very long, so disable it by default
|
obj.Recomputing = "Disabled" # recomputing TopoSeries can be very long, so disable it by default
|
||||||
|
|
||||||
|
self.assureProperties(obj)
|
||||||
|
|
||||||
|
def assureProperties(self, selfobj):
|
||||||
|
# We cannot use a hidden PythonObject property, because it contains Edges and they are not serializable
|
||||||
|
#assureProperty(selfobj, "App::PropertyPythonObject", "AnnotatedShapes", [], "Lattice TopoSeries", "internal: stores the list of shapes with their annotations")
|
||||||
|
self.AnnotatedShapes = []
|
||||||
|
|
||||||
def makeSubsequence(self, selfobj, object_to_loop):
|
def makeSubsequence(self, selfobj, object_to_loop):
|
||||||
|
|
||||||
# gather up the links
|
# gather up the links
|
||||||
|
@ -128,6 +137,8 @@ class LatticeTopoSeries(lattice2BaseFeature.LatticeFeature):
|
||||||
if selfobj.Recomputing == "Disabled":
|
if selfobj.Recomputing == "Disabled":
|
||||||
raise ValueError(selfobj.Name+": recomputing of this object is currently disabled. Modify 'Recomputing' property to enable it.")
|
raise ValueError(selfobj.Name+": recomputing of this object is currently disabled. Modify 'Recomputing' property to enable it.")
|
||||||
try:
|
try:
|
||||||
|
allAnnotatedShapes = []
|
||||||
|
self.assureProperties(selfobj)
|
||||||
|
|
||||||
# do the subsequencing in this document first, to verify stuff is set up correctly, and to obtain sequence length
|
# do the subsequencing in this document first, to verify stuff is set up correctly, and to obtain sequence length
|
||||||
if self.isVerbose():
|
if self.isVerbose():
|
||||||
|
@ -184,7 +195,7 @@ class LatticeTopoSeries(lattice2BaseFeature.LatticeFeature):
|
||||||
doc2.recompute()
|
doc2.recompute()
|
||||||
|
|
||||||
#get shape
|
#get shape
|
||||||
shape = None
|
annotatedShapes = None
|
||||||
for obj in doc2.Objects:
|
for obj in doc2.Objects:
|
||||||
if 'Invalid' in obj.State:
|
if 'Invalid' in obj.State:
|
||||||
Executer.error(obj,"Recomputing shape for subsequence index "+repr(i)+" failed.")
|
Executer.error(obj,"Recomputing shape for subsequence index "+repr(i)+" failed.")
|
||||||
|
@ -197,10 +208,11 @@ class LatticeTopoSeries(lattice2BaseFeature.LatticeFeature):
|
||||||
pass
|
pass
|
||||||
if scale < DistConfusion * 100:
|
if scale < DistConfusion * 100:
|
||||||
scale = 1.0
|
scale = 1.0
|
||||||
shape = markers.getNullShapeShape(scale)
|
annotatedShapes = [(markers.getNullShapeShape(scale), { 'IsNullShape': ('boolean', True) })]
|
||||||
if shape is None:
|
if annotatedShapes is None:
|
||||||
shape = object_to_take_in_doc2.Shape.copy()
|
annotatedShapes = getAnnotatedShapes(object_to_take_in_doc2)
|
||||||
output_shapes.append(shape)
|
output_shapes.append(Part.Compound([sh for sh, ann in annotatedShapes]))
|
||||||
|
allAnnotatedShapes.extend(annotatedShapes)
|
||||||
|
|
||||||
#update progress
|
#update progress
|
||||||
if bGui:
|
if bGui:
|
||||||
|
@ -223,6 +235,7 @@ class LatticeTopoSeries(lattice2BaseFeature.LatticeFeature):
|
||||||
|
|
||||||
|
|
||||||
selfobj.Shape = Part.makeCompound(output_shapes)
|
selfobj.Shape = Part.makeCompound(output_shapes)
|
||||||
|
self.AnnotatedShapes = allAnnotatedShapes
|
||||||
|
|
||||||
output_is_lattice = lattice2BaseFeature.isObjectLattice(screen(selfobj.ObjectToTake))
|
output_is_lattice = lattice2BaseFeature.isObjectLattice(screen(selfobj.ObjectToTake))
|
||||||
if 'Auto' in selfobj.isLattice:
|
if 'Auto' in selfobj.isLattice:
|
||||||
|
@ -234,6 +247,12 @@ class LatticeTopoSeries(lattice2BaseFeature.LatticeFeature):
|
||||||
selfobj.Recomputing = "Disabled"
|
selfobj.Recomputing = "Disabled"
|
||||||
return "suppress" # "suppress" disables most convenience code of lattice2BaseFeature. We do it because we build a nested array, which are not yet supported by lattice WB.
|
return "suppress" # "suppress" disables most convenience code of lattice2BaseFeature. We do it because we build a nested array, which are not yet supported by lattice WB.
|
||||||
|
|
||||||
|
def getAnnotatedShapes(self, selfobj):
|
||||||
|
# The attribute is not serializable (because it contains Edges), so it is necessary to execute() the object at least once to get the AnnotatedShapes
|
||||||
|
if not hasattr(self, 'AnnotatedShapes'):
|
||||||
|
self.execute(selfobj)
|
||||||
|
return self.AnnotatedShapes
|
||||||
|
|
||||||
class ViewProviderLatticeTopoSeries(lattice2BaseFeature.ViewProviderLatticeFeature):
|
class ViewProviderLatticeTopoSeries(lattice2BaseFeature.ViewProviderLatticeFeature):
|
||||||
|
|
||||||
def getIcon(self):
|
def getIcon(self):
|
||||||
|
|
|
@ -21,6 +21,8 @@
|
||||||
#* *
|
#* *
|
||||||
#***************************************************************************
|
#***************************************************************************
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
__title__="Utility functions for Lattice2"
|
__title__="Utility functions for Lattice2"
|
||||||
__author__ = "DeepSOIC"
|
__author__ = "DeepSOIC"
|
||||||
__url__ = ""
|
__url__ = ""
|
||||||
|
@ -92,3 +94,28 @@ def linkSubList_convertToOldStyle(references):
|
||||||
# old style references, no conversion required
|
# old style references, no conversion required
|
||||||
result.append(tup)
|
result.append(tup)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
def getAnnotatedShape(object, i, g, annotations_from_constraints):
|
||||||
|
kvs = annotations_from_constraints.get(i, '')
|
||||||
|
kvs = kvs.split(',')
|
||||||
|
if kvs == ['']:
|
||||||
|
kvs = []
|
||||||
|
kvs = [kv.split('=',1) for kv in kvs]
|
||||||
|
kvs = [(kv[0], ('string', kv[1])) if len(kv) == 2 else (kv[0], ('bool', True)) for kv in kvs]
|
||||||
|
kvs = dict(kvs, Geometry=('geometry', g))
|
||||||
|
sh = g.toShape().copy()
|
||||||
|
sh.Placement = object.Placement
|
||||||
|
return (sh, kvs)
|
||||||
|
|
||||||
|
def getAnnotatedShapes(object):
|
||||||
|
""" returns a list of the form [ (shape, { 'k': ('type', v), … }) …] """
|
||||||
|
if object.TypeId == 'Sketcher::SketchObject':
|
||||||
|
constraint_re_matches = [(c,re.match(r"^__(.*)\.[0-9]+$", c.Name)) for c in object.Constraints]
|
||||||
|
annotations_from_constraints = dict((c.First,match.group(1)) for c,match in constraint_re_matches if match)
|
||||||
|
return [getAnnotatedShape(object, i, g, annotations_from_constraints) for i,g in enumerate(object.Geometry)]
|
||||||
|
elif hasattr(object, 'getAnnotatedShapes') and callable(object.getAnnotatedShapes):
|
||||||
|
return object.getAnnotatedShapes()
|
||||||
|
elif hasattr(object, 'Proxy') and hasattr(object.Proxy, 'getAnnotatedShapes') and callable(object.Proxy.getAnnotatedShapes):
|
||||||
|
return object.Proxy.getAnnotatedShapes(object)
|
||||||
|
else:
|
||||||
|
return [(object.Shape.copy(), dict())]
|
||||||
|
|
Loading…
Reference in New Issue
Block a user