bool ofxGtsSurface::prepareBoolean(ofxGtsSurface &source) { if(!loaded || !source.loaded) { ofLog(OF_LOG_NOTICE, "Gts surface not loaded, could not perform boolean operation"); return false; } if(!gts_surface_is_orientable(surface)) { ofLog(OF_LOG_ERROR, "Gts surface is not an orientable manifold, could not perform boolean operation"); return false; } if(gts_surface_is_self_intersecting(surface)) { ofLog(OF_LOG_ERROR, "Gts surface self-intersects, could not perform boolean operation"); return false; } if(!gts_surface_is_orientable(source.surface)) { ofLog(OF_LOG_ERROR, "Gts surface is not an orientable manifold, could not perform boolean operation"); return false; } if(gts_surface_is_self_intersecting(source.surface)) { ofLog(OF_LOG_ERROR, "Gts surface self-intersects, could not perform boolean operation"); return false; } GSList *bboxes = NULL; gts_surface_foreach_face(surface, (GtsFunc) prepend_triangle_bbox, &bboxes); /* build bounding box tree for first surface */ tree1 = gts_bb_tree_new(bboxes); /* free list of bboxes */ g_slist_free (bboxes); is_open1 = gts_surface_volume(surface) < 0. ? TRUE : FALSE; /* build bounding boxes for second surface */ bboxes = NULL; gts_surface_foreach_face(source.surface, (GtsFunc) prepend_triangle_bbox, &bboxes); /* build bounding box tree for second surface */ tree2 = gts_bb_tree_new(bboxes); /* free list of bboxes */ g_slist_free (bboxes); is_open2 = gts_surface_volume (source.surface) < 0. ? TRUE : FALSE; si = gts_surface_inter_new (gts_surface_inter_class (), surface, source.surface, tree1, tree2, is_open1, is_open2); gboolean closed = TRUE; gts_surface_inter_check(si, &closed); boolPerformed = true; if(!closed) { ofLog(OF_LOG_NOTICE, "Gts surface is not closed, could not perform boolean operation"); return false; } return true; }
/** * gts_bb_tree_surface: * @s: a #GtsSurface. * * Returns: a new hierarchy of bounding boxes bounding the faces of @s. */ GNode * gts_bb_tree_surface (GtsSurface * s) { GSList * bboxes = NULL; GNode * tree; g_return_val_if_fail (s != NULL, NULL); gts_surface_foreach_face (s, (GtsFunc) prepend_triangle_bbox, &bboxes); tree = gts_bb_tree_new (bboxes); g_slist_free (bboxes); return tree; }
/** * gts_bb_tree_new: * @bboxes: a list of #GtsBBox. * * Builds a new hierarchy of bounding boxes for @bboxes. At each * level, the GNode->data field contains a #GtsBBox bounding box of * all the children. The tree is binary and is built by repeatedly * cutting in two approximately equal halves the bounding boxes at * each level until a leaf node (i.e. a bounding box given in @bboxes) * is reached. In order to minimize the depth of the tree, the cutting * direction is always chosen as perpendicular to the longest * dimension of the bounding box. * * Returns: a new hierarchy of bounding boxes. */ GNode * gts_bb_tree_new (GSList * bboxes) { GSList * i, * positive = NULL, * negative = NULL; GNode * node; GtsBBox * bbox; guint dir, np = 0, nn = 0; gdouble * p1, * p2; gdouble cut; g_return_val_if_fail (bboxes != NULL, NULL); if (bboxes->next == NULL) /* leaf node */ return g_node_new (bboxes->data); bbox = gts_bbox_bboxes (gts_bbox_class (), bboxes); node = g_node_new (bbox); if (bbox->x2 - bbox->x1 > bbox->y2 - bbox->y1) { if (bbox->z2 - bbox->z1 > bbox->x2 - bbox->x1) dir = 2; else dir = 0; } else if (bbox->z2 - bbox->z1 > bbox->y2 - bbox->y1) dir = 2; else dir = 1; p1 = (gdouble *) &bbox->x1; p2 = (gdouble *) &bbox->x2; cut = (p1[dir] + p2[dir])/2.; i = bboxes; while (i) { bbox = i->data; p1 = (gdouble *) &bbox->x1; p2 = (gdouble *) &bbox->x2; if ((p1[dir] + p2[dir])/2. > cut) { positive = g_slist_prepend (positive, bbox); np++; } else { negative = g_slist_prepend (negative, bbox); nn++; } i = i->next; } if (!positive) { GSList * last = g_slist_nth (negative, (nn - 1)/2); positive = last->next; last->next = NULL; } else if (!negative) { GSList * last = g_slist_nth (positive, (np - 1)/2); negative = last->next; last->next = NULL; } g_node_prepend (node, gts_bb_tree_new (positive)); g_slist_free (positive); g_node_prepend (node, gts_bb_tree_new (negative)); g_slist_free (negative); return node; }