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)
	}
Exemple #3
0
//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;
}