diff options
author | Jonathan deWerd <jjoonathan@gmail.com> | 2014-07-15 05:46:58 +0400 |
---|---|---|
committer | Jonathan deWerd <jjoonathan@gmail.com> | 2014-07-15 05:46:58 +0400 |
commit | b2ddd70949e6681e5244b0fc0414560f47a8c6ce (patch) | |
tree | b234e851f41cf529f2e0903bc83319df7100119a | |
parent | dbf2f19b355605586f87ac05909b89c7fb772675 (diff) |
Added dumber+faster grid propagator, fixed displist crash bug for >~10x10 tessellation grids.
-rw-r--r-- | source/blender/blenkernel/intern/curve.cpp | 7 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/surf_gridmesh.cpp | 104 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/surf_gridmesh.h | 37 | ||||
-rw-r--r-- | tests/interactive/nurbs_trimtess.cpp | 4 |
4 files changed, 114 insertions, 38 deletions
diff --git a/source/blender/blenkernel/intern/curve.cpp b/source/blender/blenkernel/intern/curve.cpp index 065fc1defad..3ddbe0118fc 100644 --- a/source/blender/blenkernel/intern/curve.cpp +++ b/source/blender/blenkernel/intern/curve.cpp @@ -67,6 +67,7 @@ extern "C" { #include <mach/mach.h> #include <mach/mach_time.h> #include "surf_gridmesh.h" +#include <set> /* globals */ @@ -4294,12 +4295,16 @@ void BKE_nurb_make_displist(struct Nurb *nu, struct DispList *dl) { float (*coords_tmp)[2] = (float(*)[2])MEM_mallocN(sizeof(*coords_tmp)*TESS_MAX_POLY_VERTS,"NURBS_tess_3"); int reindex_tmp[TESS_MAX_POLY_VERTS]; unsigned (*idx_tmp)[3] = (unsigned(*)[3])MEM_mallocN(sizeof(*idx_tmp)*TESS_MAX_POLY_VERTS,"NURBS_tess_4"); + std::vector<int> degenerate_polys; for (int j=0; j<totv; j++) { for (int i=0; i<totu; i++) { int cell = gm->poly_for_cell(i, j); GridMeshVert *v = &gm->v[0]; for (int poly=cell; poly; poly=v[poly].next_poly) { - if (!v[poly].next) continue; + if (!v[poly].next) { + printf("Degenerate: %i\n",poly); + continue; + } if (v[poly].is_pristine) { int ll_gp = gm->gridpt_for_cell(i, j); if (ii+6>=idxs_len) { diff --git a/source/blender/blenkernel/intern/surf_gridmesh.cpp b/source/blender/blenkernel/intern/surf_gridmesh.cpp index cfd7caefa19..ec2fbec8db3 100644 --- a/source/blender/blenkernel/intern/surf_gridmesh.cpp +++ b/source/blender/blenkernel/intern/surf_gridmesh.cpp @@ -126,9 +126,9 @@ void GridMesh::init_grid(int num_x_cells, int num_y_cells) { } coords_len = (1+nx)*(1+ny)+1; v.resize(nx*ny*4*2); - ie_grid.resize(nx*ny+1,false); - ie_isect_right.resize(nx*ny+1,false); - ie_isect_up.resize(nx*ny+1,false); + ie_grid.assign(nx*ny+1,true); + ie_isect_right.assign(nx*ny+1,false); + ie_isect_up.assign(nx*ny+1,false); vert_set_coord(0, -1234, -1234, -1234); for (int j=0; j<ny; j++) { for (int i=0; i<nx; i++) { @@ -153,6 +153,27 @@ void GridMesh::init_grid(int num_x_cells, int num_y_cells) { } } +void GridMesh::ie_print_grid(int num) { + std::vector<bool> *grid = NULL; + if (num==0) { + puts("ie_grid:"); + grid = &ie_grid; + } else if (num==1) { + puts("ie_isect_right:"); + grid = &ie_isect_right; + } else { + puts("ie_isect_up:"); + grid = &ie_isect_up; + } + for (int y=ny; y>=0; y--) { + for (int x=0; x<=nx; x++) { + bool val = grid->operator[](gridpt_for_cell(x, y)); + printf((val)?"1":"0"); + } + puts(""); + } +} + int GridMesh::vert_new() { v.push_back(GridMeshVert()); return int(v.size()-1); @@ -260,18 +281,6 @@ void GridMesh::poly_set_cyclic(int poly, bool cyc) { } } -int GridMesh::gridpt_for_cell(int x, int y) { - if (x<0||x>=nx+1) return 0; - if (y<0||y>=ny+1) return 0; - return 1+(y*(nx+1)+x); -} - -int GridMesh::poly_for_cell(int x, int y) { - if (x<0||x>=nx) return 0; - if (y<0||y>=ny) return 0; - return 1+4*(y*nx+x); -} - int GridMesh::poly_for_cell(float fx, float fy) { int x = floor((fx-llx)*inv_dx); if (x<0||x>=nx) return 0; @@ -341,7 +350,7 @@ void GridMesh::vert_add_neighbor(int v1, int v2) { } } -std::pair<int,int> GridMesh::vert_grid_cell(int vert) { +std::pair<int,int> GridMesh::cell_for_vert(int vert) { // vert = 1+4*(y*nx+x) int ynx_plus_x = (vert-1)/4; int y = ynx_plus_x/nx; @@ -682,7 +691,7 @@ void GridMesh::punch_hole(int exterior, int hole) { poly_flip_winding_direction(hole); } int v1=exterior, v2=hole; - bool v1v2_intersection_free; + bool v1v2_intersection_free = false; while (!v1v2_intersection_free) { double v1xyz[3]; vert_get_coord(v1, v1xyz); double v2xyz[3]; vert_get_coord(v2, v1xyz); @@ -736,15 +745,34 @@ void GridMesh::insert_vert_poly_gridmesh(int mpoly, int *verts_added, int *edges int edges_intersected_local = 0; while (v[v1].next) { int v2 = v[v1].next; - // Step 1: find all intersections of the edge v1,v2 + /**** Step 1: find all intersections of the edge v1,v2 vs the grid ****/ double v2xyz[3]; vert_get_coord(v2, v2xyz); - //NURBS_TESS_PRINTF("(%f,%f)---line--(%f,%f)\n",v1x,v1y,v2x,v2y); integer_cells.clear(); bottom_edges.clear(); left_edges.clear(); find_cell_line_intersections(v1xyz[0],v1xyz[1],v2xyz[0],v2xyz[1], &bottom_edges,&left_edges,&integer_cells); - edges_intersected_local += int(bottom_edges.size() + left_edges.size()); + // Step 2: flip the even/odd#intersections indicators on the respective edges + int num_bottom_edge_isects = int(bottom_edges.size()); + for (int ei_num=0; ei_num<num_bottom_edge_isects; ei_num++) { + std::pair<int,int> xy = bottom_edges[ei_num]; + int ie_isect_idx = gridpt_for_cell(xy.first, xy.second); + bool even_odd = ie_isect_right[ie_isect_idx]; + ie_isect_right[ie_isect_idx] = !even_odd; + } + int num_left_edge_isects = int(left_edges.size()); + for (int ei_num=0; ei_num<num_left_edge_isects; ei_num++) { + std::pair<int,int> xy = left_edges[ei_num]; + int ie_isect_idx = gridpt_for_cell(xy.first, xy.second); + bool even_odd = ie_isect_up[ie_isect_idx]; + ie_isect_up[ie_isect_idx] = !even_odd; + } + edges_intersected_local += num_bottom_edge_isects + num_left_edge_isects; + + // Step 3: turn "line passed through cell" events from raster algo + // into actual intersections by intersecting againt every edge in the cell, + // sorting so that even in the case of coincident edges we leave one + // polygon before entering the other. std::vector<IntersectingEdge> isect; for (size_t i=0,l=integer_cells.size(); i<l; i++) { std::pair<int,int> j = integer_cells[i]; @@ -762,7 +790,8 @@ void GridMesh::insert_vert_poly_gridmesh(int mpoly, int *verts_added, int *edges } } std::stable_sort(isect.begin(),isect.end(),intersection_edge_order); - // Step 2: insert them + + /**** Step 4: insert verts at the intersections we discovered ****/ for (IntersectingEdge ie : isect) { v1 = insert_vert(v1, v2, ie.e2, v[ie.e2].next, ie.x, ie.y); } @@ -775,6 +804,7 @@ void GridMesh::insert_vert_poly_gridmesh(int mpoly, int *verts_added, int *edges } void GridMesh::label_interior_AND(int poly2, bool invert_poly2, int *bb) { + // Step 1: Label cells that are definitely in the exterior of the boolean result. int bb_local[4]; if (!bb) { bb = bb_local; @@ -783,6 +813,38 @@ void GridMesh::label_interior_AND(int poly2, bool invert_poly2, int *bb) { int minx=bb[0], maxx=bb[1], miny=bb[2], maxy=bb[3]; if (!invert_poly2) label_exterior_cells(poly2, false, bb); + // Step 2: Ensure that the lower left corner is labeled correctly + int ll_gridpt = gridpt_for_cell(0, 0); + if (ie_grid[ll_gridpt]) { // false => not in interior. true => anything's possible + std::pair<float,float> llxy = cell_ll_corner(0,0); + ie_grid[1] = point_in_polygon(llxy.first, llxy.second, poly2) ^ invert_poly2; + } + /* Step 3: propagate the label to all other gridpoints + for (int y=0; y<=ny; y++) { + bool cur_ie = false; + int below_idx=gridpt_for_cell(0, y-1), cur_idx=gridpt_for_cell(0, y); + if (y!=0) { + cur_ie = ie_grid[cur_idx] = ie_grid[below_idx] ^ ie_isect_up[below_idx]; + } else { + cur_ie = ie_grid[cur_idx]; + } + for (int x=0; x<nx; x++) { + cur_ie = cur_ie ^ ie_isect_right[cur_idx]; + ie_grid[++cur_idx] = cur_ie; + } + } + // Step 4: Use interior/exterior calls on gridpt verts to label all verts + for (int y=miny; y<=maxy; y++) { + for (int x=minx; x<=maxx; x++) { + known_corner_t known_verts = KNOWN_CORNER_ALL; + if (!ie_grid[gridpt_for_cell(x,y)]) known_verts += KNOWN_CORNER_LL_EXTERIOR; + if (!ie_grid[gridpt_for_cell(x+1,y)]) known_verts += KNOWN_CORNER_LR_EXTERIOR; + if (!ie_grid[gridpt_for_cell(x+1,y+1)]) known_verts += KNOWN_CORNER_UR_EXTERIOR; + if (!ie_grid[gridpt_for_cell(x,y+1)]) known_verts += KNOWN_CORNER_UL_EXTERIOR; + label_interior_cell(poly_for_cell(x, y), poly2, invert_poly2, known_verts); + } + }*/ + // Alternative Step 3+4 known_corner_t known_verts_x0=0, known_verts_xsweep; for (int y=miny; y<=maxy; y++) { known_verts_x0 = KNOWN_CORNER_NEXTY(known_verts_x0); diff --git a/source/blender/blenkernel/intern/surf_gridmesh.h b/source/blender/blenkernel/intern/surf_gridmesh.h index 2f5636bc2af..50ff336d2a0 100644 --- a/source/blender/blenkernel/intern/surf_gridmesh.h +++ b/source/blender/blenkernel/intern/surf_gridmesh.h @@ -56,11 +56,12 @@ struct IntersectingEdge { #define KNOWN_CORNER_LL (1<<0) #define KNOWN_CORNER_LL_EXTERIOR (1<<1) #define KNOWN_CORNER_UL (1<<2) -#define KNOWN_CORNER_ULe_EXTERIOR (1<<3) +#define KNOWN_CORNER_UL_EXTERIOR (1<<3) #define KNOWN_CORNER_LR (1<<4) #define KNOWN_CORNER_LR_EXTERIOR (1<<5) #define KNOWN_CORNER_UR (1<<6) #define KNOWN_CORNER_UR_EXTERIOR (1<<7) +#define KNOWN_CORNER_ALL (KNOWN_CORNER_LL+KNOWN_CORNER_LR+KNOWN_CORNER_UL+KNOWN_CORNER_UR) #define KNOWN_CORNER_NEXTX(kc) ((kc)>>4) #define KNOWN_CORNER_NEXTY(kc) ((kc)>>2)&0x33 typedef unsigned char known_corner_t; @@ -68,7 +69,7 @@ typedef unsigned char known_corner_t; struct GridMesh { static float tolerance; - // 3D coordinate storage (all trimming functions ignore the 3rd coord) + // 3D coordinate storage (all trimming functions ignore the z coord) // coords[0] is defined to be invalid. // manually managed memory to avoid copy during handoff to C code GridMeshCoord *coords; @@ -77,8 +78,13 @@ struct GridMesh { void coords_import(GridMeshCoord *c, int len); // Transfers ownership to this GridMeshCoord *coords_export(int *len); // Transfers ownership to the caller - // Vertex storage. Example: "int prev" in a GridMeshVert refers to v[prev]. - // v[0] is defined to be invalid and filled with the telltale location (-1234,-1234) + // Permit usage of blender's memory management system + void* (*mallocN)(size_t sz, const char *name); + void* (*reallocN)(void *old, size_t sz, const char *name); + + // Vertex storage. Example: "int prev" in a GridMeshVert refers to + // (GridMeshVert*)v[prev]. v[0] is defined to be invalid and filled with + // the telltale location (-1234,-1234) std::vector<GridMeshVert> v; // Interior/Exterior calls are cheap at grid points due to information @@ -90,11 +96,8 @@ struct GridMesh { std::vector<bool> ie_grid; std::vector<bool> ie_isect_right; std::vector<bool> ie_isect_up; - - // Permit usage of blender's memory management system - void* (*mallocN)(size_t sz, const char *name); - void* (*reallocN)(void *old, size_t sz, const char *name); - + void ie_print_grid(int num); + double llx, lly, urx, ury; // Coordinates of lower left and upper right grid corners double dx, dy; // Width of a cell in the x, y directions double inv_dx, inv_dy; // 1/(width of a cell), 1/(height of a cell) @@ -106,6 +109,11 @@ struct GridMesh { void init_grid(int num_x_cells, int num_y_cells); ~GridMesh(); + // Coordinate utilities + int gridpt_for_cell(int x, int y) {return (0<=x&&x<=nx&&0<=y&y<=ny)? 1+(y*(nx+1)+x) : 0;} + std::pair<int,int> cell_for_vert(int vert); + std::pair<float,float> cell_ll_corner(int x, int y) {return std::make_pair(llx+x*dx,lly+y*dy);} + // Vert manipulation int vert_new(); int vert_new(int prev, int next); // Make a new vert in the middle of an existing poly @@ -115,12 +123,10 @@ struct GridMesh { int vert_id(GridMeshVert *vert) {return vert?int(vert-&v[0]):0;} int vert_neighbor_on_poly(int vert, int poly); void vert_add_neighbor(int vert, int new_neighbor); - std::pair<int,int> vert_grid_cell(int vert); - int gridpt_for_cell(int x, int y); // Poly manipulation int poly_new(const float* packed_coords, int len); - int poly_for_cell(int x, int y); + int poly_for_cell(int x, int y) {return (0<=x&&x<nx&&0<=y&y<ny)? 1+4*(y*nx+x) : 0;} int poly_for_cell(float x, float y); int poly_first_vert(int anyvert); int poly_last_vert(int anyvert); @@ -135,7 +141,6 @@ struct GridMesh { void poly_translate(int poly, double x, double y); double poly_signed_area(int poly); // ccw is positive void poly_flip_winding_direction(int poly); - void punch_hole(int exterior, int hole); // Trimming bool point_in_polygon(double x, double y, int poly); @@ -151,7 +156,10 @@ struct GridMesh { std::vector<std::pair<int,int> > *bottom_edges, std::vector<std::pair<int,int> > *left_edges, std::vector<std::pair<int,int> > *integer_cells); - // High level booleans + void punch_hole(int exterior, int hole); + + /******************** Booleans ********************/ + // High level void bool_AND(int poly2); // gridmesh -> gridmesh (intersection) poly2 void bool_SUB(int poly2); // gridmesh -> gridmesh (intersection) ~poly2 // Low level boolean support algorithms @@ -168,6 +176,7 @@ struct GridMesh { // Step 3: perform the actual trim 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 void poly_center(int poly, float *cx, float *cy); diff --git a/tests/interactive/nurbs_trimtess.cpp b/tests/interactive/nurbs_trimtess.cpp index 50b0ee7894e..5f54640a022 100644 --- a/tests/interactive/nurbs_trimtess.cpp +++ b/tests/interactive/nurbs_trimtess.cpp @@ -25,7 +25,7 @@ float intersect_check_tol = .001; //Maximum Euclidean dist between intersect pts /***************************** DEFAULT SCENE *****************************/ GridMesh *gm; int max_drawn_edges=0; // Number of edges to draw per poly (for figuring out order). 0 disables. -#define GRIDMESH_GEOM_TEST_5 +#define GRIDMESH_GEOM_TEST_4 //#define RASTER_VIZ #if defined(GRIDMESH_GEOM_TEST_1) @@ -127,7 +127,7 @@ void init_default_scene() { // Import the subject polygons into the linked list datastructure int last = 0; for (std::vector<float> poly_verts : subj_polys) { - int np = gm->poly_new(&subj0[0], int(subj0.size())); + int np = gm->poly_new(&poly_verts[0], int(poly_verts.size())); if (last) gm->v[last].next_poly = np; else |