/* csg.c * Giram - A GPLed Modelling Program. * Copyright (C) 1999-2002 DindinX * * 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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * 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. * * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include "giram.h" #include "trimesh.h" #include "object.h" #include "marching_cube.h" #include "csg.h" static void giram_csg_build_triangle_mesh(ObjectStruct *csg); static gboolean giram_csg_inside(ObjectStruct *csg, double x, double y, double z); static gboolean giram_csg_is_intersection(ObjectStruct *csg, Vector org, Vector dir); static gboolean giram_csg_click_in_XY(ObjectStruct *csg, double x, double y); static gboolean giram_csg_click_in_XZ(ObjectStruct *csg, double x, double z); static gboolean giram_csg_click_in_ZY(ObjectStruct *csg, double z, double y); static gboolean giram_csg_find_intersection_segment(ObjectStruct *csg, Vector in_point, Vector out_point, Vector inter_point, Vector inter_norm); /***************************************************************************** * giram_csg_build_triangle_mesh ******************************************************************************/ static void giram_csg_build_triangle_mesh(ObjectStruct *CSG) { CSGStruct *CCSG = (CSGStruct *)CSG; ObjectStruct *TmpObject; double sizex, sizey, sizez; TriangleListStruct *TmpTri; int DetailLevel; int i, j, k; Vector Cube[8]; Vector MaxExt, MinExt; GSList *tmp_list; if (CSG->FirstTriangle) DestroyObjectTriangleMesh(CSG); MinExt[0] = MinExt[1] = MinExt[2] = 1e100; MaxExt[0] = MaxExt[1] = MaxExt[2] = -1e100; for (tmp_list = CCSG->all_objects; tmp_list; tmp_list = g_slist_next(tmp_list)) { TmpObject = tmp_list->data; TmpObject->parent = NULL; /* FIXME: bad hack! */ giram_object_build_triangle_mesh(TmpObject); TmpObject->parent = CSG; /* Find the extents */ for (TmpTri = TmpObject->FirstTriangle ; TmpTri ; TmpTri=TmpTri->Next) { if (MinExt[0] > TmpTri->P1[0]) MinExt[0] = TmpTri->P1[0]; if (MinExt[0] > TmpTri->P2[0]) MinExt[0] = TmpTri->P2[0]; if (MinExt[0] > TmpTri->P3[0]) MinExt[0] = TmpTri->P3[0]; if (MinExt[1] > TmpTri->P1[1]) MinExt[1] = TmpTri->P1[1]; if (MinExt[1] > TmpTri->P2[1]) MinExt[1] = TmpTri->P2[1]; if (MinExt[1] > TmpTri->P3[1]) MinExt[1] = TmpTri->P3[1]; if (MinExt[2] > TmpTri->P1[2]) MinExt[2] = TmpTri->P1[2]; if (MinExt[2] > TmpTri->P2[2]) MinExt[2] = TmpTri->P2[2]; if (MinExt[2] > TmpTri->P3[2]) MinExt[2] = TmpTri->P3[2]; if (MaxExt[0] < TmpTri->P1[0]) MaxExt[0] = TmpTri->P1[0]; if (MaxExt[0] < TmpTri->P2[0]) MaxExt[0] = TmpTri->P2[0]; if (MaxExt[0] < TmpTri->P3[0]) MaxExt[0] = TmpTri->P3[0]; if (MaxExt[1] < TmpTri->P1[1]) MaxExt[1] = TmpTri->P1[1]; if (MaxExt[1] < TmpTri->P2[1]) MaxExt[1] = TmpTri->P2[1]; if (MaxExt[1] < TmpTri->P3[1]) MaxExt[1] = TmpTri->P3[1]; if (MaxExt[2] < TmpTri->P1[2]) MaxExt[2] = TmpTri->P1[2]; if (MaxExt[2] < TmpTri->P2[2]) MaxExt[2] = TmpTri->P2[2]; if (MaxExt[2] < TmpTri->P3[2]) MaxExt[2] = TmpTri->P3[2]; } } DetailLevel = 16; /* XXX should be settable */ sizex = (MaxExt[0] - MinExt[0]) / DetailLevel; sizey = (MaxExt[1] - MinExt[1]) / DetailLevel; sizez = (MaxExt[2] - MinExt[2]) / DetailLevel; /* Compute triangles for each cube of the zone */ for (i=0 ; iTrans) { MInverseEvaluatePoint(Vect, CSG->Trans, Vect); } switch (CCSG->Type) { case CSG_DIFFERENCE: if (!giram_object_inside((ObjectStruct*)(CCSG->all_objects->data), Vect[0], Vect[1], Vect[2])) return CSG->Inverse; for (tmp_list = CCSG->all_objects->next ; tmp_list ; tmp_list = g_slist_next(tmp_list)) { if (giram_object_inside((ObjectStruct*)(tmp_list->data), Vect[0], Vect[1], Vect[2])) return CSG->Inverse; } return !(CSG->Inverse); case CSG_INTERSECTION: for (tmp_list = CCSG->all_objects ; tmp_list ; tmp_list = g_slist_next(tmp_list)) { if (!giram_object_inside((ObjectStruct*)(tmp_list->data), Vect[0], Vect[1], Vect[2])) return CSG->Inverse; } return !(CSG->Inverse); case CSG_MERGE: case CSG_UNION: for (tmp_list = CCSG->all_objects ; tmp_list ; tmp_list = g_slist_next(tmp_list)) { if (giram_object_inside((ObjectStruct*)(tmp_list->data), Vect[0], Vect[1], Vect[2])) return !(CSG->Inverse); } return CSG->Inverse; } return FALSE; } /***************************************************************************** * giram_csg_is_intersection ******************************************************************************/ static gboolean giram_csg_is_intersection(ObjectStruct *CSG, Vector Origin, Vector Direction) { /* XXX: clipped_by */ Vector Org, Dir; CSGStruct *CCSG = (CSGStruct *)CSG; int i; GSList *tmp_list; if (CSG->Trans) { MInverseEvaluatePoint(Org, CSG->Trans, Origin); MInverseEvaluateVector(Dir, CSG->Trans, Direction); } else { for (i=0 ; i<3 ; i++) { Org[i] = Origin[i]; Dir[i] = Direction[i]; } } switch (CCSG->Type) { case CSG_DIFFERENCE: if (!giram_object_is_intersection((ObjectStruct*)(CCSG->all_objects->data), Org, Dir)) return CSG->Inverse; for (tmp_list = CCSG->all_objects->next ; tmp_list ; tmp_list = g_slist_next(tmp_list)) { if (giram_object_is_intersection((ObjectStruct*)(tmp_list->data), Org, Dir)) return CSG->Inverse; } return !(CSG->Inverse); case CSG_INTERSECTION: for (tmp_list = CCSG->all_objects ; tmp_list ; tmp_list = g_slist_next(tmp_list)) { if (!giram_object_is_intersection((ObjectStruct*)(tmp_list->data), Org, Dir)) return CSG->Inverse; } return !(CSG->Inverse); case CSG_MERGE: case CSG_UNION: for (tmp_list = CCSG->all_objects ; tmp_list ; tmp_list = g_slist_next(tmp_list)) { if (giram_object_is_intersection((ObjectStruct*)(tmp_list->data), Org, Dir)) return !(CSG->Inverse); } return CSG->Inverse; } return FALSE; } /***************************************************************************** * giram_csg_click_in_XY ******************************************************************************/ static gboolean giram_csg_click_in_XY(ObjectStruct *CSG, double x, double y) { /* XXX: clipped_by */ CSGStruct *CCSG = (CSGStruct *)CSG; Vector Origin = {0.0, 0.0, 0.0, 0.0, 0.0}; Vector Direction = {0.0, 0.0, 1.0, 0.0, 0.0}; GSList *tmp_list; if (CSG->Trans) { Origin[0] = x; Origin[1] = y; return giram_csg_is_intersection(CSG, Origin, Direction); } else { switch (CCSG->Type) { case CSG_DIFFERENCE: if (!giram_object_click_in_XY((ObjectStruct*)(CCSG->all_objects->data), x, y)) return CSG->Inverse; for (tmp_list = CCSG->all_objects->next ; tmp_list ; tmp_list = g_slist_next(tmp_list)) if (giram_object_click_in_XY((ObjectStruct*)(tmp_list->data), x, y)) return CSG->Inverse; return !(CSG->Inverse); case CSG_INTERSECTION: for (tmp_list = CCSG->all_objects ; tmp_list ; tmp_list = g_slist_next(tmp_list)) if (!giram_object_click_in_XY((ObjectStruct*)(tmp_list->data), x, y)) return CSG->Inverse; return !(CSG->Inverse); case CSG_MERGE: case CSG_UNION: for (tmp_list = CCSG->all_objects ; tmp_list ; tmp_list = g_slist_next(tmp_list)) if (giram_object_click_in_XY((ObjectStruct*)(tmp_list->data), x, y)) return !(CSG->Inverse); return CSG->Inverse; } } return FALSE; } /***************************************************************************** * giram_csg_click_in_XZ ******************************************************************************/ static gboolean giram_csg_click_in_XZ(ObjectStruct *CSG, double x, double y) { /* XXX: clipped_by */ CSGStruct *CCSG = (CSGStruct *)CSG; Vector Origin = {0.0, 0.0, 0.0, 0.0, 0.0}; Vector Direction = {0.0, 1.0, 0.0, 0.0, 0.0}; GSList *tmp_list; if (CSG->Trans) { Origin[0] = x; Origin[2] = y; return giram_csg_is_intersection(CSG, Origin, Direction); } else { switch (CCSG->Type) { case CSG_DIFFERENCE: if (!giram_object_click_in_XZ((ObjectStruct*)(CCSG->all_objects->data), x, y)) return CSG->Inverse; for (tmp_list = CCSG->all_objects->next ; tmp_list ; tmp_list = g_slist_next(tmp_list)) if (giram_object_click_in_XZ((ObjectStruct*)(tmp_list->data), x, y)) return CSG->Inverse; return !(CSG->Inverse); case CSG_INTERSECTION: for (tmp_list = CCSG->all_objects ; tmp_list ; tmp_list = g_slist_next(tmp_list)) if (!giram_object_click_in_XZ((ObjectStruct*)(tmp_list->data), x, y)) return CSG->Inverse; return !(CSG->Inverse); case CSG_MERGE: case CSG_UNION: for (tmp_list = CCSG->all_objects ; tmp_list ; tmp_list = g_slist_next(tmp_list)) if (giram_object_click_in_XZ((ObjectStruct*)(tmp_list->data), x, y)) return !(CSG->Inverse); return CSG->Inverse; } } return FALSE; } /***************************************************************************** * giram_csg_click_in_ZY ******************************************************************************/ static gboolean giram_csg_click_in_ZY(ObjectStruct *CSG, double x, double y) { /* XXX: clipped_by */ CSGStruct *CCSG = (CSGStruct *)CSG; Vector Origin = {0.0, 0.0, 0.0, 0.0, 0.0}; Vector Direction = {1.0, 0.0, 0.0, 0.0, 0.0}; GSList *tmp_list; if (CSG->Trans) { Origin[2] = x; Origin[1] = y; return giram_csg_is_intersection(CSG, Origin, Direction); } else { switch (CCSG->Type) { case CSG_DIFFERENCE: if (!giram_object_click_in_ZY((ObjectStruct*)(CCSG->all_objects->data), x, y)) return CSG->Inverse; for (tmp_list = CCSG->all_objects->next ; tmp_list ; tmp_list = g_slist_next(tmp_list)) if (giram_object_click_in_ZY((ObjectStruct*)(tmp_list->data), x, y)) return CSG->Inverse; return !(CSG->Inverse); case CSG_INTERSECTION: for (tmp_list = CCSG->all_objects ; tmp_list ; tmp_list = g_slist_next(tmp_list)) if (!giram_object_click_in_ZY((ObjectStruct*)(tmp_list->data), x, y)) return CSG->Inverse; return !(CSG->Inverse); case CSG_MERGE: case CSG_UNION: for (tmp_list = CCSG->all_objects ; tmp_list ; tmp_list = g_slist_next(tmp_list)) if (giram_object_click_in_ZY((ObjectStruct*)(tmp_list->data), x, y)) return !(CSG->Inverse); return CSG->Inverse; } } return FALSE; } /***************************************************************************** * giram_csg_find_intersection_segment ******************************************************************************/ static gboolean giram_csg_find_intersection_segment(ObjectStruct *csg, Vector in_point, Vector out_point, Vector inter_point, Vector inter_norm) { CSGStruct *ccsg = (CSGStruct *)csg; GSList *tmp_list; // MidPoint(inter_point, in_point, out_point);return TRUE; /* FIXME */ switch (ccsg->Type) { case CSG_DIFFERENCE: MidPoint(inter_point, in_point, out_point); break; case CSG_INTERSECTION: /* MidPoint(inter_point, in_point, out_point); break;*/ case CSG_MERGE: case CSG_UNION: for (tmp_list = ccsg->all_objects ; tmp_list ; tmp_list = g_slist_next(tmp_list)) { if (giram_object_find_intersection_segment((ObjectStruct*)(tmp_list->data), in_point, out_point, inter_point, inter_norm)) return TRUE; } MidPoint(inter_point, in_point, out_point); break; } return TRUE; } /***************************************************************************** * giram_csg_new ******************************************************************************/ ObjectStruct *giram_csg_new(GiramCSGType type) { ObjectStruct *csg; CSGStruct *ccsg; static GiramObjectClass *csg_klass = NULL; if (csg_klass == NULL) { csg_klass = giram_object_class_new(); csg_klass->build_triangle_mesh = giram_csg_build_triangle_mesh; csg_klass->inside = giram_csg_inside; csg_klass->is_intersection = giram_csg_is_intersection; csg_klass->click_in_XY = giram_csg_click_in_XY; csg_klass->click_in_XZ = giram_csg_click_in_XZ; csg_klass->click_in_ZY = giram_csg_click_in_ZY; csg_klass->find_intersection_segment = giram_csg_find_intersection_segment; } ccsg = g_new(CSGStruct, 1); csg = (ObjectStruct *)ccsg; InitObject(csg); csg->Type = CSG_OBJECT; csg->klass = csg_klass; ccsg->Type = type; ccsg->all_objects = NULL; return csg; }