实现可插值圆角矩形时遇异常行为与插值问题求助
圆角矩形插值实现问题
我正在实现支持插值的圆角矩形,但出现异常行为:角落处结果异常,有时触发p输入无效的提示(浮点数值比较问题),核心的角落插值不流畅,所有点应均匀分布,但目前存在奇怪间隙。
相关代码如下:
public class RoundRect { float width; float height; float r; float fullWidth => width + r * 2; float fullHeight => height + r * 2; float radWidth => width + r; float radHeight => height + r; public float perimeter => (radWidth * 2 + radHeight * 2); static Exception pointOut = new Exception("Point out of the rectangle"); public RoundRect(float width, float height, float radius) { if (width < radius || height < radius) { throw new Exception("Radius should be less than dimensions"); } this.width = width - 2*radius; this.height = height - 2*radius; r = radius; } public float CornerByAxisPoint(float p, bool positive) { if (Mathf.Abs(p) > r) { Debug.Log("Invalid input p: " + p + $". Must be within [-{r}, {r}]"); p = Mathf.Clamp(p, -r, r); } return Mathf.Sqrt(r * r - p * p) * (positive ? 1 : -1); } public Vector2 GetPointOnBase(float x, bool topSide) { if (x <= width) { return new Vector2(x+(topSide ? 0 : -width), (topSide ? r : -r)); } else if (x > width) { return new Vector2(x+(topSide ? 0 : -width*2-r), CornerByAxisPoint(x-width+(topSide ? 0 : -r), topSide)); } else throw pointOut; } public Vector2 GetPointOnLegs(float y, bool rightSide) { if (y <= height) { return new Vector2(0, y * (rightSide ? -1 : 1)); } else if (y > height) { return new Vector2(CornerByAxisPoint(y-height, rightSide)+(rightSide ? -r : r), (rightSide ? -y : y)); } else throw pointOut; } public Vector2 GetPoint(float p) { Debug.Log(p); if (p <= radWidth) { return GetPointOnBase(p, true)+Vector2.right*r; } //cycle top else if (p > radWidth && p <= radWidth + radHeight) { return GetPointOnLegs(p - radWidth, true)+Vector2.right*fullWidth; } //cycle right else if (p > radWidth + radHeight && p <= radWidth*2 + radHeight) { return GetPointOnBase(p - (radWidth + radHeight), false)+Vector2.right*radWidth+Vector2.down*height; //cycle bottom } else if (p > radWidth*2 + radHeight && p <= radWidth*2 + radHeight*2) { return GetPointOnLegs(p - (radWidth*2 + radHeight), false)+Vector2.down*height; //cycle left } else throw pointOut; } public Vector2 InterpolatePoint(float t) => GetPoint(Mathf.Lerp(0f, perimeter, t)); public static Vector3 OnGround(Vector2 point) { return new Vector3(point.x, 0, point.y); } }
我通过GetPointOnLegs获取左右侧边位置,GetPointOnBase获取上下底边位置。曾尝试用epsilon解决平方根无效问题,但核心的角落插值不流畅问题仍存在,因此恢复了原有代码。
补充说明:线性插值将点从0映射到周长的算法并不适用,因为单位圆的四分之一圆弧两端不对称,y的绝对差值不同,这和三角函数波形特性一致。我之前处理圆弧的方式是将点重置到单位圆范围(-1,1),再通过圆方程获取y坐标。
内容的提问来源于stack exchange,提问作者annie_pp
相关产品推荐
相关产品推荐

