Редактировать: Этот первый предпочтительный метод - версия 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
- Сделайте круг с радиусом, равным половине расстояния между
o
и p
, начните его с середины линии op
. - Вычислите точку пересечения исходный круг и вновь созданный круг.
div {
margin:5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id=app></div>