void CL_EarClipTriangulator_Impl::create_lists(bool create_ear_list) { int vert_size = vertices.size(); for( int i=0; i < vert_size; ++i ) { LinkedVertice *v = vertices[i]; if( i == 0 ) v->previous = vertices.back(); else v->previous = vertices[i-1]; if( i == (vert_size-1) ) v->next = vertices.front(); else v->next = vertices[i+1]; } unsigned int hole_size = hole.size(); for( unsigned int j = 0; j < hole.size(); ++j ) { if( j == 0 ) hole[j]->previous = hole.back(); else hole[j]->previous = hole[j-1]; if( j == (hole_size-1) ) hole[j]->next = hole.front(); else hole[j]->next = hole[j+1]; } if( create_ear_list ) { // cl_write_console_line("Ear list:"); for( std::vector<LinkedVertice*>::iterator it = vertices.begin(); it != vertices.end(); ++it ) { if( is_ear(*(*it)) ) { ear_list.push_back((*it)); (*it)->is_ear = true; // cl_write_console_line(cl_format(" (%1,%2)", (*it)->x, (*it)->y ) ); } } } }
CL_EarClipResult CL_EarClipTriangulator_Impl::triangulate() { create_lists(true); int num_triangles = vertices.size()-2; int tri_count = 0; CL_EarClipResult result(num_triangles); while( tri_count < num_triangles ) { if( ear_list.empty() ) // something went wrong, but lets not crash anyway. break; LinkedVertice *v = ear_list.back(); ear_list.pop_back(); CL_EarClipTriangulator_Triangle tri; tri.x1 = v->x; tri.y1 = v->y; tri.x2 = v->previous->x; tri.y2 = v->previous->y; tri.x3 = v->next->x; tri.y3 = v->next->y; result.get_triangles().push_back(tri); v->next->previous = v->previous; v->previous->next = v->next; if( is_ear(*v->next) ) { if( v->next->is_ear == false ) // not marked as an ear yet. Mark it, and add to the list. { v->next->is_ear = true; ear_list.push_back(v->next); } } else { if( v->next->is_ear == true ) // Not an ear any more. Delete from ear list. { v->next->is_ear = false; std::vector<LinkedVertice*>::iterator it; for( it = ear_list.begin(); it != ear_list.end(); ++it ) { if( (*it) == v->next ) { ear_list.erase(it); break; } } } } if( is_ear(*v->previous) ) { if( v->previous->is_ear == false ) // not marked as an ear yet. Mark it, and add to the list. { v->previous->is_ear = true; ear_list.push_back(v->previous); } } else { if( v->previous->is_ear == true ) // Not an ear any more. Delete from ear list. { v->previous->is_ear = false; std::vector<LinkedVertice*>::iterator it; for( it = ear_list.begin(); it != ear_list.end(); ++it ) { if( (*it) == v->previous ) { ear_list.erase(it); break; } } } } /* cl_write_console_line("Ear list:"); for( std::vector<LinkedVertice*>::iterator it = ear_list.begin(); it != ear_list.end(); ++it ) { cl_write_console_line(" (%1,%2)", (*it)->x, (*it)->y ); } cl_write_console_line(""); */ tri_count++; } // cl_write_console_line("num triangles - final: %1", tri_count ); return result; }
vector<Triangle> Math::triangulate(const vector<Vertex> &polygon) { if (polygon.size() < 3) throw love::Exception("Not a polygon"); else if (polygon.size() == 3) return vector<Triangle>(1, Triangle(polygon[0], polygon[1], polygon[2])); // collect list of connections and record leftmost item to check if the polygon // has the expected winding vector<size_t> next_idx(polygon.size()), prev_idx(polygon.size()); size_t idx_lm = 0; for (size_t i = 0; i < polygon.size(); ++i) { const Vertex &lm = polygon[idx_lm], &p = polygon[i]; if (p.x < lm.x || (p.x == lm.x && p.y < lm.y)) idx_lm = i; next_idx[i] = i+1; prev_idx[i] = i-1; } next_idx[next_idx.size()-1] = 0; prev_idx[0] = prev_idx.size()-1; // check if the polygon has the expected winding and reverse polygon if needed if (!is_oriented_ccw(polygon[prev_idx[idx_lm]], polygon[idx_lm], polygon[next_idx[idx_lm]])) next_idx.swap(prev_idx); // collect list of concave polygons list<const Vertex *> concave_vertices; for (size_t i = 0; i < polygon.size(); ++i) { if (!is_oriented_ccw(polygon[prev_idx[i]], polygon[i], polygon[next_idx[i]])) concave_vertices.push_back(&polygon[i]); } // triangulation according to kong vector<Triangle> triangles; size_t n_vertices = polygon.size(); size_t current = 1, skipped = 0, next, prev; while (n_vertices > 3) { next = next_idx[current]; prev = prev_idx[current]; const Vertex &a = polygon[prev], &b = polygon[current], &c = polygon[next]; if (is_ear(a,b,c, concave_vertices)) { triangles.push_back(Triangle(a,b,c)); next_idx[prev] = next; prev_idx[next] = prev; concave_vertices.remove(&b); --n_vertices; skipped = 0; } else if (++skipped > n_vertices) { throw love::Exception("Cannot triangulate polygon."); } current = next; } next = next_idx[current]; prev = prev_idx[current]; triangles.push_back(Triangle(polygon[prev], polygon[current], polygon[next])); return triangles; }