[SOLVED] nearestFacetOnRay no taking into account vector orientation

Need help, or want to share a macro? Post here!
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
User avatar
gabokamaze
Posts: 19
Joined: Thu Feb 10, 2022 3:12 pm

[SOLVED] nearestFacetOnRay no taking into account vector orientation

Post by gabokamaze »

Hi,
it seems that the Mesh method called nearestFacetOnRay() does not take into account the sign (or orientation) of the ray vector (second argument).
Here a exemple of what I mean :

Code: Select all

import FreeCAD
import Part,Mesh,MeshPart

myDocument = FreeCAD.newDocument("testfgg")
FreeCAD.setActiveDocument("testfgg")
myMesh = FreeCAD.ActiveDocument.addObject("Mesh::Feature","myMeshName")

cube = Part.makeBox(1,1,1)

Part.show(cube)
myMesh = MeshPart.meshFromShape(cube)
val1 = myMesh.nearestFacetOnRay((0.75, 0.25, 0.1), (0.0, +1.0, 0.0))
val2 = myMesh.nearestFacetOnRay((0.75, 0.25, 0.1), (0.0, -1.0, 0.0))
val3 = myMesh.nearestFacetOnRay((0.75, 0.75, 0.1), (0.0, +1.0, 0.0))
val4 = myMesh.nearestFacetOnRay((0.75, 0.75, 0.1), (0.0, -1.0, 0.0))

# Result
# val1 = val2 = {4: (0.75, 0.0, 0.1)}
# val3 = val4 = {6: (0.75, 1.0, 0.1)}
I was expecting than val1 return face # 6 (as vector is pointing toward +y) and val3 return face # 4 (as vector is pointing toward -y).
What is the more efficient way (from computation time point of view) to obtain this kind of result ?

Thanks by advance
Regards
Gab

FreeCAD Version used :
--------------------------------
OS: CentOS Stream 8 (GNOME/gnome)
Word size of OS: 64-bit
Word size of FreeCAD: 64-bit
Version: 0.19.24291 (Git) AppImage
Build type: Release
Branch: (HEAD detached at 0.19.2)
Hash: 7b5e18a0759de778b74d3a5c17eba9cb815035ac
Python version: 3.8.8
Qt version: 5.12.9
Coin version: 4.0.0
OCC version: 7.4.0
Locale: French/France (fr_FR)
Last edited by gabokamaze on Mon Feb 14, 2022 10:10 am, edited 2 times in total.
User avatar
Kunda1
Veteran
Posts: 13434
Joined: Thu Jan 05, 2017 9:03 pm

Re: nearestFacetOnRay no taking into account vector orientation

Post by Kunda1 »

Please add About info to your OP. Thanks.
Alone you go faster. Together we go farther
Please mark thread [Solved]
Want to contribute back to FC? Checkout:
'good first issues' | Open TODOs and FIXMEs | How to Help FreeCAD | How to report Bugs
User avatar
onekk
Veteran
Posts: 6144
Joined: Sat Jan 17, 2015 7:48 am
Contact:

Re: nearestFacetOnRay no taking into account vector orientation

Post by onekk »

Try this in your code and see that surprisingly thing are changing, so probably order of point will matter.

Code: Select all

pt1 = (0.75, 0.25, 0.1)
pt2 = (0.0, +1.0, 0.0)
pt3 = (0.75, 0.75, 0.1)
pt4 = (0.0, -1.0, 0.0)

val1 = myMesh.nearestFacetOnRay(pt2, pt1)
val2 = myMesh.nearestFacetOnRay(pt4, pt1)
val3 = myMesh.nearestFacetOnRay(pt2, pt3)
val4 = myMesh.nearestFacetOnRay(pt4, pt3)

This is to visualize lines (order of point is your original one)

Code: Select all

Part.show(Part.LineSegment(Vector(*pt1), Vector(*pt2)).toShape(), "line1")
Part.show(Part.LineSegment(Vector(*pt1), Vector(*pt4)).toShape(), "line2")
Part.show(Part.LineSegment(Vector(*pt3), Vector(*pt2)).toShape(), "line3")
Part.show(Part.LineSegment(Vector(*pt3), Vector(*pt4)).toShape(), "line4")
This to add some context on what you are expecting for.
nearestFacetOnRay(tuple, tuple) -> dict
Get the index and intersection point of the nearest facet to a ray.
The first parameter is a tuple of three floats the base point of the ray,
the second parameter is a tuple of three floats for the direction.
The result is a dictionary with an index and the intersection point or
an empty dictionary if there is no intersection.
With these values on which the point is not internal to the mesh, results seems correct

Code: Select all

pt5 = (-0.5, 0.5, 0.1)
pt6 = (1.2, 0.5, 0.1)

val5 = myMesh.nearestFacetOnRay(pt5, pt6)
Part.show(Part.LineSegment(Vector(*pt5), Vector(*pt6)).toShape(), "line5")

