/** * Scan through all the edges of fu1 and fu2, ensuring that all * edges involving the same vertex pair are indeed shared. * This means worrying about merging ("meshing") all the faces in the * proper radial orientation around the edge. * XXX probably should return count; */ void nmg_mesh_faces(struct faceuse *fu1, struct faceuse *fu2, const struct bn_tol *tol) { int count = 0; NMG_CK_FACEUSE(fu1); NMG_CK_FACEUSE(fu2); BN_CK_TOL(tol); if (RTG.NMG_debug & DEBUG_MESH_EU && RTG.NMG_debug & DEBUG_PLOTEM) { nmg_pl_2fu("Before_mesh%d.plot3", fu1, fu2, 1); } if (RTG.NMG_debug & DEBUG_MESH_EU) bu_log("meshing self (fu1 %8p)\n", (void *)fu1); count += nmg_mesh_two_faces(fu1, fu1, tol); if (RTG.NMG_debug & DEBUG_MESH_EU) bu_log("meshing self (fu2 %8p)\n", (void *)fu2); count += nmg_mesh_two_faces(fu2, fu2, tol); if (RTG.NMG_debug & DEBUG_MESH_EU) bu_log("meshing to other (fu1:%8p fu2:%8p)\n", (void *)fu1, (void *)fu2); count += nmg_mesh_two_faces(fu1, fu2, tol); if (RTG.NMG_debug & DEBUG_MESH_EU && RTG.NMG_debug & DEBUG_PLOTEM) { nmg_pl_2fu("After_mesh%d.plot3", fu1, fu2, 1); } }
/** * Make sure that the lu and fu orientation flags are consistent with * the geometric arrangement of the vertices and the faceuse normal. */ void nmg_ck_lu_orientation(struct loopuse *lu, const struct bn_tol *tolp) { struct faceuse *fu; plane_t fu_peqn; plane_t lu_peqn; fastf_t dot; NMG_CK_LOOPUSE(lu); fu = lu->up.fu_p; /* parent had better be faceuse */ NMG_CK_FACEUSE(fu); NMG_GET_FU_PLANE(fu_peqn, fu); nmg_loop_plane_newell(lu, lu_peqn); dot = VDOT(fu_peqn, lu_peqn); if (NEAR_ZERO(dot, tolp->perp)) return; /* can't determine geometric orientation */ if (dot < 0.0) { bu_log("nmg_ck_lu_orientation() lu=%p, dot=%g, fu_orient=%s, lu_orient=%s\n", (void *)lu, dot, nmg_orientation(fu->orientation), nmg_orientation(lu->orientation) ); bu_bomb("nmg_ck_lu_orientation() loop orientation flags do not match geometry\n"); } }
extern "C" void rt_nmg_brep(ON_Brep **b, const struct rt_db_internal *ip, const struct bn_tol *tol) { struct model *m; struct nmgregion *r; struct shell *s; struct faceuse *fu; // Verify NMG RT_CK_DB_INTERNAL(ip); m = (struct model *)ip->idb_ptr; NMG_CK_MODEL(m); // Both NMG and brep structures re-use components between faces. In order to track // when the conversion routine has already handled an NMG element, use an array. long *brepi = static_cast<long*>(bu_malloc(m->maxindex * sizeof(long), "rt_nmg_brep: brepi[]")); for (int i = 0; i < m->maxindex; i++) brepi[i] = -INT_MAX; // Iterate over all faces in the NMG for (BU_LIST_FOR(r, nmgregion, &m->r_hd)) { for (BU_LIST_FOR(s, shell, &r->s_hd)) { for (BU_LIST_FOR(fu, faceuse, &s->fu_hd)) { NMG_CK_FACEUSE(fu); if (fu->orientation != OT_SAME) continue; if (nmg_brep_face(b, fu, tol, brepi)) return; } (*b)->SetTrimIsoFlags(); } } }
/** * The return is the number of edges meshed. */ int nmg_mesh_face_shell(struct faceuse *fu1, struct shell *s, const struct bn_tol *tol) { register struct faceuse *fu2; int count = 0; NMG_CK_FACEUSE(fu1); NMG_CK_SHELL(s); BN_CK_TOL(tol); count += nmg_mesh_two_faces(fu1, fu1, tol); for (BU_LIST_FOR(fu2, faceuse, &s->fu_hd)) { NMG_CK_FACEUSE(fu2); count += nmg_mesh_two_faces(fu2, fu2, tol); count += nmg_mesh_two_faces(fu1, fu2, tol); } /* XXX What about wire edges in the shell? */ return count; }
/** * Mesh every edge in shell 1 with every edge in shell 2. * The return is the number of edges meshed. * * Does not use nmg_mesh_face_shell() to keep face/self meshing * to the absolute minimum necessary. */ int nmg_mesh_shell_shell(struct shell *s1, struct shell *s2, const struct bn_tol *tol) { struct faceuse *fu1; struct faceuse *fu2; int count = 0; NMG_CK_SHELL(s1); NMG_CK_SHELL(s2); BN_CK_TOL(tol); nmg_region_v_unique(s1->r_p, tol); nmg_region_v_unique(s2->r_p, tol); /* First, mesh all faces of shell 2 with themselves */ for (BU_LIST_FOR(fu2, faceuse, &s2->fu_hd)) { NMG_CK_FACEUSE(fu2); count += nmg_mesh_two_faces(fu2, fu2, tol); } /* Visit every face in shell 1 */ for (BU_LIST_FOR(fu1, faceuse, &s1->fu_hd)) { NMG_CK_FACEUSE(fu1); /* First, mesh each face in shell 1 with itself */ count += nmg_mesh_two_faces(fu1, fu1, tol); /* Visit every face in shell 2 */ for (BU_LIST_FOR(fu2, faceuse, &s2->fu_hd)) { NMG_CK_FACEUSE(fu2); count += nmg_mesh_two_faces(fu1, fu2, tol); } } /* XXX What about wire edges in the shell? */ /* Visit every wire loop in shell 1 */ /* Visit every wire edge in shell 1 */ return count; }
static void Write_euclid_face(const struct loopuse *lu, const int facet_type, const int regionid, const int face_number) { struct faceuse *fu; struct edgeuse *eu; plane_t plane; int vertex_count = 0; NMG_CK_LOOPUSE(lu); if (verbose) bu_log("Write_euclid_face: lu=%p, facet_type=%d, regionid=%d, face_number=%d\n", (void *)lu, facet_type, regionid, face_number); if (BU_LIST_FIRST_MAGIC(&lu->down_hd) != NMG_EDGEUSE_MAGIC) return; if (*lu->up.magic_p != NMG_FACEUSE_MAGIC) return; for (BU_LIST_FOR(eu, edgeuse, &lu->down_hd)) vertex_count++; fprintf(fp_out, "%10d%3d 0. 1%5d", regionid, facet_type, vertex_count); vertex_count = 0; for (BU_LIST_FOR(eu, edgeuse, &lu->down_hd)) { struct vertex *v; int i; NMG_CK_EDGEUSE(eu); v = eu->vu_p->v_p; NMG_CK_VERTEX(v); /* fprintf(fp_out, "%10d%8f%8f%8f", ++vertex_count, V3ARGS(v->vg_p->coord)); */ vertex_count++; fprintf(fp_out, "%10d", vertex_count); for (i=X; i<=Z; i++) fastf_print(fp_out, 8, v->vg_p->coord[i]); } fu = lu->up.fu_p; NMG_CK_FACEUSE(fu); NMG_GET_FU_PLANE(plane, fu); fprintf(fp_out, "%10d%15.5f%15.5f%15.5f%15.5f", face_number, V4ARGS(plane)); }
/** * Intersect all the edges in fu1 that don't lie on any of the faces * of shell s2 with s2, i.e. "interior" edges, where the endpoints lie * on s2, but the edge is not shared with a face of s2. Such edges * wouldn't have been processed by the NEWLINE version of * nmg_isect_two_generic_faces(), so intersections need to be looked * for here. Fortunately, it's easy to reject everything except edges * that need processing using only the topology structures. * * The "_int" at the end of the name is to signify that this routine * does only "interior" edges, and is not a general face/shell * intersector. */ void nmg_isect_face3p_shell_int(struct nmg_inter_struct *is, struct faceuse *fu1, struct shell *s2) { struct shell *s1; struct loopuse *lu1; struct edgeuse *eu1; NMG_CK_INTER_STRUCT(is); NMG_CK_FACEUSE(fu1); NMG_CK_SHELL(s2); s1 = fu1->s_p; NMG_CK_SHELL(s1); if (RTG.NMG_debug & DEBUG_POLYSECT) bu_log("nmg_isect_face3p_shell_int(, fu1=x%x, s2=x%x) START\n", fu1, s2); for (BU_LIST_FOR (lu1, loopuse, &fu1->lu_hd)) { NMG_CK_LOOPUSE(lu1); if (BU_LIST_FIRST_MAGIC(&lu1->down_hd) == NMG_VERTEXUSE_MAGIC) continue; for (BU_LIST_FOR (eu1, edgeuse, &lu1->down_hd)) { struct edgeuse *eu2; eu2 = nmg_find_matching_eu_in_s(eu1, s2); if (eu2) { bu_log("nmg_isect_face3p_shell_int() eu1=x%x, e1=x%x, eu2=x%x, e2=x%x (nothing to do)\n", eu1, eu1->e_p, eu2, eu2->e_p); /* Whether the edgeuse is in a face, or a wire * edgeuse, the other guys will isect it. */ continue; } /* vu2a and vu2b are in shell s2, but there is no edge * running between them in shell s2. Create a line of * intersection, and go to it!. */ bu_log("nmg_isect_face3p_shell_int(, s2=x%x) eu1=x%x, no eu2\n", s2, eu1); /* XXX eso no existe todavia */ /* nmg_isect_edge3p_shell(is, eu1, s2); */ } } if (RTG.NMG_debug & DEBUG_POLYSECT) bu_log("nmg_isect_face3p_shell_int(, fu1=x%x, s2=x%x) END\n", fu1, s2); }
void nmg_visit_faceuse(struct faceuse *fu, const struct nmg_visit_handlers *htab, void *state) /* Handler's private state */ { struct loopuse *lu; NMG_CK_FACEUSE(fu); if (htab->bef_faceuse) htab->bef_faceuse((uint32_t *)fu, state, 0); for (BU_LIST_FOR(lu, loopuse, &fu->lu_hd)) { nmg_visit_loopuse(lu, htab, state); } nmg_visit_face(fu->f_p, htab, state); if (htab->aft_faceuse) htab->aft_faceuse((uint32_t *)fu, state, 1); }
static void nmg_to_egg(struct nmgregion *r, const struct db_full_path *pathp, int UNUSED(region_id), int UNUSED(material_id), float UNUSED(color[3]), void *client_data) { struct model *m; struct shell *s; struct vertex *v; char *region_name; int region_polys=0; int vert_count=0; struct egg_conv_data *conv_data = (struct egg_conv_data *)client_data; NMG_CK_REGION(r); RT_CK_FULL_PATH(pathp); region_name = db_path_to_string(pathp); m = r->m_p; NMG_CK_MODEL(m); /* triangulate model */ nmg_triangulate_model(m, &conv_data->tol); /* Write pertinent info for this region */ fprintf(conv_data->fp, " <VertexPool> %s {\n", (region_name+1)); /* Build the VertexPool */ for (BU_LIST_FOR (s, shell, &r->s_hd)) { struct faceuse *fu; NMG_CK_SHELL(s); for (BU_LIST_FOR (fu, faceuse, &s->fu_hd)) { struct loopuse *lu; vect_t facet_normal; NMG_CK_FACEUSE(fu); if (fu->orientation != OT_SAME) continue; /* Grab the face normal and save it for all the vertex loops */ NMG_GET_FU_NORMAL(facet_normal, fu); for (BU_LIST_FOR (lu, loopuse, &fu->lu_hd)) { struct edgeuse *eu; NMG_CK_LOOPUSE(lu); if (BU_LIST_FIRST_MAGIC(&lu->down_hd) != NMG_EDGEUSE_MAGIC) continue; /* check vertex numbers for each triangle */ for (BU_LIST_FOR (eu, edgeuse, &lu->down_hd)) { NMG_CK_EDGEUSE(eu); vert_count++; v = eu->vu_p->v_p; NMG_CK_VERTEX(v); fprintf(conv_data->fp, " <Vertex> %d {\n %f %f %f\n <Normal> { %f %f %f }\n }\n", vert_count, V3ARGS(v->vg_p->coord), V3ARGS(facet_normal)); } } } } fprintf(conv_data->fp, " }\n"); vert_count = 0; for (BU_LIST_FOR (s, shell, &r->s_hd)) { struct faceuse *fu; NMG_CK_SHELL(s); for (BU_LIST_FOR (fu, faceuse, &s->fu_hd)) { struct loopuse *lu; NMG_CK_FACEUSE(fu); if (fu->orientation != OT_SAME) continue; for (BU_LIST_FOR (lu, loopuse, &fu->lu_hd)) { struct edgeuse *eu; NMG_CK_LOOPUSE(lu); if (BU_LIST_FIRST_MAGIC(&lu->down_hd) != NMG_EDGEUSE_MAGIC) continue; fprintf(conv_data->fp, " <Polygon> { \n <RGBA> { 1 1 1 1 } \n <VertexRef> { "); /* check vertex numbers for each triangle */ for (BU_LIST_FOR (eu, edgeuse, &lu->down_hd)) { NMG_CK_EDGEUSE(eu); vert_count++; v = eu->vu_p->v_p; NMG_CK_VERTEX(v); fprintf(conv_data->fp, " %d", vert_count); } fprintf(conv_data->fp, " <Ref> { \"%s\" } }\n }\n", region_name+1); region_polys++; } } } conv_data->tot_polygons += region_polys; bu_free(region_name, "region name"); }
void nmg_2_vrml(struct db_tree_state *tsp, const struct db_full_path *pathp, struct model *m) { struct mater_info *mater = &tsp->ts_mater; const struct bn_tol *tol2 = tsp->ts_tol; struct nmgregion *reg; struct bu_ptbl verts; struct vrml_mat mat; struct bu_vls vls = BU_VLS_INIT_ZERO; char *tok; int i; int first = 1; int is_light = 0; point_t ave_pt = VINIT_ZERO; struct bu_vls shape_name = BU_VLS_INIT_ZERO; char *full_path; /* There may be a better way to capture the region_id, than * getting the rt_comb_internal structure, (and may be a better * way to capture the rt_comb_internal struct), but for now I just * copied the method used in select_lights/select_non_lights above, * could have used a global variable but I noticed none other were * used, so I didn't want to be the first */ struct directory *dp; struct rt_db_internal intern; struct rt_comb_internal *comb; int id; /* static due to libbu exception handling */ static float r, g, b; NMG_CK_MODEL(m); full_path = db_path_to_string(pathp); RT_CK_FULL_PATH(pathp); dp = DB_FULL_PATH_CUR_DIR(pathp); if (!(dp->d_flags & RT_DIR_COMB)) { return; } id = rt_db_get_internal(&intern, dp, dbip, (matp_t)NULL, &rt_uniresource); if (id < 0) { bu_log("Cannot internal form of %s\n", dp->d_namep); return; } if (id != ID_COMBINATION) { bu_log("Directory/database mismatch!\n\t is '%s' a combination or not?\n", dp->d_namep); return; } comb = (struct rt_comb_internal *)intern.idb_ptr; RT_CK_COMB(comb); if (mater->ma_color_valid) { r = mater->ma_color[0]; g = mater->ma_color[1]; b = mater->ma_color[2]; } else { r = g = b = 0.5; } if (mater->ma_shader) { tok = strtok(mater->ma_shader, tok_sep); bu_strlcpy(mat.shader, tok, TXT_NAME_SIZE); } else { mat.shader[0] = '\0'; } mat.shininess = -1; mat.transparency = -1.0; mat.lt_fraction = -1.0; VSETALL(mat.lt_dir, 0.0); mat.lt_angle = -1.0; mat.tx_file[0] = '\0'; mat.tx_w = -1; mat.tx_n = -1; bu_vls_strcpy(&vls, &mater->ma_shader[strlen(mat.shader)]); (void)bu_struct_parse(&vls, vrml_mat_parse, (char *)&mat, NULL); if (bu_strncmp("light", mat.shader, 5) == 0) { /* this is a light source */ is_light = 1; } else { path_2_vrml_id(&shape_name, full_path); fprintf(fp_out, "\t\tDEF %s Shape {\n", bu_vls_addr(&shape_name)); fprintf(fp_out, "\t\t\t# Component_ID: %ld %s\n", comb->region_id, full_path); fprintf(fp_out, "\t\t\tappearance Appearance {\n"); if (bu_strncmp("plastic", mat.shader, 7) == 0) { if (mat.shininess < 0) { mat.shininess = 10; } if (mat.transparency < SMALL_FASTF) { mat.transparency = 0.0; } fprintf(fp_out, "\t\t\t\tmaterial Material {\n"); fprintf(fp_out, "\t\t\t\t\tdiffuseColor %g %g %g \n", r, g, b); fprintf(fp_out, "\t\t\t\t\tshininess %g\n", 1.0-exp(-(double)mat.shininess/20.0)); if (mat.transparency > SMALL_FASTF) { fprintf(fp_out, "\t\t\t\t\ttransparency %g\n", mat.transparency); } fprintf(fp_out, "\t\t\t\t\tspecularColor %g %g %g \n\t\t\t\t}\n", 1.0, 1.0, 1.0); } else if (bu_strncmp("glass", mat.shader, 5) == 0) { if (mat.shininess < 0) { mat.shininess = 4; } if (mat.transparency < SMALL_FASTF) { mat.transparency = 0.8; } fprintf(fp_out, "\t\t\t\tmaterial Material {\n"); fprintf(fp_out, "\t\t\t\t\tdiffuseColor %g %g %g \n", r, g, b); fprintf(fp_out, "\t\t\t\t\tshininess %g\n", 1.0-exp(-(double)mat.shininess/20.0)); if (mat.transparency > SMALL_FASTF) { fprintf(fp_out, "\t\t\t\t\ttransparency %g\n", mat.transparency); } fprintf(fp_out, "\t\t\t\t\tspecularColor %g %g %g \n\t\t\t\t}\n", 1.0, 1.0, 1.0); } else if (bu_strncmp("texture", mat.shader, 7) == 0) { if (mat.tx_w < 0) { mat.tx_w = 512; } if (mat.tx_n < 0) { mat.tx_n = 512; } if (strlen(mat.tx_file)) { int tex_fd; unsigned char tex_buf[TXT_BUF_LEN * 3]; if ((tex_fd = open(mat.tx_file, O_RDONLY | O_BINARY)) == (-1)) { bu_log("Cannot open texture file (%s)\n", mat.tx_file); perror("g-vrml: "); } else { long tex_len; long bytes_read = 0; long bytes_to_go = 0; /* Johns note - need to check (test) the texture stuff */ fprintf(fp_out, "\t\t\t\ttextureTransform TextureTransform {\n"); fprintf(fp_out, "\t\t\t\t\tscale 1.33333 1.33333\n\t\t\t\t}\n"); fprintf(fp_out, "\t\t\t\ttexture PixelTexture {\n"); fprintf(fp_out, "\t\t\t\t\trepeatS TRUE\n"); fprintf(fp_out, "\t\t\t\t\trepeatT TRUE\n"); fprintf(fp_out, "\t\t\t\t\timage %d %d %d\n", mat.tx_w, mat.tx_n, 3); tex_len = mat.tx_w*mat.tx_n * 3; while (bytes_read < tex_len) { int nbytes; long readval; bytes_to_go = tex_len - bytes_read; CLAMP(bytes_to_go, 0, TXT_BUF_LEN * 3); nbytes = 0; while (nbytes < bytes_to_go) { readval = read(tex_fd, &tex_buf[nbytes], bytes_to_go-nbytes); if (readval < 0) { perror("READ ERROR"); break; } else { nbytes += readval; } } bytes_read += nbytes; for (i = 0; i < nbytes; i += 3) { fprintf(fp_out, "\t\t\t0x%02x%02x%02x\n", tex_buf[i], tex_buf[i+1], tex_buf[i+2]); } } fprintf(fp_out, "\t\t\t\t}\n"); close(tex_fd); } } } else if (mater->ma_color_valid) { /* no shader specified, but a color is assigned */ fprintf(fp_out, "\t\t\t\tmaterial Material {\n"); fprintf(fp_out, "\t\t\t\t\tdiffuseColor %g %g %g }\n", r, g, b); } else { /* If no color was defined set the colors according to the thousands groups */ int thou = comb->region_id / 1000; thou == 0 ? fprintf(fp_out, "\t\t\tmaterial USE Material_999\n") : thou == 1 ? fprintf(fp_out, "\t\t\tmaterial USE Material_1999\n") : thou == 2 ? fprintf(fp_out, "\t\t\tmaterial USE Material_2999\n") : thou == 3 ? fprintf(fp_out, "\t\t\tmaterial USE Material_3999\n") : thou == 4 ? fprintf(fp_out, "\t\t\tmaterial USE Material_4999\n") : thou == 5 ? fprintf(fp_out, "\t\t\tmaterial USE Material_5999\n") : thou == 6 ? fprintf(fp_out, "\t\t\tmaterial USE Material_6999\n") : thou == 7 ? fprintf(fp_out, "\t\t\tmaterial USE Material_7999\n") : thou == 8 ? fprintf(fp_out, "\t\t\tmaterial USE Material_8999\n") : fprintf(fp_out, "\t\t\tmaterial USE Material_9999\n"); } } if (!is_light) { nmg_triangulate_model(m, tol2); fprintf(fp_out, "\t\t\t}\n"); fprintf(fp_out, "\t\t\tgeometry IndexedFaceSet {\n"); fprintf(fp_out, "\t\t\t\tcoord Coordinate {\n"); } /* get list of vertices */ nmg_vertex_tabulate(&verts, &m->magic); if (!is_light) { fprintf(fp_out, "\t\t\t\t\tpoint ["); } else { VSETALL(ave_pt, 0.0); } for (i = 0; i < BU_PTBL_END(&verts); i++) { struct vertex *v; struct vertex_g *vg; point_t pt_meters; v = (struct vertex *)BU_PTBL_GET(&verts, i); NMG_CK_VERTEX(v); vg = v->vg_p; NMG_CK_VERTEX_G(vg); /* convert to desired units */ VSCALE(pt_meters, vg->coord, scale_factor); if (is_light) { VADD2(ave_pt, ave_pt, pt_meters); } if (first) { if (!is_light) { fprintf(fp_out, " %10.10e %10.10e %10.10e, # point %d\n", V3ARGS(pt_meters), i); } first = 0; } else if (!is_light) { fprintf(fp_out, "\t\t\t\t\t%10.10e %10.10e %10.10e, # point %d\n", V3ARGS(pt_meters), i); } } if (!is_light) { fprintf(fp_out, "\t\t\t\t\t]\n\t\t\t\t}\n"); } else { fastf_t one_over_count; one_over_count = 1.0/(fastf_t)BU_PTBL_END(&verts); VSCALE(ave_pt, ave_pt, one_over_count); } first = 1; if (!is_light) { fprintf(fp_out, "\t\t\t\tcoordIndex [\n"); for (BU_LIST_FOR(reg, nmgregion, &m->r_hd)) { struct shell *s; NMG_CK_REGION(reg); for (BU_LIST_FOR(s, shell, ®->s_hd)) { struct faceuse *fu; NMG_CK_SHELL(s); for (BU_LIST_FOR(fu, faceuse, &s->fu_hd)) { struct loopuse *lu; NMG_CK_FACEUSE(fu); if (fu->orientation != OT_SAME) { continue; } for (BU_LIST_FOR(lu, loopuse, &fu->lu_hd)) { struct edgeuse *eu; NMG_CK_LOOPUSE(lu); if (BU_LIST_FIRST_MAGIC(&lu->down_hd) != NMG_EDGEUSE_MAGIC) { continue; } if (!first) { fprintf(fp_out, ",\n"); } else { first = 0; } fprintf(fp_out, "\t\t\t\t\t"); for (BU_LIST_FOR(eu, edgeuse, &lu->down_hd)) { struct vertex *v; NMG_CK_EDGEUSE(eu); v = eu->vu_p->v_p; NMG_CK_VERTEX(v); fprintf(fp_out, " %d,", bu_ptbl_locate(&verts, (long *)v)); } fprintf(fp_out, "-1"); } } } } fprintf(fp_out, "\n\t\t\t\t]\n\t\t\t\tnormalPerVertex FALSE\n"); fprintf(fp_out, "\t\t\t\tconvex FALSE\n"); fprintf(fp_out, "\t\t\t\tcreaseAngle 0.5\n"); fprintf(fp_out, "\t\t\t}\n\t\t}\n"); } else {
extern "C" void rt_nmg_brep(ON_Brep **b, const struct rt_db_internal *ip, const struct bn_tol *tol) { struct model *m; struct nmgregion *r; struct shell *s; struct faceuse *fu; struct loopuse *lu; struct edgeuse *eu; int edge_index; long* brepi; RT_CK_DB_INTERNAL(ip); m = (struct model *)ip->idb_ptr; NMG_CK_MODEL(m); brepi = static_cast<long*>(bu_malloc(m->maxindex * sizeof(long), "rt_nmg_brep: brepi[]")); for (int i = 0; i < m->maxindex; i++) brepi[i] = -INT_MAX; for (BU_LIST_FOR(r, nmgregion, &m->r_hd)) { for (BU_LIST_FOR(s, shell, &r->s_hd)) { for (BU_LIST_FOR(fu, faceuse, &s->fu_hd)) { NMG_CK_FACEUSE(fu); if (fu->orientation != OT_SAME) continue; // Need to create ON_NurbsSurface based on plane of // face in order to have UV space in which to define // trimming loops. Bounding points are NOT on the // face plane, so another approach must be used. // // General approach: For all loops in the faceuse, // collect all the vertices. Find the center point of // all the vertices, and search for the point with the // greatest distance from that center point. Once // found, cross the vector between the center point // and furthest point with the normal of the face and // scale the resulting vector to have the same length // as the vector to the furthest point. Add the two // resulting vectors to find the first corner point. // Mirror the first corner point across the center to // find the second corner point. Cross the two // vectors created by the first two corner points with // the face normal to get the vectors of the other two // corners, and scale the resulting vectors to the // same magnitude as the first two. These four points // bound all vertices on the plane and form a suitable // staring point for a UV space, since all points on // all the edges are equal to or further than the // distance between the furthest vertex and the center // point. // ............. ............. // . .* . . // . . . . . // . . . . . // . . . * . // . . . . . // . . . . . // . . . . . // . * * . . // . . . . // . . . . // . . . . // . *. . . // . ... ...* . // . .... .... . // . * . // ........................... // const struct face_g_plane *fg = fu->f_p->g.plane_p; struct bu_ptbl vert_table; nmg_tabulate_face_g_verts(&vert_table, fg); point_t tmppt, center, max_pt; struct vertex **pt; VSET(tmppt, 0, 0, 0); VSET(max_pt, 0, 0, 0); int ptcnt = 0; for (BU_PTBL_FOR(pt, (struct vertex **), &vert_table)) { tmppt[0] += (*pt)->vg_p->coord[0]; tmppt[1] += (*pt)->vg_p->coord[1]; tmppt[2] += (*pt)->vg_p->coord[2]; ptcnt++; if (brepi[(*pt)->vg_p->index] == -INT_MAX) { ON_BrepVertex& vert = (*b)->NewVertex((*pt)->vg_p->coord, SMALL_FASTF); brepi[(*pt)->vg_p->index] = vert.m_vertex_index; } } VSET(center, tmppt[0]/ptcnt, tmppt[1]/ptcnt, tmppt[2]/ptcnt); fastf_t max_dist = 0.0; fastf_t curr_dist; for (BU_PTBL_FOR(pt, (struct vertex **), &vert_table)) { tmppt[0] = (*pt)->vg_p->coord[0]; tmppt[1] = (*pt)->vg_p->coord[1]; tmppt[2] = (*pt)->vg_p->coord[2]; curr_dist = DIST_PT_PT(center, tmppt); if (curr_dist > max_dist) { max_dist = curr_dist; VMOVE(max_pt, tmppt); } } bu_ptbl_free(&vert_table); int ccw = 0; vect_t vtmp, uv1, uv2, uv3, uv4, vnormal; // If an outer loop is found in the nmg with a cw // orientation, use a flipped normal to form the NURBS // surface for (BU_LIST_FOR(lu, loopuse, &fu->lu_hd)) { if (lu->orientation == OT_SAME && nmg_loop_is_ccw(lu, fg->N, tol) == -1) ccw = -1; } if (ccw != -1) { VSET(vnormal, fg->N[0], fg->N[1], fg->N[2]); } else { VSET(vnormal, -fg->N[0], -fg->N[1], -fg->N[2]); } VSUB2(uv1, max_pt, center); VCROSS(vtmp, uv1, vnormal); VADD2(uv1, uv1, vtmp); VCROSS(uv2, uv1, vnormal); VREVERSE(uv3, uv1); VCROSS(uv4, uv3, vnormal); VADD2(uv1, uv1, center); VADD2(uv2, uv2, center); VADD2(uv3, uv3, center); VADD2(uv4, uv4, center); ON_3dPoint p1 = ON_3dPoint(uv1); ON_3dPoint p2 = ON_3dPoint(uv2); ON_3dPoint p3 = ON_3dPoint(uv3); ON_3dPoint p4 = ON_3dPoint(uv4); (*b)->m_S.Append(sideSurface(p1, p4, p3, p2)); ON_Surface *surf = (*(*b)->m_S.Last()); int surfindex = (*b)->m_S.Count(); // Now that we have the surface, define the face ON_BrepFace& face = (*b)->NewFace(surfindex - 1); // With the surface and the face defined, make // trimming loops and create faces. To generate UV // coordinates for each from and to for the // edgecurves, the UV origin is defined to be v1, // v1->v2 is defined as the U domain, and v1->v4 is // defined as the V domain. vect_t u_axis, v_axis; VSUB2(u_axis, uv2, uv1); VSUB2(v_axis, uv4, uv1); fastf_t u_axis_dist = MAGNITUDE(u_axis); fastf_t v_axis_dist = MAGNITUDE(v_axis); // Now that the surface context is set up, add the loops. for (BU_LIST_FOR(lu, loopuse, &fu->lu_hd)) { int edges=0; if (BU_LIST_FIRST_MAGIC(&lu->down_hd) != NMG_EDGEUSE_MAGIC) continue; // loop is a single vertex ON_BrepLoop::TYPE looptype; // Check if this is an inner or outer loop if (lu->orientation == OT_SAME) { looptype = ON_BrepLoop::outer; } else { looptype = ON_BrepLoop::inner; } ON_BrepLoop& loop = (*b)->NewLoop(looptype, face); for (BU_LIST_FOR(eu, edgeuse, &lu->down_hd)) { ++edges; vect_t ev1, ev2; struct vertex_g *vg1, *vg2; vg1 = eu->vu_p->v_p->vg_p; NMG_CK_VERTEX_G(vg1); int vert1 = brepi[vg1->index]; VMOVE(ev1, vg1->coord); vg2 = eu->eumate_p->vu_p->v_p->vg_p; NMG_CK_VERTEX_G(vg2); int vert2 = brepi[vg2->index]; VMOVE(ev2, vg2->coord); // Add edge if not already added if (brepi[eu->e_p->index] == -INT_MAX) { /* always add edges with the small vertex index as from */ if (vg1->index > vg2->index) { int tmpvert = vert1; vert1 = vert2; vert2 = tmpvert; } // Create and add 3D curve ON_Curve* c3d = new ON_LineCurve((*b)->m_V[vert1].Point(), (*b)->m_V[vert2].Point()); c3d->SetDomain(0.0, 1.0); (*b)->m_C3.Append(c3d); // Create and add 3D edge ON_BrepEdge& e = (*b)->NewEdge((*b)->m_V[vert1], (*b)->m_V[vert2] , (*b)->m_C3.Count() - 1); e.m_tolerance = 0.0; brepi[eu->e_p->index] = e.m_edge_index; } // Regardless of whether the edge existed as // an object, it needs to be added to the // trimming loop vect_t u_component, v_component; ON_3dPoint vg1pt(vg1->coord); int orientation = 0; edge_index = brepi[eu->e_p->index]; if (vg1pt != (*b)->m_V[(*b)->m_E[edge_index].m_vi[0]].Point()) { orientation = 1; } // Now, make 2d trimming curves vect_t vect1, vect2; VSUB2(vect1, ev1, uv1); VSUB2(vect2, ev2, uv1); ON_2dPoint from_uv, to_uv; double u0, u1, v0, v1; surf->GetDomain(0, &u0, &u1); surf->GetDomain(1, &v0, &v1); VPROJECT(vect1, u_axis, u_component, v_component); from_uv.y = u0 + MAGNITUDE(u_component)/u_axis_dist*(u1-u0); from_uv.x = v0 + MAGNITUDE(v_component)/v_axis_dist*(v1-v0); VPROJECT(vect2, u_axis, u_component, v_component); to_uv.y = u0 + MAGNITUDE(u_component)/u_axis_dist*(u1-u0); to_uv.x = v0 + MAGNITUDE(v_component)/v_axis_dist*(v1-v0); ON_3dPoint S1, S2; ON_3dVector Su, Sv; surf->Ev1Der(from_uv.x, from_uv.y, S1, Su, Sv); surf->Ev1Der(to_uv.x, to_uv.y, S2, Su, Sv); ON_Curve* c2d = new ON_LineCurve(from_uv, to_uv); c2d->SetDomain(0.0, 1.0); int c2i = (*b)->m_C2.Count(); (*b)->m_C2.Append(c2d); edge_index = brepi[eu->e_p->index]; ON_BrepTrim& trim = (*b)->NewTrim((*b)->m_E[edge_index], orientation, loop, c2i); trim.m_type = ON_BrepTrim::mated; trim.m_tolerance[0] = 0.0; trim.m_tolerance[1] = 0.0; } } } (*b)->SetTrimIsoFlags(); } } bu_free(brepi, "rt_nmg_brep: brepi[]"); }
static void nmg_to_obj(struct nmgregion *r, struct db_full_path *pathp, int region_id, int aircode, int los, int material_id) { struct model *m; struct shell *s; struct vertex *v; struct bu_ptbl verts; struct bu_ptbl norms; char *region_name; int numverts = 0; /* Number of vertices to output */ int numtri = 0; /* Number of triangles to output */ int i; NMG_CK_REGION( r ); RT_CK_FULL_PATH(pathp); region_name = db_path_to_string( pathp ); #if 0 printf("Attempting to process region %s\n", region_name); fflush(stdout); #endif m = r->m_p; NMG_CK_MODEL( m ); /* triangulate model */ nmg_triangulate_model( m, &tol ); /* list all vertices in result */ nmg_vertex_tabulate( &verts, &r->l.magic ); /* Get number of vertices */ numverts = BU_PTBL_END (&verts); /* get list of vertexuse normals */ if ( do_normals ) nmg_vertexuse_normal_tabulate( &norms, &r->l.magic ); /* XXX Check vertices, shells faces first? Do not want to punt mid-stream */ /* BEGIN CHECK SECTION */ /* Check vertices */ for ( i=0; i<numverts; i++ ) { v = (struct vertex *)BU_PTBL_GET( &verts, i ); NMG_CK_VERTEX( v ); } /* Check triangles */ for ( BU_LIST_FOR( s, shell, &r->s_hd ) ) { struct faceuse *fu; NMG_CK_SHELL( s ); for ( BU_LIST_FOR( fu, faceuse, &s->fu_hd ) ) { struct loopuse *lu; NMG_CK_FACEUSE( fu ); if ( fu->orientation != OT_SAME ) continue; for ( BU_LIST_FOR( lu, loopuse, &fu->lu_hd ) ) { struct edgeuse *eu; int vert_count=0; NMG_CK_LOOPUSE( lu ); if ( BU_LIST_FIRST_MAGIC( &lu->down_hd ) != NMG_EDGEUSE_MAGIC ) continue; /* check vertex numbers for each triangle */ for ( BU_LIST_FOR( eu, edgeuse, &lu->down_hd ) ) { NMG_CK_EDGEUSE( eu ); v = eu->vu_p->v_p; NMG_CK_VERTEX( v ); vert_count++; i = bu_ptbl_locate( &verts, (long *)v ); if ( i < 0 ) { /*XXX*/ bu_ptbl_free( &verts); /*XXX*/ bu_free( region_name, "region name" ); bu_log( "Vertex from eu x%x is not in nmgregion x%x\n", eu, r ); bu_exit(1, "ERROR: Can't find vertex in list!"); } } if ( vert_count > 3 ) { /*XXX*/ bu_ptbl_free( &verts); /*XXX*/ bu_free( region_name, "region name" ); bu_log( "lu x%x has %d vertices!\n", lu, vert_count ); bu_exit(1, "ERROR: LU is not a triangle\n"); } else if ( vert_count < 3 ) continue; numtri++; } } } /* END CHECK SECTION */ /* Write pertinent info for this region */ if ( usemtl ) fprintf( fp, "usemtl %d_%d_%d\n", aircode, los, material_id ); fprintf( fp, "g %s", pathp->fp_names[0]->d_namep ); for ( i=1; i<pathp->fp_len; i++ ) fprintf( fp, "/%s", pathp->fp_names[i]->d_namep ); fprintf( fp, "\n" ); /* Write vertices */ for ( i=0; i<numverts; i++ ) { v = (struct vertex *)BU_PTBL_GET( &verts, i ); NMG_CK_VERTEX( v ); if (inches) fprintf( fp, "v %f %f %f\n", V3ARGSIN( v->vg_p->coord )); else fprintf( fp, "v %f %f %f\n", V3ARGS( v->vg_p->coord )); } /* Write vertexuse normals */ if ( do_normals ) { for ( i=0; i<BU_PTBL_END( &norms ); i++ ) { struct vertexuse_a_plane *va; va = (struct vertexuse_a_plane *)BU_PTBL_GET( &norms, i ); NMG_CK_VERTEXUSE_A_PLANE( va ); if (inches) fprintf( fp, "vn %f %f %f\n", V3ARGSIN( va->N )); else fprintf( fp, "vn %f %f %f\n", V3ARGS( va->N )); } } /* output triangles */ for ( BU_LIST_FOR( s, shell, &r->s_hd ) ) { struct faceuse *fu; NMG_CK_SHELL( s ); for ( BU_LIST_FOR( fu, faceuse, &s->fu_hd ) ) { struct loopuse *lu; NMG_CK_FACEUSE( fu ); if ( fu->orientation != OT_SAME ) continue; for ( BU_LIST_FOR( lu, loopuse, &fu->lu_hd ) ) { struct edgeuse *eu; int vert_count=0; int use_normals=1; NMG_CK_LOOPUSE( lu ); if ( BU_LIST_FIRST_MAGIC( &lu->down_hd ) != NMG_EDGEUSE_MAGIC ) continue; /* Each vertexuse of the face must have a normal in order * to use the normals in Wavefront */ if ( do_normals ) { for ( BU_LIST_FOR( eu, edgeuse, &lu->down_hd ) ) { NMG_CK_EDGEUSE( eu ); if ( !eu->vu_p->a.magic_p ) { use_normals = 0; break; } if ( *eu->vu_p->a.magic_p != NMG_VERTEXUSE_A_PLANE_MAGIC ) { use_normals = 0; break; } } } else use_normals = 0; fprintf( fp, "f" ); /* list vertex numbers for each triangle */ for ( BU_LIST_FOR( eu, edgeuse, &lu->down_hd ) ) { NMG_CK_EDGEUSE( eu ); v = eu->vu_p->v_p; NMG_CK_VERTEX( v ); vert_count++; i = bu_ptbl_locate( &verts, (long *)v ); if ( i < 0 ) { bu_ptbl_free( &verts); bu_log( "Vertex from eu x%x is not in nmgregion x%x\n", eu, r ); /*XXX*/ bu_free( region_name, "region name" ); /*XXX*/ bu_exit(1, "Can't find vertex in list!\n"); } if ( use_normals ) { int j; j = bu_ptbl_locate( &norms, (long *)eu->vu_p->a.magic_p ); fprintf( fp, " %ld//%ld", i+1+vert_offset, j+1+norm_offset ); } else fprintf( fp, " %ld", i+1+vert_offset ); } fprintf( fp, "\n" ); if ( vert_count > 3 ) { bu_ptbl_free( &verts); bu_free( region_name, "region name" ); bu_log( "lu x%x has %d vertices!\n", lu, vert_count ); bu_exit(1, "ERROR: LU is not a triangle\n" ); } } } }
/* * J A C K _ F A C E S * * Continues the conversion of an nmg into Jack format. Before * this routine is called, a list of unique vertices has been * stored in a heap. Using this heap and the nmg structure, a * list of face vertices is written to the Jack data base file. */ static void jack_faces(struct nmgregion *r, FILE *fp_psurf, int *map) /* NMG region to be converted. */ /* Jack format file to write face vertices to. */ { struct edgeuse *eu; struct faceuse *fu; struct loopuse *lu; struct shell *s; struct vertex *v; for (BU_LIST_FOR(s, shell, &r->s_hd)) { /* Shell is made of faces. */ for (BU_LIST_FOR(fu, faceuse, &s->fu_hd)) { NMG_CK_FACEUSE(fu); if (fu->orientation != OT_SAME) continue; for (BU_LIST_FOR(lu, loopuse, &fu->lu_hd)) { NMG_CK_LOOPUSE(lu); if (BU_LIST_FIRST_MAGIC(&lu->down_hd) == NMG_EDGEUSE_MAGIC) { for (BU_LIST_FOR(eu, edgeuse, &lu->down_hd)) { NMG_CK_EDGEUSE(eu); NMG_CK_EDGE(eu->e_p); NMG_CK_VERTEXUSE(eu->vu_p); NMG_CK_VERTEX(eu->vu_p->v_p); NMG_CK_VERTEX_G(eu->vu_p->v_p->vg_p); fprintf(fp_psurf, "%d ", NMG_INDEX_GET(map, eu->vu_p->v_p)); } } else if (BU_LIST_FIRST_MAGIC(&lu->down_hd) == NMG_VERTEXUSE_MAGIC) { v = BU_LIST_PNEXT(vertexuse, &lu->down_hd)->v_p; NMG_CK_VERTEX(v); NMG_CK_VERTEX_G(v->vg_p); fprintf(fp_psurf, "%d ", NMG_INDEX_GET(map, v)); } else bu_log("jack_faces: loopuse mess up! (1)\n"); fprintf(fp_psurf, ";\n"); } } /* Shell contains loops. */ for (BU_LIST_FOR(lu, loopuse, &s->lu_hd)) { NMG_CK_LOOPUSE(lu); if (BU_LIST_FIRST_MAGIC(&lu->down_hd) == NMG_EDGEUSE_MAGIC) { for (BU_LIST_FOR(eu, edgeuse, &lu->down_hd)) { NMG_CK_EDGEUSE(eu); NMG_CK_EDGE(eu->e_p); NMG_CK_VERTEXUSE(eu->vu_p); NMG_CK_VERTEX(eu->vu_p->v_p); NMG_CK_VERTEX_G(eu->vu_p->v_p->vg_p); fprintf(fp_psurf, "%d ", NMG_INDEX_GET(map, eu->vu_p->v_p)); } } else if (BU_LIST_FIRST_MAGIC(&lu->down_hd) == NMG_VERTEXUSE_MAGIC) { v = BU_LIST_PNEXT(vertexuse, &lu->down_hd)->v_p; NMG_CK_VERTEX(v); NMG_CK_VERTEX_G(v->vg_p); fprintf(fp_psurf, "%d ", NMG_INDEX_GET(map, v)); } else bu_log("jack_faces: loopuse mess up! (1)\n"); fprintf(fp_psurf, ";\n"); }
void nmg_2_vrml(FILE *fp, const struct db_full_path *pathp, struct model *m, struct mater_info *mater) { struct nmgregion *reg; struct bu_ptbl verts; struct vrml_mat mat; struct bu_vls vls = BU_VLS_INIT_ZERO; char *tok; int i; int first=1; int is_light=0; float r, g, b; point_t ave_pt; char *full_path; /*There may be a better way to capture the region_id, than getting the rt_comb_internal structure, * (and may be a better way to capture the rt_comb_internal struct), but for now I just copied the * method used in select_lights/select_non_lights above, could have used a global variable but I noticed * none other were used, so I didn't want to be the first */ struct directory *dp; struct rt_db_internal intern; struct rt_comb_internal *comb; int id; NMG_CK_MODEL( m ); BARRIER_CHECK; full_path = db_path_to_string( pathp ); /* replace all occurrences of '.' with '_' */ char_replace(full_path, '.', '_'); RT_CK_FULL_PATH( pathp ); dp = DB_FULL_PATH_CUR_DIR( pathp ); if ( !(dp->d_flags & RT_DIR_COMB) ) return; id = rt_db_get_internal( &intern, dp, dbip, (matp_t)NULL, &rt_uniresource ); if ( id < 0 ) { bu_log( "Cannot internal form of %s\n", dp->d_namep ); return; } if ( id != ID_COMBINATION ) { bu_log( "Directory/database mismatch!\n\t is '%s' a combination or not?\n", dp->d_namep ); return; } comb = (struct rt_comb_internal *)intern.idb_ptr; RT_CK_COMB( comb ); if ( mater->ma_color_valid ) { r = mater->ma_color[0]; g = mater->ma_color[1]; b = mater->ma_color[2]; } else { r = g = b = 0.5; } if ( mater->ma_shader ) { tok = strtok( mater->ma_shader, tok_sep ); bu_strlcpy( mat.shader, tok, TXT_NAME_SIZE ); } else mat.shader[0] = '\0'; mat.shininess = -1; mat.transparency = -1.0; mat.lt_fraction = -1.0; VSETALL( mat.lt_dir, 0.0 ); mat.lt_angle = -1.0; mat.tx_file[0] = '\0'; mat.tx_w = -1; mat.tx_n = -1; bu_vls_strcpy( &vls, &mater->ma_shader[strlen(mat.shader)] ); (void)bu_struct_parse( &vls, vrml_mat_parse, (char *)&mat, NULL); if ( bu_strncmp( "light", mat.shader, 5 ) == 0 ) { /* this is a light source */ is_light = 1; } else { fprintf( fp, "\t<Shape DEF=\"%s\">\n", full_path); fprintf( fp, "\t\t<Appearance>\n"); if ( bu_strncmp( "plastic", mat.shader, 7 ) == 0 ) { if ( mat.shininess < 0 ) mat.shininess = 10; V_MAX(mat.transparency, 0.0); fprintf( fp, "\t\t\t<Material diffuseColor=\"%g %g %g\" shininess=\"%g\" transparency=\"%g\" specularColor=\"%g %g %g\"/>\n", r, g, b, 1.0-exp(-(double)mat.shininess/20.0), mat.transparency, 1.0, 1.0, 1.0); } else if ( bu_strncmp( "glass", mat.shader, 5 ) == 0 ) { if ( mat.shininess < 0 ) mat.shininess = 4; if ( mat.transparency < 0.0 ) mat.transparency = 0.8; fprintf( fp, "\t\t\t<Material diffuseColor=\"%g %g %g\" shininess=\"%g\" transparency=\"%g\" specularColor=\"%g %g %g\"/>\n", r, g, b, 1.0-exp(-(double)mat.shininess/20.0), mat.transparency, 1.0, 1.0, 1.0); } else if ( mater->ma_color_valid ) { fprintf( fp, "\t\t\t<Material diffuseColor=\"%g %g %g\"/>\n", r, g, b); } else { /* If no color was defined set the colors according to the thousands groups */ int thou = comb->region_id/1000; thou == 0 ? fprintf( fp, "\t\t\t<Material USE=\"Material_999\"/>\n") : thou == 1 ? fprintf( fp, "\t\t\t<Material USE=\"Material_1999\"/>\n") : thou == 2 ? fprintf( fp, "\t\t\t<Material USE=\"Material_2999\"/>\n") : thou == 3 ? fprintf( fp, "\t\t\t<Material USE=\"Material_3999\"/>\n") : thou == 4 ? fprintf( fp, "\t\t\t<Material USE=\"Material_4999\"/>\n") : thou == 5 ? fprintf( fp, "\t\t\t<Material USE=\"Material_5999\"/>\n") : thou == 6 ? fprintf( fp, "\t\t\t<Material USE=\"Material_6999\"/>\n") : thou == 7 ? fprintf( fp, "\t\t\t<Material USE=\"Material_7999\"/>\n") : thou == 8 ? fprintf( fp, "\t\t\t<Material USE=\"Material_8999\"/>\n") : fprintf( fp, "\t\t\t<Material USE=\"Material_9999\"/>\n"); } } if ( !is_light ) { process_non_light(m); fprintf( fp, "\t\t</Appearance>\n"); } /* FIXME: need code to handle light */ /* get list of vertices */ nmg_vertex_tabulate( &verts, &m->magic ); fprintf( fp, "\t\t<IndexedFaceSet coordIndex=\"\n"); first = 1; if ( !is_light ) { for ( BU_LIST_FOR( reg, nmgregion, &m->r_hd ) ) { struct shell *s; NMG_CK_REGION( reg ); for ( BU_LIST_FOR( s, shell, ®->s_hd ) ) { struct faceuse *fu; NMG_CK_SHELL( s ); for ( BU_LIST_FOR( fu, faceuse, &s->fu_hd ) ) { struct loopuse *lu; NMG_CK_FACEUSE( fu ); if ( fu->orientation != OT_SAME ) continue; for ( BU_LIST_FOR( lu, loopuse, &fu->lu_hd ) ) { struct edgeuse *eu; NMG_CK_LOOPUSE( lu ); if ( BU_LIST_FIRST_MAGIC( &lu->down_hd ) != NMG_EDGEUSE_MAGIC ) continue; if ( !first ) fprintf( fp, ",\n" ); else first = 0; fprintf( fp, "\t\t\t\t" ); for ( BU_LIST_FOR( eu, edgeuse, &lu->down_hd ) ) { struct vertex *v; NMG_CK_EDGEUSE( eu ); v = eu->vu_p->v_p; NMG_CK_VERTEX( v ); fprintf( fp, " %d,", bu_ptbl_locate( &verts, (long *)v ) ); } fprintf( fp, "-1" ); } } } } /* close coordIndex */ fprintf( fp, "\" "); fprintf( fp, "normalPerVertex=\"false\" "); fprintf( fp, "convex=\"false\" "); fprintf( fp, "creaseAngle=\"0.5\" "); /* close IndexedFaceSet open tag */ fprintf( fp, ">\n"); } fprintf( fp, "\t\t\t<Coordinate point=\""); for ( i=0; i<BU_PTBL_END( &verts ); i++ ) { struct vertex *v; struct vertex_g *vg; point_t pt_meters; v = (struct vertex *)BU_PTBL_GET( &verts, i ); NMG_CK_VERTEX( v ); vg = v->vg_p; NMG_CK_VERTEX_G( vg ); /* convert to desired units */ VSCALE( pt_meters, vg->coord, scale_factor ); if ( is_light ) VADD2( ave_pt, ave_pt, pt_meters ); if ( first ) { if ( !is_light ) fprintf( fp, " %10.10e %10.10e %10.10e, ", V3ARGS(pt_meters)); first = 0; } else if ( !is_light ) fprintf( fp, "%10.10e %10.10e %10.10e, ", V3ARGS( pt_meters )); } /* close point */ fprintf(fp, "\""); /* close Coordinate */ fprintf(fp, "/>\n"); /* IndexedFaceSet end tag */ fprintf( fp, "\t\t</IndexedFaceSet>\n"); /* Shape end tag */ fprintf( fp, "\t</Shape>\n"); BARRIER_CHECK; }
/* IEEE patch number of the Bi-Cubic Bezier patch and convert it * to a B-Spline surface (Bezier surfaces are a subset of B-spline surfaces * and output it to a BRL-CAD binary format. */ void dump_patch(int (*patch)[4]) { struct vertex *verts[4]; struct faceuse *fu; struct loopuse *lu; struct edgeuse *eu; int i, j, pt_type; fastf_t *mesh=NULL; fastf_t *ukv=NULL; fastf_t *vkv=NULL; /* U and V parametric Direction Spline parameters * Cubic = order 4, * knot size is Control point + order = 8 * control point size is 4 * point size is 3 */ for ( i=0; i<4; i++ ) verts[i] = (struct vertex *)NULL; fu = nmg_cface( s, verts, 4 ); NMG_CK_FACEUSE( fu ); for ( i=0; i<4; i++ ) { struct vertexuse *vu; vect_t uvw; point_t pnt; int k, j; switch ( i ) { default: case 0: VSET( uvw, 0.0, 0.0, 0.0 ); k = 0; j = 0; break; case 1: VSET( uvw, 1.0, 0.0, 0.0 ); k = 0; j = 3; break; case 2: VSET( uvw, 1.0, 1.0, 0.0 ); k = 3; j = 3; break; case 3: VSET( uvw, 0.0, 1.0, 0.0 ); k = 3; j = 0; break; } VSET( pnt , ducks[patch[k][j]-1].x * 1000 , ducks[patch[k][j]-1].y * 1000 , ducks[patch[k][j]-1].z * 1000 ); nmg_vertex_gv( verts[i], pnt ); for ( BU_LIST_FOR( vu, vertexuse, &verts[i]->vu_hd ) ) nmg_vertexuse_a_cnurb( vu, uvw ); } pt_type = RT_NURB_MAKE_PT_TYPE(3, RT_NURB_PT_XYZ, 0); /* see nurb.h for details */ nmg_face_g_snurb( fu, 4, 4, 8, 8, ukv, vkv, 4, 4, pt_type, mesh ); NMG_CK_FACE( fu->f_p ); NMG_CK_FACE_G_SNURB( fu->f_p->g.snurb_p ); mesh = fu->f_p->g.snurb_p->ctl_points; /* Copy the control points */ for ( i = 0; i< 4; i++) for ( j = 0; j < 4; j++) { *mesh = ducks[patch[i][j]-1].x * 1000; *(mesh+1) = ducks[patch[i][j]-1].y * 1000; *(mesh+2) = ducks[patch[i][j]-1].z * 1000; mesh += 3; } /* Both u and v knot vectors are [ 0 0 0 0 1 1 1 1] */ ukv = fu->f_p->g.snurb_p->u.knots; vkv = fu->f_p->g.snurb_p->v.knots; /* set the knot vectors */ for ( i=0; i<4; i++ ) { *(ukv+i) = 0.0; *(vkv+i) = 0.0; } for ( i=0; i<4; i++ ) { *(ukv+4+i) = 1.0; *(vkv+4+i) = 1.0; } /* set eu geometry */ pt_type = RT_NURB_MAKE_PT_TYPE(2, RT_NURB_PT_UV, 0); /* see nurb.h for details */ lu = BU_LIST_FIRST( loopuse, &fu->lu_hd ); NMG_CK_LOOPUSE( lu ); for ( BU_LIST_FOR( eu, edgeuse, &lu->down_hd ) ) { #if 0 nmg_edge_g_cnurb( eu, 2, 0, (fastf_t *)NULL, 2 , pt_type, (fastf_t *)NULL ); #else nmg_edge_g_cnurb_plinear( eu ); #endif } nmg_face_bb( fu->f_p, &tol ); }
/** * Make a life-and-death decision on every element of a shell. * Descend the "great chain of being" from the face to loop to edge to * vertex, saving or demoting along the way. * * Note that there is no moving of items from one shell to another. */ HIDDEN void nmg_eval_shell(register struct shell *s, struct nmg_bool_state *bs) { struct faceuse *fu; struct faceuse *nextfu; struct loopuse *lu; struct loopuse *nextlu; struct edgeuse *eu; struct edgeuse *nexteu; struct vertexuse *vu; int loops_retained; NMG_CK_SHELL(s); BN_CK_TOL(bs->bs_tol); if (RTG.NMG_debug & DEBUG_VERIFY) nmg_vshell(&s->r_p->s_hd, s->r_p); /* * For each face in the shell, process all the loops in the face, * and then handle the face and all loops as a unit. */ nmg_eval_plot(bs, nmg_eval_count++); /* debug */ fu = BU_LIST_FIRST(faceuse, &s->fu_hd); while (BU_LIST_NOT_HEAD(fu, &s->fu_hd)) { NMG_CK_FACEUSE(fu); nextfu = BU_LIST_PNEXT(faceuse, fu); /* Faceuse mates will be handled at same time as OT_SAME fu */ if (fu->orientation != OT_SAME) { fu = nextfu; continue; } if (fu->fumate_p == nextfu) nextfu = BU_LIST_PNEXT(faceuse, nextfu); /* Consider this face */ NMG_CK_FACE(fu->f_p); loops_retained = 0; lu = BU_LIST_FIRST(loopuse, &fu->lu_hd); while (BU_LIST_NOT_HEAD(lu, &fu->lu_hd)) { NMG_CK_LOOPUSE(lu); nextlu = BU_LIST_PNEXT(loopuse, lu); if (lu->lumate_p == nextlu) nextlu = BU_LIST_PNEXT(loopuse, nextlu); NMG_CK_LOOP(lu->l_p); nmg_ck_lu_orientation(lu, bs->bs_tol); switch (nmg_eval_action(&lu->l_p->magic, bs)) { case BACTION_KILL: /* Kill by demoting loop to edges */ if (BU_LIST_FIRST_MAGIC(&lu->down_hd) == NMG_VERTEXUSE_MAGIC) { /* loop of single vertex */ (void)nmg_klu(lu); } else if (nmg_demote_lu(lu) == 0) { nmg_eval_plot(bs, nmg_eval_count++); /* debug */ } lu = nextlu; continue; case BACTION_RETAIN: loops_retained++; break; default: bu_bomb("nmg_eval_shell() bad BACTION\n"); } lu = nextlu; } if (RTG.NMG_debug & DEBUG_BOOLEVAL) bu_log("faceuse %p loops retained=%d\n", (void *)fu, loops_retained); if (RTG.NMG_debug & DEBUG_VERIFY) nmg_vshell(&s->r_p->s_hd, s->r_p); /* * Here, faceuse will have 0 or more loopuses still in it. * Decide the fate of the face; if the face dies, * then any remaining loops, edges, etc., will die too. */ if (BU_LIST_IS_EMPTY(&fu->lu_hd)) { if (loops_retained) bu_bomb("nmg_eval_shell() empty faceuse with retained loops?\n"); /* faceuse is empty, face & mate die */ if (RTG.NMG_debug & DEBUG_BOOLEVAL) bu_log("faceuse %p empty, kill\n", (void *)fu); nmg_kfu(fu); /* kill face & mate, dequeue from shell */ if (RTG.NMG_debug & DEBUG_VERIFY) nmg_vshell(&s->r_p->s_hd, s->r_p); nmg_eval_plot(bs, nmg_eval_count++); /* debug */ fu = nextfu; continue; } if (loops_retained <= 0) { nmg_pr_fu(fu, (char *)NULL); bu_bomb("nmg_eval_shell() non-empty faceuse, no loops retained?\n"); } fu = nextfu; } if (RTG.NMG_debug & DEBUG_VERIFY) nmg_vshell(&s->r_p->s_hd, s->r_p); /* * For each loop in the shell, process. * Each loop is either a wire-loop, or a vertex-with-self-loop. * Only consider wire loops here. */ nmg_eval_plot(bs, nmg_eval_count++); /* debug */ lu = BU_LIST_FIRST(loopuse, &s->lu_hd); while (BU_LIST_NOT_HEAD(lu, &s->lu_hd)) { NMG_CK_LOOPUSE(lu); nextlu = BU_LIST_PNEXT(loopuse, lu); if (lu->lumate_p == nextlu) nextlu = BU_LIST_PNEXT(loopuse, nextlu); if (BU_LIST_FIRST_MAGIC(&lu->down_hd) == NMG_VERTEXUSE_MAGIC) { /* ignore vertex-with-self-loop */ lu = nextlu; continue; } NMG_CK_LOOP(lu->l_p); switch (nmg_eval_action(&lu->l_p->magic, bs)) { case BACTION_KILL: /* Demote the loopuse into wire edges */ /* kill loop & mate */ if (nmg_demote_lu(lu) == 0) nmg_eval_plot(bs, nmg_eval_count++); /* debug */ lu = nextlu; continue; case BACTION_RETAIN: break; default: bu_bomb("nmg_eval_shell() bad BACTION\n"); } lu = nextlu; } if (RTG.NMG_debug & DEBUG_VERIFY) nmg_vshell(&s->r_p->s_hd, s->r_p); /* * For each wire-edge in the shell, ... */ nmg_eval_plot(bs, nmg_eval_count++); /* debug */ eu = BU_LIST_FIRST(edgeuse, &s->eu_hd); while (BU_LIST_NOT_HEAD(eu, &s->eu_hd)) { NMG_CK_EDGEUSE(eu); nexteu = BU_LIST_PNEXT(edgeuse, eu); /* may be head */ if (eu->eumate_p == nexteu) nexteu = BU_LIST_PNEXT(edgeuse, nexteu); /* Consider this edge */ NMG_CK_EDGE(eu->e_p); switch (nmg_eval_action(&eu->e_p->magic, bs)) { case BACTION_KILL: /* Demote the edegeuse (and mate) into vertices */ if (nmg_demote_eu(eu) == 0) nmg_eval_plot(bs, nmg_eval_count++); /* debug */ eu = nexteu; continue; case BACTION_RETAIN: break; default: bu_bomb("nmg_eval_shell() bad BACTION\n"); } eu = nexteu; } /* * For each lone vertex-with-self-loop, process. * Note that these are intermixed in the loop list. * Each loop is either a wire-loop, or a vertex-with-self-loop. * Only consider cases of vertex-with-self-loop here. * * This case has to be handled separately, because a wire-loop * may be demoted to a set of wire-edges above, some of which * may be retained. The non-retained wire-edges may in turn * be demoted into vertex-with-self-loop objects above, * which will be processed here. */ nmg_eval_plot(bs, nmg_eval_count++); /* debug */ lu = BU_LIST_FIRST(loopuse, &s->lu_hd); while (BU_LIST_NOT_HEAD(lu, &s->lu_hd)) { NMG_CK_LOOPUSE(lu); nextlu = BU_LIST_PNEXT(loopuse, lu); if (BU_LIST_FIRST_MAGIC(&lu->down_hd) != NMG_VERTEXUSE_MAGIC) { /* ignore any remaining wire-loops */ lu = nextlu; continue; } if (nextlu == lu->lumate_p) nextlu = BU_LIST_PNEXT(loopuse, nextlu); vu = BU_LIST_PNEXT(vertexuse, &lu->down_hd); NMG_CK_VERTEXUSE(vu); NMG_CK_VERTEX(vu->v_p); switch (nmg_eval_action(&vu->v_p->magic, bs)) { case BACTION_KILL: /* Eliminate the loopuse, and mate */ nmg_klu(lu); lu = nextlu; continue; case BACTION_RETAIN: break; default: bu_bomb("nmg_eval_shell() bad BACTION\n"); } lu = nextlu; } if (RTG.NMG_debug & DEBUG_VERIFY) nmg_vshell(&s->r_p->s_hd, s->r_p); /* * Final case: shell of a single vertexuse */ vu = s->vu_p; if (vu) { NMG_CK_VERTEXUSE(vu); NMG_CK_VERTEX(vu->v_p); switch (nmg_eval_action(&vu->v_p->magic, bs)) { case BACTION_KILL: nmg_kvu(vu); nmg_eval_plot(bs, nmg_eval_count++); /* debug */ s->vu_p = (struct vertexuse *)0; /* sanity */ break; case BACTION_RETAIN: break; default: bu_bomb("nmg_eval_shell() bad BACTION\n"); } } if (RTG.NMG_debug & DEBUG_VERIFY) nmg_vshell(&s->r_p->s_hd, s->r_p); nmg_eval_plot(bs, nmg_eval_count++); /* debug */ }
void process_non_light(struct model *m) { /* static due to bu exception handling */ static struct shell *s; static struct shell *next_s; static struct faceuse *fu; static struct faceuse *next_fu; static struct loopuse *lu; static struct nmgregion *reg; /* triangulate any faceuses with holes */ for ( BU_LIST_FOR( reg, nmgregion, &m->r_hd ) ) { NMG_CK_REGION( reg ); s = BU_LIST_FIRST( shell, ®->s_hd ); while ( BU_LIST_NOT_HEAD( s, ®->s_hd ) ) { NMG_CK_SHELL( s ); next_s = BU_LIST_PNEXT( shell, &s->l ); fu = BU_LIST_FIRST( faceuse, &s->fu_hd ); while ( BU_LIST_NOT_HEAD( &fu->l, &s->fu_hd ) ) { int shell_is_dead=0; NMG_CK_FACEUSE( fu ); next_fu = BU_LIST_PNEXT( faceuse, &fu->l ); if ( fu->orientation != OT_SAME ) { fu = next_fu; continue; } if ( fu->fumate_p == next_fu ) { /* make sure next_fu is not the mate of fu */ next_fu = BU_LIST_PNEXT( faceuse, &next_fu->l ); } /* check if this faceuse has any holes */ for ( BU_LIST_FOR( lu, loopuse, &fu->lu_hd ) ) { NMG_CK_LOOPUSE( lu ); if ( lu->orientation == OT_OPPOSITE ) { /* this is a hole, so * triangulate the faceuse */ if ( !BU_SETJUMP ) { /* try */ if ( nmg_triangulate_fu( fu, &tol ) ) { if ( nmg_kfu( fu ) ) { (void) nmg_ks( s ); shell_is_dead = 1; } } } else { /* catch */ bu_log( "A face has failed triangulation!\n" ); if ( next_fu == fu->fumate_p ) next_fu = BU_LIST_PNEXT( faceuse, &next_fu->l ); if ( nmg_kfu( fu ) ) { (void) nmg_ks( s ); shell_is_dead = 1; } } BU_UNSETJUMP; break; } } if ( shell_is_dead ) break; fu = next_fu; } s = next_s; } } }
static void nmg_to_acad(struct nmgregion *r, const struct db_full_path *pathp, int region_id) { struct model *m; struct shell *s; struct vertex *v; struct bu_ptbl verts; char *region_name; int numverts = 0; /* Number of vertices to output */ int numtri = 0; /* Number of triangles to output */ int tricount = 0; /* Triangle number */ int i; NMG_CK_REGION(r); RT_CK_FULL_PATH(pathp); region_name = db_path_to_string(pathp); m = r->m_p; NMG_CK_MODEL(m); /* triangulate model */ nmg_triangulate_model(m, &tol); /* list all vertices in result */ nmg_vertex_tabulate(&verts, &r->l.magic); /* Get number of vertices */ numverts = BU_PTBL_END (&verts); /* BEGIN CHECK SECTION */ /* Check vertices */ for (i=0; i<numverts; i++) { v = (struct vertex *)BU_PTBL_GET(&verts, i); NMG_CK_VERTEX(v); } /* Check triangles */ for (BU_LIST_FOR(s, shell, &r->s_hd)) { struct faceuse *fu; NMG_CK_SHELL(s); for (BU_LIST_FOR(fu, faceuse, &s->fu_hd)) { struct loopuse *lu; NMG_CK_FACEUSE(fu); if (fu->orientation != OT_SAME) continue; for (BU_LIST_FOR(lu, loopuse, &fu->lu_hd)) { struct edgeuse *eu; int vert_count=0; NMG_CK_LOOPUSE(lu); if (BU_LIST_FIRST_MAGIC(&lu->down_hd) != NMG_EDGEUSE_MAGIC) continue; /* check vertex numbers for each triangle */ for (BU_LIST_FOR(eu, edgeuse, &lu->down_hd)) { NMG_CK_EDGEUSE(eu); v = eu->vu_p->v_p; NMG_CK_VERTEX(v); vert_count++; i = bu_ptbl_locate(&verts, (long *)v); if (i < 0) { bu_ptbl_free(&verts); bu_free(region_name, "region name"); bu_log("Vertex from eu %p is not in nmgregion %p\n", (void *)eu, (void *)r); bu_exit(1, "ERROR: Triangle vertex was not located\n"); } } if (vert_count > 3) { bu_ptbl_free(&verts); bu_free(region_name, "region name"); bu_log("lu %p has too many (%d) vertices!\n", (void *)lu, vert_count); bu_exit(1, "ERROR: LU is not a triangle\n"); } else if (vert_count < 3) continue; numtri++; } } } /* END CHECK SECTION */ /* Write pertinent info for this region */ fprintf(fp, "%s\n", (region_name+1)); /* No mirror plane */ fprintf(fp, "%d\n", 0); /* Number of vertices */ fprintf(fp, "%d\n", numverts); /* Write numverts, then vertices */ for (i=0; i<numverts; i++) { v = (struct vertex *)BU_PTBL_GET(&verts, i); NMG_CK_VERTEX(v); if (inches) fprintf(fp, "%f %f %f\n", V3ARGSIN(v->vg_p->coord)); else fprintf(fp, "%f %f %f\n", V3ARGS(v->vg_p->coord)); } /* Number of sub-parts (always 1 with BRL-CAD) */ fprintf(fp, "%d\n", 1); /* Write out name again */ fprintf(fp, "%s\n", (region_name+1)); /* Number of triangles, number of vert/tri (3) */ fprintf(fp, "%d %d\n", numtri, 3); /* output triangles */ for (BU_LIST_FOR(s, shell, &r->s_hd)) { struct faceuse *fu; NMG_CK_SHELL(s); for (BU_LIST_FOR(fu, faceuse, &s->fu_hd)) { struct loopuse *lu; NMG_CK_FACEUSE(fu); if (fu->orientation != OT_SAME) continue; for (BU_LIST_FOR(lu, loopuse, &fu->lu_hd)) { struct edgeuse *eu; int vert_count=0; NMG_CK_LOOPUSE(lu); if (BU_LIST_FIRST_MAGIC(&lu->down_hd) != NMG_EDGEUSE_MAGIC) continue; /* list vertex numbers for each triangle */ for (BU_LIST_FOR(eu, edgeuse, &lu->down_hd)) { NMG_CK_EDGEUSE(eu); v = eu->vu_p->v_p; NMG_CK_VERTEX(v); vert_count++; i = bu_ptbl_locate(&verts, (long *)v); if (i < 0) { bu_ptbl_free(&verts); bu_log("Vertex from eu %p is not in nmgregion %p\n", (void *)eu, (void *)r); bu_free(region_name, "region name"); bu_exit(1, "ERROR: Can't find vertex in list!\n"); } fprintf(fp, " %d", i+1); } /* Output other info. for triangle ICOAT, component#, facet# */ /* Map Icoat from material table later */ /* fprintf(fp, "%s icomp=%d material=%d:\n", (region_name+1), region_id);*/ fprintf(fp, " %d %d %d\n", 0, region_id, ++tricount); if (vert_count > 3) { bu_ptbl_free(&verts); bu_free(region_name, "region name"); bu_log("lu %p has %d vertices!\n", (void *)lu, vert_count); bu_exit(1, "ERROR: LU is not a triangle\n"); } else if (vert_count < 3) continue; tot_polygons++; } } } /* regions_converted++; printf("Processed region %s\n", region_name); printf("Regions attempted = %d Regions done = %d\n", regions_tried, regions_converted); fflush(stdout); */ bu_ptbl_free(&verts); bu_free(region_name, "region name"); }
/* routine to output the faceted NMG representation of a BRL-CAD region */ static void output_nmg(struct nmgregion *r, const struct db_full_path *pathp, int UNUSED(region_id), int UNUSED(material_id)) { struct model *m; struct shell *s; struct vertex *v; char *region_name; NMG_CK_REGION(r); RT_CK_FULL_PATH(pathp); region_name = db_path_to_string(pathp); m = r->m_p; NMG_CK_MODEL(m); /* triangulate model */ nmg_triangulate_model(m, &tol); /* Output triangles */ if (verbose) { printf("Convert these triangles to your format for region %s\n", region_name); } else { printf("Converted %s\n", region_name); } for (BU_LIST_FOR(s, shell, &r->s_hd)) { struct faceuse *fu; NMG_CK_SHELL(s); for (BU_LIST_FOR(fu, faceuse, &s->fu_hd)) { struct loopuse *lu; /* vect_t facet_normal; */ NMG_CK_FACEUSE(fu); if (fu->orientation != OT_SAME) continue; /* Grab the face normal if needed */ /* NMG_GET_FU_NORMAL(facet_normal, fu); */ for (BU_LIST_FOR(lu, loopuse, &fu->lu_hd)) { struct edgeuse *eu; NMG_CK_LOOPUSE(lu); if (BU_LIST_FIRST_MAGIC(&lu->down_hd) != NMG_EDGEUSE_MAGIC) continue; /* loop through the edges in this loop (facet) */ if (verbose) printf("\tfacet:\n"); for (BU_LIST_FOR(eu, edgeuse, &lu->down_hd)) { NMG_CK_EDGEUSE(eu); v = eu->vu_p->v_p; NMG_CK_VERTEX(v); if (verbose) printf("\t\t(%g %g %g)\n", V3ARGS(v->vg_p->coord)); } tot_polygons++; } } } bu_free(region_name, "region name"); }
static size_t show_dangling_edges(struct ged *gedp, const uint32_t *magic_p, const char *name, int out_type) { FILE *plotfp = NULL; const char *manifolds = NULL; const struct edgeuse *eur; int done; point_t pt1, pt2; size_t i, cnt; struct bn_vlblock *vbp = NULL; struct bu_list *vhead = NULL; struct bu_ptbl faces; struct bu_vls plot_file_name = BU_VLS_INIT_ZERO; struct edgeuse *eu = NULL; struct face *fp = NULL; struct faceuse *fu, *fu1, *fu2; struct faceuse *newfu = NULL; struct loopuse *lu = NULL; /* out_type: 0 = none, 1 = show, 2 = plot */ if (out_type < 0 || out_type > 2) { bu_log("Internal error, open edge test failed.\n"); return 0; } if (out_type == 1) { vbp = rt_vlblock_init(); vhead = rt_vlblock_find(vbp, 0xFF, 0xFF, 0x00); } bu_ptbl_init(&faces, 64, "faces buffer"); nmg_face_tabulate(&faces, magic_p); cnt = 0; for (i = 0; i < (size_t)BU_PTBL_END(&faces) ; i++) { fp = (struct face *)BU_PTBL_GET(&faces, i); NMG_CK_FACE(fp); fu = fu1 = fp->fu_p; NMG_CK_FACEUSE(fu1); fu2 = fp->fu_p->fumate_p; NMG_CK_FACEUSE(fu2); done = 0; while (!done) { NMG_CK_FACEUSE(fu); for (BU_LIST_FOR(lu, loopuse, &fu->lu_hd)) { NMG_CK_LOOPUSE(lu); if (BU_LIST_FIRST_MAGIC(&lu->down_hd) == NMG_EDGEUSE_MAGIC) { for (BU_LIST_FOR(eu, edgeuse, &lu->down_hd)) { NMG_CK_EDGEUSE(eu); eur = nmg_radial_face_edge_in_shell(eu); newfu = eur->up.lu_p->up.fu_p; while (manifolds && NMG_MANIFOLDS(manifolds, newfu) & NMG_2MANIFOLD && eur != eu->eumate_p) { eur = nmg_radial_face_edge_in_shell(eur->eumate_p); newfu = eur->up.lu_p->up.fu_p; } if (eur == eu->eumate_p) { VMOVE(pt1, eu->vu_p->v_p->vg_p->coord); VMOVE(pt2, eu->eumate_p->vu_p->v_p->vg_p->coord); if (out_type == 1) { BN_ADD_VLIST(vbp->free_vlist_hd, vhead, pt1, BN_VLIST_LINE_MOVE); BN_ADD_VLIST(vbp->free_vlist_hd, vhead, pt2, BN_VLIST_LINE_DRAW); } else if (out_type == 2) { if (!plotfp) { bu_vls_sprintf(&plot_file_name, "%s.%p.pl", name, (void *)magic_p); if ((plotfp = fopen(bu_vls_addr(&plot_file_name), "wb")) == (FILE *)NULL) { bu_vls_free(&plot_file_name); bu_log("Error, unable to create plot file (%s), open edge test failed.\n", bu_vls_addr(&plot_file_name)); return 0; } } pdv_3line(plotfp, pt1, pt2); } cnt++; } } } } if (fu == fu1) fu = fu2; if (fu == fu2) done = 1; }; } if (out_type == 1) { /* Add overlay */ _ged_cvt_vlblock_to_solids(gedp, vbp, (char *)name, 0); rt_vlblock_free(vbp); bu_log("Showing open edges...\n"); } else if (out_type == 2) { if (plotfp) { (void)fclose(plotfp); bu_log("Wrote plot file (%s)\n", bu_vls_addr(&plot_file_name)); bu_vls_free(&plot_file_name); } } bu_ptbl_free(&faces); return cnt; }
int read_faces(struct model *m, FILE *fgeom) { int nverts, nfaces, nedges; int i, j, fail=0; fastf_t *pts; struct vertex **verts; struct faceuse **outfaceuses; struct nmgregion *r; struct shell *s; size_t ret; /* Get numbers of vertices and faces, and grab the appropriate amount of memory */ if (fscanf(fgeom, "%d %d %d", &nverts, &nfaces, &nedges) != 3) bu_exit(1, "Cannot read number of vertices, faces, edges.\n"); pts = (fastf_t *) bu_malloc(sizeof(fastf_t) * 3 * nverts, "points list"); verts = (struct vertex **) bu_malloc(sizeof(struct vertex *) * nverts, "vertices"); outfaceuses = (struct faceuse **) bu_malloc(sizeof(struct faceuse *) * nfaces, "faceuses"); /* Read in vertex geometry, store in geometry list */ for (i = 0; i < nverts; i++) { double scan[3]; if (fscanf(fgeom, "%lf %lf %lf", &scan[0], &scan[1], &scan[2]) != 3) { bu_exit(1, "Not enough data points in geometry file.\n"); } pts[3*i] = scan[0]; pts[3*i+1] = scan[1]; pts[3*i+2] = scan[2]; verts[i] = (struct vertex *) 0; ret = fscanf(fgeom, "%*[^\n]"); if (ret > 0) bu_log("unknown parsing error\n"); } r = nmg_mrsv(m); /* Make region, empty shell, vertex. */ s = BU_LIST_FIRST(shell, &r->s_hd); for (i = 0; i < nfaces; i++) { /* Read in each of the faces */ struct vertex **vlist; int *pinds; if (fscanf(fgeom, "%d", &nedges) != 1) { bu_exit(1, "Not enough faces in geometry file.\n"); } /* Grab memory for list for this face. */ vlist = (struct vertex **) bu_malloc(sizeof(struct vertex *) * nedges, "vertex list"); pinds = (int *) bu_malloc(sizeof(int) * nedges, "point indices"); for (j = 0; j < nedges; j++) { /* Read list of point indices. */ if (fscanf(fgeom, "%d", &pinds[j]) != 1) { bu_exit(1, "Not enough points on face.\n"); } vlist[j] = verts[pinds[j]-1]; } outfaceuses[i] = nmg_cface(s, vlist, nedges); /* Create face. */ NMG_CK_FACEUSE(outfaceuses[i]); for (j = 0; j < nedges; j++) /* Save (possibly) newly created vertex structs. */ verts[pinds[j]-1] = vlist[j]; ret = fscanf(fgeom, "%*[^\n]"); if (ret > 0) bu_log("unknown parsing error\n"); bu_free((char *)vlist, "vertext list"); bu_free((char *)pinds, "point indices"); } for (i = 0; i < nverts; i++) if (verts[i] != 0) nmg_vertex_gv(verts[i], &pts[3*i]); else fprintf(stderr, "Warning: vertex %d unused.\n", i+1); for (i = 0; i < nfaces; i++) { plane_t pl; fprintf(stderr, "planeeqning face %d.\n", i); if ( nmg_loop_plane_area( BU_LIST_FIRST( loopuse, &outfaceuses[i]->lu_hd ), pl ) < 0.0 ) fail = 1; else nmg_face_g( outfaceuses[i], pl ); } if (fail) return -1; nmg_gluefaces(outfaceuses, nfaces, &tol); nmg_region_a(r, &tol); bu_free((char *)pts, "points list"); return 0; }
/** * Make all the edgeuses around eu2's edge to refer to eu1's edge, * taking care to organize them into the proper angular orientation, * so that the attached faces are correctly arranged radially * around the edge. * * This depends on both edges being part of face loops, * with vertex and face geometry already associated. * * The two edgeuses being joined might well be from separate shells, * so the issue of preserving (simple) faceuse orientation parity * (SAME, OPPOSITE, OPPOSITE, SAME, ...) * can't be used here -- that only applies to faceuses from the same shell. * * Some of the edgeuses around both edges may be wires. * * Call to nmg_check_radial at end has been deleted. * Note that after two radial EU's have been joined * a third cannot be joined to them without creating * unclosed space that nmg_check_radial will find. */ void nmg_radial_join_eu(struct edgeuse *eu1, struct edgeuse *eu2, const struct bn_tol *tol) { NMG_CK_EDGEUSE(eu1); NMG_CK_EDGEUSE(eu1->radial_p); NMG_CK_EDGEUSE(eu1->eumate_p); NMG_CK_EDGEUSE(eu2); NMG_CK_EDGEUSE(eu2->radial_p); NMG_CK_EDGEUSE(eu2->eumate_p); BN_CK_TOL(tol); if (eu1->e_p == eu2->e_p) return; if (!NMG_ARE_EUS_ADJACENT(eu1, eu2)) bu_bomb("nmg_radial_join_eu() edgeuses don't share vertices.\n"); if (eu1->vu_p->v_p == eu1->eumate_p->vu_p->v_p) bu_bomb("nmg_radial_join_eu(): 0 length edge (topology)\n"); if (bn_pt3_pt3_equal(eu1->vu_p->v_p->vg_p->coord, eu1->eumate_p->vu_p->v_p->vg_p->coord, tol)) { bu_log("vertices should have been fused:\n"); bu_log("\tvertex %p (%.12f %.12f %.12f)\n", (void *)eu1->vu_p->v_p, V3ARGS(eu1->vu_p->v_p->vg_p->coord)); bu_log("\tvertex %p (%.12f %.12f %.12f)\n", (void *)eu1->eumate_p->vu_p->v_p, V3ARGS(eu1->eumate_p->vu_p->v_p->vg_p->coord)); bu_bomb("nmg_radial_join_eu(): 0 length edge (geometry)\n"); } #if 1 nmg_radial_join_eu_NEW(eu1, eu2, tol); return; #else /* Ensure faces are of same orientation, if both eu's have faces */ fu1 = nmg_find_fu_of_eu(eu1); fu2 = nmg_find_fu_of_eu(eu2); if (fu1 && fu2) { if (fu1->orientation != fu2->orientation) { eu2 = eu2->eumate_p; fu2 = nmg_find_fu_of_eu(eu2); if (fu1->orientation != fu2->orientation) bu_bomb("nmg_radial_join_eu(): Cannot find matching orientations for faceuses\n"); } } /* XXX This angle-based algorithm can't handle snurb faces! */ if (fu1 && fu1->f_p->g.magic_p && *fu1->f_p->g.magic_p == NMG_FACE_G_SNURB_MAGIC) return; if (fu2 && fu2->f_p->g.magic_p && *fu2->f_p->g.magic_p == NMG_FACE_G_SNURB_MAGIC) return; /* Construct local coordinate system for this edge, * so all angles can be measured relative to a common reference. */ nmg_eu_2vecs_perp(xvec, yvec, zvec, original_eu1, tol); if (RTG.NMG_debug & DEBUG_MESH_EU) { bu_log("nmg_radial_join_eu(eu1=%p, eu2=%p) e1=%p, e2=%p\n", (void *)eu1, (void *)eu2, (void *)eu1->e_p, (void *)eu2->e_p); nmg_euprint("\tJoining", eu1); nmg_euprint("\t to", eu2); bu_log("Faces around eu1:\n"); nmg_pr_fu_around_eu_vecs(eu1, xvec, yvec, zvec, tol); bu_log("Faces around eu2:\n"); nmg_pr_fu_around_eu_vecs(eu2, xvec, yvec, zvec, tol); } best_eg = nmg_pick_best_edge_g(eu1, eu2, tol); for (iteration1=0; eu2 && iteration1 < 10000; iteration1++) { int code = 0; struct edgeuse *first_eu1 = eu1; int wire_skip = 0; /* Resume where we left off from last eu2 insertion */ /* find a place to insert eu2 around eu1's edge */ for (iteration2=0; iteration2 < 10000; iteration2++) { struct faceuse *fur; abs1 = abs2 = absr = -M_2PI; eur = eu1->radial_p; NMG_CK_EDGEUSE(eur); fu2 = nmg_find_fu_of_eu(eu2); if (fu2 == (struct faceuse *)NULL) { /* eu2 is a wire, it can go anywhere */ bu_log("eu2=%p is a wire, insert after eu1=%p\n", (void *)eu2, (void *)eu1); goto insert; } fu1 = nmg_find_fu_of_eu(eu1); if (fu1 == (struct faceuse *)NULL) { /* eu1 is a wire, skip on to real face eu */ bu_log("eu1=%p is a wire, skipping on\n", (void *)eu1); wire_skip++; goto cont; } fur = nmg_find_fu_of_eu(eur); while (fur == (struct faceuse *)NULL) { /* eur is wire, advance eur */ bu_log("eur=%p is a wire, advancing to non-wire eur\n", (void *)eur); eur = eur->eumate_p->radial_p; wire_skip++; if (eur == eu1->eumate_p) { bu_log("went all the way around\n"); /* Went all the way around */ goto insert; } fur = nmg_find_fu_of_eu(eur); } NMG_CK_FACEUSE(fu1); NMG_CK_FACEUSE(fu2); NMG_CK_FACEUSE(fur); /* * Can't just check for shared fg here, * the angle changes by +/- 180 degrees, * depending on which side of the eu the loop is on * along this edge. */ abs1 = nmg_measure_fu_angle(eu1, xvec, yvec, zvec); abs2 = nmg_measure_fu_angle(eu2, xvec, yvec, zvec); absr = nmg_measure_fu_angle(eur, xvec, yvec, zvec); if (RTG.NMG_debug & DEBUG_MESH_EU) { bu_log(" abs1=%g, abs2=%g, absr=%g\n", abs1*RAD2DEG, abs2*RAD2DEG, absr*RAD2DEG); } /* If abs1 == absr, warn about unfused faces, and skip. */ if (NEAR_EQUAL(abs1, absr, 1.0e-8)) { if (fu1->f_p->g.plane_p == fur->f_p->g.plane_p) { /* abs1 == absr, faces are fused, don't insert here. */ if (RTG.NMG_debug & DEBUG_MESH_EU) { bu_log("fu1 and fur share face geometry %p (flip1=%d, flip2=%d), skip\n", (void *)fu1->f_p->g.plane_p, fu1->f_p->flip, fur->f_p->flip); } goto cont; } bu_log("nmg_radial_join_eu: WARNING 2 faces should have been fused, may be ambiguous.\n abs1=%e, absr=%e, asb2=%e\n", abs1*RAD2DEG, absr*RAD2DEG, abs2*RAD2DEG); bu_log(" fu1=%p, f1=%p, f1->flip=%d, fg1=%p\n", (void *)fu1, (void *)fu1->f_p, fu1->f_p->flip, (void *)fu1->f_p->g.plane_p); bu_log(" fu2=%p, f2=%p, f2->flip=%d, fg2=%p\n", (void *)fu2, (void *)fu2->f_p, fu2->f_p->flip, (void *)fu2->f_p->g.plane_p); bu_log(" fur=%p, fr=%p, fr->flip=%d, fgr=%p\n", (void *)fur, (void *)fur->f_p, fur->f_p->flip, (void *)fur->f_p->g.plane_p); PLPRINT(" fu1", fu1->f_p->g.plane_p->N); PLPRINT(" fu2", fu2->f_p->g.plane_p->N); PLPRINT(" fur", fur->f_p->g.plane_p->N); { int debug = RTG.NMG_debug; if (nmg_two_face_fuse(fu1->f_p, fur->f_p, tol) == 0) bu_bomb("faces didn't fuse?\n"); RTG.NMG_debug = debug; } bu_log(" nmg_radial_join_eu() skipping this eu\n"); goto cont; } /* * If abs1 < abs2 < absr * (taking into account 360 wrap), * then insert face here. * Special handling if abs1==abs2 or abs2==absr. */ code = nmg_is_angle_in_wedge(abs1, absr, abs2); if (RTG.NMG_debug & DEBUG_MESH_EU) bu_log(" code=%d %s\n", code, (code!=0)?"INSERT_HERE":"skip"); if (code > 0) break; if (code == -1) { /* absr == abs2 */ break; } if (code <= -2) { /* abs1 == abs2 */ break; } cont: /* If eu1 is only one pair of edgeuses, done */ if (eu1 == eur->eumate_p) break; eu1 = eur->eumate_p; if (eu1 == first_eu1) { /* If all eu's were wires, here is fine */ if (wire_skip >= iteration2) break; /* Nope, something bad happened */ bu_bomb("nmg_radial_join_eu(): went full circle, no face insertion point.\n"); break; } } if (iteration2 >= 10000) { bu_bomb("nmg_radial_join_eu: infinite loop (2)\n"); } /* find the next use of the edge eu2 is on. If eu2 and its * mate are the last uses of the edge, there will be no next * edgeuse to move. (Loop termination condition). */ insert: nexteu = eu2->radial_p; if (nexteu == eu2->eumate_p) nexteu = (struct edgeuse *)NULL; /* because faces are always created with counter-clockwise * exterior loops and clockwise interior loops, * radial edgeuses IN THE SAME SHELL will never point in * the same direction or share the same vertex. We thus make * sure that eu2 is an edgeuse which might be radial to eu1 * XXX Need to look back for last eu IN THE SHELL OF eu2. * XXX Even this isn't good enough, as we may be inserting * XXX something new _after_ that last starting point. */ eus = eu1; while (nmg_find_s_of_eu(eus) != nmg_find_s_of_eu(eu2)) { eus = eus->eumate_p->radial_p; if (eus == eu1) break; /* full circle */ } if (eu2->vu_p->v_p == eus->vu_p->v_p) eu2 = eu2->eumate_p; if (RTG.NMG_debug & DEBUG_MESH_EU) { bu_log(" Inserting. code=%d\n", code); bu_log("joining eu1=%p eu2=%p with abs1=%g, absr=%g\n", (void *)eu1, (void *)eu2, abs1*RAD2DEG, absr*RAD2DEG); } /* * Make eu2 radial to eu1. * This should insert eu2 between eu1 and eu1->radial_p * (which may be less far around than eur, but that's OK). * This does NOT change the edge geometry pointer. */ nmg_je(eu1, eu2); if (RTG.NMG_debug & DEBUG_MESH_EU) { bu_log("After nmg_je(), faces around original_eu1 are:\n"); nmg_pr_fu_around_eu_vecs(original_eu1, xvec, yvec, zvec, tol); } /* Proceed to the next source edgeuse */ eu2 = nexteu; } if (iteration1 >= 10000) bu_bomb("nmg_radial_join_eu: infinite loop (1)\n"); NMG_CK_EDGEUSE(original_eu1); /* * Make another pass, ensuring that all edgeuses are using the * "best_eg" line. */ eu1 = original_eu1; for (;;) { if (eu1->g.lseg_p != best_eg) { nmg_use_edge_g(eu1, &best_eg->l.magic); } eu1 = eu1->eumate_p->radial_p; if (eu1 == original_eu1) break; } if (RTG.NMG_debug & DEBUG_MESH_EU) bu_log("nmg_radial_join_eu: END\n"); #endif }
/* * Default keypoint in model space is established in "pt". Returns * GED_ERROR if unable to determine a keypoint, otherwise returns * GED_OK. */ int _ged_get_solid_keypoint(struct ged *const gedp, fastf_t *const pt, const struct rt_db_internal *const ip, const fastf_t *const mat) { point_t mpt; RT_CK_DB_INTERNAL(ip); switch (ip->idb_type) { case ID_CLINE: { struct rt_cline_internal *cli = (struct rt_cline_internal *)ip->idb_ptr; RT_CLINE_CK_MAGIC(cli); VMOVE(mpt, cli->v); break; } case ID_PARTICLE: { struct rt_part_internal *part = (struct rt_part_internal *)ip->idb_ptr; RT_PART_CK_MAGIC(part); VMOVE(mpt, part->part_V); break; } case ID_PIPE: { struct rt_pipe_internal *pipeip; struct wdb_pipept *pipe_seg; pipeip = (struct rt_pipe_internal *)ip->idb_ptr; RT_PIPE_CK_MAGIC(pipeip); pipe_seg = BU_LIST_FIRST(wdb_pipept, &pipeip->pipe_segs_head); VMOVE(mpt, pipe_seg->pp_coord); break; } case ID_METABALL: { struct rt_metaball_internal *metaball = (struct rt_metaball_internal *)ip->idb_ptr; struct wdb_metaballpt *metaballpt; RT_METABALL_CK_MAGIC(metaball); VSETALL(mpt, 0.0); metaballpt = BU_LIST_FIRST(wdb_metaballpt, &metaball->metaball_ctrl_head); VMOVE(mpt, metaballpt->coord); break; } case ID_ARBN: { struct rt_arbn_internal *arbn = (struct rt_arbn_internal *)ip->idb_ptr; size_t i, j, k; int good_vert = 0; RT_ARBN_CK_MAGIC(arbn); for (i = 0; i < arbn->neqn; i++) { for (j = i + 1; j < arbn->neqn; j++) { for (k = j + 1; k < arbn->neqn; k++) { if (!bn_mkpoint_3planes(mpt, arbn->eqn[i], arbn->eqn[j], arbn->eqn[k])) { size_t l; good_vert = 1; for (l = 0; l < arbn->neqn; l++) { if (l == i || l == j || l == k) continue; if (DIST_PT_PLANE(mpt, arbn->eqn[l]) > gedp->ged_wdbp->wdb_tol.dist) { good_vert = 0; break; } } if (good_vert) break; } } if (good_vert) break; } if (good_vert) break; } break; } case ID_EBM: { struct rt_ebm_internal *ebm = (struct rt_ebm_internal *)ip->idb_ptr; point_t pnt; RT_EBM_CK_MAGIC(ebm); VSETALL(pnt, 0.0); MAT4X3PNT(mpt, ebm->mat, pnt); break; } case ID_BOT: { struct rt_bot_internal *bot = (struct rt_bot_internal *)ip->idb_ptr; VMOVE(mpt, bot->vertices); break; } case ID_DSP: { struct rt_dsp_internal *dsp = (struct rt_dsp_internal *)ip->idb_ptr; point_t pnt; RT_DSP_CK_MAGIC(dsp); VSETALL(pnt, 0.0); MAT4X3PNT(mpt, dsp->dsp_stom, pnt); break; } case ID_HF: { struct rt_hf_internal *hf = (struct rt_hf_internal *)ip->idb_ptr; RT_HF_CK_MAGIC(hf); VMOVE(mpt, hf->v); break; } case ID_VOL: { struct rt_vol_internal *vol = (struct rt_vol_internal *)ip->idb_ptr; point_t pnt; RT_VOL_CK_MAGIC(vol); VSETALL(pnt, 0.0); MAT4X3PNT(mpt, vol->mat, pnt); break; } case ID_HALF: { struct rt_half_internal *haf = (struct rt_half_internal *)ip->idb_ptr; RT_HALF_CK_MAGIC(haf); VSCALE(mpt, haf->eqn, haf->eqn[H]); break; } case ID_ARB8: { struct rt_arb_internal *arb = (struct rt_arb_internal *)ip->idb_ptr; RT_ARB_CK_MAGIC(arb); VMOVE(mpt, arb->pt[0]); break; } case ID_ELL: case ID_SPH: { struct rt_ell_internal *ell = (struct rt_ell_internal *)ip->idb_ptr; RT_ELL_CK_MAGIC(ell); VMOVE(mpt, ell->v); break; } case ID_SUPERELL: { struct rt_superell_internal *superell = (struct rt_superell_internal *)ip->idb_ptr; RT_SUPERELL_CK_MAGIC(superell); VMOVE(mpt, superell->v); break; } case ID_TOR: { struct rt_tor_internal *tor = (struct rt_tor_internal *)ip->idb_ptr; RT_TOR_CK_MAGIC(tor); VMOVE(mpt, tor->v); break; } case ID_TGC: case ID_REC: { struct rt_tgc_internal *tgc = (struct rt_tgc_internal *)ip->idb_ptr; RT_TGC_CK_MAGIC(tgc); VMOVE(mpt, tgc->v); break; } case ID_GRIP: { struct rt_grip_internal *gip = (struct rt_grip_internal *)ip->idb_ptr; RT_GRIP_CK_MAGIC(gip); VMOVE(mpt, gip->center); break; } case ID_ARS: { struct rt_ars_internal *ars = (struct rt_ars_internal *)ip->idb_ptr; RT_ARS_CK_MAGIC(ars); VMOVE(mpt, &ars->curves[0][0]); break; } case ID_RPC: { struct rt_rpc_internal *rpc = (struct rt_rpc_internal *)ip->idb_ptr; RT_RPC_CK_MAGIC(rpc); VMOVE(mpt, rpc->rpc_V); break; } case ID_RHC: { struct rt_rhc_internal *rhc = (struct rt_rhc_internal *)ip->idb_ptr; RT_RHC_CK_MAGIC(rhc); VMOVE(mpt, rhc->rhc_V); break; } case ID_EPA: { struct rt_epa_internal *epa = (struct rt_epa_internal *)ip->idb_ptr; RT_EPA_CK_MAGIC(epa); VMOVE(mpt, epa->epa_V); break; } case ID_EHY: { struct rt_ehy_internal *ehy = (struct rt_ehy_internal *)ip->idb_ptr; RT_EHY_CK_MAGIC(ehy); VMOVE(mpt, ehy->ehy_V); break; } case ID_HYP: { struct rt_hyp_internal *hyp = (struct rt_hyp_internal *)ip->idb_ptr; RT_HYP_CK_MAGIC(hyp); VMOVE(mpt, hyp->hyp_Vi); break; } case ID_ETO: { struct rt_eto_internal *eto = (struct rt_eto_internal *)ip->idb_ptr; RT_ETO_CK_MAGIC(eto); VMOVE(mpt, eto->eto_V); break; } case ID_POLY: { struct rt_pg_face_internal *_poly; struct rt_pg_internal *pg = (struct rt_pg_internal *)ip->idb_ptr; RT_PG_CK_MAGIC(pg); _poly = pg->poly; VMOVE(mpt, _poly->verts); break; } case ID_SKETCH: { struct rt_sketch_internal *skt = (struct rt_sketch_internal *)ip->idb_ptr; RT_SKETCH_CK_MAGIC(skt); VMOVE(mpt, skt->V); break; } case ID_EXTRUDE: { struct rt_extrude_internal *extr = (struct rt_extrude_internal *)ip->idb_ptr; RT_EXTRUDE_CK_MAGIC(extr); if (extr->skt && extr->skt->verts) { VJOIN2(mpt, extr->V, extr->skt->verts[0][0], extr->u_vec, extr->skt->verts[0][1], extr->v_vec); } else { VMOVE(mpt, extr->V); } break; } case ID_NMG: { struct vertex *v; struct vertexuse *vu; struct edgeuse *eu; struct loopuse *lu; struct faceuse *fu; struct shell *s; struct nmgregion *r; struct model *m = (struct model *) ip->idb_ptr; NMG_CK_MODEL(m); /* set default first */ VSETALL(mpt, 0.0); if (BU_LIST_IS_EMPTY(&m->r_hd)) break; r = BU_LIST_FIRST(nmgregion, &m->r_hd); if (!r) break; NMG_CK_REGION(r); if (BU_LIST_IS_EMPTY(&r->s_hd)) break; s = BU_LIST_FIRST(shell, &r->s_hd); if (!s) break; NMG_CK_SHELL(s); if (BU_LIST_IS_EMPTY(&s->fu_hd)) fu = (struct faceuse *)NULL; else fu = BU_LIST_FIRST(faceuse, &s->fu_hd); if (fu) { NMG_CK_FACEUSE(fu); lu = BU_LIST_FIRST(loopuse, &fu->lu_hd); NMG_CK_LOOPUSE(lu); if (BU_LIST_FIRST_MAGIC(&lu->down_hd) == NMG_EDGEUSE_MAGIC) { eu = BU_LIST_FIRST(edgeuse, &lu->down_hd); NMG_CK_EDGEUSE(eu); NMG_CK_VERTEXUSE(eu->vu_p); v = eu->vu_p->v_p; } else { vu = BU_LIST_FIRST(vertexuse, &lu->down_hd); NMG_CK_VERTEXUSE(vu); v = vu->v_p; } NMG_CK_VERTEX(v); if (!v->vg_p) break; VMOVE(mpt, v->vg_p->coord); break; } if (BU_LIST_IS_EMPTY(&s->lu_hd)) lu = (struct loopuse *)NULL; else lu = BU_LIST_FIRST(loopuse, &s->lu_hd); if (lu) { NMG_CK_LOOPUSE(lu); if (BU_LIST_FIRST_MAGIC(&lu->down_hd) == NMG_EDGEUSE_MAGIC) { eu = BU_LIST_FIRST(edgeuse, &lu->down_hd); NMG_CK_EDGEUSE(eu); NMG_CK_VERTEXUSE(eu->vu_p); v = eu->vu_p->v_p; } else { vu = BU_LIST_FIRST(vertexuse, &lu->down_hd); NMG_CK_VERTEXUSE(vu); v = vu->v_p; } NMG_CK_VERTEX(v); if (!v->vg_p) break; VMOVE(mpt, v->vg_p->coord); break; } if (BU_LIST_IS_EMPTY(&s->eu_hd)) eu = (struct edgeuse *)NULL; else eu = BU_LIST_FIRST(edgeuse, &s->eu_hd); if (eu) { NMG_CK_EDGEUSE(eu); NMG_CK_VERTEXUSE(eu->vu_p); v = eu->vu_p->v_p; NMG_CK_VERTEX(v); if (!v->vg_p) break; VMOVE(mpt, v->vg_p->coord); break; } vu = s->vu_p; if (vu) { NMG_CK_VERTEXUSE(vu); v = vu->v_p; NMG_CK_VERTEX(v); if (!v->vg_p) break; VMOVE(mpt, v->vg_p->coord); break; } } default: VSETALL(mpt, 0.0); bu_vls_printf(gedp->ged_result_str, "get_solid_keypoint: unrecognized solid type"); return GED_ERROR; } MAT4X3PNT(pt, mat, mpt); return GED_OK; }
static void nmg_to_dxf(struct nmgregion *r, const struct db_full_path *pathp, int UNUSED(region_id), int UNUSED(material_id), float color[3]) { struct model *m; struct shell *s; struct vertex *v; struct bu_ptbl verts; char *region_name; int region_polys=0; int tri_count=0; int color_num; int do_triangulate=0; NMG_CK_REGION(r); RT_CK_FULL_PATH(pathp); region_name = db_path_to_string(pathp); m = r->m_p; NMG_CK_MODEL(m); /* Count triangles */ for (BU_LIST_FOR(s, shell, &r->s_hd)) { struct faceuse *fu; NMG_CK_SHELL(s); for (BU_LIST_FOR(fu, faceuse, &s->fu_hd)) { struct loopuse *lu; int vert_count=0; NMG_CK_FACEUSE(fu); if (fu->orientation != OT_SAME) continue; for (BU_LIST_FOR(lu, loopuse, &fu->lu_hd)) { struct edgeuse *eu; if (BU_LIST_FIRST_MAGIC(&lu->down_hd) != NMG_EDGEUSE_MAGIC) continue; for (BU_LIST_FOR(eu, edgeuse, &lu->down_hd)) { vert_count++; } if (vert_count > 3) { do_triangulate = 1; goto triangulate; } tri_count++; } } } triangulate: if (do_triangulate) { /* triangulate model */ nmg_triangulate_model(m, &tol); /* Count triangles */ tri_count = 0; for (BU_LIST_FOR(s, shell, &r->s_hd)) { struct faceuse *fu; for (BU_LIST_FOR(fu, faceuse, &s->fu_hd)) { struct loopuse *lu; if (fu->orientation != OT_SAME) continue; for (BU_LIST_FOR(lu, loopuse, &fu->lu_hd)) { if (BU_LIST_FIRST_MAGIC(&lu->down_hd) != NMG_EDGEUSE_MAGIC) continue; tri_count++; } } } } nmg_vertex_tabulate(&verts, &r->l.magic); color_num = find_closest_color(color); if (polyface_mesh) { size_t i; fprintf(fp, "0\nPOLYLINE\n8\n%s\n62\n%d\n70\n64\n71\n%lu\n72\n%d\n", region_name, color_num, (unsigned long)BU_PTBL_LEN(&verts), tri_count); for (i = 0; i < BU_PTBL_LEN(&verts); i++) { fprintf(fp, "0\nVERTEX\n8\n%s\n", region_name); v = (struct vertex *)BU_PTBL_GET(&verts, i); NMG_CK_VERTEX(v); if (inches) { fprintf(fp, "10\n%f\n20\n%f\n30\n%f\n70\n192\n", V3ARGSIN(v->vg_p->coord)); } else { fprintf(fp, "10\n%f\n20\n%f\n30\n%f\n70\n192\n", V3ARGS(v->vg_p->coord)); } } } /* Check triangles */ for (BU_LIST_FOR(s, shell, &r->s_hd)) { struct faceuse *fu; NMG_CK_SHELL(s); for (BU_LIST_FOR(fu, faceuse, &s->fu_hd)) { struct loopuse *lu; NMG_CK_FACEUSE(fu); if (fu->orientation != OT_SAME) continue; for (BU_LIST_FOR(lu, loopuse, &fu->lu_hd)) { struct edgeuse *eu; int vert_count=0; NMG_CK_LOOPUSE(lu); if (BU_LIST_FIRST_MAGIC(&lu->down_hd) != NMG_EDGEUSE_MAGIC) continue; if (polyface_mesh) { fprintf(fp, "0\nVERTEX\n8\n%s\n70\n128\n10\n0.0\n20\n0.0\n30\n0.0\n", region_name); } else { fprintf(fp, "0\n3DFACE\n8\n%s\n62\n%d\n", region_name, color_num); } /* check vertex numbers for each triangle */ for (BU_LIST_FOR(eu, edgeuse, &lu->down_hd)) { NMG_CK_EDGEUSE(eu); vert_count++; v = eu->vu_p->v_p; NMG_CK_VERTEX(v); if (polyface_mesh) { fprintf(fp, "%d\n%d\n", vert_count+70, bu_ptbl_locate(&verts, (long *)v) + 1); } else { if (inches) { fprintf(fp, "%d\n%f\n%d\n%f\n%d\n%f\n", 10 + vert_count - 1, v->vg_p->coord[X] / 25.4, 20 + vert_count - 1, v->vg_p->coord[Y] / 25.4, 30 + vert_count -1, v->vg_p->coord[Z] / 25.4); } else { fprintf(fp, "%d\n%f\n%d\n%f\n%d\n%f\n", 10 + vert_count - 1, v->vg_p->coord[X], 20 + vert_count - 1, v->vg_p->coord[Y], 30 + vert_count -1, v->vg_p->coord[Z]); } } } if (vert_count > 3) { bu_free(region_name, "region name"); bu_log("lu %p has %d vertices!\n", (void *)lu, vert_count); bu_exit(1, "ERROR: LU is not a triangle\n"); } else if (vert_count < 3) { continue; } else { /* repeat the last vertex for the benefit of codes * that interpret the dxf specification for * 3DFACES as requiring a fourth vertex even when * only three are input. */ if (!polyface_mesh) { vert_count++; if (inches) { fprintf(fp, "%d\n%f\n%d\n%f\n%d\n%f\n", 10 + vert_count - 1, v->vg_p->coord[X] / 25.4, 20 + vert_count - 1, v->vg_p->coord[Y] / 25.4, 30 + vert_count -1, v->vg_p->coord[Z] / 25.4); } else { fprintf(fp, "%d\n%f\n%d\n%f\n%d\n%f\n", 10 + vert_count - 1, v->vg_p->coord[X], 20 + vert_count - 1, v->vg_p->coord[Y], 30 + vert_count -1, v->vg_p->coord[Z]); } } } tot_polygons++; region_polys++; } } } bu_ptbl_free(&verts); bu_free(region_name, "region name"); if (polyface_mesh) { fprintf(fp, "0\nSEQEND\n"); } }