title: Scale a Bezier Curve Proportionally - calculate control points
body: <p>I'm trying to take a bezier curve (any arbitrary curve in Core Graphics) and shrink (or expand) it proportionally given another two end points.  I have an approach that sort of works, but it ends up 'flattening' out the curves, and not retaining the shape exactly.  Maybe I've messed up the code or logic, but I have the two original points along with the control point(s).  Given another set of end points I want to calculate the appropriate control points to produce the same shape between the new end points.  </p>
  
  <p>Here's the main code that will calculate 1 control point:</p>
  
  <pre><code>CGPoint (^ScaledCtrlPoint)(CGPoint, CGPoint, CGPoint, CGPoint, CGPoint) = ^CGPoint (CGPoint refPoint1, CGPoint refPoint2, CGPoint bevPoint1, CGPoint bevPoint2, CGPoint ctrlPoint){
          //Normalize points to refPoint1
          refPoint2.x -= refPoint1.x; refPoint2.y -= refPoint1.y;
          ctrlPoint.x -= refPoint1.x; ctrlPoint.y -= refPoint1.y;
          //Normalize bevPoints to bevPoint1
          bevPoint2.x -= bevPoint1.x; bevPoint2.y -= bevPoint1.y;
          //Calculate control point angle
          CGFloat theta = PointTheta(refPoint2);
          CGFloat refHyp = (refPoint2.y != 0.0f) ? refPoint2.y / sinf(theta) : refPoint2.x / cosf(theta);
          theta = PointTheta(bevPoint2);
          CGFloat bevHyp = (bevPoint2.y != 0.0f) ? bevPoint2.y / sinf(theta) : bevPoint2.x / cosf(theta);
          theta = PointTheta(ctrlPoint);
          CGFloat ctrlHyp = (ctrlPoint.y != 0.0f) ? ctrlPoint.y / sinf(theta) : ctrlPoint.x / cosf(theta);
          ctrlHyp *= (bevHyp / refHyp);
          return CGPointMake(bevPoint1.x + cosf(theta) * ctrlHyp, bevPoint1.y + sinf(theta) * ctrlHyp);
      };
  </code></pre>
  
  <p>The <code>bevPoints</code> are the new points I'm using to calculate the new control point.  The <code>refPoints</code> and <code>ctrlPoint</code> are the original points of the bezier curve.  As you can see, I'm trying to scale the ctrlPoint down (could also work up) by the same ratio as the the original end points are to the new end points.</p>
  
  <p>I also use another function, which I use to calculate incident angles.  It's pretty simple:</p>
  
  <pre><code>CGFloat         PointTheta(CGPoint point){
      //This assumes an origin of {0, 0} and returns a theta for the given point
      CGFloat theta = atanf(point.y / point.x);
      //Using arc tan requires some adjustment depending on the point quadrant
      if (point.x == 0.0f) theta = (point.y &gt;= 0.0f) ? M_PI_2 : M_PI + M_PI_2;
      else if (point.x &lt; 0.0f) theta += M_PI;
      else if (point.x &gt; 0.0f &amp;&amp; point.y &lt; 0.0f) theta += (M_PI * 2);
      return theta;
  }
  </code></pre>