diff options
author | Jonathan deWerd <jjoonathan@gmail.com> | 2014-07-03 07:05:20 +0400 |
---|---|---|
committer | Jonathan deWerd <jjoonathan@gmail.com> | 2014-07-03 07:05:20 +0400 |
commit | 66056dc8c0f5ad040ea03061704257cc3648e58e (patch) | |
tree | 6ff4d866866b1ad876956c4f7d44f3175d636d97 | |
parent | 99c45cd6d858d7e9475e2564ec8b3f8f1435bda8 (diff) |
Bugfixes: now GridMesh can *actually* be ANDed with multiple successive polygons.
-rw-r--r-- | source/blender/editors/curve/GridMesh.cpp | 171 | ||||
-rw-r--r-- | source/blender/editors/curve/GridMesh.h | 6 | ||||
-rw-r--r-- | source/blender/editors/curve/GridMesh_GLUT_debug_tool.cpp | 42 |
3 files changed, 147 insertions, 72 deletions
diff --git a/source/blender/editors/curve/GridMesh.cpp b/source/blender/editors/curve/GridMesh.cpp index 6050b00c646..a7006f215a9 100644 --- a/source/blender/editors/curve/GridMesh.cpp +++ b/source/blender/editors/curve/GridMesh.cpp @@ -34,6 +34,16 @@ inline static int xs_FloorToInt(double val) { //return floor(val); //Alternative implementation if the trick is buggy } +static void print_kc(known_corner_t kc) { + if (kc&KNOWN_CORNER_LL) + printf("LL%c",(kc&KNOWN_CORNER_LL_EXTERIOR)?'e':'i'); + if (kc&KNOWN_CORNER_UL) + printf("UL%c",(kc&KNOWN_CORNER_UL_EXTERIOR)?'e':'i'); + if (kc&KNOWN_CORNER_LR) + printf("LR%c",(kc&KNOWN_CORNER_LR_EXTERIOR)?'e':'i'); + if (kc&KNOWN_CORNER_UR) + printf("UR%c",(kc&KNOWN_CORNER_UR_EXTERIOR)?'e':'i'); +} void GridMesh::set_ll_ur(double lowerleft_x, double lowerleft_y, double upperright_x, double upperright_y) { @@ -241,10 +251,10 @@ void GridMesh::poly_grid_BB(int poly, int *bb) { //int bb[4] = {minx,maxx,miny,m maxy = fmax(g.y,maxy); vert = g.next; } while (vert && vert!=first); - bb[0] = xs_FloorToInt(minx); - bb[1] = xs_FloorToInt(maxx); - bb[2] = xs_FloorToInt(miny); - bb[3] = xs_FloorToInt(maxy); + bb[0] = xs_FloorToInt((minx-llx)*inv_dx); + bb[1] = xs_FloorToInt((maxx-llx)*inv_dx); + bb[2] = xs_FloorToInt((miny-lly)*inv_dy); + bb[3] = xs_FloorToInt((maxy-lly)*inv_dy); } // Sets is_interior flag of all vertices of poly and all vertices @@ -465,6 +475,26 @@ int GridMesh::insert_vert(int poly1left, return newv1; } +// gridmesh -> gridmesh (intersection) poly2 +void GridMesh::bool_AND(int poly2) { + int bb[4]; + poly_grid_BB(poly2, bb); + insert_vert_poly_gridmesh(poly2); + label_interior_freepoly(poly2); + label_interior_AND(poly2,false,bb); + trim_to_odd(); +} + +// gridmesh -> gridmesh (intersection) ~poly2 +void GridMesh::bool_SUB(int poly2) { + int bb[4]; + poly_grid_BB(poly2, bb); + insert_vert_poly_gridmesh(poly2); + label_interior_freepoly(poly2); + label_interior_AND(poly2,true,bb); + trim_to_odd(bb); +} + static bool intersection_edge_order(const IntersectingEdge& e1, const IntersectingEdge& e2) { double diff = e1.alpha1-e2.alpha1; if (abs(diff)<1e-5 && e1.cellidx!=e2.cellidx) { @@ -488,15 +518,17 @@ int GridMesh::insert_vert_poly_gridmesh(int mpoly) { std::vector<IntersectingEdge> isect; for (size_t i=0,l=integer_cells.size(); i<l; i++) { std::pair<int,int> j = integer_cells[i]; - int cell_poly = poly_for_cell(j.first, j.second); - if (!cell_poly) continue; - std::vector<IntersectingEdge> isect_tmp = edge_poly_intersections(v1, cell_poly); - for (IntersectingEdge& e : isect_tmp) { - //printf("(%i,%i)",j.first,j.second); - e.cellidx = int(i); + int cell_polys = poly_for_cell(j.first, j.second); + for (int cell_poly=cell_polys; cell_poly; cell_poly=v[cell_poly].next_poly) { + if (!cell_poly || !v[cell_poly].next) continue; + std::vector<IntersectingEdge> isect_tmp = edge_poly_intersections(v1, cell_poly); + for (IntersectingEdge& e : isect_tmp) { + //printf("(%i,%i)",j.first,j.second); + e.cellidx = int(i); + } + //printf("\n"); + isect.insert(isect.end(),isect_tmp.begin(),isect_tmp.end()); } - //printf("\n"); - isect.insert(isect.end(),isect_tmp.begin(),isect_tmp.end()); } std::stable_sort(isect.begin(),isect.end(),intersection_edge_order); // Step 2: insert them @@ -510,9 +542,12 @@ int GridMesh::insert_vert_poly_gridmesh(int mpoly) { return verts_added; } -void GridMesh::label_interior_AND(int poly2, bool invert_poly2) { - int bb[4]; - poly_grid_BB(poly2, bb); +void GridMesh::label_interior_AND(int poly2, bool invert_poly2, int *bb) { + int bb_local[4]; + if (!bb) { + bb = bb_local; + poly_grid_BB(poly2, bb); + } int minx=bb[0], maxx=bb[1], miny=bb[2], maxy=bb[3]; if (!invert_poly2) label_exterior_cells(poly2, false, bb); @@ -534,8 +569,8 @@ void GridMesh::label_interior_AND(int poly2, bool invert_poly2) { } } -void GridMesh::label_interior_SUB(int poly2) { - label_interior_AND(poly2, true); +void GridMesh::label_interior_SUB(int poly2, int *bb) { + label_interior_AND(poly2, true, bb); } void GridMesh::label_exterior_cells(int poly, bool interior_lbl, int* bb) { @@ -568,35 +603,39 @@ void GridMesh::label_exterior_cells(int poly, bool interior_lbl, int* bb) { } -// lr,ul = {0=unknown, 1=known_exterior, 2=known_interior} +// cell's next_poly list is considered +// poly2's next_poly list is ignored known_corner_t GridMesh::label_interior_cell(int cell, int poly2, bool bool_SUB, known_corner_t kin) { - //printf("%i kin:%i\n",cell,int(kin)); + printf("%i kin:%i=",cell,int(kin)); print_kc(kin); puts(""); bool interior = false; known_corner_t ret=0; for (int poly=cell; poly; poly=v[poly].next_poly) { + printf(" subpoly:%i DEG=%i\n",poly,int(v[poly].next==0)); if (v[poly].next==0) continue; // Skip degenerate polys // First, try to find a known corner bool found_known_corner = false; + int kc_vert=poly; if (kin) { - int vert = cell; do { - char k = v[vert].corner; - if (k && kin|KNOWN_CORNER(k-1)) { + char k = v[kc_vert].corner; + if (k && kin&KNOWN_CORNER(k-1)) { found_known_corner = true; interior = !(kin&KNOWN_CORNER_EXTERIOR(k-1)); + if (bool_SUB) interior = !interior; + printf(" %i k_propagate->%i.interior:%i sub:%i\n",poly, kc_vert, int(interior),int(bool_SUB)); break; } - vert = v[vert].next; - } while (vert && vert!=cell); + kc_vert = v[kc_vert].next; + } while (kc_vert && kc_vert!=poly); } - // If using a known corner didn't work, use the slow PIP test + // If using a known corner didn't work, use the slow PIP test to find a known corner if (!found_known_corner) { interior = point_in_polygon(v[poly].x, v[poly].y, poly2); - //printf(" pip:%i\n",int(interior)); if (bool_SUB) interior = !interior; + printf(" %i pip->%i.interior:%i sub:%i\n",poly, poly, int(interior),int(bool_SUB)); } // One way or another, (bool)interior is good now. - int vert = cell; + int vert = kc_vert; do { if (v[vert].is_intersection) { v[vert].is_interior = true; @@ -610,15 +649,22 @@ known_corner_t GridMesh::label_interior_cell(int cell, int poly2, bool bool_SUB, if (!interior) ret |= KNOWN_CORNER_EXTERIOR(k-1); } } + printf(" %i is_interior:%i is_intersection:%i next:%i\n",vert,int(v[vert].is_interior),int(v[vert].is_intersection),v[vert].next); vert = v[vert].next; - } while (vert && vert!=cell); + } while (vert && vert!=kc_vert); } return ret; } -void GridMesh::trim_to_odd() { - for (int i=0; i<nx; i++) { - for (int j=0; j<ny; j++) { +void GridMesh::trim_to_odd(int *bb) { + //int bb[] = {minx,maxx,miny,maxy} + int minx=0, maxx=nx-1, miny=0, maxy=ny-1; + if (bb) { + minx=bb[0]; maxx=bb[1]; miny=bb[2]; maxy=bb[3]; + } + for (int j=miny; j<=maxy; j++) { + for (int i=minx; i<=maxx; i++) { + printf("tto %i,%i\n",i,j); trim_to_odd(poly_for_cell(i,j)); } } @@ -630,7 +676,11 @@ void GridMesh::trim_to_odd(int poly0) { std::vector<int> trace_origins; std::vector<int> trace; // Holds verts of the polygon being traced trace.reserve(256); - for (int poly=poly0; poly; poly=v[poly].next_poly) { + for (int poly=poly0, next_poly=v[poly0].next_poly; + poly; + poly=next_poly, next_poly=v[poly].next_poly) { + if (!v[poly].next) continue; + printf(" poly %i\n",poly); trace_origins.push_back(poly); while (trace_origins.size()) { trace.clear(); @@ -685,36 +735,37 @@ void GridMesh::trim_to_odd(int poly0) { v[vert].is_used = true; vert = next; } - printf("Poly %i.%i: ",poly,this_trace_poly); - for (int v : trace) {printf(",%i",v);} - puts(""); - if (trace.size()) { - // Link the vertices - // Handle the case of an initial/final double vertex specially - int first_neighbor=v[*trace.begin()].neighbor, lastv=*trace.rbegin(); - if (first_neighbor==lastv) - trace.pop_back(); + size_t trace_sz = trace.size(); + if (trace_sz) { + int first = trace[0]; + printf(" 0poly %i.%i: ",poly,this_trace_poly); + for (int i : trace) {printf(",%i",i);}; puts(""); // Link all but the endpoints, skipping doubles for (int i=1,l=int(trace.size()); i<l; i++) { int left=trace[i-1], right=trace[i]; - if (v[left].neighbor==right && i+1<l) { - i += 1; - int rright = trace[i]; - v[left].next = rright; - v[rright].prev = left; - } else { - v[left].next = right; - v[right].prev = left; + if (v[left].neighbor==right) { + if (i==l-1) { + trace.pop_back(); + } else { + right = trace[(++i)]; + } } + v[left].next = right; + v[right].prev = left; } - for (int i : trace) { - v[i].first = trace[0]; + int last = *trace.rbegin(); + if (v[last].neighbor==first) { + last = v[last].prev; } - // Link the endpoints. Doubles skipped via pop_back - int first=trace[0], last=trace[trace.size()-1]; - v[first].prev = last; v[last].next = first; + v[first].prev = last; + printf(" 2poly %i.%i: ",poly,this_trace_poly); + vert=first; do { + printf(",%i",vert); + vert = v[vert].next; + } while (vert!=first); + puts(""); // Hook up the backbone if (!previous_trace_poly) { v[poly0].next_poly = this_trace_poly; @@ -726,6 +777,18 @@ void GridMesh::trim_to_odd(int poly0) { previous_trace_poly = this_trace_poly; } } + printf(" poly@end:%i\n",poly); + } + for (int poly=poly0; poly; poly=v[poly].next_poly) { + int vert = poly; + do { + v[vert].first = poly; + v[vert].is_intersection = false; + v[vert].is_interior = true; + v[vert].is_used = false; + v[vert].neighbor = 0; + vert = v[vert].next; + } while (vert && vert!=poly); } } diff --git a/source/blender/editors/curve/GridMesh.h b/source/blender/editors/curve/GridMesh.h index 791f8fa4201..338735ae476 100644 --- a/source/blender/editors/curve/GridMesh.h +++ b/source/blender/editors/curve/GridMesh.h @@ -117,13 +117,13 @@ struct GridMesh { // Step 1: insert verts at intersections int insert_vert_poly_gridmesh(int poly); // Returns # of vertices inserted. // Step 2: find mutual entry/exit points - void label_interior_AND(int poly2, bool invert_poly2=false); - void label_interior_SUB(int poly2); + void label_interior_AND(int poly2, bool invert_poly2=false, int *bb=NULL); + void label_interior_SUB(int poly2, int *bb=NULL); void label_exterior_cells(int poly, bool interior_lbl, int* bb=NULL); known_corner_t label_interior_cell(int cell, int poly2, bool bool_SUB, known_corner_t kin); void label_interior_freepoly(int poly); // Step 3: perform the actual trim - void trim_to_odd(); + void trim_to_odd(int *bb=NULL); void trim_to_odd(int poly); // Trim one grid poly, leaving behind parts w/odd winding# in .next_poly linked list #if defined(ENABLE_GLUT_DEMO) // Draw diff --git a/source/blender/editors/curve/GridMesh_GLUT_debug_tool.cpp b/source/blender/editors/curve/GridMesh_GLUT_debug_tool.cpp index 665726342fb..f5f00bb37e1 100644 --- a/source/blender/editors/curve/GridMesh_GLUT_debug_tool.cpp +++ b/source/blender/editors/curve/GridMesh_GLUT_debug_tool.cpp @@ -53,8 +53,8 @@ int gm_nx=2, gm_ny=2; #if defined(GRIDMESH_GEOM_TEST_3) bool clip_cyclic = true; // Required for initialization bool subj_cyclic = true; -std::vector<float> clip_verts = {.2,.2, 1.8,.2, 1.8,1.8, .2,1.8}; -std::vector<float> subj0 = {.8,.8, 1.2,.8, 1.2,1.2, .8,1.2}; +std::vector<float> clip_verts = {0.200000,0.200000, 4.436000,-0.268000, 4.460000,3.356000, 0.284000,4.292000}; +std::vector<float> subj0 = {0.800000,0.800000, 1.200000,0.800000, 1.200000,1.200000, 0.800000,1.200000}; std::vector<std::vector<float>> subj_polys = {subj0}; std::vector<float> inout_pts = {}; float gm_llx=0,gm_lly=0,gm_urx=4,gm_ury=4; // GridMesh params @@ -344,21 +344,23 @@ void GLUT_keyboard(unsigned char ch, int x, int y ) { if (ch==GLUT_KEY_RETURN) { dump_polys_to_stdout(); } - if (ch=='i') { - gm->insert_vert_poly_gridmesh(clip); -// for (int poly=subj; poly; poly=gm->v[poly].next_poly) { -// gm->insert_vert_poly_gridmesh(poly); -// } + if (clip && ch=='o') { + gm->bool_AND(clip); + clip = 0; + glutPostRedisplay(); + } + if (subj && ch=='i') { + gm->insert_vert_poly_gridmesh(subj); glutPostRedisplay(); } - if (ch=='l') { - gm->label_interior_AND(clip); - gm->label_interior_freepoly(clip); + if (subj && ch=='l') { + gm->label_interior_AND(subj); + gm->label_interior_freepoly(subj); glutPostRedisplay(); } - if (ch=='t') { + if (subj && ch=='t') { gm->trim_to_odd(); - subj = 0; // Subject was destroyed in trimming process + subj = gm->v[subj].next_poly; // Subject was destroyed in trimming process glutPostRedisplay(); } if (ch=='1') toggle_cyclic(clip); @@ -386,11 +388,21 @@ void GLUT_specialkey(int ch, int x, int y) { } void create_new_poly(float sx, float sy) { GreinerV2f *v = gm->v; - int last_backbone = subj; - while (v[last_backbone].next_poly) last_backbone = v[last_backbone].next_poly; int newpoly = gm->vert_new(); v[newpoly].x = sx; v[newpoly].y = sy; - v[last_backbone].next_poly = newpoly; + v[newpoly].first = newpoly; + v[newpoly].next = newpoly; v[newpoly].prev = newpoly; + if (subj) { + int last_backbone = subj; + while (v[last_backbone].next_poly) last_backbone = v[last_backbone].next_poly; + v[last_backbone].next_poly = newpoly; + } else { + subj = newpoly; + } + grabbed_vert = newpoly; + printf("Added subj vert. subj = "); + for (int vert=subj; vert; vert=v[vert].next_poly) printf(",%i",vert); + puts(""); glutPostRedisplay(); } void create_pt(float sx, float sy) { |