static intptr_t mesh_octree_find_index(MocNode **bt, MVert *mvert, float *co) { float *vec; int a; if(*bt==NULL) return -1; for(a=0; a<MOC_NODE_RES; a++) { if((*bt)->index[a]) { /* does mesh verts and editmode, code looks potential dangerous, octree should really be filled OK! */ if(mvert) { vec= (mvert+(*bt)->index[a]-1)->co; if(compare_v3v3(vec, co, MOC_THRESH)) return (*bt)->index[a]-1; } else { EditVert *eve= (EditVert *)((*bt)->index[a]); if(compare_v3v3(eve->co, co, MOC_THRESH)) return (*bt)->index[a]; } } else return -1; } if( (*bt)->next) return mesh_octree_find_index(&(*bt)->next, mvert, co); return -1; }
static void testvertexnearedge(ScanFillContext *sf_ctx) { /* only vertices with ->h==1 are being tested for * being close to an edge, if true insert */ ScanFillVert *eve; ScanFillEdge *eed, *ed1; for (eve = sf_ctx->fillvertbase.first; eve; eve = eve->next) { if (eve->h == 1) { /* find the edge which has vertex eve */ ed1 = sf_ctx->filledgebase.first; while (ed1) { if (ed1->v1 == eve || ed1->v2 == eve) break; ed1 = ed1->next; } if (ed1->v1 == eve) { ed1->v1 = ed1->v2; ed1->v2 = eve; } for (eed = sf_ctx->filledgebase.first; eed; eed = eed->next) { if (eve != eed->v1 && eve != eed->v2 && eve->poly_nr == eed->poly_nr) { if (compare_v3v3(eve->co, eed->v1->co, SF_EPSILON)) { ed1->v2 = eed->v1; eed->v1->h++; eve->h = 0; break; } else if (compare_v3v3(eve->co, eed->v2->co, SF_EPSILON)) { ed1->v2 = eed->v2; eed->v2->h++; eve->h = 0; break; } else { if (boundinsideEV(eed, eve)) { const float dist = dist_to_line_v2(eed->v1->xy, eed->v2->xy, eve->xy); if (dist < SF_EPSILON) { /* new edge */ ed1 = BLI_addfilledge(sf_ctx, eed->v1, eve); /* printf("fill: vertex near edge %x\n",eve); */ ed1->f = 0; ed1->poly_nr = eed->poly_nr; eed->v1 = eve; eve->h = 3; break; } } } } } } } }
/* get a vector, vec, that points from v1->co to wherever makes sense to * the bevel operation as a whole based on the relationship between v1 and v2 * (won't necessarily be a vec from v1->co to v2->co, though it probably will be); * the return value is -1 for failure, 0 if we used vert co's, and 1 if we used transform origins */ static int BME_bevel_get_vec(float *vec, BME_Vert *v1, BME_Vert *v2, BME_TransData_Head *td) { BME_TransData *vtd1, *vtd2; vtd1 = BME_get_transdata(td,v1); vtd2 = BME_get_transdata(td,v2); if (!vtd1 || !vtd2) { //printf("BME_bevel_get_vec() got called without proper BME_TransData\n"); return -1; } /* compare the transform origins to see if we can use the vert co's; * if they belong to different origins, then we will use the origins to determine * the vector */ if (compare_v3v3(vtd1->org,vtd2->org,0.000001f)) { VECSUB(vec,v2->co,v1->co); if (len_v3(vec) < 0.000001f) { mul_v3_fl(vec,0); } return 0; } else { VECSUB(vec,vtd2->org,vtd1->org); if (len_v3(vec) < 0.000001f) { mul_v3_fl(vec,0); } return 1; } }
// compare two vertices, and return true if both are almost identical (they can be shared) bool RAS_TexVert::closeTo(const RAS_TexVert* other) { const float eps = FLT_EPSILON; for (int i = 0; i < MAX_UNIT; i++) { if (!compare_v2v2(m_uvs[i], other->m_uvs[i], eps)) { return false; } } return (/* m_flag == other->m_flag && */ /* at the moment the face only stores the smooth/flat setting so don't bother comparing it */ (m_rgba == other->m_rgba) && compare_v3v3(m_normal, other->m_normal, eps) && compare_v3v3(m_tangent, other->m_tangent, eps) /* don't bother comparing m_localxyz since we know there from the same vert */ /* && compare_v3v3(m_localxyz, other->m_localxyz, eps))*/ ); }
static bool node_select_grouped_color(SpaceNode *snode, bNode *node_act) { bNode *node; bool changed = false; for (node = snode->edittree->nodes.first; node; node = node->next) { if ((node->flag & SELECT) == 0) { if (compare_v3v3(node->color, node_act->color, 0.005f)) { nodeSetSelected(node, true); changed = true; } } } return changed; }
/** * accumulate edge-vectors from all polys. */ static void calc_tangent_loop_accum(const float v_dir_prev[3], const float v_dir_next[3], float r_tspace[3][3]) { add_v3_v3v3(r_tspace[1], v_dir_prev, v_dir_next); if (compare_v3v3(v_dir_prev, v_dir_next, FLT_EPSILON * 10.0f) == false) { const float weight = fabsf(acosf(dot_v3v3(v_dir_next, v_dir_prev))); float nor[3]; cross_v3_v3v3(nor, v_dir_prev, v_dir_next); normalize_v3(nor); cross_v3_v3v3(r_tspace[0], r_tspace[1], nor); mul_v3_fl(nor, weight); /* accumulate weighted normals */ add_v3_v3(r_tspace[2], nor); } }
unsigned int BLI_scanfill_calc_ex(ScanFillContext *sf_ctx, const int flag, const float nor_proj[3]) { /* * - fill works with its own lists, so create that first (no faces!) * - for vertices, put in ->tmp.v the old pointer * - struct elements xs en ys are not used here: don't hide stuff in it * - edge flag ->f becomes 2 when it's a new edge * - mode: & 1 is check for crossings, then create edges (TO DO ) * - returns number of triangle faces added. */ ListBase tempve, temped; ScanFillVert *eve; ScanFillEdge *eed, *eed_next; PolyFill *pflist, *pf; float *min_xy_p, *max_xy_p; unsigned int totfaces = 0; /* total faces added */ unsigned short a, c, poly = 0; bool ok; float mat_2d[3][3]; BLI_assert(!nor_proj || len_squared_v3(nor_proj) > FLT_EPSILON); #ifdef DEBUG for (eve = sf_ctx->fillvertbase.first; eve; eve = eve->next) { /* these values used to be set, * however they should always be zero'd so check instead */ BLI_assert(eve->f == 0); BLI_assert(sf_ctx->poly_nr || eve->poly_nr == 0); BLI_assert(eve->edge_tot == 0); } #endif #if 0 if (flag & BLI_SCANFILL_CALC_QUADTRI_FASTPATH) { const int totverts = BLI_countlist(&sf_ctx->fillvertbase); if (totverts == 3) { eve = sf_ctx->fillvertbase.first; addfillface(sf_ctx, eve, eve->next, eve->next->next); return 1; } else if (totverts == 4) { float vec1[3], vec2[3]; eve = sf_ctx->fillvertbase.first; /* no need to check 'eve->next->next->next' is valid, already counted */ /* use shortest diagonal for quad */ sub_v3_v3v3(vec1, eve->co, eve->next->next->co); sub_v3_v3v3(vec2, eve->next->co, eve->next->next->next->co); if (dot_v3v3(vec1, vec1) < dot_v3v3(vec2, vec2)) { addfillface(sf_ctx, eve, eve->next, eve->next->next); addfillface(sf_ctx, eve->next->next, eve->next->next->next, eve); } else { addfillface(sf_ctx, eve->next, eve->next->next, eve->next->next->next); addfillface(sf_ctx, eve->next->next->next, eve, eve->next); } return 2; } } #endif /* first test vertices if they are in edges */ /* including resetting of flags */ for (eed = sf_ctx->filledgebase.first; eed; eed = eed->next) { BLI_assert(sf_ctx->poly_nr != SF_POLY_UNSET || eed->poly_nr == SF_POLY_UNSET); eed->v1->f = SF_VERT_AVAILABLE; eed->v2->f = SF_VERT_AVAILABLE; } for (eve = sf_ctx->fillvertbase.first; eve; eve = eve->next) { if (eve->f == SF_VERT_AVAILABLE) { break; } } if (UNLIKELY(eve == NULL)) { return 0; } else { float n[3]; if (nor_proj) { copy_v3_v3(n, nor_proj); } else { /* define projection: with 'best' normal */ /* Newell's Method */ /* Similar code used elsewhere, but this checks for double ups * which historically this function supports so better not change */ /* warning: this only gives stable direction with single polygons, * ideally we'd calcualte connectivity and calculate each polys normal, see T41047 */ const float *v_prev; zero_v3(n); eve = sf_ctx->fillvertbase.last; v_prev = eve->co; for (eve = sf_ctx->fillvertbase.first; eve; eve = eve->next) { if (LIKELY(!compare_v3v3(v_prev, eve->co, SF_EPSILON))) { add_newell_cross_v3_v3v3(n, v_prev, eve->co); v_prev = eve->co; } } } if (UNLIKELY(normalize_v3(n) == 0.0f)) { return 0; } axis_dominant_v3_to_m3(mat_2d, n); } /* STEP 1: COUNT POLYS */ if (sf_ctx->poly_nr != SF_POLY_UNSET) { poly = (unsigned short)(sf_ctx->poly_nr + 1); sf_ctx->poly_nr = SF_POLY_UNSET; } if (flag & BLI_SCANFILL_CALC_POLYS && (poly == 0)) { for (eve = sf_ctx->fillvertbase.first; eve; eve = eve->next) { mul_v2_m3v3(eve->xy, mat_2d, eve->co); /* get first vertex with no poly number */ if (eve->poly_nr == SF_POLY_UNSET) { unsigned int toggle = 0; /* now a sort of select connected */ ok = true; eve->poly_nr = poly; while (ok) { ok = false; toggle++; for (eed = (toggle & 1) ? sf_ctx->filledgebase.first : sf_ctx->filledgebase.last; eed; eed = (toggle & 1) ? eed->next : eed->prev) { if (eed->v1->poly_nr == SF_POLY_UNSET && eed->v2->poly_nr == poly) { eed->v1->poly_nr = poly; eed->poly_nr = poly; ok = true; } else if (eed->v2->poly_nr == SF_POLY_UNSET && eed->v1->poly_nr == poly) { eed->v2->poly_nr = poly; eed->poly_nr = poly; ok = true; } else if (eed->poly_nr == SF_POLY_UNSET) { if (eed->v1->poly_nr == poly && eed->v2->poly_nr == poly) { eed->poly_nr = poly; ok = true; } } } } poly++; } } /* printf("amount of poly's: %d\n", poly); */ } else if (poly) { /* we pre-calculated poly_nr */ for (eve = sf_ctx->fillvertbase.first; eve; eve = eve->next) { mul_v2_m3v3(eve->xy, mat_2d, eve->co); } } else { poly = 1; for (eve = sf_ctx->fillvertbase.first; eve; eve = eve->next) { mul_v2_m3v3(eve->xy, mat_2d, eve->co); eve->poly_nr = 0; } for (eed = sf_ctx->filledgebase.first; eed; eed = eed->next) { eed->poly_nr = 0; } } /* STEP 2: remove loose edges and strings of edges */ if (flag & BLI_SCANFILL_CALC_LOOSE) { unsigned int toggle = 0; for (eed = sf_ctx->filledgebase.first; eed; eed = eed->next) { if (eed->v1->edge_tot++ > 250) break; if (eed->v2->edge_tot++ > 250) break; } if (eed) { /* otherwise it's impossible to be sure you can clear vertices */ #ifdef DEBUG printf("No vertices with 250 edges allowed!\n"); #endif return 0; } /* does it only for vertices with (->edge_tot == 1) */ testvertexnearedge(sf_ctx); ok = true; while (ok) { ok = false; toggle++; for (eed = (toggle & 1) ? sf_ctx->filledgebase.first : sf_ctx->filledgebase.last; eed; eed = eed_next) { eed_next = (toggle & 1) ? eed->next : eed->prev; if (eed->v1->edge_tot == 1) { eed->v2->edge_tot--; BLI_remlink(&sf_ctx->fillvertbase, eed->v1); BLI_remlink(&sf_ctx->filledgebase, eed); ok = true; } else if (eed->v2->edge_tot == 1) { eed->v1->edge_tot--; BLI_remlink(&sf_ctx->fillvertbase, eed->v2); BLI_remlink(&sf_ctx->filledgebase, eed); ok = true; } } } if (BLI_listbase_is_empty(&sf_ctx->filledgebase)) { /* printf("All edges removed\n"); */ return 0; } } else { /* skip checks for loose edges */ for (eed = sf_ctx->filledgebase.first; eed; eed = eed->next) { eed->v1->edge_tot++; eed->v2->edge_tot++; } #ifdef DEBUG /* ensure we're right! */ for (eed = sf_ctx->filledgebase.first; eed; eed = eed->next) { BLI_assert(eed->v1->edge_tot != 1); BLI_assert(eed->v2->edge_tot != 1); } #endif } /* CURRENT STATUS: * - eve->f :1 = available in edges * - eve->poly_nr :polynumber * - eve->edge_tot :amount of edges connected to vertex * - eve->tmp.v :store! original vertex number * * - eed->f :1 = boundary edge (optionally set by caller) * - eed->poly_nr :poly number */ /* STEP 3: MAKE POLYFILL STRUCT */ pflist = MEM_mallocN(sizeof(*pflist) * (size_t)poly, "edgefill"); pf = pflist; for (a = 0; a < poly; a++) { pf->edges = pf->verts = 0; pf->min_xy[0] = pf->min_xy[1] = 1.0e20f; pf->max_xy[0] = pf->max_xy[1] = -1.0e20f; pf->f = SF_POLY_NEW; pf->nr = a; pf++; } for (eed = sf_ctx->filledgebase.first; eed; eed = eed->next) { pflist[eed->poly_nr].edges++; } for (eve = sf_ctx->fillvertbase.first; eve; eve = eve->next) { pflist[eve->poly_nr].verts++; min_xy_p = pflist[eve->poly_nr].min_xy; max_xy_p = pflist[eve->poly_nr].max_xy; min_xy_p[0] = (min_xy_p[0]) < (eve->xy[0]) ? (min_xy_p[0]) : (eve->xy[0]); min_xy_p[1] = (min_xy_p[1]) < (eve->xy[1]) ? (min_xy_p[1]) : (eve->xy[1]); max_xy_p[0] = (max_xy_p[0]) > (eve->xy[0]) ? (max_xy_p[0]) : (eve->xy[0]); max_xy_p[1] = (max_xy_p[1]) > (eve->xy[1]) ? (max_xy_p[1]) : (eve->xy[1]); if (eve->edge_tot > 2) { pflist[eve->poly_nr].f = SF_POLY_VALID; } } /* STEP 4: FIND HOLES OR BOUNDS, JOIN THEM * ( bounds just to divide it in pieces for optimization, * the edgefill itself has good auto-hole detection) * WATCH IT: ONLY WORKS WITH SORTED POLYS!!! */ if ((flag & BLI_SCANFILL_CALC_HOLES) && (poly > 1)) { unsigned short *polycache, *pc; /* so, sort first */ qsort(pflist, (size_t)poly, sizeof(PolyFill), vergpoly); #if 0 pf = pflist; for (a = 0; a < poly; a++) { printf("poly:%d edges:%d verts:%d flag: %d\n", a, pf->edges, pf->verts, pf->f); PRINT2(f, f, pf->min[0], pf->min[1]); pf++; } #endif polycache = pc = MEM_callocN(sizeof(*polycache) * (size_t)poly, "polycache"); pf = pflist; for (a = 0; a < poly; a++, pf++) { for (c = (unsigned short)(a + 1); c < poly; c++) { /* if 'a' inside 'c': join (bbox too) * Careful: 'a' can also be inside another poly. */ if (boundisect(pf, pflist + c)) { *pc = c; pc++; } /* only for optimize! */ /* else if (pf->max_xy[0] < (pflist+c)->min[cox]) break; */ } while (pc != polycache) { pc--; mergepolysSimp(sf_ctx, pf, pflist + *pc); } } MEM_freeN(polycache); } #if 0 printf("after merge\n"); pf = pflist; for (a = 0; a < poly; a++) { printf("poly:%d edges:%d verts:%d flag: %d\n", a, pf->edges, pf->verts, pf->f); pf++; } #endif /* STEP 5: MAKE TRIANGLES */ tempve.first = sf_ctx->fillvertbase.first; tempve.last = sf_ctx->fillvertbase.last; temped.first = sf_ctx->filledgebase.first; temped.last = sf_ctx->filledgebase.last; BLI_listbase_clear(&sf_ctx->fillvertbase); BLI_listbase_clear(&sf_ctx->filledgebase); pf = pflist; for (a = 0; a < poly; a++) { if (pf->edges > 1) { splitlist(sf_ctx, &tempve, &temped, pf->nr); totfaces += scanfill(sf_ctx, pf, flag); } pf++; } BLI_movelisttolist(&sf_ctx->fillvertbase, &tempve); BLI_movelisttolist(&sf_ctx->filledgebase, &temped); /* FREE */ MEM_freeN(pflist); return totfaces; }
int BLI_edgefill(int mat_nr) { /* - fill works with its own lists, so create that first (no faces!) - for vertices, put in ->tmp.v the old pointer - struct elements xs en ys are not used here: don't hide stuff in it - edge flag ->f becomes 2 when it's a new edge - mode: & 1 is check for crossings, then create edges (TO DO ) */ ListBase tempve, temped; EditVert *eve; EditEdge *eed,*nexted; PolyFill *pflist,*pf; float *minp, *maxp, *v1, *v2, norm[3], len; short a,c,poly=0,ok=0,toggle=0; /* reset variables */ eve= fillvertbase.first; while(eve) { eve->f= 0; eve->xs= 0; eve->h= 0; eve= eve->next; } /* first test vertices if they are in edges */ /* including resetting of flags */ eed= filledgebase.first; while(eed) { eed->f= eed->f1= eed->h= 0; eed->v1->f= 1; eed->v2->f= 1; eed= eed->next; } eve= fillvertbase.first; while(eve) { if(eve->f & 1) { ok=1; break; } eve= eve->next; } if(ok==0) return 0; /* NEW NEW! define projection: with 'best' normal */ /* just use the first three different vertices */ /* THIS PART STILL IS PRETTY WEAK! (ton) */ eve= fillvertbase.last; len= 0.0; v1= eve->co; v2= 0; eve= fillvertbase.first; while(eve) { if(v2) { if( compare_v3v3(v2, eve->co, COMPLIMIT)==0) { len= normal_tri_v3( norm,v1, v2, eve->co); if(len != 0.0) break; } } else if(compare_v3v3(v1, eve->co, COMPLIMIT)==0) { v2= eve->co; } eve= eve->next; } if(len==0.0) return 0; /* no fill possible */ norm[0]= fabs(norm[0]); norm[1]= fabs(norm[1]); norm[2]= fabs(norm[2]); if(norm[2]>=norm[0] && norm[2]>=norm[1]) { cox= 0; coy= 1; } else if(norm[1]>=norm[0] && norm[1]>=norm[2]) { cox= 0; coy= 2; } else { cox= 1; coy= 2; } /* STEP 1: COUNT POLYS */ eve= fillvertbase.first; while(eve) { /* get first vertex with no poly number */ if(eve->xs==0) { poly++; /* now a sortof select connected */ ok= 1; eve->xs= poly; while(ok) { ok= 0; toggle++; if(toggle & 1) eed= filledgebase.first; else eed= filledgebase.last; while(eed) { if(eed->v1->xs==0 && eed->v2->xs==poly) { eed->v1->xs= poly; eed->f1= poly; ok= 1; } else if(eed->v2->xs==0 && eed->v1->xs==poly) { eed->v2->xs= poly; eed->f1= poly; ok= 1; } else if(eed->f1==0) { if(eed->v1->xs==poly && eed->v2->xs==poly) { eed->f1= poly; ok= 1; } } if(toggle & 1) eed= eed->next; else eed= eed->prev; } } } eve= eve->next; } /* printf("amount of poly's: %d\n",poly); */ /* STEP 2: remove loose edges and strings of edges */ eed= filledgebase.first; while(eed) { if(eed->v1->h++ >250) break; if(eed->v2->h++ >250) break; eed= eed->next; } if(eed) { /* otherwise it's impossible to be sure you can clear vertices */ callLocalErrorCallBack("No vertices with 250 edges allowed!"); return 0; } /* does it only for vertices with ->h==1 */ testvertexnearedge(); ok= 1; while(ok) { ok= 0; toggle++; if(toggle & 1) eed= filledgebase.first; else eed= filledgebase.last; while(eed) { if(toggle & 1) nexted= eed->next; else nexted= eed->prev; if(eed->v1->h==1) { eed->v2->h--; BLI_remlink(&fillvertbase,eed->v1); BLI_remlink(&filledgebase,eed); ok= 1; } else if(eed->v2->h==1) { eed->v1->h--; BLI_remlink(&fillvertbase,eed->v2); BLI_remlink(&filledgebase,eed); ok= 1; } eed= nexted; } } if(filledgebase.first==0) { /* printf("All edges removed\n"); */ return 0; } /* CURRENT STATUS: - eve->f :1= availalble in edges - eve->xs :polynumber - eve->h :amount of edges connected to vertex - eve->tmp.v :store! original vertex number - eed->f : - eed->f1 :poly number */ /* STEP 3: MAKE POLYFILL STRUCT */ pflist= (PolyFill *)MEM_callocN(poly*sizeof(PolyFill),"edgefill"); pf= pflist; for(a=1;a<=poly;a++) { pf->nr= a; pf->min[0]=pf->min[1]=pf->min[2]= 1.0e20; pf->max[0]=pf->max[1]=pf->max[2]= -1.0e20; pf++; } eed= filledgebase.first; while(eed) { pflist[eed->f1-1].edges++; eed= eed->next; } eve= fillvertbase.first; while(eve) { pflist[eve->xs-1].verts++; minp= pflist[eve->xs-1].min; maxp= pflist[eve->xs-1].max; minp[cox]= (minp[cox])<(eve->co[cox]) ? (minp[cox]) : (eve->co[cox]); minp[coy]= (minp[coy])<(eve->co[coy]) ? (minp[coy]) : (eve->co[coy]); maxp[cox]= (maxp[cox])>(eve->co[cox]) ? (maxp[cox]) : (eve->co[cox]); maxp[coy]= (maxp[coy])>(eve->co[coy]) ? (maxp[coy]) : (eve->co[coy]); if(eve->h>2) pflist[eve->xs-1].f= 1; eve= eve->next; } /* STEP 4: FIND HOLES OR BOUNDS, JOIN THEM * ( bounds just to divide it in pieces for optimization, * the edgefill itself has good auto-hole detection) * WATCH IT: ONLY WORKS WITH SORTED POLYS!!! */ if(poly>1) { short *polycache, *pc; /* so, sort first */ qsort(pflist, poly, sizeof(PolyFill), vergpoly); /*pf= pflist; for(a=1;a<=poly;a++) { printf("poly:%d edges:%d verts:%d flag: %d\n",a,pf->edges,pf->verts,pf->f); PRINT2(f, f, pf->min[0], pf->min[1]); pf++; }*/ polycache= pc= MEM_callocN(sizeof(short)*poly, "polycache"); pf= pflist; for(a=0; a<poly; a++, pf++) { for(c=a+1;c<poly;c++) { /* if 'a' inside 'c': join (bbox too) * Careful: 'a' can also be inside another poly. */ if(boundisect(pf, pflist+c)) { *pc= c; pc++; } /* only for optimize! */ /* else if(pf->max[cox] < (pflist+c)->min[cox]) break; */ } while(pc!=polycache) { pc--; mergepolysSimp(pf, pflist+ *pc); } } MEM_freeN(polycache); } /* printf("after merge\n"); pf= pflist; for(a=1;a<=poly;a++) { printf("poly:%d edges:%d verts:%d flag: %d\n",a,pf->edges,pf->verts,pf->f); pf++; } */ /* STEP 5: MAKE TRIANGLES */ tempve.first= fillvertbase.first; tempve.last= fillvertbase.last; temped.first= filledgebase.first; temped.last= filledgebase.last; fillvertbase.first=fillvertbase.last= 0; filledgebase.first=filledgebase.last= 0; pf= pflist; for(a=0;a<poly;a++) { if(pf->edges>1) { splitlist(&tempve,&temped,pf->nr); scanfill(pf, mat_nr); } pf++; } BLI_movelisttolist(&fillvertbase,&tempve); BLI_movelisttolist(&filledgebase,&temped); /* FREE */ MEM_freeN(pflist); return 1; }
static void testvertexnearedge(void) { /* only vertices with ->h==1 are being tested for being close to an edge, if true insert */ EditVert *eve; EditEdge *eed,*ed1; float dist,vec1[2],vec2[2],vec3[2]; eve= fillvertbase.first; while(eve) { if(eve->h==1) { vec3[0]= eve->co[cox]; vec3[1]= eve->co[coy]; /* find the edge which has vertex eve */ ed1= filledgebase.first; while(ed1) { if(ed1->v1==eve || ed1->v2==eve) break; ed1= ed1->next; } if(ed1->v1==eve) { ed1->v1= ed1->v2; ed1->v2= eve; } eed= filledgebase.first; while(eed) { if(eve!=eed->v1 && eve!=eed->v2 && eve->xs==eed->f1) { if(compare_v3v3(eve->co,eed->v1->co, COMPLIMIT)) { ed1->v2= eed->v1; eed->v1->h++; eve->h= 0; break; } else if(compare_v3v3(eve->co,eed->v2->co, COMPLIMIT)) { ed1->v2= eed->v2; eed->v2->h++; eve->h= 0; break; } else { vec1[0]= eed->v1->co[cox]; vec1[1]= eed->v1->co[coy]; vec2[0]= eed->v2->co[cox]; vec2[1]= eed->v2->co[coy]; if(boundinsideEV(eed,eve)) { dist= dist_to_line_v2(vec1,vec2,vec3); if(dist<COMPLIMIT) { /* new edge */ ed1= BLI_addfilledge(eed->v1, eve); /* printf("fill: vertex near edge %x\n",eve); */ ed1->f= ed1->h= 0; ed1->f1= eed->f1; eed->v1= eve; eve->h= 3; break; } } } } eed= eed->next; } } eve= eve->next; } }
int BLI_edgefill_ex(ScanFillContext *sf_ctx, const short do_quad_tri_speedup, const float nor_proj[3]) { /* * - fill works with its own lists, so create that first (no faces!) * - for vertices, put in ->tmp.v the old pointer * - struct elements xs en ys are not used here: don't hide stuff in it * - edge flag ->f becomes 2 when it's a new edge * - mode: & 1 is check for crossings, then create edges (TO DO ) * - returns number of triangle faces added. */ ListBase tempve, temped; ScanFillVert *eve; ScanFillEdge *eed, *nexted; PolyFill *pflist, *pf; float *min_xy_p, *max_xy_p; short a, c, poly = 0, ok = 0, toggle = 0; int totfaces = 0; /* total faces added */ int co_x, co_y; /* reset variables */ eve = sf_ctx->fillvertbase.first; a = 0; while (eve) { eve->f = 0; eve->poly_nr = 0; eve->h = 0; eve = eve->next; a += 1; } if (do_quad_tri_speedup && (a == 3)) { eve = sf_ctx->fillvertbase.first; addfillface(sf_ctx, eve, eve->next, eve->next->next); return 1; } else if (do_quad_tri_speedup && (a == 4)) { float vec1[3], vec2[3]; eve = sf_ctx->fillvertbase.first; /* no need to check 'eve->next->next->next' is valid, already counted */ /* use shortest diagonal for quad */ sub_v3_v3v3(vec1, eve->co, eve->next->next->co); sub_v3_v3v3(vec2, eve->next->co, eve->next->next->next->co); if (dot_v3v3(vec1, vec1) < dot_v3v3(vec2, vec2)) { addfillface(sf_ctx, eve, eve->next, eve->next->next); addfillface(sf_ctx, eve->next->next, eve->next->next->next, eve); } else { addfillface(sf_ctx, eve->next, eve->next->next, eve->next->next->next); addfillface(sf_ctx, eve->next->next->next, eve, eve->next); } return 2; } /* first test vertices if they are in edges */ /* including resetting of flags */ eed = sf_ctx->filledgebase.first; while (eed) { eed->poly_nr = 0; eed->v1->f = SF_VERT_UNKNOWN; eed->v2->f = SF_VERT_UNKNOWN; eed = eed->next; } eve = sf_ctx->fillvertbase.first; while (eve) { if (eve->f & SF_VERT_UNKNOWN) { ok = 1; break; } eve = eve->next; } if (ok == 0) { return 0; } else { float n[3]; if (nor_proj) { copy_v3_v3(n, nor_proj); } else { /* define projection: with 'best' normal */ /* Newell's Method */ /* Similar code used elsewhere, but this checks for double ups * which historically this function supports so better not change */ float *v_prev; zero_v3(n); eve = sf_ctx->fillvertbase.last; v_prev = eve->co; for (eve = sf_ctx->fillvertbase.first; eve; eve = eve->next) { if (LIKELY(!compare_v3v3(v_prev, eve->co, SF_EPSILON))) { add_newell_cross_v3_v3v3(n, v_prev, eve->co); v_prev = eve->co; } } } if (UNLIKELY(normalize_v3(n) == 0.0f)) { return 0; } axis_dominant_v3(&co_x, &co_y, n); } /* STEP 1: COUNT POLYS */ eve = sf_ctx->fillvertbase.first; while (eve) { eve->xy[0] = eve->co[co_x]; eve->xy[1] = eve->co[co_y]; /* get first vertex with no poly number */ if (eve->poly_nr == 0) { poly++; /* now a sort of select connected */ ok = 1; eve->poly_nr = poly; while (ok) { ok = 0; toggle++; if (toggle & 1) eed = sf_ctx->filledgebase.first; else eed = sf_ctx->filledgebase.last; while (eed) { if (eed->v1->poly_nr == 0 && eed->v2->poly_nr == poly) { eed->v1->poly_nr = poly; eed->poly_nr = poly; ok = 1; } else if (eed->v2->poly_nr == 0 && eed->v1->poly_nr == poly) { eed->v2->poly_nr = poly; eed->poly_nr = poly; ok = 1; } else if (eed->poly_nr == 0) { if (eed->v1->poly_nr == poly && eed->v2->poly_nr == poly) { eed->poly_nr = poly; ok = 1; } } if (toggle & 1) eed = eed->next; else eed = eed->prev; } } } eve = eve->next; } /* printf("amount of poly's: %d\n",poly); */ /* STEP 2: remove loose edges and strings of edges */ eed = sf_ctx->filledgebase.first; while (eed) { if (eed->v1->h++ > 250) break; if (eed->v2->h++ > 250) break; eed = eed->next; } if (eed) { /* otherwise it's impossible to be sure you can clear vertices */ callLocalErrorCallBack("No vertices with 250 edges allowed!"); return 0; } /* does it only for vertices with ->h==1 */ testvertexnearedge(sf_ctx); ok = 1; while (ok) { ok = 0; toggle++; if (toggle & 1) eed = sf_ctx->filledgebase.first; else eed = sf_ctx->filledgebase.last; while (eed) { if (toggle & 1) nexted = eed->next; else nexted = eed->prev; if (eed->v1->h == 1) { eed->v2->h--; BLI_remlink(&sf_ctx->fillvertbase, eed->v1); BLI_remlink(&sf_ctx->filledgebase, eed); ok = 1; } else if (eed->v2->h == 1) { eed->v1->h--; BLI_remlink(&sf_ctx->fillvertbase, eed->v2); BLI_remlink(&sf_ctx->filledgebase, eed); ok = 1; } eed = nexted; } } if (sf_ctx->filledgebase.first == 0) { /* printf("All edges removed\n"); */ return 0; } /* CURRENT STATUS: * - eve->f :1= availalble in edges * - eve->xs :polynumber * - eve->h :amount of edges connected to vertex * - eve->tmp.v :store! original vertex number * * - eed->f :1= boundary edge (optionally set by caller) * - eed->poly_nr :poly number */ /* STEP 3: MAKE POLYFILL STRUCT */ pflist = (PolyFill *)MEM_callocN(poly * sizeof(PolyFill), "edgefill"); pf = pflist; for (a = 1; a <= poly; a++) { pf->nr = a; pf->min_xy[0] = pf->min_xy[1] = 1.0e20; pf->max_xy[0] = pf->max_xy[1] = -1.0e20; pf++; } eed = sf_ctx->filledgebase.first; while (eed) { pflist[eed->poly_nr - 1].edges++; eed = eed->next; } eve = sf_ctx->fillvertbase.first; while (eve) { pflist[eve->poly_nr - 1].verts++; min_xy_p = pflist[eve->poly_nr - 1].min_xy; max_xy_p = pflist[eve->poly_nr - 1].max_xy; min_xy_p[0] = (min_xy_p[0]) < (eve->xy[0]) ? (min_xy_p[0]) : (eve->xy[0]); min_xy_p[1] = (min_xy_p[1]) < (eve->xy[1]) ? (min_xy_p[1]) : (eve->xy[1]); max_xy_p[0] = (max_xy_p[0]) > (eve->xy[0]) ? (max_xy_p[0]) : (eve->xy[0]); max_xy_p[1] = (max_xy_p[1]) > (eve->xy[1]) ? (max_xy_p[1]) : (eve->xy[1]); if (eve->h > 2) pflist[eve->poly_nr - 1].f = 1; eve = eve->next; } /* STEP 4: FIND HOLES OR BOUNDS, JOIN THEM * ( bounds just to divide it in pieces for optimization, * the edgefill itself has good auto-hole detection) * WATCH IT: ONLY WORKS WITH SORTED POLYS!!! */ if (poly > 1) { short *polycache, *pc; /* so, sort first */ qsort(pflist, poly, sizeof(PolyFill), vergpoly); #if 0 pf = pflist; for (a = 1; a <= poly; a++) { printf("poly:%d edges:%d verts:%d flag: %d\n", a, pf->edges, pf->verts, pf->f); PRINT2(f, f, pf->min[0], pf->min[1]); pf++; } #endif polycache = pc = MEM_callocN(sizeof(short) * poly, "polycache"); pf = pflist; for (a = 0; a < poly; a++, pf++) { for (c = a + 1; c < poly; c++) { /* if 'a' inside 'c': join (bbox too) * Careful: 'a' can also be inside another poly. */ if (boundisect(pf, pflist + c)) { *pc = c; pc++; } /* only for optimize! */ /* else if (pf->max_xy[0] < (pflist+c)->min[cox]) break; */ } while (pc != polycache) { pc--; mergepolysSimp(sf_ctx, pf, pflist + *pc); } } MEM_freeN(polycache); } #if 0 printf("after merge\n"); pf = pflist; for (a = 1; a <= poly; a++) { printf("poly:%d edges:%d verts:%d flag: %d\n", a, pf->edges, pf->verts, pf->f); pf++; } #endif /* STEP 5: MAKE TRIANGLES */ tempve.first = sf_ctx->fillvertbase.first; tempve.last = sf_ctx->fillvertbase.last; temped.first = sf_ctx->filledgebase.first; temped.last = sf_ctx->filledgebase.last; sf_ctx->fillvertbase.first = sf_ctx->fillvertbase.last = NULL; sf_ctx->filledgebase.first = sf_ctx->filledgebase.last = NULL; pf = pflist; for (a = 0; a < poly; a++) { if (pf->edges > 1) { splitlist(sf_ctx, &tempve, &temped, pf->nr); totfaces += scanfill(sf_ctx, pf); } pf++; } BLI_movelisttolist(&sf_ctx->fillvertbase, &tempve); BLI_movelisttolist(&sf_ctx->filledgebase, &temped); /* FREE */ MEM_freeN(pflist); return totfaces; }