def execute(self,selfobj): #validity check if isObjectLattice(selfobj.Object): import lattice2Executer lattice2Executer.warning(selfobj,"A generic shape is expected, but a placement/array was supplied. It will be treated as a generic shape.") rst = [] #variable to receive the final list of shapes lnkobj = selfobj.Object for subname in selfobj.SubNames: subname = subname.strip() if len(subname)==0: raise ValueError("Empty subname! Not allowed.") if 'Face' in subname: index = int(subname.replace('Face',''))-1 rst.append(lnkobj.Shape.Faces[index]) elif 'Edge' in subname: index = int(subname.replace('Edge',''))-1 rst.append(lnkobj.Shape.Edges[index]) elif 'Vertex' in subname: index = int(subname.replace('Vertex',''))-1 rst.append(lnkobj.Shape.Vertexes[index]) else: lattice2Executer.warning(selfobj,"Unexpected subelement name: "+subname+". Trying to extract it with .Shape.getElement()...") rst.append(linkobj.Shape.getElement(subname)) if len(rst) == 0: scale = 1.0 try: if selfobj.Object: scale = selfobj.Object[0].Shape.BoundBox.DiagonalLength/math.sqrt(3) except Exception as err: App.Console.PrintError(selfobj.Name+": Failed to estimate size of marker shape") if scale < DistConfusion * 100: scale = 1.0 selfobj.Shape = markers.getNullShapeShape(scale) raise ValueError('Nothing is linked, apparently!') #Feeding empty compounds to FreeCAD seems to cause rendering issues, otherwise it would have been a good idea to output nothing. if len(rst) > 1: selfobj.Shape = Part.makeCompound(rst) else: # don't make compound of one shape, output it directly sh = rst[0] # absorb placement of original shape sh = ShapeCopy.transformCopy(sh) # apply Placement that is filled into feature's Placement property (not necessary) sh.Placement = selfobj.Placement selfobj.Shape = sh
def execute(self, selfobj): self.assureProperties(selfobj) #validity check if isObjectLattice(screen(selfobj.Object)): import lattice2Executer lattice2Executer.warning( selfobj, "A generic shape is expected, but a placement/array was supplied. It will be treated as a generic shape." ) lnkobj = screen(selfobj.Object) sh = lnkobj.Shape # subsequencing full_link = (lnkobj, selfobj.SubNames) if selfobj.Looping == 'Single': lnkseq = [full_link] else: lnkseq = LSS.Subsequence_auto(full_link, selfobj.CompoundTraversal, selfobj.Looping) # main code seq_packs = [ ] #pack = single item of subsequence. Pack contains list of elements that were selected. shape_count = 0 for lnk in lnkseq: # loop over subsequence (if Looping == 'Single', this loop will only loop once) # extract the pack assert ( lnk[0] is lnkobj ) # all links should point to elements of one object anyway subnames = lnk[1] pack = [ ] #acculumator, to eventually become a compound of shapes for this subsequence item for subname in subnames: subname = subname.strip() if len(subname) == 0: raise ValueError("Empty subname! Not allowed.") if 'Face' in subname: # manual handling of standard cases, because support for negative indexing is needed index = int(subname.replace('Face', '')) - 1 pack.append(sh.Faces[index]) elif 'Edge' in subname: index = int(subname.replace('Edge', '')) - 1 pack.append(sh.Edges[index]) elif 'Vertex' in subname: index = int(subname.replace('Vertex', '')) - 1 pack.append(sh.Vertexes[index]) else: #fail-safe. non-standard sublink. import lattice2Executer lattice2Executer.warning( selfobj, "Unexpected subelement name: " + subname + ". Trying to extract it with .Shape.getElement()...") pack.append(sh.getElement(subname)) shape_count += len(pack) # convert list into compound if len(pack) == 1: pack = ShapeCopy.transformCopy(pack[0]) else: pack = Part.makeCompound(pack) # accumulate seq_packs.append(pack) # convert list into compound if len(seq_packs) == 1: seq_packs = seq_packs[0] else: seq_packs = Part.makeCompound(seq_packs) if shape_count == 0: # no shapes collected, FAIL! scale = 1.0 try: if screen(selfobj.Object): scale = screen( selfobj.Object ).Shape.BoundBox.DiagonalLength / math.sqrt(3) except Exception as err: App.Console.PrintError( selfobj.Name + ": Failed to estimate size of marker shape") if scale < DistConfusion * 100: scale = 1.0 selfobj.Shape = markers.getNullShapeShape(scale) raise ValueError( 'Nothing is linked, apparently!' ) #Feeding empty compounds to FreeCAD seems to cause rendering issues, otherwise it would have been a good idea to output nothing. # done! selfobj.Shape = seq_packs
def execute(self,obj): rst = [] #variable to receive the final list of shapes shp = screen(obj.Base).Shape if obj.Mode == 'bypass': rst = [shp] elif obj.Mode == 'Leaves': rst = LCE.AllLeaves(shp) elif obj.Mode == 'CompSolids': rst = shp.CompSolids elif obj.Mode == 'Solids': rst = shp.Solids elif obj.Mode == 'Shells': rst = shp.Shells elif obj.Mode == 'OpenWires': openWires = [] shells = shp.Shells for shell in shells: openEdges = shell.getFreeEdges().childShapes() if len(openEdges) > 1: # edges need to be fused into wires clusters = Part.getSortedClusters(openEdges) wires = [Part.Wire(cluster) for cluster in clusters] else: wires = openEdges openWires.extend(wires) rst = openWires elif obj.Mode == 'Faces': rst = shp.Faces elif obj.Mode == 'Wires': rst = shp.Wires elif obj.Mode == 'Edges': rst = shp.Edges elif obj.Mode == 'Seam edges': rst = getAllSeams(shp) elif obj.Mode == 'Non-seam edges': seams = getAllSeams(shp) edges = shp.Edges rst = [] for e in edges: bIsSeam = False for s in seams: if e.isSame(s): bIsSeam = True break if not bIsSeam: rst.append(e) elif obj.Mode == 'Vertices': rst = shp.Vertexes else: raise ValueError('Downgrade mode not implemented:'+obj.Mode) if len(rst) == 0: scale = 1.0 if not screen(obj.Base).Shape.isNull(): scale = screen(obj.Base).Shape.BoundBox.DiagonalLength/math.sqrt(3) if scale < DistConfusion * 100: scale = 1.0 obj.Shape = markers.getNullShapeShape(scale) raise ValueError('Downgrade output is null') #Feeding empty compounds to FreeCAD seems to cause rendering issues, otherwise it would have been a good idea to output nothing. obj.Shape = Part.makeCompound(rst) return
def derivedExecute(self, selfobj): if selfobj.Recomputing == "Disabled": raise ValueError( selfobj.Name + ": recomputing of this object is currently disabled. Modify 'Recomputing' property to enable it." ) try: # do the subsequencing in this document first, to verify stuff is set up correctly, and to obtain sequence length if self.isVerbose(): print("In-place pre-subsequencing, for early check") n_seq, subs_linkdict = self.makeSubsequence( selfobj, screen(selfobj.ObjectToLoopOver)) bGui = bool( App.GuiUp ) and Executer.globalIsCreatingLatticeFeature #disabled for most recomputes, because it causes a crash if property edits are approved by hitting Enter if bGui: import PySide progress = PySide.QtGui.QProgressDialog( u"Recomputing " + selfobj.Label, u"Abort", 0, n_seq + 1) progress.setModal(True) progress.show() doc1 = selfobj.Document doc2 = App.newDocument() object_to_take_in_doc2 = None # define the variable, to prevent del() in finally block from raising another error object_to_loop_in_doc2 = None try: if self.isVerbose(): print( "Copying object with dependencies to a temporary document..." ) doc2.copyObject(screen(selfobj.ObjectToTake), True) if self.isVerbose(): print("Enabling nested para/toposeries, if any...") #if there are nested para/toposeries in the dependencies, make sure to enable them for objd2 in doc2.Objects: if hasattr(objd2, "Recomputing"): try: objd2.Recomputing = "Enabled" objd2.purgeTouched() except exception: Executer.warning( selfobj, "Failed to enable recomputing of " + objd2.Name) object_to_take_in_doc2 = doc2.getObject( screen(selfobj.ObjectToTake).Name) object_to_loop_in_doc2 = doc2.getObject( screen(selfobj.ObjectToLoopOver).Name) if bGui: progress.setValue(1) if self.isVerbose(): print("Repeating subsequencing in temporary document...") n_seq, subs_linkdict = self.makeSubsequence( selfobj, object_to_loop_in_doc2) output_shapes = [] for i in range(n_seq): if self.isVerbose(): print("Computing {x}/{y}".format(x=i + 1, y=n_seq)) for key in subs_linkdict: writeProperty(doc2, key[0], key[1], subs_linkdict[key][i]) #recompute doc2.recompute() #get shape shape = None for obj in doc2.Objects: if 'Invalid' in obj.State: Executer.error( obj, "Recomputing shape for subsequence index " + repr(i) + " failed.") scale = 1.0 try: if not screen( selfobj.ObjectToTake).Shape.isNull(): scale = screen( selfobj.ObjectToTake ).Shape.BoundBox.DiagonalLength / math.sqrt( 3) except Exception: pass if scale < DistConfusion * 100: scale = 1.0 shape = markers.getNullShapeShape(scale) if shape is None: shape = object_to_take_in_doc2.Shape.copy() output_shapes.append(shape) #update progress if bGui: progress.setValue(progress.value() + 1) if progress.wasCanceled(): raise Executer.CancelError() finally: #delete all references, before destroying the document. Probably not required, but to be sure... if self.isVerbose(): print("Cleanup...") del (object_to_take_in_doc2) del (object_to_loop_in_doc2) doc2_name = doc2.Name del (doc2) App.closeDocument(doc2_name) if bGui: progress.setValue(n_seq + 1) selfobj.Shape = Part.makeCompound(output_shapes) output_is_lattice = lattice2BaseFeature.isObjectLattice( screen(selfobj.ObjectToTake)) if 'Auto' in selfobj.isLattice: new_isLattice = 'Auto-On' if output_is_lattice else 'Auto-Off' if selfobj.isLattice != new_isLattice: #check, to not cause onChanged without necessity (onChange messes with colors, it's better to keep user color) selfobj.isLattice = new_isLattice finally: if selfobj.Recomputing == "Recompute Once": 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.
def derivedExecute(self,selfobj): # values generator should be functional even if recomputing is disabled, so do it first self.assureGenerator(selfobj) self.generator.updateReadonlyness() self.generator.execute() if selfobj.Recomputing == "Disabled": raise ValueError(selfobj.Name+": recomputing of this object is currently disabled. Modify 'Recomputing' property to enable it.") try: #test parameter references and read out their current values refstr = selfobj.ParameterRef #dict(selfobj.ExpressionEngine)["ParameterRef"] refstrs = refstr.replace(";","\t").split("\t") defvalues = [] for refstr in refstrs: refstr = refstr.strip(); val = None; try: val = getParameter(selfobj.Document,refstr) except Exception as err: App.Console.PrintError("{obj}: failed to read out parameter '{param}': {err}\n" .format(obj= selfobj.Name, param= refstr, err= err.message)) defvalues.append(val) N_params = len(defvalues) if N_params == 0: raise ValueError(selfobj.Name+": ParameterRef is not set. It is required.") #parse values values = [] for strrow in selfobj.Values: if len(strrow) == 0: break; row = strrow.split(";") row = [(strv.strip() if len(strv.strip())>0 else None) for strv in row] # clean out spaces and replace empty strings with None if len(row) < N_params: row += [None]*(N_params - len(row)) values.append(row) # convert values to type, filling in defaults where values are missing for row in values: for icol in range(N_params): strv = row[icol] val = None if strv is None: val = defvalues[icol] elif selfobj.ParameterType == 'float' or selfobj.ParameterType == 'int': val = float(strv.replace(",",".")) if selfobj.ParameterType == 'int': val = int(round(val)) elif selfobj.ParameterType == 'string': val = strv.strip() else: raise ValueError(selfobj.Name + ": ParameterType option not implemented: "+selfobj.ParameterType) row[icol] = val if len(values) == 0: scale = 1.0 try: if not selfobj.Object.Shape.isNull(): scale = selfobj.Object.Shape.BoundBox.DiagonalLength/math.sqrt(3) except Exception: pass if scale < DistConfusion * 100: scale = 1.0 selfobj.Shape = markers.getNullShapeShape(scale) raise ValueError(selfobj.Name + ": list of values is empty.") bGui = False #bool(App.GuiUp) #disabled temporarily, because it causes a crash if property edits are approved by hitting Enter if bGui: import PySide progress = PySide.QtGui.QProgressDialog(u"Recomputing "+selfobj.Label, u"Abort", 0, len(values)+1) progress.setModal(True) progress.show() doc1 = selfobj.Document doc2 = App.newDocument() object_in_doc2 = None # define the variable, to prevent del() in finally block from raising another error try: doc2.copyObject(selfobj.Object, True) #if there are nested paraseries in the dependencies, make sure to enable them for objd2 in doc2.Objects: if hasattr(objd2,"Recomputing"): try: objd2.Recomputing = "Enabled" objd2.purgeTouched() except exception: lattice2Executer.warning(selfobj,"Failed to enable recomputing of "+objd2.Name) object_in_doc2 = doc2.getObject(selfobj.Object.Name) if bGui: progress.setValue(1) output_shapes = [] for row in values: for icol in range(len(row)): setParameter(doc2, refstrs[icol].strip(), row[icol]) #recompute doc2.recompute() #get shape shape = None for obj in doc2.Objects: if 'Invalid' in obj.State: lattice2Executer.error(obj,"Recomputing shape for parameter value of "+repr(row)+" failed.") scale = 1.0 try: if not selfobj.Object.Shape.isNull(): scale = selfobj.Object.Shape.BoundBox.DiagonalLength/math.sqrt(3) except Exception: pass if scale < DistConfusion * 100: scale = 1.0 shape = markers.getNullShapeShape(scale) if shape is None: shape = object_in_doc2.Shape.copy() output_shapes.append(shape) #update progress if bGui: progress.setValue(progress.value()+1) if progress.wasCanceled(): raise lattice2Executer.CancelError() finally: #delete all references, before destroying the document. Probably not required, but to be sure... del(object_in_doc2) doc2_name = doc2.Name del(doc2) App.closeDocument(doc2_name) if bGui: progress.setValue(len(values)+1) selfobj.Shape = Part.makeCompound(output_shapes) output_is_lattice = lattice2BaseFeature.isObjectLattice(selfobj.Object) if 'Auto' in selfobj.isLattice: new_isLattice = 'Auto-On' if output_is_lattice else 'Auto-Off' if selfobj.isLattice != new_isLattice:#check, to not cause onChanged without necessity (onChange messes with colors, it's better to keep user color) selfobj.isLattice = new_isLattice finally: if selfobj.Recomputing == "Recompute Once": 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.
def execute(self, obj): # please, don't override. Override derivedExecute instead. plms = self.derivedExecute(obj) if plms is not None: if plms == "suppress": return obj.NumElements = len(plms) shapes = [] markerSize = obj.MarkerSize if markerSize < DistConfusion: markerSize = getMarkerSizeEstimate(plms, obj) marker = lattice2Markers.getPlacementMarker( scale=markerSize, markerID=obj.MarkerShape) bExposing = False if obj.ExposePlacement: if len(plms) == 1: bExposing = True else: lattice2Executer.warning( obj, "Multiple placements are being fed, can't expose placements. Placement property will be forced to zero." ) obj.Placement = App.Placement() if bExposing: obj.Shape = shallowCopy(marker) obj.Placement = plms[0] else: for plm in plms: sh = shallowCopy(marker) sh.Placement = plm shapes.append(sh) if len(shapes) == 0: obj.Shape = lattice2Markers.getNullShapeShape(markerSize) raise ValueError('Lattice object is null') sh = Part.makeCompound(shapes) sh.Placement = obj.Placement obj.Shape = sh if obj.isLattice == 'Auto-Off': obj.isLattice = 'Auto-On' else: # DerivedExecute didn't return anything. Thus we assume it # has assigned the shape, and thus we don't do anything. # Moreover, we assume that it is no longer a lattice object, so: if obj.isLattice == 'Auto-On': obj.isLattice = 'Auto-Off' if obj.ExposePlacement: if obj.Shape.ShapeType == "Compound": children = obj.Shape.childShapes() if len(children) == 1: obj.Placement = children[0].Placement obj.Shape = children[0] else: obj.Placement = App.Placement() else: #nothing to do - FreeCAD will take care to make obj.Placement and obj.Shape.Placement synchronized. pass return
def execute(self, obj): # please, don't override. Override derivedExecute instead. plms = self.derivedExecute(obj) if plms is not None: if plms == "suppress": return obj.NumElements = len(plms) shapes = [] markerSize = obj.MarkerSize if markerSize < DistConfusion: markerSize = getMarkerSizeEstimate(plms) marker = lattice2Markers.getPlacementMarker(scale=markerSize, markerID=obj.MarkerShape) bExposing = False if obj.ExposePlacement: if len(plms) == 1: bExposing = True else: lattice2Executer.warning( obj, "Multiple placements are being fed, can't expose placements. Placement property will be forced to zero.", ) obj.Placement = App.Placement() if bExposing: obj.Shape = shallowCopy(marker) obj.Placement = plms[0] else: for plm in plms: sh = shallowCopy(marker) sh.Placement = plm shapes.append(sh) if len(shapes) == 0: obj.Shape = lattice2Markers.getNullShapeShape(markerSize) raise ValueError("Lattice object is null") sh = Part.makeCompound(shapes) obj.Shape = sh if obj.isLattice == "Auto-Off": obj.isLattice = "Auto-On" else: # DerivedExecute didn't return anything. Thus we assume it # has assigned the shape, and thus we don't do anything. # Moreover, we assume that it is no longer a lattice object, so: if obj.isLattice == "Auto-On": obj.isLattice = "Auto-Off" if obj.ExposePlacement: if obj.Shape.ShapeType == "Compound": children = obj.Shape.childShapes() if len(children) == 1: obj.Placement = children[0].Placement obj.Shape = children[0] else: obj.Placement = App.Placement() else: # nothing to do - FreeCAD will take care to make obj.Placement and obj.Shape.Placement synchronized. pass return
def derivedExecute(self, selfobj): # values generator should be functional even if recomputing is disabled, so do it first self.assureGenerator(selfobj) self.generator.updateReadonlyness() self.generator.execute() if selfobj.Recomputing == "Disabled": raise ValueError( selfobj.Name + ": recomputing of this object is currently disabled. Modify 'Recomputing' property to enable it." ) try: #test parameter references and read out their current values refstr = selfobj.ParameterRef #dict(selfobj.ExpressionEngine)["ParameterRef"] refstrs = refstr.replace(";", "\t").split("\t") defvalues = [] for refstr in refstrs: refstr = refstr.strip() val = None try: val = getParameter(selfobj.Document, refstr) except Exception as err: App.Console.PrintError( "{obj}: failed to read out parameter '{param}': {err}\n" .format(obj=selfobj.Name, param=refstr, err=str(err))) defvalues.append(val) N_params = len(defvalues) if N_params == 0: raise ValueError(selfobj.Name + ": ParameterRef is not set. It is required.") #parse values values = [] for strrow in selfobj.Values: if len(strrow) == 0: break row = strrow.split(";") row = [ (strv.strip() if len(strv.strip()) > 0 else None) for strv in row ] # clean out spaces and replace empty strings with None if len(row) < N_params: row += [None] * (N_params - len(row)) values.append(row) # convert values to type, filling in defaults where values are missing for row in values: for icol in range(N_params): strv = row[icol] val = None if strv is None: val = defvalues[icol] elif selfobj.ParameterType == 'float' or selfobj.ParameterType == 'int': val = float(strv.replace(",", ".")) if selfobj.ParameterType == 'int': val = int(round(val)) elif selfobj.ParameterType == 'string': val = strv.strip() else: raise ValueError( selfobj.Name + ": ParameterType option not implemented: " + selfobj.ParameterType) row[icol] = val if len(values) == 0: scale = 1.0 try: if not screen(selfobj.Object).Shape.isNull(): scale = screen( selfobj.Object ).Shape.BoundBox.DiagonalLength / math.sqrt(3) except Exception: pass if scale < DistConfusion * 100: scale = 1.0 selfobj.Shape = markers.getNullShapeShape(scale) raise ValueError(selfobj.Name + ": list of values is empty.") bGui = False #bool(App.GuiUp) #disabled temporarily, because it causes a crash if property edits are approved by hitting Enter if bGui: import PySide progress = PySide.QtGui.QProgressDialog( u"Recomputing " + selfobj.Label, u"Abort", 0, len(values) + 1) progress.setModal(True) progress.show() doc1 = selfobj.Document doc2 = App.newDocument( ) #create temporary doc to do the computations # assign doc's filename before copying objects, otherwise we get errors with xlinks try: doc2.FileName = doc1.FileName except Exception as err: pass #in old FreeCADs, FileName property is read-only, we can safely ignore that object_in_doc2 = None # define the variable, to prevent del() in finally block from raising another error try: doc2.copyObject(screen(selfobj.Object), True) #if there are nested paraseries in the dependencies, make sure to enable them for objd2 in doc2.Objects: if hasattr(objd2, "Recomputing"): try: objd2.Recomputing = "Enabled" objd2.purgeTouched() except exception: lattice2Executer.warning( selfobj, "Failed to enable recomputing of " + objd2.Name) object_in_doc2 = doc2.getObject(screen(selfobj.Object).Name) if bGui: progress.setValue(1) output_shapes = [] for row in values: for icol in range(len(row)): setParameter(doc2, refstrs[icol].strip(), row[icol]) #recompute doc2.recompute() #get shape shape = None for obj in doc2.Objects: if 'Invalid' in obj.State: lattice2Executer.error( obj, "Recomputing shape for parameter value of " + repr(row) + " failed.") scale = 1.0 try: if not screen(selfobj.Object).Shape.isNull(): scale = screen( selfobj.Object ).Shape.BoundBox.DiagonalLength / math.sqrt( 3) except Exception: pass if scale < DistConfusion * 100: scale = 1.0 shape = markers.getNullShapeShape(scale) if shape is None: shape = object_in_doc2.Shape.copy() output_shapes.append(shape) #update progress if bGui: progress.setValue(progress.value() + 1) if progress.wasCanceled(): raise lattice2Executer.CancelError() finally: #delete all references, before destroying the document. Probably not required, but to be sure... del (object_in_doc2) doc2_name = doc2.Name del (doc2) App.closeDocument(doc2_name) if bGui: progress.setValue(len(values) + 1) selfobj.Shape = Part.makeCompound(output_shapes) output_is_lattice = lattice2BaseFeature.isObjectLattice( screen(selfobj.Object)) if 'Auto' in selfobj.isLattice: new_isLattice = 'Auto-On' if output_is_lattice else 'Auto-Off' if selfobj.isLattice != new_isLattice: #check, to not cause onChanged without necessity (onChange messes with colors, it's better to keep user color) selfobj.isLattice = new_isLattice finally: if selfobj.Recomputing == "Recompute Once": 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.
def execute(self, obj): #validity check if isObjectLattice(screen(obj.Base)): import lattice2Executer lattice2Executer.warning( obj, "A generic shape is expected, but an array of placements was supplied. It will be treated as a generic shape." ) rst = [] #variable to receive the final list of shapes shps = screen(obj.Base).Shape.childShapes() if obj.FilterType == 'bypass': rst = shps elif obj.FilterType == 'specific items': rst = [] flags = [False] * len(shps) ranges = obj.items.split(';') for r in ranges: r_v = r.split(':') if len(r_v) == 1: i = int(r_v[0]) rst.append(shps[i]) flags[i] = True elif len(r_v) == 2 or len(r_v) == 3: if len(r_v) == 2: r_v.append( "" ) # fix issue #1: instead of checking length here and there, simply add the missing field =) ifrom = None if len(r_v[0].strip()) == 0 else int(r_v[0]) ito = None if len(r_v[1].strip()) == 0 else int(r_v[1]) istep = None if len(r_v[2].strip()) == 0 else int(r_v[2]) rst = rst + shps[ifrom:ito:istep] for b in flags[ifrom:ito:istep]: b = True else: raise ValueError('index range cannot be parsed:' + r) if obj.Invert: rst = [] for i in range(0, len(shps)): if not flags[i]: rst.append(shps[i]) elif obj.FilterType == 'collision-pass': stencil = screen(obj.Stencil).Shape for s in shps: d = s.distToShape(stencil) if bool(d[0] < DistConfusion) ^ bool(obj.Invert): rst.append(s) elif obj.FilterType == 'window-volume' or obj.FilterType == 'window-area' or obj.FilterType == 'window-length' or obj.FilterType == 'window-distance': vals = [0.0] * len(shps) for i in range(0, len(shps)): if obj.FilterType == 'window-volume': vals[i] = shps[i].Volume elif obj.FilterType == 'window-area': vals[i] = shps[i].Area elif obj.FilterType == 'window-length': vals[i] = shps[i].Length elif obj.FilterType == 'window-distance': vals[i] = shps[i].distToShape(obj.Stencil.Shape)[0] maxval = max(vals) if obj.Stencil: if obj.FilterType == 'window-volume': maxval = obj.Stencil.Shape.Volume elif obj.FilterType == 'window-area': maxval = obj.Stencil.Shape.Area elif obj.FilterType == 'window-length': maxval = obj.Stencil.Shape.Length if obj.OverrideMaxVal: maxval = obj.OverrideMaxVal valFrom = obj.WindowFrom / 100.0 * maxval valTo = obj.WindowTo / 100.0 * maxval for i in range(0, len(shps)): if bool(vals[i] >= valFrom and vals[i] <= valTo) ^ obj.Invert: rst.append(shps[i]) else: raise ValueError('Filter mode not implemented:' + obj.FilterType) if len(rst) == 0: scale = 1.0 if not screen(obj.Base).Shape.isNull(): scale = screen( obj.Base).Shape.BoundBox.DiagonalLength / math.sqrt( 3) / math.sqrt(len(shps)) if scale < DistConfusion * 100: scale = 1.0 obj.Shape = markers.getNullShapeShape(scale) raise ValueError( 'Nothing passes through the filter' ) #Feeding empty compounds to FreeCAD seems to cause rendering issues, otherwise it would have been a good idea to output nothing. if len(rst) > 1: obj.Shape = Part.makeCompound(rst) else: # don't make compound of one shape, output it directly sh = rst[0] sh = ShapeCopy.transformCopy(sh) sh.Placement = obj.Placement obj.Shape = sh return
def execute(self,obj): rst = [] #variable to receive the final list of shapes shp = obj.Base.Shape if obj.Mode == 'bypass': rst = [shp] elif obj.Mode == 'Leaves': rst = LCE.AllLeaves(shp) elif obj.Mode == 'CompSolids': rst = shp.CompSolids elif obj.Mode == 'Solids': rst = shp.Solids elif obj.Mode == 'Shells': rst = shp.Shells elif obj.Mode == 'OpenWires': openWires = [] shells = shp.Shells for shell in shells: openEdges = shell.getFreeEdges().childShapes() if len(openEdges) > 1: # edges need to be fused into wires clusters = Part.getSortedClusters(openEdges) wires = [Part.Wire(cluster) for cluster in clusters] else: wires = openEdges openWires.extend(wires) rst = openWires elif obj.Mode == 'Faces': rst = shp.Faces elif obj.Mode == 'Wires': rst = shp.Wires elif obj.Mode == 'Edges': rst = shp.Edges elif obj.Mode == 'Seam edges': rst = getAllSeams(shp) elif obj.Mode == 'Non-seam edges': seams = getAllSeams(shp) edges = shp.Edges rst = [] for e in edges: bIsSeam = False for s in seams: if e.isSame(s): bIsSeam = True break if not bIsSeam: rst.append(e) elif obj.Mode == 'Vertices': rst = shp.Vertexes else: raise ValueError('Downgrade mode not implemented:'+obj.Mode) if len(rst) == 0: scale = 1.0 if not obj.Base.Shape.isNull(): scale = obj.Base.Shape.BoundBox.DiagonalLength/math.sqrt(3) if scale < DistConfusion * 100: scale = 1.0 obj.Shape = markers.getNullShapeShape(scale) raise ValueError('Downgrade output is null') #Feeding empty compounds to FreeCAD seems to cause rendering issues, otherwise it would have been a good idea to output nothing. obj.Shape = Part.makeCompound(rst) return
def execute(self,obj): #validity check if isObjectLattice(obj.Base): import lattice2Executer lattice2Executer.warning(obj,"A generic shape is expected, but an array of placements was supplied. It will be treated as a generic shape.") rst = [] #variable to receive the final list of shapes shps = obj.Base.Shape.childShapes() if obj.FilterType == 'bypass': rst = shps elif obj.FilterType == 'specific items': rst = [] flags = [False] * len(shps) ranges = obj.items.split(';') for r in ranges: r_v = r.split(':') if len(r_v) == 1: i = int(r_v[0]) rst.append(shps[i]) flags[i] = True elif len(r_v) == 2 or len(r_v) == 3: if len(r_v) == 2: r_v.append("") # fix issue #1: instead of checking length here and there, simply add the missing field =) ifrom = None if len(r_v[0].strip()) == 0 else int(r_v[0]) ito = None if len(r_v[1].strip()) == 0 else int(r_v[1]) istep = None if len(r_v[2].strip()) == 0 else int(r_v[2]) rst=rst+shps[ifrom:ito:istep] for b in flags[ifrom:ito:istep]: b = True else: raise ValueError('index range cannot be parsed:'+r) if obj.Invert : rst = [] for i in xrange(0,len(shps)): if not flags[i]: rst.append(shps[i]) elif obj.FilterType == 'collision-pass': stencil = obj.Stencil.Shape for s in shps: d = s.distToShape(stencil) if bool(d[0] < DistConfusion) ^ bool(obj.Invert): rst.append(s) elif obj.FilterType == 'window-volume' or obj.FilterType == 'window-area' or obj.FilterType == 'window-length' or obj.FilterType == 'window-distance': vals = [0.0] * len(shps) for i in xrange(0,len(shps)): if obj.FilterType == 'window-volume': vals[i] = shps[i].Volume elif obj.FilterType == 'window-area': vals[i] = shps[i].Area elif obj.FilterType == 'window-length': vals[i] = shps[i].Length elif obj.FilterType == 'window-distance': vals[i] = shps[i].distToShape(obj.Stencil.Shape)[0] maxval = max(vals) if obj.Stencil: if obj.FilterType == 'window-volume': maxval = obj.Stencil.Shape.Volume elif obj.FilterType == 'window-area': maxval = obj.Stencil.Shape.Area elif obj.FilterType == 'window-length': maxval = obj.Stencil.Shape.Length if obj.OverrideMaxVal: maxval = obj.OverrideMaxVal valFrom = obj.WindowFrom / 100.0 * maxval valTo = obj.WindowTo / 100.0 * maxval for i in xrange(0,len(shps)): if bool(vals[i] >= valFrom and vals[i] <= valTo) ^ obj.Invert: rst.append(shps[i]) else: raise ValueError('Filter mode not implemented:'+obj.FilterType) if len(rst) == 0: scale = 1.0 if not obj.Base.Shape.isNull(): scale = obj.Base.Shape.BoundBox.DiagonalLength/math.sqrt(3)/math.sqrt(len(shps)) if scale < DistConfusion * 100: scale = 1.0 print scale obj.Shape = markers.getNullShapeShape(scale) raise ValueError('Nothing passes through the filter') #Feeding empty compounds to FreeCAD seems to cause rendering issues, otherwise it would have been a good idea to output nothing. if len(rst) > 1: obj.Shape = Part.makeCompound(rst) else: # don't make compound of one shape, output it directly sh = rst[0] sh = ShapeCopy.transformCopy(sh) sh.Placement = obj.Placement obj.Shape = sh return