// comments relate to Sugihara-Iri paper // this is roughly "algorithm A" from the paper, page 15/50 void VoronoiDiagram::addVertexSite(const Point& p) { // only add vertices within the far_radius circle assert( p.xyNorm() < far_radius ); // 1) find the closest face and associated generator gen_count++; HEFace closest_face = fgrid->grid_find_closest_face( p ); // 2) among the vertices on the closest_face // find the seed, which has the lowest detH HEVertex v_seed = findSeedVertex(closest_face, p); g[v_seed].type = IN; VertexVector v0; v0.push_back(v_seed); // 3) augment the vertex set to be deleted // vertex set must remain a tree // must not delete cycles augment_vertex_set_M(v0, p); // 4) add new vertices on all edges that connect v0 IN edges to OUT edges add_new_voronoi_vertices(v0, p); // 5) generate new edges that form a loop around the region to be deleted HEFace newface = split_faces(p); // 6) fix the next-pointers in newface, then remove set v0 remove_vertex_set(v0, newface); // 7) reset IN/OUT/UNDECIDED for verts, and INCIDENT/NONINCIDENT for faces reset_labels(); assert( vdChecker.isValid(this) ); }
union tree * evaluate(union tree *tr, const struct rt_tess_tol *ttol, const struct bn_tol *tol) { RT_CK_TREE(tr); switch (tr->tr_op) { case OP_NOP: return tr; case OP_NMG_TESS: /* ugh, keep it as nmg_tess and just shove the rt_bot_internal ptr * in as nmgregion. :/ Also, only doing the first shell of the first * model. Primitives should only provide a single shell, right? */ { struct rt_db_internal ip; struct nmgregion *nmgr = BU_LIST_FIRST(nmgregion, &tr->tr_d.td_r->m_p->r_hd); /* the bot temporary format may be unnecessary if we can walk * the nmg shells and generate soup from them directly. */ struct rt_bot_internal *bot = nmg_bot(BU_LIST_FIRST(shell, &nmgr->s_hd), tol); /* causes a crash. nmg_kr(nmgr); free(nmgr); */ tr->tr_d.td_r->m_p = (struct model *)bot2soup(bot, tol); SOUP_CKMAG((struct soup_s *)tr->tr_d.td_r->m_p); /* fill in a db_internal with our new bot so we can free it */ RT_DB_INTERNAL_INIT(&ip); ip.idb_major_type = DB5_MAJORTYPE_BRLCAD; ip.idb_minor_type = ID_BOT; ip.idb_meth = &OBJ[ID_BOT]; ip.idb_ptr = bot; ip.idb_meth->ft_ifree(&ip); } return tr; case OP_UNION: case OP_INTERSECT: case OP_SUBTRACT: RT_CK_TREE(tr->tr_b.tb_left); RT_CK_TREE(tr->tr_b.tb_right); tr->tr_b.tb_left = evaluate(tr->tr_b.tb_left, ttol, tol); tr->tr_b.tb_right = evaluate(tr->tr_b.tb_right, ttol, tol); RT_CK_TREE(tr->tr_b.tb_left); RT_CK_TREE(tr->tr_b.tb_right); SOUP_CKMAG(tr->tr_b.tb_left->tr_d.td_r->m_p); SOUP_CKMAG(tr->tr_b.tb_right->tr_d.td_r->m_p); split_faces(tr->tr_b.tb_left, tr->tr_b.tb_right, tol); RT_CK_TREE(tr->tr_b.tb_left); RT_CK_TREE(tr->tr_b.tb_right); SOUP_CKMAG(tr->tr_b.tb_left->tr_d.td_r->m_p); SOUP_CKMAG(tr->tr_b.tb_right->tr_d.td_r->m_p); break; default: bu_bomb("bottess evaluate(): bad op (first pass)\n"); } switch (tr->tr_op) { case OP_UNION: return compose(tr->tr_b.tb_left, tr->tr_b.tb_right, OUTSIDE, SAME, OUTSIDE); case OP_INTERSECT: return compose(tr->tr_b.tb_left, tr->tr_b.tb_right, INSIDE, SAME, INSIDE); case OP_SUBTRACT: return invert(compose(tr->tr_b.tb_left, invert(tr->tr_b.tb_right), OUTSIDE, OPPOSITE, INSIDE)); default: bu_bomb("bottess evaluate(): bad op (second pass, CSG)\n"); } bu_bomb("Got somewhere I shouldn't have\n"); return NULL; }