You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

实现可插值圆角矩形时遇异常行为与插值问题求助

圆角矩形插值实现问题

我正在实现支持插值的圆角矩形,但出现异常行为:角落处结果异常,有时触发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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 12:16:20