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
|
||||||
|
@ -70,40 +70,47 @@ example = """
|
||||||
# In the stack representations below, the topmost element is on the right.
|
# In the stack representations below, the topmost element is on the right.
|
||||||
|
|
||||||
# <instruction> : <stack before> : <stack after> : description
|
# <instruction> : <stack before> : <stack after> : description
|
||||||
# QUOTE : ... : ... closure : quotes the following instructions until "QUOTE END" for later use via CALL, PARTIAL or a higher-order function like MAP
|
# QUOTE : ... : ... closure : quotes the following instructions until "QUOTE END" for later use via CALL, PARTIAL or a higher-order function like MAP
|
||||||
# END QUOTE : ends quotation mode
|
# END QUOTE : ends quotation mode
|
||||||
# CALL : ... closure : ...UpdatedStack : calls the closure and lets it manipulate the stack (no protection). The closure's saved stack is appended, so its instructions start executing with the stack "... saved"
|
# CALL : ... closure : ...UpdatedStack : calls the closure and lets it manipulate the stack (no protection). The closure's saved stack is appended, so its instructions start executing with the stack "... saved"
|
||||||
# PARTIAL : ... arg closure : ... closure' : adds the arg on top of the saved stack of the closure
|
# PARTIAL : ... arg closure : ... closure' : adds the arg on top of the saved stack of the closure
|
||||||
# DEBUG : ... : ... : prints the current stack
|
# DEBUG : ... : ... : prints the current stack
|
||||||
# MAP : ... list closure : ... list' : calls the closure for each of the elements of the list. The closure's instructions are executed with the stack "... saved elt". After each call, the top of the stack is popped and stored in a list. This list is left as the top of the stack at the end
|
# MAP : ... list closure : ... list' : calls the closure for each of the elements of the list. The closure's instructions are executed with the stack "... saved elt". After each call, the top of the stack is popped and stored in a list. This list is left as the top of the stack at the end
|
||||||
# FILTER : ... list closure : ... list' : calls the closure for each of the elements of the list. The closure's instructions are executed with the stack "... saved elt". After each call, the top of the stack is popped and if it is true, the original element is added to a list. This list is left as the top of the stack at the end
|
# FILTER : ... list closure : ... list' : calls the closure for each of the elements of the list. The closure's instructions are executed with the stack "... saved elt". After each call, the top of the stack is popped and if it is true, the original element is added to a list. This list is left as the top of the stack at the end
|
||||||
# STR some text : ... : ... string : pushes "some text" on the stack. The entire line is pushed after removing the first four characters "STR "
|
# STR some text : ... : ... string : pushes "some text" on the stack. The entire line is pushed after removing the first four characters "STR "
|
||||||
# FLOAT 3.14 : ... : ... float : pushes 3.14 on the stack
|
# FLOAT 3.14 : ... : ... float : pushes 3.14 on the stack
|
||||||
# INT 123 : ... : ... int : pushes 123 on the stack
|
# INT 123 : ... : ... int : pushes 123 on the stack
|
||||||
# BOOL True : ... : ... bool : pushes True on the stack. Booleans are True or False
|
# BOOL True : ... : ... bool : pushes True on the stack. Booleans are True or False
|
||||||
# NOT : ... bool : ... bool : pops the top of the stack which must be a boolean, and pushes back its negation
|
# NOT : ... bool : ... bool : pops the top of the stack which must be a boolean, and pushes back its negation
|
||||||
# EQUAL : ... t t : ... bool : pops two elements, pushes True if top == bot, False otherwise. Comparing elements of different types will always return False.
|
# EQUAL : ... t t : ... bool : pops two elements, pushes True if top == bot, False otherwise. Comparing elements of different types will always return False.
|
||||||
# LT : ... t t : ... bool : pops two elements, pushes True if top < bot, False otherwise. Comparing elements of different types will always return False.
|
# LT : ... 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.
|
# 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.
|
||||||
# DROP : ... t : ... : pops the top of the stack and discards it
|
# AND : ... bool bool : ... bool : pops two booleans, pushes (top and bot)
|
||||||
# DUP : ... t : ... t t : pops the top of the stack, and pushes it back twice (duplication of the top of the stack)
|
# OR : ... bool bool : ... bool : pops two booleans, pushes (top or bot)
|
||||||
# SWAP : ... t u : ... u t : pops two elements, and pushes them back in reverse order
|
# XOR : ... bool bool : ... bool : pops two booleans, pushes (top xor bot)
|
||||||
# PAIR : ... t u : ... pair : pops two elements, and pushes a pair containing these two elements
|
# NAND : ... bool bool : ... bool : pops two booleans, pushes (top nand bot)
|
||||||
# UNPAIR : ... pair : ... t u : pops a pair and pushes its two elements back onto the stack
|
# NOR : ... bool bool : ... bool : pops two booleans, pushes (top nor bot)
|
||||||
# NIL : ... : ... list : pushes the empty list onto the stack
|
# NXOR : ... bool bool : ... bool : pops two booleans, pushes (top nxor bot)
|
||||||
# CONS : ... list t : ... list : pops two elements, adds the top at the head of the bot, and pushes back the new list
|
# DROP : ... t : ... : pops the top of the stack and discards it
|
||||||
# UNCONS : ... list : ... list t : pops the top of the stack which must be a list, and pushes back the tail of the list and its first element
|
# DUP : ... t : ... t t : pops the top of the stack, and pushes it back twice (duplication of the top of the stack)
|
||||||
# NOP : ... : ... : No operation (NOOP is also accepted)
|
# SWAP : ... t u : ... u t : pops two elements, and pushes them back in reverse order
|
||||||
# SET xyz : ... t : ... : pops the top of the stack, and saves it as a global variable named xyz
|
# PAIR : ... t u : ... pair : pops two elements, and pushes a pair containing these two elements
|
||||||
# GET xyz : ... : ... t : pushes the contents of the global variable xyz on top of the stack
|
# UNPAIR : ... pair : ... t u : pops a pair and pushes its two elements back onto 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.
|
# NIL : ... : ... list : pushes the empty list onto the stack
|
||||||
# .attribute : ... t : ... u : gets the attribute from the object on the top of the stack. Allowed attributes are {allowed_attributes}
|
# CONS : ... list t : ... list : pops two elements, adds the top at the head of the bot, and pushes back the new list
|
||||||
|
# UNCONS : ... list : ... list t : pops the top of the stack which must be a list, and pushes back the tail of the list and its first element
|
||||||
|
# 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
|
||||||
|
# GET xyz : ... : ... t : pushes the contents of the global variable xyz on top of the stack
|
||||||
|
# .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 : ... 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")
|
||||||
stack[-1] = ('closure', (stack[-1][1][0] + [line], stack[-1][1][1]))
|
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]))
|
||||||
|
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