Учитывая точку за пределами ar c, как найти точку на ar c, которая простирается до этой точки? - PullRequest
0 голосов
/ 10 февраля 2020

Учитывая точку за пределами ar c, как найти точку на ar c, которая простирается до этой точки?

Например, радиус круга ( R ) - 10 см, его центральная точка - [0,0].
Начало ( o ) линии ( 8 ) находится в [-3, 10]
Как мы можем найти точку ( p ) (p8), если касательная в этой точке продолжается до начала линии?

Решение о грубой силе не будет приемлемо.

Extensions of arc

Ответы [ 3 ]

1 голос
/ 11 февраля 2020

WLOG круг центрируется в начале координат. Мы express считаем, что точка на окружности, пусть (u, v), образует прямой угол с линиями к центру и к целевой точке (x, y):

u (x - u) + v (y - v) = 0

или

u x + v y = r².

Переписываем и возводим в квадрат, чтобы получить

(r² - u²) y² = (r² - u x)²,

квадратное c уравнение в u. Отсюда следует v = √(r² - u²) и у вас есть точка касания.

1 голос
/ 11 февраля 2020

Пусть координаты точки равны px, py, а центр окружности равен (0,0) (если нет - вычтите центр cx, cy из всех координат, чтобы упростить уравнения, добавьте их обратно в конец).

Вы Можно написать два уравнения для неизвестных x,y. Уравнение окружности и перпендикулярность одно - касательная перпендикулярна радиус-вектору, их точечное произведение равно нулю.

(x - px) * x + (y - py) * y = 0
x^2 + y^2 = r^2

x^2 - px * x + y^2 - py * y = 0
r^2 - px * x = py * y
y = (r^2 - px * x) / py
y^2  = r^4 / py ^2 - x * 2 * r^2 * px / py^2 + x^2 * px^2 / py^2    

x^2 * (1 + px^2 / py^2) - x * 2 * r^2 * px / py^2 +  (r^4 / py^2 - r^2) = 0
x^2 * (py^2 + px^2) - x * 2 * r^2 * px  +  (r^4 - r^2 * py^2) = 0

Решите последнее квадратное c уравнение для x, затем вычислите y.

enter image description here

Delphi функция для справки (примечание: случай py = 0 рассматривается отдельно)

function GetTangentPts(px, py, r: Double): TArray<Double>;
var
  px2, py2, pxpy, r2, Dis, x, y: Double;
begin
  px2 := px * px;
  py2 := py * py;
  r2 := r * r;
  pxpy := px2 + py2;
  Dis := pxpy - r2;
  if Dis < 0 then    //point is inside
    Exit(nil)
  else if Dis = 0 then begin    //point is at circumference
    SetLength(Result, 2);
    if py = 0 then begin
      x := px;
      y := 0;
    end else begin
      x := px * r2 / pxpy;
      y := (r2 - px * x) / py;
    end;
    Result[0] := x;
    Result[1] := y;
  end else begin       //general case, two tangents
    SetLength(Result, 4);
    if py = 0 then begin
       y := - r * Sqrt(Dis) / px;
       x := px / Abs(px) * r * Sqrt(1 - Dis/px2);
       Result[0] := x;
       Result[1] := y;
       y := r * Sqrt(Dis) / px;
       Result[2] := x;
       Result[3] := y;
    end else begin
      x := (px * r2 - r * Sqrt(py2 * Dis)) / pxpy;
      y := (r2 - px * x) / py;
      Result[0] := x;
      Result[1] := y;
      x := (px * r2 + r * Sqrt(py2 * Dis)) / pxpy;
      y := (r2 - px * x) / py;
      Result[2] := x;
      Result[3] := y;
    end;
  end;
end;

некоторые результаты:

10.00 10.00 10.00 //two perpendicular tangents
 0.00
10.00
10.00
 0.00

-10.00 10.00 10.00
-10.00
 0.00
 0.00
10.00

 1.00  1.00 10.00
 //inside

 0.00 10.00 10.00 //horizontal tangent
 0.00
10.00

10.00  0.00 10.00 //vertical tangent
10.00
 0.00

