Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

STL file support #1

Open
szaghi opened this issue Nov 15, 2017 · 30 comments
Open

STL file support #1

szaghi opened this issue Nov 15, 2017 · 30 comments
Assignees

Comments

@szaghi
Copy link

szaghi commented Nov 15, 2017

Dear Vladimir,

I am using your nice binding with great satisfaction, it is really a helpful code.

I would like to deal directly with a STL file input (instead of OFF), do you think it is possible?

Cheers.

@LadaF
Copy link
Owner

LadaF commented Nov 15, 2017 via email

@szaghi
Copy link
Author

szaghi commented Nov 16, 2017

Hi Vladimir,

thank you very much for your help, it is really appreciated.

It is probably time to update it. It already gives a lot of warnings about deprecation. It is just hard to find the time.

I see the warning, but I am not up to the task to write c++ code, I cannot help, my bad.

I also using meshconv, but dealing directly with STL is more convenient. Anyhow, thank you again for sharing this helpful code!

Cheers.

@szaghi szaghi closed this as completed Nov 16, 2017
@LadaF
Copy link
Owner

LadaF commented Nov 16, 2017

I will keep this open, I think it is worth doing something in the relatively near future.

@LadaF LadaF reopened this Nov 16, 2017
@LadaF LadaF self-assigned this Nov 16, 2017
@szaghi
Copy link
Author

szaghi commented Nov 16, 2017

I will keep this open, I think it is worth doing something in the relatively near future.

If I can help in some way, please let me know.

Cheers.

@szaghi
Copy link
Author

szaghi commented Apr 27, 2018

Dear Vladimir,

at the end I decided to move toward a fully Fortran library for the computation of point-surface(triangulated)-distance. I wrote a library (still in beta) that does IO directly STL files and does (signed or not) distance computation by means of also AABB acceleration (point-in-polyhedron test still does not exploit AABB tree hierarchy, but it is a simple step that I hope to add next week).

Preliminary tests show very good accuracy and computation speed, but I have to clean the code and to make more tests and analysis.

The library is here (develop branch)

https://github.com/szaghi/FOSSIL/tree/develop

I hope it could be of some help also for you.

@LadaF
Copy link
Owner

LadaF commented Apr 30, 2018

Thank you, that sounds really promising! Messing with the CGAL traits and templates is really hard, I tried to do something, but it is just very difficult for me. But, to be fair, I couldn't find the right Demo example to begin with, and it is right here in the Stack Overflow answer you linked!

Anyway, I think a smaller Fortran code might be much better. I wonder whether the class of accepted STL files will be similar to CGAL or wider as I often have problems loading a file even when Meshlab told me it is orientable.

@szaghi
Copy link
Author

szaghi commented May 2, 2018

Hi Vladimir,

currently, the library accepts (blindly) any STL, it is almost agnostic, it assumes the input to be really a "cloud of triangles" as an STL should be.

The distance (square or square root) computation should work as it, but if you ask for signed distance the quality of STL does matter. In particular, it is important that the facets normals are consistent (or similarly that the three points of facet are well numbered, the normals are recomputed by the library by the three points-facet) and/or the whole polyhedra has not holes (namely the surface is watertight), but no checks is done before assigning the distance sign. I use Salome to generate STL from CAD (iges generally), thus making normals consistent or generating watertight STL is relatively simple.

If I will have the time, I'll try to understand the algorithm of admesh for filling holes and sanitizing normals in order to put them into the library and doing the right checks/actions before trying to compute the sign.

I'll public the first stable release soon.

Thank you again for your help.

Cheers.

@szaghi
Copy link
Author

szaghi commented May 7, 2018

Hi Vladimir,

good news: I found the time to add some methods to inspect and sanitize STL. Now the library can "repair" inconsistent normals orientation, reconstruct triangles connectivity and compute volume. Now it is possible to alert for holes and the like and eventually to try to fill them (not yet implemented). I'll add some transformation methods (scale, rotate, mirror...) before the 1.0.0 version, but it is quite usable now. At the end I added most part of the admesh tools combining it with a robust and efficient (signed) distance computation, that was what I need to pre-process my (very) bad input STL files.