print("val5", val5)

val6 = myMesh.nearestFacetOnRay(pt6, pt5)
Part.show(Part.LineSegment(Vector(*pt6), Vector(*pt5)).toShape(), "line6")

print("val6", val6)

Hope it helps

Regards

Carlo D.
GitHub page: https://github.com/onekk/freecad-doc.
- In deep articles on FreeCAD.
- Learning how to model with scripting.
- Various other stuffs.

Blog: https://okkmkblog.wordpress.com/
User avatar
gabokamaze
Posts: 19
Joined: Thu Feb 10, 2022 3:12 pm

Re: nearestFacetOnRay no taking into account vector orientation

Post by gabokamaze »

Hi Carlo,
Thanks for your contribution. Unfortunatly, it does not help. :(
The nearestFacetOnRay method need 2 arguments :
  • the first one correspond to the coordinates of a point
  • the second one correspond to the vector on which an intersection with the base mesh is searched
So, regarding your remark ("probably order of point will matter"), it is obvious that if you change order of the 2 arguments, result will be different.
For another of your remarks ("With these values on which the point is not internal to the mesh, results seems correct") : this is a particular case (the point is outside of the base mesh). I will deal with complexe shapes, and I could be inside the bounding box of the base mesh, so I cannot modify the "problem" to change the coordinates of the base point (1st argument).

To clarify : nearestFacetOnRay search the intersection between a Facets and a line defined by the 2 arguments provided to this methods (i.e. : coordinates of 1 point and a vector). It could exists several solutions (several Facets can be found), and the method return the closest Facets without taking into account the sign of the vector (this is proven by the results of my test-case for which one "val1"="val2" but vector used for "val2" is the opposite vector used for "val1", and the same reasoning for "val3" and "val4"). And this is excatly what I am searching : find the nearest facet of a mesh from 1 point in a signed direction.

I could reimplement this method, but I am sure that it will be less efficient because I need to iterate on each facets ... and I think the native structure/containers of FreeCAD is optimized.

Is there another way, another method, ... to do this without "reinvent the wheel" ?

Thanks by advance
Regards
Gab
User avatar
onekk
Veteran
Posts: 6144
Joined: Sat Jan 17, 2015 7:48 am
Contact:

Re: nearestFacetOnRay no taking into account vector orientation

Post by onekk »

gabokamaze wrote: Fri Feb 11, 2022 5:00 pm Is there another way, another method, ... to do this without "reinvent the wheel" ?

You have to deal with the way the functions is made, if not results are not consistent.

Maybe you could even take the bounding box, and then calculate two point on the line you are testing place outside the bounding box.

But this has to deal with the way function is testing the Facets.

Sadly I have no idea of how the routine will work, so maybe you have to wait for someone else that will step in and maybe give some other solution.

Regards

Carlo D.
GitHub page: https://github.com/onekk/freecad-doc.
- In deep articles on FreeCAD.
- Learning how to model with scripting.
- Various other stuffs.

Blog: https://okkmkblog.wordpress.com/
TheMarkster
Veteran
Posts: 5505
Joined: Thu Apr 05, 2018 1:53 am

Re: nearestFacetOnRay no taking into account vector orientation

Post by TheMarkster »

Edit: You need a recent build of 0.20 or else modify the code to make it work. Part.show() didn't have a return value in 0.19.

------------

It looks like both directions are being searched. I revised the code a bit for some experimenting.

Code: Select all

import FreeCAD
import Part,Mesh,MeshPart

myDocument = FreeCAD.newDocument("testfgg")
FreeCAD.setActiveDocument("testfgg")
myMesh = FreeCAD.ActiveDocument.addObject("Mesh::Feature","myMeshName")
myMesh.ViewObject.DisplayMode="Flat Lines"
myMesh.ViewObject.Transparency = 50
cube = Part.makeBox(1,1,1)
off = FreeCAD.Vector(.1,0,0)
#Part.show(cube).ViewObject.Transparency = 50
p1 = Part.Vertex(FreeCAD.Vector(0.5,0.25,0.1))

ray1 = p1.extrude(FreeCAD.Vector(0,1,0))
Part.show(ray1,"ray1")
Part.show(p1,"p1").ViewObject.PointSize = 10
p1.Placement.move(off)
ray2 = p1.extrude(FreeCAD.Vector(0,-1,0))
Part.show(ray2,"ray2")
Part.show(p1,"p1_moved").ViewObject.PointSize = 10


myMesh.Mesh = MeshPart.meshFromShape(cube)
val1 = myMesh.Mesh.nearestFacetOnRay(tuple(p1.Point), (0.0, +1.0, 0.0))
val2 = myMesh.Mesh.nearestFacetOnRay(tuple(p1.Point), (0.0, -1.0, 0.0))
print(f"val1 = {val1}")
print(f"val2 = {val2}")
f1 = val1.popitem()[0]
f2 = val2.popitem()[0]
facet1 = myMesh.Mesh.Facets[f1]
for p in facet1.Points:
    Part.show(Part.Vertex(p)).ViewObject.PointSize=10
facet2 = myMesh.Mesh.Facets[f2]
for p in facet2.Points:
    Part.show(Part.Vertex(p)).ViewObject.PointSize=10

Snip macro screenshot-1a4ce3.png
Snip macro screenshot-1a4ce3.png (55.86 KiB) Viewed 1178 times
The 3 enlarged vertices show which facet is being returned.
wmayer
Founder
Posts: 20243
Joined: Thu Feb 19, 2009 10:32 am
Contact:

Re: nearestFacetOnRay no taking into account vector orientation

Post by wmayer »

gabokamaze wrote: Fri Feb 11, 2022 5:00 pm I could reimplement this method, but I am sure that it will be less efficient because I need to iterate on each facets ... and I think the native structure/containers of FreeCAD is optimized.
This is the function that is called on C++ side: https://github.com/FreeCAD/FreeCAD/blob ... hm.cpp#L69
The relevant function is Foraminate() that you can find here: https://github.com/FreeCAD/FreeCAD/blob ... s.cpp#L863

The last argument fMaxAngle gives the maximum angle between the ray and the normal of the triangle which by default is set to PI and that's why the algorithm finds triangles that lie in opposite direction of the ray.

If you want to ensure that the algorithm ignores these triangles then the following must be done:
  • An overloaded function MeshAlgorithm::NearestFacetOnRay() must be added which offers an argument to control the max. angle
  • The Python wrapper must be extended to support to pass an angle which is optional and by default set to PI. This is to make sure the default behaviour doesn't change.
  • In your client code you then have to set this 3rd parameter and set it e.g. to math.pi/2
wmayer
Founder
Posts: 20243
Joined: Thu Feb 19, 2009 10:32 am
Contact:

Re: nearestFacetOnRay no taking into account vector orientation

Post by wmayer »

git commit a6f0f69ed6

With

Code: Select all

import math

val1 = myMesh.nearestFacetOnRay((0.75, 0.25, 0.1), (0.0, +1.0, 0.0), math.pi/2)
val4 = myMesh.nearestFacetOnRay((0.75, 0.75, 0.1), (0.0, -1.0, 0.0), math.pi/2)
it gives you now the expected result.
User avatar
gabokamaze
Posts: 19
Joined: Thu Feb 10, 2022 3:12 pm

Re: nearestFacetOnRay no taking into account vector orientation

Post by gabokamaze »

Thank you Carlo, TheMarkster and wmayer for the time spend on my interrogation.

I think the more straight forward solution is the one provided by wmayer ("add an overloaded function MeshAlgorithm::NearestFacetOnRay()").
Moreover, thank you wmayer for the modification done on the source code.

For 2 main reasons (I am not really experiment in C++ and compilation skills, and I prefer to work on a release version of FreeCAD), I am going to implement something on my code to do what I want. Even if it will be less performant, it will be a temporarly solution until the modification done by wmayer on source code will be release.

Regards,
Gab
User avatar
onekk
Veteran
Posts: 6144
Joined: Sat Jan 17, 2015 7:48 am
Contact:

Re: nearestFacetOnRay no taking into account vector orientation

Post by onekk »

gabokamaze wrote: Mon Feb 14, 2022 8:41 am Thank you Carlo, TheMarkster and wmayer for the time spend on my interrogation.
...

I prefer to work on a release version of FreeCAD)
For the Thanks, You are welcome, but my comment was not a solution, only a "different point of view".


For stable version, as the actual state of the art, dev version are very similar to release versions, as usually bugs are fixed first in dev versions and then maybe backported to some point.release, and there is some care to not release buggy code.

@wmayer is doing a very good job and his "antennas" are very tuned on "users troubles", when there is some question, is responding every time in a authoritative way and with good expanations. :)

I'm speaking for Linux as it has AppIMage, released with a weekly interval.

It is usally "safe" to use a dev version as FC has not reached a "stable" condition, i.e. no 1.0 version is out where there are bugfixes only till 1.1

So the only thing that remain stable in "stable release" of FC are bugs until they are fixed and a new point.release (example 0.19, 0.19.1, etc) was released.

Usually broken things, remain broken in FC dev version for short time, usually on a Weekly interval if you use an AppImage.

I think even for Portable Builds and for Mac there is some release mechanism for dev version that release new version on a short term.

Regards

Carlo D.
GitHub page: https://github.com/onekk/freecad-doc.
- In deep articles on FreeCAD.
- Learning how to model with scripting.
- Various other stuffs.

Blog: https://okkmkblog.wordpress.com/
Post Reply