1

I am trying to fill a STL file with points in Fortran. I have written a basic code but it is not working.

My method has been to use a random number generator to generate a point. I then normalize this point to the dimensions of the STL bounding box.

I then throw out the "z" coordinate for the the first triangle in the STL. I check if the random point is with the max and min value of the "x" and "y" coordinate of the first triangle. If so I project the random point vertically onto the triangle plane and calculate the "z" value should it intersect with the plane. I then check if the z value of the random point is less than the value of the projected point (Ray casting). If yes I increase a counter, which is initially set to zero, by one.

I do this for every triangle in the STL. If the counter is even the random point is outside the volume, if it is odd the random point is inside the volume and the point is stored.

I then generate a new random point and start again. I have included the important code below. Apologies for the length (lots of comments and blank lines for readability).

! Set inital counter for validated points
k = 1

! Do for all randomly generated points
DO i=1,100000

  ! Create a random point with coordinates x, y and z.
  CALL RANDOM_NUMBER(rand)

  ! Normalise the random coordinates to the bounding box.
  rand(1:3) = (rand(1:3) * (cord(1:3) - cord(4:6))) + cord(4:6)

  ! Set the initial counter for the vertices
  j = 1

  ! Set the number of intersections with the random point and the triangle
  no_insect = 0 

  ! Do for all triangles in STL
  DO num = 1, notri

      ! Get the maximum "x" value for the current triangle
      maxtempx = MAXVAL(vertices(1,j:j+2))

      ! Get the minimum "x" value for the current triangle
      mintempx = MINVAL(vertices(1,j:j+2))

      ! If the random point is within the bounds continue
      IF (rand(1)>=mintempx .AND. rand(1)<=maxtempx) THEN

        ! Get the maximum "y" value for the current triangle
        maxtempy = MAXVAL(vertices(2,j:j+2))

        ! Get the minimum "y" value for the current triangle
        mintempy = MINVAL(vertices(2,j:j+2))    

        ! If the random point is within the bounds continue     
        IF (rand(2)>=mintempy .AND. rand(2)<=maxtempy) THEN

            ! Find the "z" value of the point as projected onto the triangle plane
            tempz = ((norm(1,num)*(rand(1)-vertices(1,j))) &
                +(norm(2,num)*(rand(2)-vertices(2,j))) &
                - (norm(3,num)*vertices(3,j))) / (-norm(3,num))

            ! If the "z" value of the randomly generated point goes vertically up
            ! through the projected point then increase the number of plane intersections
            ! by one. (Ray casting vertically up, could go down also).

            IF (rand(3)<= tempz) THEN
                no_insect = no_insect + 1   
            END IF  

        END IF
    END IF

    ! Go to the start of the next triangle
    j = j + 3
  END DO  

  ! If there is an odd number of triangle intersections not 
  ! including 0 intersections then store the point

  IF (MOD(no_insect,2)/=0 .AND. no_insect/=0) THEN
    point(k,1:3) = rand(1:3)
    WRITE(1,"(1X, 3(F10.8, 3X))") point(k,1), point(k,2), point(k,3)
    k = k + 1
  END IF

END DO 

My results have been complete rubbish (see images)enter image description here Image 1 - Test STL file (ship taken from here). Part of the program (code not shown) reads in binary STL files and stores the surface normals of each triangle and the vertices which make up this triangle. I then wrote the vertices to a text file and call GNUPLOT to connect the vertices of each triangle as show above. This plot is just a test to ensure that the STL files are being read and stored correctly. It does not use the surface normals. enter image description here. Image 2 - This is a plot of the candidate points which were accepted as being inside the STL volume. (Stored in the final if loop shown in code above). These accepted points are then later written to a text file and plotted with GNUPLOT (NOT SHOWN). Had the algorithm worked this plot should be a point cloud of the triangulated mesh shown above. (It also plots the 8 bounding box coordinates to ensure that the random particles are generated in the correct range)

I appreciate that this does not take into account for points generated on vertices or rays which run parallel and intersect with edges. I just wanted to start with a rough code. Could you please advise if there is a problem with my methodology or code? Let me know if the question is too broad and I will delete it and try to be more specific.

1QuickQuestion
  • 417
  • 6
  • 16
  • Could you comment the images. What do they show> Are both the results of your code? – Vladimir F Героям слава Sep 18 '14 at 11:00
  • @VladimirF , I have added some comments to the above images. In short - Image 1 is a generic triangulated mesh which has been read in by the program and then plotted to ensure correct storage. Image 2 is intended to be a plot of the same volume populated with points (i.e the random points which have been tested using the code above and found to be inside the triangulated mesh). – 1QuickQuestion Sep 18 '14 at 11:18
  • 1
    So what you need is to check if a point is inside the non-convex polyhedron? I would use a library for that. I use CGAL to read an OFF file, but it does not return inside or not directly, I then have to count the number of intersections with a ray. What about http://gts.sourceforge.net/ ? – Vladimir F Героям слава Sep 18 '14 at 11:31
  • @VladimirF Yes, I am trying to check if a point is inside a non-convex three dimensional polyhedron. I am pretty new to coding and Fortran (have never used a library before) and I don't know any C++. I'll have a look through the GTS library and see if there is anything I can use. – 1QuickQuestion Sep 18 '14 at 11:47
  • But still feel free to ask for the algorithm here, but be aware it is not that easy. – Vladimir F Героям слава Sep 18 '14 at 12:14
  • @VladimirF I thought it would have been much simplified since the polyhedron is made up of triangles. I can easily test if a point is inside any of these triangles in plan view. The part of my code which is broken is the "z" coordinate test which is effectively a vertical ray cast. For some reason counting the number of triangles the random point is above (or below) in the x-y plane and then checking if this is odd or even is not correctly determining if the point is inside or outside the overall polyhedron. This is the part I need to fix. – 1QuickQuestion Sep 18 '14 at 13:08

1 Answers1

1

I realized my code could be handy for others. I placed it at https://github.com/LadaF/Fortran---CGAL-polyhedra under the GNU GPL v3 license.

You can query, whether a point is inside a point or not. First, you read the file by cgal_polyhedron_read. You must store the type(c_ptr) :: ptree that is crated and use it in your next calls.

The function cgal_polyhedron_inside returns whether a point is inside a polyhedron, or not. It requires one reference point, which must be known to be outside.

When you are finished call cgal_polyhedron_finalize.

You must have the file as a purely tridiagonal manifold mesh in an OFF file. You can create it from the STL file using http://www.cs.princeton.edu/~min/meshconv/ .

  • Could you please comment on how you define the "ptree" type in the main program which uses the call cgal_polyhedron_read(ptree, fname)? Where ptree is a type output. – 1QuickQuestion Sep 18 '14 at 15:37
  • 1
    See the `test.f90`, compile it using `make_test_gcc.sh`. Tested with gcc 4.8 and CGAL 4.1. – Vladimir F Героям слава Sep 18 '14 at 16:21
  • I gave up trying to get CGAL to work on Windows 7 using MinGW and gfortran. Compiling on Ubuntu gave the error "undefined reference to symbol '_zn5boost6system15system_categoryev'". This was resolved by adding -lboost_system to the end of the makefile as highlighted [here](http://stackoverflow.com/questions/20057127/freeling-error-with-python-and-java-api-undefined-symbol-zn5boost6system15sys) – 1QuickQuestion Sep 22 '14 at 12:59