Blender-like grid

Need help, or want to share a macro? Post here!
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
User avatar
Chris_G
Veteran
Posts: 2579
Joined: Tue Dec 31, 2013 4:10 pm
Location: France
Contact:

Re: Blender-like grid

Post by Chris_G »

pablogil wrote:As you said it could be something related with Pivy... so, is there any possibility to use it in any official build? maybe a simpler version?
I am sure this is a pivy bug.
Unfortunately, I don't see any way to do it without pivy's sensors, that are crashing FC.
So, currently, the 2 possibilities are :
- build looo's pivy branch : https://github.com/looooo/pivy
- wait for official pivy to get fixed
User avatar
pablogil
Posts: 881
Joined: Wed Nov 26, 2014 3:19 pm
Location: Badajoz (Spain)
Contact:

Re: Blender-like grid

Post by pablogil »

Chris_G wrote:
pablogil wrote:As you said it could be something related with Pivy... so, is there any possibility to use it in any official build? maybe a simpler version?
I am sure this is a pivy bug.
Unfortunately, I don't see any way to do it without pivy's sensors, that are crashing FC.
So, currently, the 2 possibilities are :
- build looo's pivy branch : https://github.com/looooo/pivy
- wait for official pivy to get fixed
Thank you very much, I'll have then to wait to pivy fix because I'm pretty out of time.
I'll stay tuned in case you have updated on the macro, it's so useful
Dark and Light stylesheets v2.0 to theme your FreeCAD UI, more information here
triplus
Veteran
Posts: 9471
Joined: Mon Dec 12, 2011 4:45 pm

Re: Blender-like grid

Post by triplus »

Note that yesterday when i did the test i didn't mention i got the crash too. But i was able to complete the test by using this procedure:
  • Start FreeCAD
  • Run the Grid macro
  • Change to perspective view (can be changed back to orthographic view after)
  • Enjoy
User avatar
Chris_G
Veteran
Posts: 2579
Joined: Tue Dec 31, 2013 4:10 pm
Location: France
Contact:

Re: Blender-like grid

Post by Chris_G »

triplus wrote:Note that yesterday when i did the test i didn't mention i got the crash too. But i was able to complete the test by using this procedure:

Start FreeCAD
Run the Grid macro
Change to perspective view (can be changed back to orthographic view after)
Enjoy
Ahaha, in fact, by doing this, you hitted another bug, that saved you from the crash. Funny :lol:
The grid object attaches a sensor to the camera node to watch its movement. As soon as the camera moves, FC crashes( with default pivy )
But when changing the camera type, the grid sensors get detached from the new camera, and no crash happens.
But by doing this, you were not able to see the eye-candy effect when the grids gets gradually visible or invisible when moving the camera.
triplus
Veteran
Posts: 9471
Joined: Mon Dec 12, 2011 4:45 pm

Re: Blender-like grid

Post by triplus »

Well that's a first! Great bug. ;)
User avatar
Chris_G
Veteran
Posts: 2579
Joined: Tue Dec 31, 2013 4:10 pm
Location: France
Contact:

Re: Blender-like grid

Post by Chris_G »

triplus wrote:Well that's a first! Great bug. ;)
Thanks, I'm pretty proud of this one :lol:
cox
Posts: 971
Joined: Wed Nov 26, 2014 11:37 pm

Re: Blender-like grid

Post by cox »

This looks very nice, nice work Chris_G :D
Need help? Feel free to ask, but please read the guidelines first
User avatar
pablogil
Posts: 881
Joined: Wed Nov 26, 2014 3:19 pm
Location: Badajoz (Spain)
Contact:

Re: Blender-like grid

Post by pablogil »

Hahaha, nice "hack" @triplus, that way I was able to play with it!
Dark and Light stylesheets v2.0 to theme your FreeCAD UI, more information here
User avatar
Chris_G
Veteran
Posts: 2579
Joined: Tue Dec 31, 2013 4:10 pm
Location: France
Contact:

Re: Blender-like grid

Post by Chris_G »

Hey, good news !
I think I managed to get it working without using coin sensors.
This version uses coin engines instead.
When changing the camera type (orthographic / perspective), you need to change a property of the grid, to reattach the new camera to it.

Code: Select all

import FreeCAD
import FreeCADGui
import math
from pivy import coin