Cheers.

@LadaF
Copy link
Owner

LadaF commented May 10, 2018 via email

@szaghi
Copy link
Author

szaghi commented May 11, 2018

:-)

You are too much kind. Indeed, all seems to work smooth, but for example I need to check more accurately the robustness of the connectivity reconstruction algorithm. Nevertheless, I am going to use it in production, thus any weakness will arise soon.

As for the installation/use you do not need FoBiS: I can give you a legacy makefile if you like it and a more simple install script not based on git.

Let me know if you want to try it.

Cheers.

@szaghi
Copy link
Author

szaghi commented May 16, 2018

Hi Vladimir,

a new release is out, v1.0.1, it brings two interesting news (I hope):

  • a standalone program that does essentially the same job of admesh except for filling holes;
  • the capability to automatically connect facets that are disconnected but very close (the common scenario when dealing with poor STL inputs).

For now I am quite satisfied by the current features of FOSSIL, but if you have any requests I am happy to try to add them (probably tomorrow I'll add the possibility to trim out facets outside a given bound box, a sort of clip method).

Cheers

@LadaF
Copy link
Owner

LadaF commented May 17, 2018 via email

@LadaF
Copy link
Owner

LadaF commented May 17, 2018

Just as a note, I now used the Quadric Edge Collapse Decimation in Meshlab to reduce the number of facets 10x and the file was loaded very quickly. By several orders of magnitude faster.

Vlada

@szaghi
Copy link
Author

szaghi commented May 17, 2018

Hi Vladimir,

great test!

Efficiency has not been still taken into account, I am focused more on the robustness/correctness, but the next step is to improve IO and manipulation speed. As you know, I am not a very good programmer, your help into optimizing the library could be very helpful.

I am using gfortran 7.x, thus 5.3.1 is out of my scope, I cannot help in this regards. Anyhow, I had tried to be standard conforming, thus if the only change you needed was to modify source allocation I can certainly patch my code to "incorporate" your more robust allocation.

The negative volume simply indicates that the normal are not "all counter clock oriented/consistent": try to sanitize them and recompute volume

call file_stl%sanitize_normals
call file_stl%compute_volume
print*, call file_stl%statistics()

Thank you very much for your feedback!

@LadaF
Copy link
Owner

LadaF commented May 18, 2018 via email

@szaghi
Copy link
Author

szaghi commented May 18, 2018

@LadaF

Hi Vladimir, this sounds an interesting test that could help me to find a lot of bugs: the nearby search should be quite simple, I guessed that the problem was on connectivity reconstruction, but as often happens I am wrong.

Can you share this STL? Or another (maybe reduced/manipulated to be shared) raising the same issue?

Thank you again for the feedbacks.

@LadaF
Copy link
Owner

LadaF commented May 18, 2018

I returned to the original STL I tried first (from the thingiverse link). I analyzed it using Oracle Studio Analyzer. It has been a very nice tool for many years, extremely under-rated in my opinion.

The call to build_connectivity starts after 0.2 s and then takes 526 s. Almost all of the time it spends in compute_vertices_nearby and inside that the majority of time is spent in the are_nearby computations.

My guess is that it is just called for too many combinations of vertices and that there has to be some heuristic to limit the number of calls for distant pairs.

screen1

screen2

@szaghi
Copy link
Author

szaghi commented May 18, 2018

@LadaF

Yep, in fact my idea was just to exploit the already present AABB levels to speedup also nearby search. I'll try to do it monday.

Oracle Studio Analyzer sounds interesting, thanks!

@LadaF
Copy link
Owner

LadaF commented Jun 4, 2018

I tried the current develop branch and it loaded the file really fast! Just the API has changed somewhat from the README file so I didn't get far yet, but I was able to print the size of the facet array. Is there a reason why the facets are now returned as a separate array in load_from_file?

@szaghi
Copy link
Author

szaghi commented Jun 4, 2018

@LadaF

Oh no, my bad, I was to slow...

Yes, there was a reason for separating file handler from surface one: I need to write the facets contained into each AABB block (that is a member of surface handler) created to speedup distance/connectivity computation, thus in order to avoid code-duplication I used the same file handler to save AABBs STL, just like a surface STL... a little cumbersome, but the code now has less duplication.

I hope to push a stable release soon with up-to-date documentation, I am sorry. Anyhow for very big input like yours I suggest to use high refinement levels (>2, maybe 5 or 6 or even more) for AABB structure. I am thinking to insert a method to automatically set a good refinement level basing on the shortest edge length...

Thank you very much for your feedback.

@szaghi
Copy link
Author

szaghi commented Jun 4, 2018

@LadaF

Vladimir, I pushed a new stable release, this should be quite stable (I should not break the compatibility anymore).

It should be quite efficient now in loading and analyze big input, anyhow it has also the "clip" feature on loading: if the input is really huge you can load it by "clip" (providing bound box extents) and only the facets falling inside the clip will be loaded (it could be of some help for partioning the workload/tests...). I also added a new "distance" method: compute_distance is subroutine (instead of a function) that returns the shortest distance, but, if asked for, it returns also the index of the closest facet (the index of the closest edge/vertex outputs will come). Obviously, the distance function calls this new one without querying the index, but knowing that index could be helpful in some scenario. There is not a overhead between them, they are the same, but the function returns only the distance value, the subroutine can return also the index(es).

Cheers.

@LadaF
Copy link
Owner

LadaF commented Jun 4, 2018 via email

@ZviHantsis
Copy link

ZviHantsis commented Jun 4, 2018

@LadaF , First off, I figured I should move the comment to the FOSSIL page, I have deleted the comment here as such. Maybe I shouldn't have.

As for the issue at hand:
Perhaps my terminology is incorrect, but I am using Steve Lionel's (Intel) terminology, which is also used on Stackoverflow and others.

But allow me to clarify:
Say that module A has a code calling a procedure with optional arguments which exists in module B.

I have referred specifically to an interface block in the calling module A which specifies, among other things, the OPTIONAL arguments as well. So that the calling code in module A will know to communicate properly if an optional argument was passed or not to the procedure on module B. If such an interface does not exist - the present(optional argument) in the procedure in module B will always return .true.

@LadaF
Copy link
Owner

LadaF commented Jun 4, 2018 via email

@ZviHantsis
Copy link

I definitely agree you know what you are talking about - your reputation goes way ahead of you.
However, is this correct also when using only parts of the module?
If use fossil_aabb_tree_object, only : aabb_tree_object is used, does that include the interface for all the public methods in 'module fossil_aabb_tree_object' under contains?

@LadaF
Copy link
Owner

LadaF commented Jun 4, 2018 via email

@ZviHantsis
Copy link

Alright, so it's not the "optional" issue.
In that case, I do not know what is the problem - I used the fossil_test_distance test case which was updated with v1.0.4 and got the exact same issue as I reported.

subroutine fossil_test_distance
!< FOSSIL, test distance computation.

use fossil, only : file_stl_object, surface_stl_object
use penf, only : I4P, I8P, R8P, str
use vecfor, only : ex_R8P, ey_R8P, ez_R8P, vector_R8P
use fossil_aabb_tree_object, only : aabb_tree_object

implicit none

type(file_stl_object)         :: file_stl                !< STL file.
type(surface_stl_object)      :: surface_stl             !< STL surface.
type(vector_R8P), allocatable :: grid(:,:,:)             !< Grid.
real(R8P),        allocatable :: distance(:,:,:)         !< Distance of grid points to STL surface.
character(999)                :: file_name_stl           !< Input STL file name.
integer(I4P)                  :: refinement_levels       !< AABB refinement levels used.
logical                       :: save_aabb_tree_geometry !< Sentinel to save AABB geometry.
logical                       :: save_aabb_tree_stl      !< Sentinel to save AABB stl.
logical                       :: test_brute_force        !< Sentinel to test also brute force.
character(999)                :: sign_algorithm          !< Algorithm used for "point in polyhedron" test.
integer(I4P)                  :: ni, nj, nk              !< Grid dimensions.
integer(I4P)                  :: i, j, k                 !< Counter.
real(R8P)                     :: Dx, Dy, Dz              !< Space steps.
integer(I4P)                  :: file_unit               !< File unit.
integer(I8P)                  :: timing(0:4)             !< Tic toc timing.
logical                       :: are_tests_passed(1)     !< Result of tests check.

are_tests_passed = .false.

!file_name_stl="~/Geomerty/naca0012-ascii.stl"
file_name_stl="~/Geomerty/naca0012-binary.stl"

refinement_levels=2
save_aabb_tree_geometry=.false.
save_aabb_tree_stl=.false.
test_brute_force=.false.
sign_algorithm='ray_intersections'

call file_stl%load_from_file(facet=surface_stl%facet, file_name=trim(adjustl(file_name_stl)), guess_format=.true.)
print*,size(surface_stl%facet),surface_stl%facets_number                   !<------------- this is the output
call surface_stl%analize(aabb_refinement_levels=refinement_levels)         !<------------- this is line 1005 where the error occurs
print '(A)', 'STL statistics before sanitization'
print '(A)', file_stl%statistics()
print '(A)', surface_stl%statistics()
call surface_stl%sanitize
call surface_stl%analize
print '(A)', 'STL statistics after sanitization'
print '(A)', surface_stl%statistics()
.
.
.

And the output was:

         188           0
forrtl: severe (408): fort: (8): Attempt to fetch from allocatable variable ID when it is not allocated

Image              PC                Routine            Line        Source
testCode           000000000058E532  fossil_list_id_ob         104  fossil_list_id_object.f90
testCode           00000000005BA300  fossil_aabb_objec          64  fossil_aabb_object.f90
testCode           000000000053983C  fossil_aabb_node_          60  fossil_aabb_node_object.f90
testCode           00000000006C43CD  fossil_aabb_tree_         180  fossil_aabb_tree_object.f90
testCode           00000000006C9A8C  fossil_aabb_tree_         249  fossil_aabb_tree_object.f90
testCode           00000000005DD866  fossil_surface_st         101  fossil_surface_stl.f90
testCode           0000000000728407  ib_module_mp_foss        1005 TEST_combine_fossil.f90

I tried with ascii and binary formats, also tried to redo this "manually".
Note that it does read the correct amount of facets, but %number_facets is still zero...

@szaghi
Copy link
Author

szaghi commented Jun 5, 2018

@ZviHantsis your last example is not useful: please provide a full executable test in order I can try to fix the possible bug. It is not my fossil_test_distance, but it looks like to be extracted from it.

Anyhow, I do not understand the opitional gate...

Cheers

@LadaF
Copy link
Owner

LadaF commented Jun 5, 2018 via email

@LadaF
Copy link
Owner

LadaF commented Nov 28, 2023

Returning to the issue in the title, here is some explanation why dealing with STL files is complicated and hence the need for complicated code in CGAL demos, such as https://github.com/CGAL/cgal/blob/master/Polyhedron/demo/Polyhedron/Scene_polygon_soup_item.cpp and why FOSSIL needs subroutines such as build_connectivity and compute_vertices_nearby. This is used in an STL io plugin https://github.com/CGAL/cgal/blob/master/Polyhedron/demo/Polyhedron/Plugins/IO/STL_io_plugin.cpp but the use of it is not shown in any example, but it may be the way to get STL files as a CGAL Polyhedron.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants