小圆圈可左右移动任意数量 我必须在哪里计算红点的坐标 它的位置是,如果它们相交。我只在这种情况下计算。我必须找到交点,并确保它是红点上的交点,而不是它下面的交点,所以总是那个Y值较高的交点。
我已经解决了三角形和蓝点的所有距离。 如何计算红点?
如果您想查看我当前的代码以帮助调试它,请尝试此操作。
我的游乐场测试:
//: Playground - noun: a place where people can play
import UIKit
infix operator **
let pretendWidth: CGFloat = 374
let pretendHeight: CGFloat = 7
// Testing scenario is pretendWidth..<(pretendWidth + (pretendHeight / 2))
let spacer: CGFloat = 0.5
extension CGFloat {
public static func **(base: CGFloat, exp: CGFloat) -> CGFloat {
return CGFloat(pow(Double(base), Double(exp)))
}
}
class BottomBarGradientNode: UIView {
override func draw(_ rect: CGRect) {
guard let context = UIGraphicsGetCurrentContext() else { return }
context.saveGState()
context.clip(to: bounds)
// Gradient Creation
let locations: [CGFloat] = [0, 1]
let components: [CGFloat] = [0.2706, 0.6863, 0.8902, 1, 0, 0.8745, 0.7294, 1]
let colorSpace = CGColorSpaceCreateDeviceRGB()
let gradient: CGGradient = CGGradient(colorSpace: colorSpace, colorComponents: components, locations: locations, count: 2)!
let startPoint = CGPoint(x: bounds.maxX, y: bounds.maxY)
let endPoint = CGPoint(x: bounds.minX, y: bounds.minY)
let halfHeight = bounds.height / 2
let path = UIBezierPath()
let startPointForPath = CGPoint(x: bounds.width - halfHeight, y: 0)
path.move(to: startPointForPath)
let firstCenterPoint = CGPoint(x: bounds.width - halfHeight, y: halfHeight)
let secondCenterPoint = CGPoint(x: pretendWidth - bounds.height, y: 0)
Computation: if bounds.width > (pretendWidth + halfHeight) {
path.addArc(withCenter: secondCenterPoint, radius: bounds.height, startAngle: 0, endAngle: CGFloat.pi / 2, clockwise: true)
} else if bounds.width > pretendWidth {
//
// ------------------------------------------------------------------------------------------------------------------------------------
// Though this looks like a complicated geometry problem, this is really best done as an ugly algebra problem.
// We want the coordinates of the red dot: (x,y)
// We know the red dot is on the big circle and since that circle is not moving I'm going to call it's center (0,0) thus:
// x^2 + y^2 = 49
// We also know that the red dot is on the little circle, it has a moving center but we know that the y value for that
// center is always -3.5. so we'll let the x-value of that center be t:
// (x-t)^2 + (y-3.5)^2 = (3.5)^2
// which expands to:
// x^2 - 2xt + t^2 + y^2 -7y + (3.5)^2 = (3.5)^2
// which when we plug in our other equation simplifies to:
// y = (1/7)(-2tx + 49 + t^2)
// plugging that back into the first equation gives:
// x^2 + ((1/7)(-2tx + 49 + t^2))^2 = 49
// which is terrible to look out but turns out to be a quadratic equation in x, so from this point you'd just simplify
// and plug it into the quadratic formula. Pick the value of x that is smaller in magnitude (be careful about negatives
// here). Then plug that x back into the first equation to solve for y.
// ------------------------------------------------------------------------------------------------------------------------------------
//
let boundsHeightSquared = bounds.height ** 2
let distanceFromOtherCenter = firstCenterPoint.x - secondCenterPoint.x
// x^2 + ((1/7)(-2tx + 49 + t^2))^2 = 49 <<<< translates to VVVVVV
//
// ((4/49)t^2 + 1)(x^2) + (-4t - (4t^3/49))(x) + (2t^2 + (t^4)/49) = 0
// ^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^
// value1(a) value2(b) value3(c)
let value1 = ((4 * (distanceFromOtherCenter ** 2)) / boundsHeightSquared) + 1
let value2 = (-4 * distanceFromOtherCenter) - ((4 * (distanceFromOtherCenter ** 3)) / boundsHeightSquared)
let value3 = (2 * (distanceFromOtherCenter ** 2)) + ((distanceFromOtherCenter ** 4) / boundsHeightSquared)
let (first, second) = getQuadraticValues(a: value1, b: value2, c: value3)
// guarentee positive values
var areBothGreaterThanZero: Bool = false
var chosenX: CGFloat!
if first < 0 { chosenX = second }
else if second < 0 { chosenX = first }
else { chosenX = first < second ? first : second; areBothGreaterThanZero = true }
// y = (1/7)(-2tx + 49 + t^2)
var chosenY = (1 / bounds.height) * ((-2 * distanceFromOtherCenter * chosenX) + boundsHeightSquared - (distanceFromOtherCenter ** 2))
// last check on weird values
if chosenY < 0 && areBothGreaterThanZero {
chosenX = first < second ? first : second
chosenY = (1 / bounds.height) * ((-2 * distanceFromOtherCenter * chosenX) + boundsHeightSquared - (distanceFromOtherCenter ** 2))
}
// Computatation failed. Show full segment.
if chosenY < 0 {
print("Computation Failed")
path.addArc(withCenter: secondCenterPoint, radius: bounds.height, startAngle: 0, endAngle: CGFloat.pi / 2, clockwise: true)
break Computation
}
// true point
let intersectingPoint = CGPoint(x: chosenX + secondCenterPoint.x, y: chosenY)
// c^2 = a^2 + b^2 - 2abCOS(C)
// (a^2 + b^2 - c^2) / 2ab = COS(C)
let topPoint = CGPoint(x: firstCenterPoint.x, y: 0)
// compute c (distance)
let firstDistanceBetweenPoints = getDistanceBetweenTwoPoints(firstPoint: intersectingPoint, secondPoint: topPoint)
// where a and b are halfHeight
let firstCosC = getCosC(a: halfHeight, b: halfHeight, c: firstDistanceBetweenPoints)
let firstAngle = acos(firstCosC)
path.addArc(withCenter: firstCenterPoint, radius: halfHeight, startAngle: CGFloat.pi * 1.5, endAngle: CGFloat.pi * 1.5 + firstAngle, clockwise: true)
// c^2 = a^2 + b^2 - 2abCOS(C)
// (a^2 + b^2 - c^2) / 2ab = COS(C)
let lastPoint = CGPoint(x: pretendWidth, y: 0)
// compute c (distance)
let secondDistanceBetweenPoints = getDistanceBetweenTwoPoints(firstPoint: lastPoint, secondPoint: intersectingPoint)
// where a and b are bounds.height
let secondCosC = getCosC(a: bounds.height, b: bounds.height, c: secondDistanceBetweenPoints)
let secondAngle = acos(secondCosC)
path.addArc(withCenter: secondCenterPoint, radius: bounds.height, startAngle: secondAngle, endAngle: CGFloat.pi / 2, clockwise: true)
} else {
path.addArc(withCenter: firstCenterPoint, radius: halfHeight, startAngle: CGFloat.pi * 1.5, endAngle: CGFloat.pi / 2, clockwise: true)
}
path.addLine(to: CGPoint(x: bounds.height, y: bounds.height))
let finalCenterPoint = CGPoint(x: bounds.height, y: 0)
path.addArc(withCenter: finalCenterPoint, radius: bounds.height, startAngle: CGFloat.pi / 2, endAngle: CGFloat.pi, clockwise: true)
path.addLine(to: startPointForPath)
path.close()
path.addClip()
context.drawLinearGradient(gradient, start: startPoint, end: endPoint, options: .drawsAfterEndLocation)
context.restoreGState()
}
}
func getDistanceBetweenTwoPoints(firstPoint: CGPoint, secondPoint: CGPoint) -> CGFloat {
let diffX = (firstPoint.x - secondPoint.x) ** 2
let diffY = (firstPoint.y - secondPoint.y) ** 2
return sqrt(diffX + diffY)
}
func getSlopeBetweenTwoPoints(firstPoint: CGPoint, secondPoint: CGPoint) -> CGFloat {
let diffY = firstPoint.y - secondPoint.y
let diffX = firstPoint.x - secondPoint.x
return diffY / diffX
}
func getHypotenuse(firstDistance: CGFloat, secondDistance: CGFloat) -> CGFloat {
return sqrt((firstDistance ** 2) + (secondDistance ** 2))
}
func getQuadraticValues(a: CGFloat, b: CGFloat, c: CGFloat) -> (CGFloat, CGFloat) {
let first = (-b + sqrt((b ** 2) - (4 * a * c))) / (2 * a)
let second = (-b - sqrt((b ** 2) - (4 * a * c))) / (2 * a)
return (first, second)
}
func getCosC(a: CGFloat, b: CGFloat, c: CGFloat) -> CGFloat {
// (a^2 + b^2 - c^2) / 2ab = COS(C)
return ((a ** 2) + (b ** 2) - (c ** 2)) / (2 * a * b)
}
// Testing scenario is pretendWidth..<(pretendWidth + (height / 2))
let bounds = CGRect(x: 0, y: 0, width: pretendWidth + spacer, height: pretendHeight)
let bar = BottomBarGradientNode(frame: bounds)
答案 0 :(得分:1)
找到两个交叉点,然后选择合适的交点。或者根据 y 坐标制定解决方案,然后在那里选择更高的解决方案来计算 x 坐标。
圆1的等式是( x 2 + y 2 )+ a <子> 1 子> X + b'/ EM> <子> 1 子> ý + ç <子> 1 子> = 0。以这种形式写下两个圆,然后从另一个中减去一个方程。二次项将取消,剩下的等式描述圆的radical axis。 ax + by + c = 0其中 a = a 1 - a 2 等等。解决 x = - ( by + c )/ a 。将此术语插入圆的原始方程之一,并且在 y 中有一个二次方程式。
现在 y 中的二次方程的形式为 py 2 + qy + r = 0并有解决方案 - q ±sqrt( q 2 -4 pr )/ 2 p 的。查看 p 的符号,然后在平方根前面选择相同的符号,以获得具有更大 y 值的解决方案。将其插回到激进轴的等式中以计算 x 坐标。
如果没有交集, q 2 -4 pr &lt; 0,你的解决方案将变得复杂。如果 a = 0,您的激进轴是水平的,因此您无法通过 y 值对其进行参数化,并通过 y 值选择解决方案没有任何意义。