class gridNode(coin.SoSeparator):
    def __init__(self):
        super(gridNode, self).__init__()

        self.vec = coin.SoTransformVec3f()
        #self.vec.matrix.connectFrom(cam.orientation)
        self.vec.vector = coin.SbVec3f(0,0,-1)

        self.calc = coin.SoCalculator()
        self.calc.A.connectFrom(self.vec.direction)
        self.calc.expression.set1Value(0,"ta=0.5") # maxviz
        self.calc.expression.set1Value(1,"tb=20.0") # factor
        self.calc.expression.set1Value(2,"tA=vec3f(1,0,0)") # plane normal
        self.calc.expression.set1Value(3,"tc=dot(A,tA)")
        self.calc.expression.set1Value(4,"td=fabs(tc)")
        self.calc.expression.set1Value(5,"oa=1.0-ta*pow(td,tb)")
        self.calc.expression.set1Value(6,"oA=vec3f(oa,0,0)")

        self.material1 = coin.SoMaterial()
        self.material2 = coin.SoMaterial()
        self.material3 = coin.SoMaterial()
        self.coord = coin.SoCoordinate3()
        self.line1 = coin.SoIndexedLineSet()
        self.line2 = coin.SoIndexedLineSet()
        self.lineSet = coin.SoIndexedLineSet()

        self.addChild(self.coord)
        self.addChild(self.material1)
        self.addChild(self.line1)
        self.addChild(self.material2)
        self.addChild(self.line2)
        self.addChild(self.material3)
        self.addChild(self.lineSet)
        
        self._vector1 = coin.SbVec3f(1,0,0)
        self._vector2 = coin.SbVec3f(0,1,0)
        self.normal = self._vector1.cross(self._vector2)

        self._mainDim = 100
        self._subDim = 10
        self._maxviz = 1.0
        self._factor = 1.0
        
        self._numGridLines = 4
        self.material1.diffuseColor = coin.SbColor(1,0,0)
        self.material2.diffuseColor = coin.SbColor(0,1,0)
        self.material3.diffuseColor = coin.SbColor(0.5,0.5,0.5)
        self.material3.transparency.connectFrom(self.calc.oa)

    @property
    def transparency(self):
        return self.material3.transparency.getValues()[0]

    @transparency.setter
    def transparency(self, tr):
#        self.material3.transparency = tr
#        self.material2.transparency = tr
        self.material3.transparency = tr

    @property
    def vector1color(self):
        return self.material1.diffuseColor.getValues()[0].getValue()

    @vector1color.setter
    def vector1color(self, color):
        self.material1.diffuseColor = (color[0], color[1], color[2])

    @property
    def vector2color(self):
        return self.material2.diffuseColor.getValues()[0].getValue()

    @vector2color.setter
    def vector2color(self, color):
        self.material2.diffuseColor = (color[0], color[1], color[2])

    @property
    def gridcolor(self):
        return self.material3.diffuseColor.getValues()[0].getValue()

    @gridcolor.setter
    def gridcolor(self, color):
        self.material3.diffuseColor = (color[0], color[1], color[2])

    @property
    def vector1dir(self):
        return self._vector1.getValue()

    @vector1dir.setter
    def vector1dir(self, vec):
        self._vector1 = coin.SbVec3f(vec)
        self.normal = self._vector1.cross(self._vector2)
        self.calc.expression.set1Value(2,"tA=vec3f(%f,%f,%f)"%(self.normal.getValue()[0],self.normal.getValue()[1],self.normal.getValue()[2]))
        self.buildGrid()

    @property
    def vector2dir(self):
        return self._vector2.getValue()

    @vector2dir.setter
    def vector2dir(self, vec):
        self._vector2 = coin.SbVec3f(vec)
        self.normal = self._vector1.cross(self._vector2)
        self.calc.expression.set1Value(2,"tA=vec3f(%f,%f,%f)"%(self.normal.getValue()[0],self.normal.getValue()[1],self.normal.getValue()[2]))
        self.buildGrid()

    @property
    def mainDim(self):
        return self._mainDim

    @mainDim.setter
    def mainDim(self, n):
        self._mainDim = n
        self.buildGrid()
        
    @property
    def subDim(self):
        return self._subDim

    @subDim.setter
    def subDim(self, n):
        self._subDim = n
        self.buildGrid()

    @property
    def maxviz(self):
        return self._maxviz

    @maxviz.setter
    def maxviz(self, n):
        self._maxviz = n
        self.calc.expression.set1Value(0,"ta=%f"%n) # maxviz

    @property
    def factor(self):
        return self._factor

    @factor.setter
    def factor(self, n):
        self._factor = n
        self.calc.expression.set1Value(1,"tb=%f"%n) # factor

    def linkTo(self, cam):
        self.vec.matrix.connectFrom(cam.orientation)

    def buildGrid(self):
        n = int(1.0 * self._mainDim / self._subDim)
        r = []
        nr = []
        for i in range(1,n):
            r.append(  1.0 * self._subDim * i)
            nr.append(-1.0 * self._subDim * i)
        r.append(  self._mainDim)
        nr.append(-self._mainDim)
        nr.reverse()
        fullRange = nr + r
        pts = []
        pts.append(-self._mainDim * self._vector1)
        pts.append( self._mainDim * self._vector1)
        pts.append(-self._mainDim * self._vector2)
        pts.append( self._mainDim * self._vector2)
        for i in fullRange:
            pts.append(i * self._vector2 - self._mainDim * self._vector1)
            pts.append(i * self._vector2 + self._mainDim * self._vector1)
            pts.append(i * self._vector1 - self._mainDim * self._vector2)
            pts.append(i * self._vector1 + self._mainDim * self._vector2)
        self.coord.point.setValues(0,len(pts),pts)
        self._numGridLines = len(fullRange) * 2
        #self.gridcolor = self.gridcolor
        #self.transparency = self.transparency
        a = []
        l = len(pts)-4
        for i in range(l/2):
            a.append(2*i + 4)
            a.append(2*i + 5)
            a.append(-1)
        self.line1.coordIndex.setValue(0)
        self.line1.coordIndex.setValues(0, 3, [0,1,-1])
        self.line2.coordIndex.setValue(0)
        self.line2.coordIndex.setValues(0, 3, [2,3,-1])
        self.lineSet.coordIndex.setValue(0)
        self.lineSet.coordIndex.setValues(0, len(a), a)


