tessellate() with local cords ?

Post here for help on using FreeCAD's graphical user interface (GUI).
Forum rules
and Helpful information
IMPORTANT: Please click here and read this first, before asking for help

Also, be nice to others! Read the FreeCAD code of conduct!
Post Reply
jacknotreally
Posts: 75
Joined: Mon Dec 14, 2009 9:49 am

tessellate() with local cords ?

Post by jacknotreally »

I would like to tessellate a shape with local cords.
I think the placement (transformation-matrix) will be transformed into each point inside tesselation() by FreeCAD.
Now i have to create a second shape with transformGeomtry and the inverted Placement just to undo something which will done later.

The reason is, that i would like to transfer shape´s to a external application and i would like to transfer local cords for triangle meshes and transformations separate.

Is there a way do do this?

Cheers,
Jack - not really
wmayer
Founder
Posts: 20309
Joined: Thu Feb 19, 2009 10:32 am
Contact:

Re: tessellate() with local cords ?

Post by wmayer »

First of all you need a definition of "local coords". Assuming you have a face where e.g. the 1st derivative of the underlying surface is defined in (0,0). Then you can build a local coordinate system for your shape this way:

v1...axis in u-direction at (0,0)
v2...axis in v-direction at (0,0)
v3...normal at (0,0) or cross product of v1 and v2
p...surface point at (0,0)

The vectors v1,v2 and v3 are perpendicular to each other so that they can be used to define your local coordinate system with p as origin.
So, you can define a 3x3 rotation matrix R=(v1,v2,v3) and the translation vector p and thus the transformation

Code: Select all

X' = R * X + p
To get the transformation from global to local coordinates you need the inverse of the above transformation. Since R is a so called orthonormal matrix its inverse is equal to its transposed matrix.

Code: Select all

X = R^T * X' - R^T * p
In Python it looks like:

Code: Select all

from FreeCAD import Base

face = ... # a topo face as reference
(v1,v2) = face.derivative1At(0,0)
v3=face.normalAt(0,0)
p=face.valueat(0,0)

mat = Base.Matrix()
mat.A11 = v1.x
mat.A21 = v2.x
mat.A31 = v3.x
mat.A12 = v1.y
mat.A22 = v2.y
mat.A32 = v3.y
mat.A13 = v1.z
mat.A23 = v2.z
mat.A33 = v3.z
mat.A14 = -(v1.x*p.x + v1.y*p.y + v1.z*p.z)
mat.A24 = -(v2.x*p.x + v2.y*p.y + v2.z*p.z)
mat.A34 = -(v3.x*p.x + v3.y*p.y + v3.z*p.z)
Now, you can tessellate your shape and apply the transformation to each of your point to get it expressed as local coordinate.

Code: Select all

(v,f)=face.tessellate(0.01)
for i in v:
    print mat.multiply(i)
Here is a full script with a plane as example which we transform first

Code: Select all

from FreeCAD import Base
import Part

face=Part.makePlane(10,10)
r=Base.Matrix()
r.rotateX(1.0)
r.rotateY(1.0)
r.rotateZ(1.0)
r.move(12,23,34)
face.Matrix=r

(v1,v2)=face.derivative1At(0,0)
v3=face.normalAt(0,0)
p=face.valueAt(0,0)

mat = Base.Matrix()
mat.A11 = v1.x
mat.A21 = v2.x
mat.A31 = v3.x
mat.A12 = v1.y
mat.A22 = v2.y
mat.A32 = v3.y
mat.A13 = v1.z
mat.A23 = v2.z
mat.A33 = v3.z
mat.A14 = -(v1.x*p.x + v1.y*p.y + v1.z*p.z)
mat.A24 = -(v2.x*p.x + v2.y*p.y + v2.z*p.z)
mat.A34 = -(v3.x*p.x + v3.y*p.y + v3.z*p.z)

(v,f)=face.tessellate(0.01)
for i in v:
    print mat.multiply(i)
jacknotreally
Posts: 75
Joined: Mon Dec 14, 2009 9:49 am

Re: tessellate() with local cords ?

Post by jacknotreally »

First off all: For me everything works fine.
Just the "scale" could be a problem.

This is for my understanding and may be for optimization.
I am not much experienced in this and only know little about the FreeCAD/OCC Kernel.

