void PathRenderer::subdivide_bezier(int level, float cp0_x, float cp0_y, float cp1_x, float cp1_y, float cp2_x, float cp2_y, float cp3_x, float cp3_y, float t0, float t1) { const float split_angle_cos = 0.99f; float tc = (t0 + t1) * 0.5f; clan::Pointf sp = point_on_bezier(cp0_x, cp0_y, cp1_x, cp1_y, cp2_x, cp2_y, cp3_x, cp3_y, t0); clan::Pointf cp = point_on_bezier(cp0_x, cp0_y, cp1_x, cp1_y, cp2_x, cp2_y, cp3_x, cp3_y, tc); clan::Pointf ep = point_on_bezier(cp0_x, cp0_y, cp1_x, cp1_y, cp2_x, cp2_y, cp3_x, cp3_y, t1); clan::Vec2f sp2cp(cp.x - sp.x, cp.y - sp.y); clan::Vec2f cp2ep(ep.x - cp.x, ep.y - cp.y); float dot = clan::Vec2f::dot(sp2cp.normalize(), cp2ep.normalize()); if (dot < split_angle_cos && level < 15) { subdivide_bezier(level + 1, cp0_x, cp0_y, cp1_x, cp1_y, cp2_x, cp2_y, cp3_x, cp3_y, t0, tc); subdivide_bezier(level + 1, cp0_x, cp0_y, cp1_x, cp1_y, cp2_x, cp2_y, cp3_x, cp3_y, tc, t1); } else { line(ep.x, ep.y); } }
void PathRenderer::cubic_bezier(float cp1_x, float cp1_y, float cp2_x, float cp2_y, float cp3_x, float cp3_y) { float cp0_x = last_x; float cp0_y = last_y; float estimated_length = std::sqrt((cp1_x - cp0_x) * (cp1_x - cp0_x) + (cp1_y - cp0_y) * (cp1_y - cp0_y)) + std::sqrt((cp1_x - cp0_x) * (cp1_x - cp0_x) + (cp1_y - cp0_y) * (cp1_y - cp0_y)) + std::sqrt((cp1_x - cp0_x) * (cp1_x - cp0_x) + (cp1_y - cp0_y) * (cp1_y - cp0_y)); float min_segs = 10.0f; float segs = estimated_length / 5.0f; int steps = (int)std::ceil(std::sqrt(segs * segs * 0.3f + min_segs)); for (int i = 0; i < steps; i++) { //clan::Pointf sp = point_on_bezier(cp0_x, cp0_y, cp1_x, cp1_y, cp2_x, cp2_y, cp3_x, cp3_y, i / (float)steps); clan::Pointf ep = point_on_bezier(cp0_x, cp0_y, cp1_x, cp1_y, cp2_x, cp2_y, cp3_x, cp3_y, (i + 1) / (float)steps); line(ep.x, ep.y); } // http://ciechanowski.me/blog/2014/02/18/drawing-bezier-curves/ // http://antigrain.com/research/adaptive_bezier/ (best method, unfortunately GPL example code) }
//returns the distance along the edge which is farthest from the other edges double fatgraph_remotest(fatgraph* fg, int edge) { //go through 100 points on edge and find the one which is farthest from //all the other edges vector2d currentPoint; double currentDist; double minDistToThisPoint; double pointMaxDistAway; double maxDist; double i; int j; int k; vector2d* bezier1 = (vector2d*)malloc((fg->num_edges)*sizeof(vector2d)); vector2d* bezier2 = (vector2d*)malloc((fg->num_edges)*sizeof(vector2d)); for (j=0; j<fg->num_edges; j++) { //find the beziers for (k=0; k<fg->verts[fg->edges[j].start].num_edges; k++) { if (j == fg->verts[fg->edges[j].start].edges[k] && fg->verts[fg->edges[j].start].edges_initial[k] == 1) { bezier1[j] = fg->verts[fg->edges[j].start].bezier[k]; break; } } for (k=0; k<fg->verts[fg->edges[j].end].num_edges; k++) { if (j == fg->verts[fg->edges[j].end].edges[k] && fg->verts[fg->edges[j].end].edges_initial[k] == 0) { bezier2[j] = fg->verts[fg->edges[j].end].bezier[k]; break; } } bezier1[j] = vector2d_add(fg->verts[fg->edges[j].start].loc, bezier1[j]); bezier2[j] = vector2d_add(fg->verts[fg->edges[j].end].loc, bezier2[j]); } //printf("I'm finding the remotest point on edge %d\n", edge); //now find the best point maxDist = 0; for (i=0; i<1; i+=0.01) { minDistToThisPoint = 1e8; currentPoint = point_on_bezier(fg->verts[fg->edges[edge].start].loc, fg->verts[fg->edges[edge].end].loc, bezier1[edge], bezier2[edge], i); //distances to edges for (j=0; j<fg->num_edges; j++) { if (j==edge) { continue; } currentDist = distance_to_bezier_fast(fg->verts[fg->edges[j].start].loc, fg->verts[fg->edges[j].end].loc, bezier1[j], bezier2[j], currentPoint.x, currentPoint.y); if (currentDist < minDistToThisPoint) { minDistToThisPoint = currentDist; } } //distances to vertices for (j=0; j<fg->num_verts; j++) { currentDist = sqrt( (currentPoint.x - fg->verts[j].loc.x)* (currentPoint.x - fg->verts[j].loc.x) + (currentPoint.y - fg->verts[j].loc.y)* (currentPoint.y - fg->verts[j].loc.y) ); if (currentDist < minDistToThisPoint) { minDistToThisPoint = currentDist; } } if (minDistToThisPoint > maxDist) { maxDist = minDistToThisPoint; pointMaxDistAway = i; //printf("New remotest point (distance %f) at %f\n", maxDist, i); } } free(bezier1); free(bezier2); return pointMaxDistAway; }