class gridObject:
    def __init__(self, obj):
        obj.Proxy = self

class gridVP:
    def __init__(self, obj ):
        obj.addProperty("App::PropertyDistance",  "Total",         "Size",   "Size of a grid quadrant").Total = '100mm'
        obj.addProperty("App::PropertyDistance",  "Subdivision",   "Size",   "Size of subdivisions").Subdivision = '10mm'
        obj.addProperty("App::PropertyFloat",     "XY_Attenuation", "View",   "XY plane attenuation").XY_Attenuation = 1.0
        obj.addProperty("App::PropertyFloat",     "XZ_Attenuation", "View",   "XZ plane attenuation").XZ_Attenuation = 50.0
        obj.addProperty("App::PropertyFloat",     "YZ_Attenuation", "View",   "YZ plane attenuation").YZ_Attenuation = 50.0
        obj.addProperty("App::PropertyFloat",     "XY_Visibility",  "View",   "XY plane max visibility").XY_Visibility = 1.0
        obj.addProperty("App::PropertyFloat",     "XZ_Visibility",  "View",   "XZ plane max visibility").XZ_Visibility = 0.5
        obj.addProperty("App::PropertyFloat",     "YZ_Visibility",  "View",   "YZ plane max visibility").YZ_Visibility = 0.5
        obj.addProperty("App::PropertyColor",     "GridColor",     "Color",  "Grid Color").GridColor = (0.5,0.5,0.5)
        obj.Proxy = self

    def attach(self, obj):
        self.xy = gridNode()
        self.xy.vector1dir = (1,0,0)
        self.xy.vector1color = (1,0,0)
        self.xy.vector2dir = (0,1,0)
        self.xy.vector2color = (0,1,0)
        self.xy.mainDim = 100
        self.xy.subDim = 10
        self.xy.maxviz = 1.0
    
        self.xz = gridNode()
        self.xz.vector1dir = (1,0,0)
        self.xz.vector1color = (1,0,0)
        self.xz.vector2dir = (0,0,1)
        self.xz.vector2color = (0,0,1)
        self.xz.mainDim = 100
        self.xz.subDim = 10
        self.xz.maxviz = 0.5
    
        self.yz = gridNode()
        self.yz.vector1dir = (0,1,0)
        self.yz.vector1color = (0,1,0)
        self.yz.vector2dir = (0,0,1)
        self.yz.vector2color = (0,0,1)
        self.yz.mainDim = 100
        self.yz.subDim = 10
        self.yz.maxviz = 0.5
    
        self.sg = FreeCADGui.ActiveDocument.ActiveView.getSceneGraph()
        self.cam = FreeCADGui.ActiveDocument.ActiveView.getCameraNode()
    
        self.xy.linkTo(self.cam)
        self.xy.factor = 1.
        self.xz.linkTo(self.cam)
        self.xz.factor = 50.
        self.yz.linkTo(self.cam)
        self.yz.factor = 50.

        self.grid = coin.SoSeparator()

        self.grid.addChild(self.xy)
        self.grid.addChild(self.xz)
        self.grid.addChild(self.yz)
        self.sg.addChild(self.grid)

    def updateCam(self):
        self.cam = FreeCADGui.ActiveDocument.ActiveView.getCameraNode()
        self.xy.linkTo(self.cam)
        self.xz.linkTo(self.cam)
        self.yz.linkTo(self.cam)

    def onChanged(self, vp, prop):
        self.updateCam()
        if prop == 'Total':
            if float(vp.Total) >= float(vp.Subdivision):
                self.xy.mainDim = float(vp.Total)
                self.xz.mainDim = float(vp.Total)
                self.yz.mainDim = float(vp.Total)
            else:
                vp.Total = vp.Subdivision
        if prop == 'Subdivision':
            if float(vp.Total) >= float(vp.Subdivision):
                self.xy.subDim = float(vp.Subdivision)
                self.xz.subDim = float(vp.Subdivision)
                self.yz.subDim = float(vp.Subdivision)
            else:
                vp.Subdivision = vp.Total
        if prop == 'XY_Attenuation':
            if vp.XY_Attenuation < 0.1:
                vp.XY_Attenuation = 0.1
            elif vp.XY_Attenuation > 100:
                vp.XY_Attenuation = 100
            self.xy.factor = vp.XY_Attenuation
        if prop == 'XZ_Attenuation':
            if vp.XZ_Attenuation < 0.1:
                vp.XZ_Attenuation = 0.1
            elif vp.XZ_Attenuation > 100:
                vp.XZ_Attenuation = 100
            self.xz.factor = vp.XZ_Attenuation
        if prop == 'YZ_Attenuation':
            if vp.YZ_Attenuation < 0.1:
                vp.YZ_Attenuation = 0.1
            elif vp.YZ_Attenuation > 100:
                vp.YZ_Attenuation = 100
            self.yz.factor = vp.YZ_Attenuation
        if prop == 'XY_Visibility':
            if vp.XY_Visibility < 0.0:
                vp.XY_Visibility = 0.0
            elif vp.XY_Visibility > 1.0:
                vp.XY_Visibility = 1.0
            self.xy.maxviz = vp.XY_Visibility
        if prop == 'XZ_Visibility':
            if vp.XZ_Visibility < 0.0:
                vp.XZ_Visibility = 0.0
            elif vp.XZ_Visibility > 1.0:
                vp.XZ_Visibility = 1.0
            self.xz.maxviz = vp.XZ_Visibility
        if prop == 'YZ_Visibility':
            if vp.YZ_Visibility < 0.0:
                vp.YZ_Visibility = 0.0
            elif vp.YZ_Visibility > 1.0:
                vp.YZ_Visibility = 1.0
            self.yz.maxviz = vp.YZ_Visibility
        if prop == 'GridColor':
            self.xy.gridcolor = vp.GridColor
            self.xz.gridcolor = vp.GridColor
            self.yz.gridcolor = vp.GridColor

    def onDelete(self, feature, subelements):
        self.sg.removeChild(self.grid)
        return(True)