I am familiarized to use homogeneous transformation matrix within OpenGL and scene graphs.
What i mean with local coordinates is:

Code: Select all

Creating a Shape (Box size 100 overall, zero point at middle). So all coordinates will be in between +/- 50.
This i would call local.
Setting the pos-placement to (X=200) will produce coordinates during tessellation from +250..150 in x-axes.
This i would call world.
Now i want to export the shape to my application. All in "local" coordinates and additional i will transfer a 4 x 4 homogeneous transformation matrix (for position/rotation/scale)
Afterwards, i would like to change the position/rotation/scale of the shape in my application.
After change i would like to update the FreeCAD drawing (shape) by ONLY transferring the 4 x 4 homogeneous transformation matrix back to the shape.

The placement is a 4 x 4 homogeneous transformation matrix, but unfortunately it does what is´s name sounds like:
place.. + rotation, but no scale.
Although it seems it could, but the placement implementation seems to prevented this (ignoring the diagonals scaling cells).

If i would have a free wish this would be: ;)

Code: Select all

Shape.SetTransform4x4Matrix(Matrix) # modifying translation/rotation/scale
and
Matrix=Shape.GetTransform4x4Matrix()
and last 
..tesselate(quality,LocalOrWorld) #with or without the Shape transformation matrix
Now i am doing something like this to "un-transform" the shape placement (i think something like your suggestion):

Code: Select all

    pn=FreeCAD.Placement()
    p=shapeIn.Placement #shapeIn is the incoming shape
    if pn.Rotation.Q==p.Rotation.Q and pn.Base==p.Base:
        # identity matrix, nothing to do
        shape=shapeIn
    else:
        # remove Placement from shape
        m=shapeIn.Placement.toMatrix()
        m.invert()
        shape=shapeIn.transformGeometry(m)
    for f in shape.Faces:
        ..... 
        av=f.tessellate(0.8)

To Transfer scaling back to FreeCAD, i don´t have have a better idea then:

Code: Select all

.. removing scaling from my transformation matrix
.. update transformation matrix to FreeCAD Shape-placement  # position and rotation will be ok
.. making a shape.scale() with the scaling part of original transformation matrix
but this would generate other tessellation-coordinates then before (the next time)

Cheers,
Jack - not really
jacknotreally
Posts: 75
Joined: Mon Dec 14, 2009 9:49 am

Re: tessellate() with local cords ?

Post by jacknotreally »

in addition:
Maybe it´s not a good idea to change the scale of shape.
If it´s feature-based then its property´s should be changed to get a new "scale"
wmayer
Founder
Posts: 20309
Joined: Thu Feb 19, 2009 10:32 am
Contact:

Re: tessellate() with local cords ?

Post by wmayer »

Creating a Shape (Box size 100 overall, zero point at middle). So all coordinates will be in between +/- 50.
This i would call local.
So, in other words: the gravity center of the object lies in the origin and is aligned to the coordinate axes.
The placement is a 4 x 4 homogeneous transformation matrix, but unfortunately it does what is´s name sounds like:
place.. + rotation, but no scale. Although it seems it could, but the placement implementation seems to prevented this (ignoring the diagonals scaling cells).
For a shape you can use the method scale() which sets the internal placement of the shape -- in OCC this placement is realized by the class TopLoc_Location. Afterwards you can use the attribute "Matrix" instead of "Placement" and this matrix also contains your scale factor.
If i would have a free wish this would be:
Shape.SetTransform4x4Matrix(Matrix) # modifying translation/rotation/scale
and
Matrix=Shape.GetTransform4x4Matrix()
and last
..tesselate(quality,LocalOrWorld) #with or without the Shape transformation matrix
The Matrix attribute does exactly this.
Maybe it´s not a good idea to change the scale of shape.
If it´s feature-based then its property´s should be changed to get a new "scale"
The scaling could lead to strange results. Especially for some more complex geometries you can create self-intersections or even worse things.
jacknotreally
Posts: 75
Joined: Mon Dec 14, 2009 9:49 am

Re: tessellate() with local cords ?

Post by jacknotreally »

Hi Werner,

Ok, now i think its clear. It is the same topic as: viewtopic.php?f=3&t=655&p=4502#p4502

Cheers,
Jack - not really
Post Reply