import sys if sys.version_info.major >= 3: from importlib import reload import FreeCAD import os, time, dummy, FreeCADGui import Part from PySide import QtGui, QtCore from pivy import coin import loooMarkers as loooMarkers reload(loooMarkers) path_curvesWB = os.path.dirname(dummy.__file__) path_curvesWB_icons = os.path.join( path_curvesWB, 'Resources', 'icons') def to1D(pts,weights): array = [] for row,wrow in zip(pts,weights): for pt,w in zip(row,wrow): array.append((pt.x * w, pt.y * w, pt.z * w, w)) return array def toRat4D(pts,weights): array = [] for row,wrow in zip(pts,weights): r = [] for pt,w in zip(row,wrow): r.append((pt.x * w, pt.y * w, pt.z * w, w)) array.append(r) return array def getKnotsMults(array): knots = [] mults = [] for val in array: if val in knots: mults[-1] += 1 else: knots.append(val) mults.append(1) return (knots,mults) def makeBezierSurface(bs,poles): #bs=Part.BezierSurface() uLen = len(poles) vLen = len(poles[0]) bs.increase(uLen-1,vLen-1) i=0 for ii in range(uLen): for jj in range(vLen): bs.setPole(ii+1,jj+1,poles[ii][jj]); return(bs) def makeBSplineSurface(bs,poles): #bs=Part.BezierSurface() uLen = len(poles) vLen = len(poles[0]) bs.increaseDegree(uLen-1,vLen-1) i=0 for ii in range(uLen): for jj in range(vLen): bs.setPole(ii+1,jj+1,poles[ii][jj]); return(bs) class coinSurface(): def __init__(self, surf): # The control points for this surface self.pts = to1D(surf.getPoles(),surf.getWeights()) # The knot vector try: self.Uknots = surf.UKnotSequence except: self.Uknots = [0.0]*len(surf.getPoles()) + [1.0]*len(surf.getPoles()) print(str(self.Uknots)) try: self.Vknots = surf.VKnotSequence except: self.Vknots = [0.0]*len(surf.getPoles()[0]) + [1.0]*len(surf.getPoles()[0]) print(str(self.Vknots)) #self.Vknots = surf.VKnotSequence self.surfaceNode = coin.SoSeparator() self.surfSep = coin.SoSeparator() # Define the Bezier surface including the control # points and a complexity. self.material = coin.SoMaterial() self.material.transparency.setValue(0.0) FreeCAD.Console.PrintMessage("transparency OK\n") self.complexity = coin.SoComplexity() #self.controlPts = coin.SoCoordinate3() self.surface = coin.SoNurbsSurface() self.complexity.value = 1.0 #self.complexity.type = self.complexity.SCREEN_SPACE self.material.ambientColor.setValue(coin.SbColor(0.3,0,0)) #self.material.diffuseColor.setValue(coin.SbColor(0.8,1,0.8)) self.material.specularColor.setValue(coin.SbColor(1,1,1)) self.material.shininess.setValue(0.5) #self.material.transparency.setValue(0.5) #self.material.orderedRGBA = 0xcccccc88 #self.controlPts.point.setValues(0, len(self.pts), self.pts) self.surface.numUControlPoints = len(surf.getPoles()) self.surface.numVControlPoints = len(surf.getPoles()[0]) self.surface.uKnotVector.setValues(0, len(self.Uknots), self.Uknots) self.surface.vKnotVector.setValues(0, len(self.Vknots), self.Vknots) self.surfSep.addChild(self.material) self.surfSep.addChild(self.complexity) #self.surfSep.addChild(self.controlPts) self.surfSep.addChild(self.surface) self.surfaceNode.addChild(self.surfSep) #self.material.transparency.setValue(0.5) def update(self,pts): #FreeCAD.Console.PrintMessage("coinSurf update\n") #self.pts = pts #self.controlPts.point.setValues(0,len(self.pts),self.pts) #self.material.transparency.setValue(0.5) pass class coinGrid(): def __init__(self, mlist): self.colorRed = coin.SoBaseColor() self.colorRed.rgb=(1,0,0) self.colorGreen = coin.SoBaseColor() self.colorGreen.rgb=(0,1,0) self.colorBlue = coin.SoBaseColor() self.colorBlue.rgb=(0,0,1) self.colorYellow = coin.SoBaseColor() self.colorYellow.rgb=(1,1,0) self.colorPurple = coin.SoBaseColor() self.colorPurple.rgb=(1,0,1) self.colorCyan = coin.SoBaseColor() self.colorCyan.rgb=(0,1,1) self.colorWhite = coin.SoBaseColor() self.colorWhite.rgb=(1,1,1) self.colorBlack = coin.SoBaseColor() self.colorBlack.rgb=(0,0,0) self.Ulen = len(mlist) self.Vlen = len(mlist[0]) self.pts = [] for row in mlist: for pt in row: self.pts.append(pt.points[0]) num = [] for u in range(self.Ulen): for v in range(self.Vlen): num.append(u*self.Vlen+v) num.append(-1) num2 = [] for v in range(self.Vlen): for u in range(self.Ulen): num2.append(u*self.Vlen+v) num2.append(-1) print(str(num)) print(str(num2)) self.gridSep = coin.SoSeparator() #self.coords = coin.SoCoordinate3() #self.coords.point.setValues(0,len(self.pts),self.pts) self.Line = coin.SoIndexedLineSet() self.Line.coordIndex.setValues(0,len(num),num) self.Node = coin.SoSeparator() #self.Node.addChild(self.coords) self.Node.addChild(self.colorBlue) self.Node.addChild(self.Line) self.Line2 = coin.SoIndexedLineSet() self.Line2.coordIndex.setValues(0,len(num2),num2) self.Node2 = coin.SoSeparator() #self.Node2.addChild(self.coords) self.Node2.addChild(self.colorPurple) self.Node2.addChild(self.Line2) self.gridSep.addChild(self.Node) self.gridSep.addChild(self.Node2) def update(self,pts): #FreeCAD.Console.PrintMessage("coinGrid update\n") #self.pts = pts #self.coords.point.setValues(0,len(self.pts),self.pts) pass class SurfaceEdit(QtGui.QWidget): def __init__(self): super(SurfaceEdit, self).__init__() FreeCADGui.Selection.addObserver(self) self.grid = None self.CoinSurf = None self.selectedObject = None self.selectedSurface = None self.points = None self.SoCoords = coin.SoCoordinate4() self.cpc = None self.viewer = None self.render = None self.action = None self.glAction = None self.markerList = [] self.view = FreeCADGui.ActiveDocument.ActiveView self.sg = self.view.getSceneGraph() self.initUI() def addSelection(self,doc,obj,sub,pnt): # Selection object #def setPreselection(self,doc,obj,sub): # Preselection object FreeCAD.Console.PrintMessage("addSelection"+ "\n") FreeCAD.Console.PrintMessage(str(doc)+ " / ") # Name of the document FreeCAD.Console.PrintMessage(str(obj)+ " / ") # Name of the object FreeCAD.Console.PrintMessage(str(sub)+ " / ") # The part of the object name FreeCAD.Console.PrintMessage(str(pnt)+ "\n") # Coordinates of the object FreeCAD.Console.PrintMessage("______"+ "\n") self.apply() self.clear() self.getSelection() def removeSelection(self,doc,obj,sub): # Delete the selected object FreeCAD.Console.PrintMessage("removeSelection"+ "\n") def setSelection(self,doc): # Selection in ComboView FreeCAD.Console.PrintMessage("setSelection"+ "\n") def clearSelection(self,doc): # If click on the screen, clear the selection FreeCAD.Console.PrintMessage("clearSelection"+ "\n") # If click on another object, clear the previous object #self.clear() def updateViewObjects(self): #FreeCAD.Console.PrintMessage("updateViewObjects started"+ "\n") pts = [] for row in self.markerList: for pt in row: pts.append(pt.points[0]) self.Points = pts self.SoCoords.point.setValues(0,0,[]) self.SoCoords.point.setValues(0,len(self.Points),self.Points) #self.CoinSurf.update(pts) #self.grid.update(pts) #self.CoinSurf.material.transparency.setValue(0.0) def buildViz(self): self.viewer=self.view.getViewer() FreeCAD.Console.PrintMessage(str(self.viewer)+ "\n") self.render=self.viewer.getSoRenderManager() FreeCAD.Console.PrintMessage(str(self.render)+ "\n") self.render.setRenderMode(self.render.WIREFRAME_OVERLAY) self.action=self.render.getGLRenderAction() FreeCAD.Console.PrintMessage(str(self.action.getTypeId().getName())+ "\n") # => "SoBoxSelectionRenderAction" is our own class if ( str(self.action.getTypeId().getName()) == "SoBoxSelectionRenderAction" ): # replace it with the standard render action self.glAction=coin.SoGLRenderAction(self.render.getViewportRegion()) FreeCAD.Console.PrintMessage(str(self.glAction)+ "\n") self.render.setGLRenderAction(self.glAction) FreeCAD.Console.PrintMessage('setGLRenderAction : OK'+ "\n") self.cpc = loooMarkers.Container() # control point container self.markerList = [] array = toRat4D(self.selectedSurface.getPoles(), self.selectedSurface.getWeights()) for j in range(len(array[0])): markerRow = [] for i in range(len(array)): p = [array[i][j][0], array[i][j][1], array[i][j][2], array[i][j][3]] #[pt.x, pt.y, pt.z, pt.w] marker = loooMarkers.Marker([p], dynamic=True) markerRow.append(marker) self.markerList.append(markerRow) self.markerList[0][0].marker.markerIndex = coin.SoMarkerSet.SQUARE_FILLED_9_9 self.markerList[0][-1].marker.markerIndex = coin.SoMarkerSet.DIAMOND_FILLED_9_9 #SQUARE_FILLED_9_9 self.markerList[-1][0].marker.markerIndex = coin.SoMarkerSet.TRIANGLE_FILLED_9_9 for row in self.markerList: self.cpc.addChildren(row) self.cpc.nbUPoles = len(self.markerList) self.cpc.nbVPoles = len(self.markerList[0]) self.updateViewObjects() self.CoinSurf = coinSurface(self.selectedSurface) self.grid = coinGrid(self.markerList) self.vizSep = coin.SoSeparator() self.vizSep.addChild(self.SoCoords) self.vizSep.addChild(self.grid.gridSep) FreeCAD.Console.PrintMessage("Grid added\n") self.vizSep.addChild(self.CoinSurf.surfaceNode) FreeCAD.Console.PrintMessage("Surface added\n") self.vizSep.addChild(self.cpc) FreeCAD.Console.PrintMessage("container added\n") self.cpc.register(self.view) FreeCAD.Console.PrintMessage("container registered\n") self.sg.addChild(self.vizSep) #self.sg.addChild(self.grid.gridSep) #FreeCAD.Console.PrintMessage("Grid added\n") #self.sg.addChild(self.CoinSurf.surfaceNode) #FreeCAD.Console.PrintMessage("Surface added\n") self.cpc.on_drag.append(self.updateViewObjects) def getSelection(self): self.selectedSurface = None self.surfaceType = None sel = FreeCADGui.Selection.getSelectionEx() if sel != []: sel0 = sel[0] if sel0.HasSubObjects: ss = sel0.SubObjects[0] if ss.ShapeType == 'Face': surf = ss.Surface self.selectedFace = ss self.selectedObject = sel0.Object if "Wireframe" in self.selectedObject.ViewObject.listDisplayModes(): self.selectedObject.ViewObject.DisplayMode = "Wireframe" if issubclass(type(surf),Part.BezierSurface): self.selectedSurface = surf self.surfaceType = "Bezier" FreeCAD.Console.PrintMessage("Bezier Surface Selected\n") self.buildViz() FreeCAD.Console.PrintMessage("buildViz OK\n") elif issubclass(type(surf),Part.BSplineSurface): self.selectedSurface = surf self.surfaceType = "BSpline" FreeCAD.Console.PrintMessage("BSpline Surface Selected\n") self.buildViz() FreeCAD.Console.PrintMessage("buildViz OK\n") else: FreeCAD.Console.PrintMessage(str(surf) + " Selected\n") self.selectedSurface = ss.toNurbs().Faces[0].Surface self.surfaceType = "BSpline" FreeCAD.Console.PrintMessage("Converted to BSpline Surface\n") self.buildViz() FreeCAD.Console.PrintMessage("buildViz OK\n") def initUI(self): self.getSelection() self.value = 99 self.sliderRange = 100 self.val = QtGui.QLabel(self) self.val.setText('Surface Display') self.val.setGeometry(80, 15, 180, 30) sld = QtGui.QSlider(QtCore.Qt.Horizontal, self) sld.setFocusPolicy(QtCore.Qt.NoFocus) sld.setMaximum(self.sliderRange) sld.setGeometry(30, 40, 200, 30) sld.setValue(99) sld.valueChanged[int].connect(self.changeComplexity) self.txt = QtGui.QLabel(self) self.txt.setText('Fast Fine') self.txt.setGeometry(30, 55, 240, 30) self.value2 = 0 self.sliderRange2 = 100 self.val2 = QtGui.QLabel(self) self.val2.setText('Surface Transparency') self.val2.setGeometry(80, 140, 180, 30) sld2 = QtGui.QSlider(QtCore.Qt.Horizontal, self) sld2.setFocusPolicy(QtCore.Qt.NoFocus) sld2.setMaximum(self.sliderRange2) sld2.setGeometry(30, 160, 200, 30) sld2.valueChanged[int].connect(self.changeTransparency) self.txt2 = QtGui.QLabel(self) self.txt2.setText('0 100') self.txt2.setGeometry(30, 175, 240, 30) self.OKButton = QtGui.QPushButton("OK",self) self.OKButton.clicked.connect(self.activate) self.OKButton.setAutoDefault(False) self.OKButton.move(30, 260) self.cancelButton = QtGui.QPushButton('Quit', self) self.cancelButton.clicked.connect(self.onCancel) self.cancelButton.setAutoDefault(True) self.cancelButton.move(130, 260) FreeCAD.Console.PrintMessage("InitUI OK\n") self.doc1 = QtGui.QLabel(self) self.doc1.setText('\'g\' : Grab selected poles') self.doc1.setGeometry(30, 340, 180, 30) self.doc2 = QtGui.QLabel(self) self.doc2.setText('\'x\',\'y\',\'z\' : Axis constraint') self.doc2.setGeometry(30, 380, 180, 30) def rounded(self,v): return(str(int(v*100)/100.)) def changeComplexity(self, value): FreeCAD.Console.PrintMessage("UI changeValue\n") self.value = value v = 1. * value / (self.sliderRange) if self.CoinSurf: self.CoinSurf.complexity.value = v def changeTransparency(self, value): FreeCAD.Console.PrintMessage("UI changeValue\n") self.value2 = value v = 1. * value / (self.sliderRange2) if self.CoinSurf: self.CoinSurf.material.transparency.setValue(v) def apply(self): t = time.time() if 1: #self.surfaceType == "Bezier": #FreeCAD.Console.PrintMessage(str(self.selectedSurface.getPoles())) poles = [] weights = [] for j in range(len(self.markerList[0])): ptrow= [] wrow = [] for i in range(len(self.markerList)): w = self.markerList[i][j].points[0][3] if w: v = FreeCAD.Vector(self.markerList[i][j].points[0][0]/w,self.markerList[i][j].points[0][1]/w,self.markerList[i][j].points[0][2]/w) else: v = FreeCAD.Vector(0,0,0) FreeCAD.Console.PrintMessage(str(v)+" - "+str(w)+"\n") ptrow.append(v) wrow.append(w) poles.append(ptrow) weights.append(wrow) #FreeCAD.Console.PrintMessage("Weight - "+str(weights)+"\n") if self.surfaceType == "BSpline": s = Part.BSplineSurface() #s = makeBSplineSurface(s, poles) #FreeCAD.Console.PrintMessage("UKnots : " + str(self.CoinSurf.Uknots) + "\n") Ukm = getKnotsMults(self.CoinSurf.Uknots) Uknots = Ukm[0] Umults = Ukm[1] Vkm = getKnotsMults(self.CoinSurf.Vknots) Vknots = Vkm[0] Vmults = Vkm[1] Udeg = len(self.CoinSurf.Uknots) - len(poles) - 1 Vdeg = len(self.CoinSurf.Vknots) - len(poles[0]) - 1 s.buildFromPolesMultsKnots(poles,Umults,Vmults,Uknots,Vknots,False,False,Udeg,Vdeg,weights) #FreeCAD.Console.PrintMessage("Weight - "+str(s.getWeights())+"\n") elif self.surfaceType == "Bezier": s = Part.BSplineSurface() #s = makeBSplineSurface(s, poles) #FreeCAD.Console.PrintMessage("UKnots : " + str(self.CoinSurf.Uknots) + "\n") Ukm = getKnotsMults(self.CoinSurf.Uknots) Uknots = Ukm[0] Umults = Ukm[1] Vkm = getKnotsMults(self.CoinSurf.Vknots) Vknots = Vkm[0] Vmults = Vkm[1] Udeg = len(self.CoinSurf.Uknots) - len(poles) - 1 Vdeg = len(self.CoinSurf.Vknots) - len(poles[0]) - 1 s.buildFromPolesMultsKnots(poles,Umults,Vmults,Uknots,Vknots,False,False,Udeg,Vdeg,weights) #************ Crash with oce 0.17 ******************* #s = Part.BezierSurface() #uLen = len(poles) #vLen = len(poles[0]) #s.increase(uLen-1,vLen-1) #for ii in range(uLen): #for jj in range(vLen): #s.setPole( ii+1,jj+1,poles[ii][jj]) #s.setWeight(ii+1,jj+1,weights[ii][jj]) ##for i in range(len(weights)): ##for j in range(len(weights[i])): ##FreeCAD.Console.PrintMessage("Weight - "+str(i+1)+ " "+str(j+1)+ " -> " + str(weights[i][j]) + "\n") ##s.setWeight(i+1,j+1,weights[i][j]) faces = [] for f in self.selectedObject.Shape.Faces: if not f.isSame(self.selectedFace): print(str(f)) faces.append(f) faces.append(s.toShape()) print(str(faces)) shell = Part.Shell(faces) Part.show(shell) #self.selectedObject.ViewObject.Visibility = False FreeCAD.Console.PrintMessage(str(time.time()-t)) def activate(self): self.apply() self.onCancel() if "Wireframe" in self.selectedObject.ViewObject.listDisplayModes(): self.selectedObject.ViewObject.DisplayMode = "Wireframe" def clear(self): if self.selectedObject: if "Flat Lines" in self.selectedObject.ViewObject.listDisplayModes(): self.selectedObject.ViewObject.DisplayMode = "Flat Lines" self.selectedObject.touch() if self.render: self.render.setRenderMode(self.render.AS_IS) #if self.CoinSurf: #self.sg.removeChild(self.CoinSurf.surfaceNode) #if self.grid: #self.sg.removeChild(self.grid.gridSep) #if self.SoCoords: #self.sg.removeChild(self.SoCoords) if self.cpc: self.cpc.removeAllChildren() self.cpc.unregister() if self.vizSep: self.sg.removeChild(self.vizSep) FreeCAD.activeDocument().recompute() def onCancel(self): self.clear() FreeCADGui.Selection.removeObserver(self) # Uninstall the resident function mw = getMainWindow() tab = getComboView(getMainWindow()) tab.removeTab(2) SurfaceEditTool.active = False def getMainWindow(): "returns the main window" # using QtGui.qApp.activeWindow() isn't very reliable because if another # widget than the mainwindow is active (e.g. a dialog) the wrong widget is # returned toplevel = QtGui.qApp.topLevelWidgets() for i in toplevel: if i.metaObject().className() == "Gui::MainWindow": return i raise Exception("No main window found") def getComboView(mw): dw=mw.findChildren(QtGui.QDockWidget) for i in dw: if str(i.objectName()) == "Combo View": return i.findChild(QtGui.QTabWidget) elif str(i.objectName()) == "Python Console": return i.findChild(QtGui.QTabWidget) raise Exception ("No tab widget found") class SurfaceEditTool: def __init__(self): SurfaceEditTool.active = False def Activated(self): if not SurfaceEditTool.active: mw = getMainWindow() tab = getComboView(getMainWindow()) tab2=SurfaceEdit() tab.addTab(tab2,"Surface Edit Tool") tab2.show() #zebraWidget.show() SurfaceEditTool.active = True else: FreeCAD.Console.PrintMessage("Tool already active\n") def GetResources(self): return {'Pixmap' : path_curvesWB_icons+'/surfEdit.svg', 'MenuText': 'SurfaceEditTool', 'ToolTip': 'Edit NURBS Surfaces'} FreeCADGui.addCommand('SurfaceEditTool', SurfaceEditTool())