def main():

    obj=FreeCAD.ActiveDocument.addObject("App::FeaturePython","Grid")
    gridObject(obj)
    gridVP(obj.ViewObject)


if __name__ == '__main__':
    main()
User avatar
pablogil
Posts: 881
Joined: Wed Nov 26, 2014 3:19 pm
Location: Badajoz (Spain)
Contact:

Re: Blender-like grid

Post by pablogil »

Chris_G wrote:Hey, good news !
I think I managed to get it working without using coin sensors.
This version uses coin engines instead.
When changing the camera type (orthographic / perspective), you need to change a property of the grid, to reattach the new camera to it.

Code: Select all

import FreeCAD
import FreeCADGui
import math
from pivy import coin

class gridNode(coin.SoSeparator):
    def __init__(self):
        super(gridNode, self).__init__()

        self.vec = coin.SoTransformVec3f()
        #self.vec.matrix.connectFrom(cam.orientation)
        self.vec.vector = coin.SbVec3f(0,0,-1)

        self.calc = coin.SoCalculator()
        self.calc.A.connectFrom(self.vec.direction)
        self.calc.expression.set1Value(0,"ta=0.5") # maxviz
        self.calc.expression.set1Value(1,"tb=20.0") # factor
        self.calc.expression.set1Value(2,"tA=vec3f(1,0,0)") # plane normal
        self.calc.expression.set1Value(3,"tc=dot(A,tA)")
        self.calc.expression.set1Value(4,"td=fabs(tc)")
        self.calc.expression.set1Value(5,"oa=1.0-ta*pow(td,tb)")
        self.calc.expression.set1Value(6,"oA=vec3f(oa,0,0)")

        self.material1 = coin.SoMaterial()
        self.material2 = coin.SoMaterial()
        self.material3 = coin.SoMaterial()
        self.coord = coin.SoCoordinate3()
        self.line1 = coin.SoIndexedLineSet()
        self.line2 = coin.SoIndexedLineSet()
        self.lineSet = coin.SoIndexedLineSet()

        self.addChild(self.coord)
        self.addChild(self.material1)
        self.addChild(self.line1)
        self.addChild(self.material2)
        self.addChild(self.line2)
        self.addChild(self.material3)
        self.addChild(self.lineSet)
        
        self._vector1 = coin.SbVec3f(1,0,0)
        self._vector2 = coin.SbVec3f(0,1,0)
        self.normal = self._vector1.cross(self._vector2)

        self._mainDim = 100
        self._subDim = 10
        self._maxviz = 1.0
        self._factor = 1.0
        
        self._numGridLines = 4
        self.material1.diffuseColor = coin.SbColor(1,0,0)
        self.material2.diffuseColor = coin.SbColor(0,1,0)
        self.material3.diffuseColor = coin.SbColor(0.5,0.5,0.5)
        self.material3.transparency.connectFrom(self.calc.oa)

    @property
    def transparency(self):
        return self.material3.transparency.getValues()[0]

    @transparency.setter
    def transparency(self, tr):
