2013-06-23 18:18:38 +02:00
/* ADMesh -- process triangulated solid meshes
2014-09-23 14:34:37 +02:00
* Copyright (C) 1995, 1996 Anthony D. Martin <amartin@engr.csulb.edu>
* Copyright (C) 2013, 2014 several contributors, see AUTHORS
2013-06-23 18:18:38 +02:00
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
2014-09-23 14:34:37 +02:00
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
2013-06-23 18:18:38 +02:00
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
2014-09-23 14:34:37 +02:00
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
2013-06-23 18:18:38 +02:00
*
2014-09-23 14:34:37 +02:00
* Questions, comments, suggestions, etc to
* https://github.com/admesh/admesh/issues
2013-06-23 18:18:38 +02:00
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "stl.h"
2017-08-03 17:31:31 +02:00
static int stl_check_normal_vector ( stl_file * stl , int facet_num , int normal_fix_flag );
2013-06-23 18:18:38 +02:00
2019-06-10 17:17:36 +02:00
static void reverse_facet ( stl_file * stl , int facet_num )
{
stl -> stats . facets_reversed += 1 ;
2013-06-23 18:18:38 +02:00
2019-06-10 17:17:36 +02:00
int neighbor [ 3 ] = { stl -> neighbors_start [ facet_num ]. neighbor [ 0 ], stl -> neighbors_start [ facet_num ]. neighbor [ 1 ], stl -> neighbors_start [ facet_num ]. neighbor [ 2 ] };
int vnot [ 3 ] = { stl -> neighbors_start [ facet_num ]. which_vertex_not [ 0 ], stl -> neighbors_start [ facet_num ]. which_vertex_not [ 1 ], stl -> neighbors_start [ facet_num ]. which_vertex_not [ 2 ] };
2014-09-23 14:34:37 +02:00
2019-06-10 17:17:36 +02:00
// reverse the facet
stl_vertex tmp_vertex = stl -> facet_start [ facet_num ]. vertex [ 0 ];
stl -> facet_start [ facet_num ]. vertex [ 0 ] =
stl -> facet_start [ facet_num ]. vertex [ 1 ];
stl -> facet_start [ facet_num ]. vertex [ 1 ] = tmp_vertex ;
2013-06-23 18:18:38 +02:00
2019-06-10 17:17:36 +02:00
// fix the vnots of the neighboring facets
if ( neighbor [ 0 ] != - 1 )
stl -> neighbors_start [ neighbor [ 0 ]]. which_vertex_not [( vnot [ 0 ] + 1 ) % 3 ] = ( stl -> neighbors_start [ neighbor [ 0 ]]. which_vertex_not [( vnot [ 0 ] + 1 ) % 3 ] + 3 ) % 6 ;
if ( neighbor [ 1 ] != - 1 )
stl -> neighbors_start [ neighbor [ 1 ]]. which_vertex_not [( vnot [ 1 ] + 1 ) % 3 ] = ( stl -> neighbors_start [ neighbor [ 1 ]]. which_vertex_not [( vnot [ 1 ] + 1 ) % 3 ] + 4 ) % 6 ;
if ( neighbor [ 2 ] != - 1 )
stl -> neighbors_start [ neighbor [ 2 ]]. which_vertex_not [( vnot [ 2 ] + 1 ) % 3 ] = ( stl -> neighbors_start [ neighbor [ 2 ]]. which_vertex_not [( vnot [ 2 ] + 1 ) % 3 ] + 2 ) % 6 ;
2013-06-23 18:18:38 +02:00
2019-06-10 17:17:36 +02:00
// swap the neighbors of the facet that is being reversed
stl -> neighbors_start [ facet_num ]. neighbor [ 1 ] = neighbor [ 2 ];
stl -> neighbors_start [ facet_num ]. neighbor [ 2 ] = neighbor [ 1 ];
2013-06-23 18:18:38 +02:00
2019-06-10 17:17:36 +02:00
// swap the vnots of the facet that is being reversed
stl -> neighbors_start [ facet_num ]. which_vertex_not [ 1 ] = vnot [ 2 ];
stl -> neighbors_start [ facet_num ]. which_vertex_not [ 2 ] = vnot [ 1 ];
2013-06-23 18:18:38 +02:00
2019-06-10 17:17:36 +02:00
// reverse the values of the vnots of the facet that is being reversed
stl -> neighbors_start [ facet_num ]. which_vertex_not [ 0 ] = ( stl -> neighbors_start [ facet_num ]. which_vertex_not [ 0 ] + 3 ) % 6 ;
stl -> neighbors_start [ facet_num ]. which_vertex_not [ 1 ] = ( stl -> neighbors_start [ facet_num ]. which_vertex_not [ 1 ] + 3 ) % 6 ;
stl -> neighbors_start [ facet_num ]. which_vertex_not [ 2 ] = ( stl -> neighbors_start [ facet_num ]. which_vertex_not [ 2 ] + 3 ) % 6 ;
2013-06-23 18:18:38 +02:00
}
2019-06-10 17:17:36 +02:00
void stl_fix_normal_directions ( stl_file * stl )
{
2013-06-23 18:18:38 +02:00
/* int edge_num;*/
/* int vnot;*/
int checked = 0 ;
int facet_num ;
/* int next_facet;*/
int i ;
int j ;
2014-09-23 14:34:37 +02:00
struct stl_normal {
2013-06-23 18:18:38 +02:00
int facet_num ;
struct stl_normal * next ;
};
struct stl_normal * head ;
struct stl_normal * tail ;
struct stl_normal * newn ;
struct stl_normal * temp ;
2014-09-23 14:34:37 +02:00
2018-02-15 16:10:47 +01:00
int reversed_count = 0 ;
int id ;
int force_exit = 0 ;
2019-05-14 19:46:01 +02:00
// this may happen for malformed models, see: https://github.com/prusa3d/PrusaSlicer/issues/2209
2019-05-07 15:09:15 +02:00
if ( stl -> stats . number_of_facets == 0 ) return ;
2013-06-23 18:18:38 +02:00
/* Initialize linked list. */
2019-06-04 22:06:42 +02:00
head = new stl_normal ;
tail = new stl_normal ;
2013-06-23 18:18:38 +02:00
head -> next = tail ;
tail -> next = tail ;
/* Initialize list that keeps track of already fixed facets. */
2019-06-04 22:06:42 +02:00
std :: vector < char > norm_sw ( stl -> stats . number_of_facets , 0 );
2018-02-15 16:10:47 +01:00
/* Initialize list that keeps track of reversed facets. */
2019-06-04 22:06:42 +02:00
std :: vector < int > reversed_ids ( stl -> stats . number_of_facets , 0 );
2013-06-23 18:18:38 +02:00
facet_num = 0 ;
2014-09-23 14:34:37 +02:00
/* If normal vector is not within tolerance and backwards:
Arbitrarily starts at face 0. If this one is wrong, we're screwed. Thankfully, the chances
of it being wrong randomly are low if most of the triangles are right: */
2018-02-15 16:10:47 +01:00
if ( stl_check_normal_vector ( stl , 0 , 0 ) == 2 ) {
2019-06-10 17:17:36 +02:00
reverse_facet ( stl , 0 );
2018-02-15 16:10:47 +01:00
reversed_ids [ reversed_count ++ ] = 0 ;
}
2013-07-31 00:01:53 +02:00
2014-09-23 14:34:37 +02:00
/* Say that we've fixed this facet: */
2013-06-23 18:18:38 +02:00
norm_sw [ facet_num ] = 1 ;
checked ++ ;
2014-09-23 14:34:37 +02:00
for (;;) {
/* Add neighbors_to_list.
Add unconnected neighbors to the list:a */
for ( j = 0 ; j < 3 ; j ++ ) {
/* Reverse the neighboring facets if necessary. */
if ( stl -> neighbors_start [ facet_num ]. which_vertex_not [ j ] > 2 ) {
/* If the facet has a neighbor that is -1, it means that edge isn't shared by another facet */
2018-02-15 16:10:47 +01:00
if ( stl -> neighbors_start [ facet_num ]. neighbor [ j ] != - 1 ) {
if ( norm_sw [ stl -> neighbors_start [ facet_num ]. neighbor [ j ]] == 1 ) {
/* trying to modify a facet already marked as fixed, revert all changes made until now and exit (fixes: #716, #574, #413, #269, #262, #259, #230, #228, #206) */
for ( id = reversed_count - 1 ; id >= 0 ; -- id ) {
2019-06-10 17:17:36 +02:00
reverse_facet ( stl , reversed_ids [ id ]);
2018-02-15 16:10:47 +01:00
}
force_exit = 1 ;
break ;
} else {
2019-06-10 17:17:36 +02:00
reverse_facet ( stl , stl -> neighbors_start [ facet_num ]. neighbor [ j ]);
2018-02-15 16:10:47 +01:00
reversed_ids [ reversed_count ++ ] = stl -> neighbors_start [ facet_num ]. neighbor [ j ];
}
}
2014-09-23 14:34:37 +02:00
}
/* If this edge of the facet is connected: */
if ( stl -> neighbors_start [ facet_num ]. neighbor [ j ] != - 1 ) {
/* If we haven't fixed this facet yet, add it to the list: */
if ( norm_sw [ stl -> neighbors_start [ facet_num ]. neighbor [ j ]] != 1 ) {
/* Add node to beginning of list. */
2019-06-04 22:06:42 +02:00
newn = new stl_normal ;
2014-09-23 14:34:37 +02:00
newn -> facet_num = stl -> neighbors_start [ facet_num ]. neighbor [ j ];
newn -> next = head -> next ;
head -> next = newn ;
}
}
2013-06-23 18:18:38 +02:00
}
2018-02-15 16:10:47 +01:00
/* an error occourred, quit the for loop and exit */
if ( force_exit ) break ;
2014-09-23 14:34:37 +02:00
/* Get next facet to fix from top of list. */
if ( head -> next != tail ) {
facet_num = head -> next -> facet_num ;
if ( norm_sw [ facet_num ] != 1 ) { /* If facet is in list mutiple times */
norm_sw [ facet_num ] = 1 ; /* Record this one as being fixed. */
checked ++ ;
}
temp = head -> next ; /* Delete this facet from the list. */
head -> next = head -> next -> next ;
2019-06-04 22:06:42 +02:00
delete temp ;
2014-09-23 14:34:37 +02:00
} else { /* if we ran out of facets to fix: */
/* All of the facets in this part have been fixed. */
stl -> stats . number_of_parts += 1 ;
if ( checked >= stl -> stats . number_of_facets ) {
/* All of the facets have been checked. Bail out. */
break ;
} else {
/* There is another part here. Find it and continue. */
for ( i = 0 ; i < stl -> stats . number_of_facets ; i ++ ) {
if ( norm_sw [ i ] == 0 ) {
/* This is the first facet of the next part. */
facet_num = i ;
if ( stl_check_normal_vector ( stl , i , 0 ) == 2 ) {
2019-06-10 17:17:36 +02:00
reverse_facet ( stl , i );
2018-02-15 16:10:47 +01:00
reversed_ids [ reversed_count ++ ] = i ;
2014-09-23 14:34:37 +02:00
}
norm_sw [ facet_num ] = 1 ;
checked ++ ;
break ;
}
}
}
}
}
2019-06-04 22:06:42 +02:00
delete head ;
delete tail ;
2013-06-23 18:18:38 +02:00
}
2019-06-10 17:17:36 +02:00
static int stl_check_normal_vector ( stl_file * stl , int facet_num , int normal_fix_flag )
{
2013-06-23 18:18:38 +02:00
/* Returns 0 if the normal is within tolerance */
/* Returns 1 if the normal is not within tolerance, but direction is OK */
/* Returns 2 if the normal is not within tolerance and backwards */
/* Returns 4 if the status is unknown. */
2014-09-23 14:34:37 +02:00
2013-06-23 18:18:38 +02:00
stl_facet * facet ;
facet = & stl -> facet_start [ facet_num ];
2018-08-22 15:03:35 +02:00
stl_normal normal ;
2013-06-23 18:18:38 +02:00
stl_calculate_normal ( normal , facet );
stl_normalize_vector ( normal );
2018-08-22 15:03:35 +02:00
stl_normal normal_dif = ( normal - facet -> normal ). cwiseAbs ();
2014-09-23 14:34:37 +02:00
2018-08-22 15:03:35 +02:00
const float eps = 0.001f ;
if ( normal_dif ( 0 ) < eps && normal_dif ( 1 ) < eps && normal_dif ( 2 ) < eps ) {
2014-09-23 14:34:37 +02:00
/* It is not really necessary to change the values here */
/* but just for consistency, I will. */
2018-08-22 15:03:35 +02:00
facet -> normal = normal ;
2014-09-23 14:34:37 +02:00
return 0 ;
}
2018-08-22 15:03:35 +02:00
stl_normal test_norm = facet -> normal ;
2013-06-23 18:18:38 +02:00
stl_normalize_vector ( test_norm );
2018-08-22 15:03:35 +02:00
normal_dif = ( normal - test_norm ). cwiseAbs ();
if ( normal_dif ( 0 ) < eps && normal_dif ( 1 ) < eps && normal_dif ( 2 ) < eps ) {
2014-09-23 14:34:37 +02:00
if ( normal_fix_flag ) {
2018-08-22 15:03:35 +02:00
facet -> normal = normal ;
2013-06-23 18:18:38 +02:00
stl -> stats . normals_fixed += 1 ;
2014-09-23 14:34:37 +02:00
}
return 1 ;
}
2018-08-22 15:03:35 +02:00
test_norm *= - 1.f ;
normal_dif = ( normal - test_norm ). cwiseAbs ();
if ( normal_dif ( 0 ) < eps && normal_dif ( 1 ) < eps && normal_dif ( 2 ) < eps ) {
// Facet is backwards.
2014-09-23 14:34:37 +02:00
if ( normal_fix_flag ) {
2018-08-22 15:03:35 +02:00
facet -> normal = normal ;
2014-09-23 14:34:37 +02:00
stl -> stats . normals_fixed += 1 ;
}
return 2 ;
}
if ( normal_fix_flag ) {
2018-08-22 15:03:35 +02:00
facet -> normal = normal ;
2014-09-23 14:34:37 +02:00
stl -> stats . normals_fixed += 1 ;
}
2013-06-23 18:18:38 +02:00
return 4 ;
}
2019-06-10 17:17:36 +02:00
void stl_fix_normal_values ( stl_file * stl )
{
for ( uint32_t i = 0 ; i < stl -> stats . number_of_facets ; ++ i )
stl_check_normal_vector ( stl , i , 1 );
2013-06-23 18:18:38 +02:00
}
2018-08-22 15:03:35 +02:00
void stl_reverse_all_facets ( stl_file * stl )
{
2019-06-10 17:17:36 +02:00
stl_normal normal ;
for ( uint32_t i = 0 ; i < stl -> stats . number_of_facets ; ++ i ) {
reverse_facet ( stl , i );
stl_calculate_normal ( normal , & stl -> facet_start [ i ]);
stl_normalize_vector ( normal );
stl -> facet_start [ i ]. normal = normal ;
}
2013-06-23 18:18:38 +02:00
}