Point on an outer circle intercepted by a line perpendicular to the tangent of an inner circle?

edited March 2014 in How To...

Basically, I want to find this point (highlighted in blue):

This Point

Given the coordinates of the centers of both circles and both circles' radii, as well as the coordinates of the point on the inner circle.

The point on the inner circle is already selected randomly as follows:

          float a = radians(random(0, 360));
          float pX = innerCircRad*cos(a);
          float pY = innerCircRad*sin(a);

Not sure if that helps at all, but that's what I'm doing.

Answers

  • edited March 2014

    Is this applicable? ;-) (just copied this phrase)

    ??

    http://en.wikipedia.org/wiki/Spirograph#Mathematical_basis

  • Holy crap what?

  • Sorry, just took me a second to digest. It may be... I'll take a look.

  • I don't think so.

  • It would take me longer to digest this... ;-)

  • which of the two is it not? both?

  • Answer ✓

    Since the red line is a tangent to the smaller circle and the green line is perpendicular to it, then if we extend the green line it will pass through the centre of the smaller circle. So now we have two points on the line we need to find the line-circle intersection and there are several algorithms for that. The only other problem is that if we consider the green line to be of infinite length then there will 2 intersections of the outer circle and we have to decide which one to use.

    Anyway the sketch below does all that for you - move the mouse round the centre of the smaller circle to see what I mean.

    Although lengthy the code should be easy enough to follow and there is no need to understand how the line_circle_p code works - just accept it does what it says on the can. :\">

    final float ACCY    = 1E-9f;
    
    float cx0, cy0, rad0, ix0, iy0;
    float cx1, cy1, rad1, ix1, iy1;
    float angle;
    
    public void setup() {
      size(400, 400);
      // Big circle
      cx1 = width/2;
      cy1 = height/2;
      rad1 = width/2.2;
      // Little circle
      cx0 = 2.9 * width/4;
      cy0 = 2.5 * height/4;
      rad0 =rad1/ 2.7;
    }
    
    public void draw() {
      background(255);
      // Draw circles
      noFill();
      stroke(0, 0, 200);
      strokeWeight(2);
      ellipse(cx1, cy1, 2*rad1, 2*rad1); // outer
      stroke(200, 0, 200);
      ellipse(cx0, cy0, 2*rad0, 2*rad0); // Angle depends on mouse position
      angle = atan2(mouseY - cy0, mouseX - cx0);
      // Calculate intersection with small circle
      ix0 = cx0 + rad0 * cos(angle);
      iy0 = cy0 + rad0 * sin(angle);
      // Get the 2 possible intersection points on the outer circle
      float[] pts = line_circle_p(cx0, cy0, ix0, iy0, cx1, cy1, rad1);
      // Now work out which one we want
      ix1 = pts[0];
      iy1 = pts[1];
      if ( (ix1-cx0)*(ix0-cx0) + (iy1-cy0)*(iy0-cy0) < 0) {
        ix1 = pts[2];
        iy1 = pts[3];
      }
      // Draw the line linking the points
      stroke(200, 0, 0);
      strokeWeight(2);  
      line(cx0, cy0, ix1, iy1);
      // draw intersection on outer circle
      noStroke();
      fill(255, 0, 0, 96);
      ellipse(ix1, iy1, 16, 16);
    }
    
    /**
     * Calculate the points of intersection between a line and the
     * circumference of a circle.
     * [x0, y0] - [x1, y1] the line end coordinates 
     * [cx, cy] the centre of the circle
     * r the radius of the circle
     *
     * An array is returned that contains the intersection points in x, y order.
     * If the returned array is of length: 
     * 0 then there is no intersection 
     * 2 there is just one intersection (the line is a tangent to the circle) 
     * 4 there are two intersections 
     */
    public float[] line_circle_p(float x0, float y0, float x1, float y1, float cx, float cy, float r) {
      float[] result = null;
      float f = (x1 - x0);
      float g = (y1 - y0);
      float fSQ = f*f;
      float gSQ = g*g;
      float fgSQ = fSQ + gSQ;
    
      float xc0 = cx - x0;
      float yc0 = cy - y0;
    
      float fygx = f*yc0 - g*xc0;
      float root = r*r*fgSQ - fygx*fygx;
      if (root > -ACCY) {
        float[] temp = null;
        int np = 0;
        float fxgy = f*xc0 + g*yc0;
        if (root < ACCY) {    // tangent so just one point
          float t = fxgy / fgSQ;
          temp = new float[] { 
            x0 + f*t, y0 + g*t
          };
          np = 2;
        }
        else {  // possibly two intersections
          temp = new float[4];
          root = sqrt(root);
          float t = (fxgy - root)/fgSQ;
          //     if (t >= 0 && t <= 1) {
          temp[np++] = x0 + f*t;
          temp[np++] = y0 + g*t;
          t = (fxgy + root)/fgSQ;
          temp[np++] = x0 + f*t;
          temp[np++] = y0 + g*t;
        }
        if (temp != null) {
          result = new float[np];
          System.arraycopy(temp, 0, result, 0, np);
        }
      }
      return (result == null) ? new float[0] : result;
    }
    
  • Thank you! This is perfect!

Sign In or Register to comment.