-14.14  0.00 10.00  //two tangents from OX-axis
-7.07
 7.07
-7.07
-7.07
0 голосов
/ 11 февраля 2020

Редактировать: Этот первый предпочтительный метод - версия js, в значительной степени основанная на методе @ MBo Исправляет пару ошибок там.

function tangentLines(centerX, centerY, radius, pX, pY) {
  var horizontalAdjustment, verticalAdjustment, pX_Squared, pY_Squared,
    pXY_Squared, radiusSquared, delta, x, y, result, onSameY, temp

  // Center the circle at [0,0] to simplify things
  onSameY = pY === centerY
  horizontalAdjustment = centerX
  verticalAdjustment = centerY
  pX -= horizontalAdjustment
  pY -= verticalAdjustment
  centerX = centerY = 0
  // If pY is on the same vertical as centerY then temporarily swap pX and pY
  // to avoid bug caused by division of 0
  if(onSameY){
    temp = pY
    pY = pX
    pX = temp
  }

  pX_Squared = pX * pX
  pY_Squared = pY * pY
  radiusSquared = radius * radius
  pXY_Squared = pX_Squared + pY_Squared
  delta = pY_Squared * (pXY_Squared - radiusSquared)

  // Point is inside i.e. no tangent
  if (delta < 0 || pXY_Squared < radiusSquared) {
    return false
  }

  // Point is on circumference only one tangent point
  if (delta === 0) {
    x = (pX * radiusSquared)
    if (pXY_Squared) { x /= pXY_Squared }

    y = (radiusSquared - pX * x)
    if (pY) { y /= pY }
    x += horizontalAdjustment
    y += verticalAdjustment
    return onSameY ? [y,x] : [x, y]
  }

  // Regular case point is outside of tangent there are 2 tangent points
  x = (pX * radiusSquared - radius * Math.sqrt(delta))
  if (pXY_Squared) { x /= pXY_Squared }
  y = (radiusSquared - pX * x)
  if (pY) { y /= pY }
  x += horizontalAdjustment
  y += verticalAdjustment
  result = [
    onSameY ? [y, x] : [x, y],
    []
  ]
  x = (pX * radiusSquared + radius * Math.sqrt(delta))
  if (pXY_Squared) { x /= pXY_Squared }
  y = (radiusSquared - pX * x)
  if (pY) { y /= pY }
  x += horizontalAdjustment
  y += verticalAdjustment
  result[1] = onSameY ? [y, x] : [x, y]
  return result
}

new Vue({
  el: '#app',
  template: `
        <div>
          <div>
            centerX: <input v-model="centerX" @input="intersectionPoints">
            centerY:  <input v-model="centerY" @input="intersectionPoints">
            <div>radius: <input v-model="radius" @input="intersectionPoints"></div>
          </div>
          <div>
            pointX: <input v-model="pointX" @input="intersectionPoints">
            pointY: <input v-model="pointY" @input="intersectionPoints">
          </div>
          <div v-if=result>
          <div>Insect points: {{result}}</div>
          </div>
          <div v-if=!result>No intersections :-(</div>
        </div>
            `,
  data: function() {
    return {
      centerX: 200,
      centerY: 200,
      radius: 100,
      pointX: 160,
      pointY: 100,
      result: null
    };
  },
  methods: {
    intersectionPoints() {
      this.result = tangentLines(
        +this.centerX,
        +this.centerY,
        +this.radius,
        +this.pointX,
        +this.pointY
      );
    }
  },
  mounted: function() {
    this.intersectionPoints();
  }
});

// Without Vue just use something like
// tangentLines(200, 200, 100, 160, 100);
div {
  margin: .5em;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app"></div>

Вот исходный код, который я придумал.

На основе ответа @Aretino https://math.stackexchange.com/questions/3541795/given-a-point-outside-of-an-arc-how-can-one-find-the-point-on-the-arc-which-ext/3541928#3541928

  1. Сделайте круг с радиусом, равным половине расстояния между o и p, начните его с середины линии op.
  2. Вычислите точку пересечения исходный круг и вновь созданный круг.

Intersection point

div {
margin:5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id=app></div>

...