#        self.material3.transparency = tr
#        self.material2.transparency = tr
        self.material3.transparency = tr

    @property
    def vector1color(self):
        return self.material1.diffuseColor.getValues()[0].getValue()

    @vector1color.setter
    def vector1color(self, color):
        self.material1.diffuseColor = (color[0], color[1], color[2])

    @property
    def vector2color(self):
        return self.material2.diffuseColor.getValues()[0].getValue()

    @vector2color.setter
    def vector2color(self, color):
        self.material2.diffuseColor = (color[0], color[1], color[2])

    @property
    def gridcolor(self):
        return self.material3.diffuseColor.getValues()[0].getValue()

    @gridcolor.setter
    def gridcolor(self, color):
        self.material3.diffuseColor = (color[0], color[1], color[2])

    @property
    def vector1dir(self):
        return self._vector1.getValue()

    @vector1dir.setter
    def vector1dir(self, vec):
        self._vector1 = coin.SbVec3f(vec)
        self.normal = self._vector1.cross(self._vector2)
        self.calc.expression.set1Value(2,"tA=vec3f(%f,%f,%f)"%(self.normal.getValue()[0],self.normal.getValue()[1],self.normal.getValue()[2]))
        self.buildGrid()

    @property
    def vector2dir(self):
        return self._vector2.getValue()

    @vector2dir.setter
    def vector2dir(self, vec):
        self._vector2 = coin.SbVec3f(vec)
        self.normal = self._vector1.cross(self._vector2)
        self.calc.expression.set1Value(2,"tA=vec3f(%f,%f,%f)"%(self.normal.getValue()[0],self.normal.getValue()[1],self.normal.getValue()[2]))
        self.buildGrid()

    @property
    def mainDim(self):
        return self._mainDim

    @mainDim.setter
    def mainDim(self, n):
        self._mainDim = n
        self.buildGrid()
        
    @property
    def subDim(self):
        return self._subDim

    @subDim.setter
    def subDim(self, n):
        self._subDim = n
        self.buildGrid()

    @property
    def maxviz(self):
        return self._maxviz

    @maxviz.setter
    def maxviz(self, n):
        self._maxviz = n
        self.calc.expression.set1Value(0,"ta=%f"%n) # maxviz

    @property
    def factor(self):
        return self._factor

    @factor.setter
    def factor(self, n):
        self._factor = n
        self.calc.expression.set1Value(1,"tb=%f"%n) # factor

    def linkTo(self, cam):
        self.vec.matrix.connectFrom(cam.orientation)

    def buildGrid(self):
        n = int(1.0 * self._mainDim / self._subDim)
        r = []
        nr = []
        for i in range(1,n):
            r.append(  1.0 * self._subDim * i)
            nr.append(-1.0 * self._subDim * i)
        r.append(  self._mainDim)
        nr.append(-self._mainDim)
        nr.reverse()
        fullRange = nr + r
        pts = []
        pts.append(-self._mainDim * self._vector1)
        pts.append( self._mainDim * self._vector1)
        pts.append(-self._mainDim * self._vector2)
        pts.append( self._mainDim * self._vector2)
        for i in fullRange:
            pts.append(i * self._vector2 - self._mainDim * self._vector1)
            pts.append(i * self._vector2 + self._mainDim * self._vector1)
            pts.append(i * self._vector1 - self._mainDim * self._vector2)
            pts.append(i * self._vector1 + self._mainDim * self._vector2)
        self.coord.point.setValues(0,len(pts),pts)
        self._numGridLines = len(fullRange) * 2
        #self.gridcolor = self.gridcolor
        #self.transparency = self.transparency
        a = []
        l = len(pts)-4
        for i in range(l/2):
            a.append(2*i + 4)
            a.append(2*i + 5)
            a.append(-1)
        self.line1.coordIndex.setValue(0)
        self.line1.coordIndex.setValues(0, 3, [0,1,-1])
        self.line2.coordIndex.setValue(0)
        self.line2.coordIndex.setValues(0, 3, [2,3,-1])
        self.lineSet.coordIndex.setValue(0)
        self.lineSet.coordIndex.setValues(0, len(a), a)


class gridObject:
    def __init__(self, obj):
        obj.Proxy = self

class gridVP:
    def __init__(self, obj ):
        obj.addProperty("App::PropertyDistance",  "Total",         "Size",   "Size of a grid quadrant").Total = '100mm'
        obj.addProperty("App::PropertyDistance",  "Subdivision",   "Size",   "Size of subdivisions").Subdivision = '10mm'
        obj.addProperty("App::PropertyFloat",     "XY_Attenuation", "View",   "XY plane attenuation").XY_Attenuation = 1.0
        obj.addProperty("App::PropertyFloat",     "XZ_Attenuation", "View",   "XZ plane attenuation").XZ_Attenuation = 50.0
        obj.addProperty("App::PropertyFloat",     "YZ_Attenuation", "View",   "YZ plane attenuation").YZ_Attenuation = 50.0
        obj.addProperty("App::PropertyFloat",     "XY_Visibility",  "View",   "XY plane max visibility").XY_Visibility = 1.0
        obj.addProperty("App::PropertyFloat",     "XZ_Visibility",  "View",   "XZ plane max visibility").XZ_Visibility = 0.5
        obj.addProperty("App::PropertyFloat",     "YZ_Visibility",  "View",   "YZ plane max visibility").YZ_Visibility = 0.5
        obj.addProperty("App::PropertyColor",     "GridColor",     "Color",  "Grid Color").GridColor = (0.5,0.5,0.5)
        obj.Proxy = self

    def attach(self, obj):
        self.xy = gridNode()
        self.xy.vector1dir = (1,0,0)
        self.xy.vector1color = (1,0,0)
        self.xy.vector2dir = (0,1,0)
        self.xy.vector2color = (0,1,0)
        self.xy.mainDim = 100
        self.xy.subDim = 10
        self.xy.maxviz = 1.0
    
        self.xz = gridNode()
        self.xz.vector1dir = (1,0,0)
        self.xz.vector1color = (1,0,0)
        self.xz.vector2dir = (0,0,1)
        self.xz.vector2color = (0,0,1)
        self.xz.mainDim = 100
        self.xz.subDim = 10
        self.xz.maxviz = 0.5
    
        self.yz = gridNode()
        self.yz.vector1dir = (0,1,0)
        self.yz.vector1color = (0,1,0)
        self.yz.vector2dir = (0,0,1)
        self.yz.vector2color = (0,0,1)
        self.yz.mainDim = 100
        self.yz.subDim = 10
        self.yz.maxviz = 0.5
    
        self.sg = FreeCADGui.ActiveDocument.ActiveView.getSceneGraph()
        self.cam = FreeCADGui.ActiveDocument.ActiveView.getCameraNode()
    
        self.xy.linkTo(self.cam)
        self.xy.factor = 1.
        self.xz.linkTo(self.cam)
        self.xz.factor = 50.
        self.yz.linkTo(self.cam)
        self.yz.factor = 50.

        self.grid = coin.SoSeparator()

        self.grid.addChild(self.xy)
        self.grid.addChild(self.xz)
        self.grid.addChild(self.yz)
        self.sg.addChild(self.grid)

    def updateCam(self):
        self.cam = FreeCADGui.ActiveDocument.ActiveView.getCameraNode()
        self.xy.linkTo(self.cam)
        self.xz.linkTo(self.cam)
        self.yz.linkTo(self.cam)

    def onChanged(self, vp, prop):
        self.updateCam()
        if prop == 'Total':
            if float(vp.Total) >= float(vp.Subdivision):
                self.xy.mainDim = float(vp.Total)
                self.xz.mainDim = float(vp.Total)
                self.yz.mainDim = float(vp.Total)
            else:
                vp.Total = vp.Subdivision
        if prop == 'Subdivision':
            if float(vp.Total) >= float(vp.Subdivision):
                self.xy.subDim = float(vp.Subdivision)
                self.xz.subDim = float(vp.Subdivision)
                self.yz.subDim = float(vp.Subdivision)
            else:
                vp.Subdivision = vp.Total
        if prop == 'XY_Attenuation':
            if vp.XY_Attenuation < 0.1:
                vp.XY_Attenuation = 0.1
            elif vp.XY_Attenuation > 100:
                vp.XY_Attenuation = 100
            self.xy.factor = vp.XY_Attenuation
        if prop == 'XZ_Attenuation':
            if vp.XZ_Attenuation < 0.1:
                vp.XZ_Attenuation = 0.1
            elif vp.XZ_Attenuation > 100:
                vp.XZ_Attenuation = 100
            self.xz.factor = vp.XZ_Attenuation
        if prop == 'YZ_Attenuation':
            if vp.YZ_Attenuation < 0.1:
                vp.YZ_Attenuation = 0.1
            elif vp.YZ_Attenuation > 100:
                vp.YZ_Attenuation = 100
            self.yz.factor = vp.YZ_Attenuation
        if prop == 'XY_Visibility':
            if vp.XY_Visibility < 0.0:
                vp.XY_Visibility = 0.0
            elif vp.XY_Visibility > 1.0:
                vp.XY_Visibility = 1.0
            self.xy.maxviz = vp.XY_Visibility
        if prop == 'XZ_Visibility':
            if vp.XZ_Visibility < 0.0:
                vp.XZ_Visibility = 0.0
            elif vp.XZ_Visibility > 1.0:
                vp.XZ_Visibility = 1.0
            self.xz.maxviz = vp.XZ_Visibility
        if prop == 'YZ_Visibility':
            if vp.YZ_Visibility < 0.0:
                vp.YZ_Visibility = 0.0
            elif vp.YZ_Visibility > 1.0:
                vp.YZ_Visibility = 1.0
            self.yz.maxviz = vp.YZ_Visibility
        if prop == 'GridColor':
            self.xy.gridcolor = vp.GridColor
            self.xz.gridcolor = vp.GridColor
            self.yz.gridcolor = vp.GridColor

    def onDelete(self, feature, subelements):
        self.sg.removeChild(self.grid)
        return(True)

def main():

    obj=FreeCAD.ActiveDocument.addObject("App::FeaturePython","Grid")
    gridObject(obj)
    gridVP(obj.ViewObject)


if __name__ == '__main__':
    main()
Awesome!
It works perfectly and I love it :D
Tomorrow I will try to play with it more in deep to fine tune it to my taste but I have seen that toggling visibility off/on doesn't work, it is always visible... is that a little bug?
Dark and Light stylesheets v2.0 to theme your FreeCAD UI, more information here
Post Reply