我如何将标准化坐标系中点的位置转换为具有相对位置的常规坐标系?

How would I convert the position of a point in a normalized coordinate system, to a regular coordinate system that has a relative position?

这个数学不是特定于平台的,我会用任何语言作为答案。这很难解释我为什么要这样做,但我会尝试包含图片。

我有一个将地图作为容器覆盖的视图(视图 A)。目的是包含我们的内容,同时在用户拖动地图时保持固定在地图上。该视图有一个坐标系,原点位于屏幕的左上角。这将是我们的绝对坐标系,我们试图在其中转换位置。

接下来,我们在视图 A 和屏幕上可见的内容之间形成一个矩形。我在我的 UIView 中使用以下 属性 实现了这一点:

    var visibleRect: CGRect {
        guard let superview = self.superview?.superview else {
            return CGRect(x: 0, y: 0, width: 0, height: 0)
        }
        // Convert the superview's coordinate system to the current view's coordinate system and find the intersecting rectangle. This is so we don't have to render excessive particles.
        let val = self.bounds.intersection(
            self.convert(superview.frame, from: superview)
        )
        return val
    }

这个returns说的是Rectangle,其原点相对于View A的原点。这个Rectangle的目的是Metal View不能太大,所以我将Metal View限制在可见的范围内绘制专门同时保持 Metal View 相对于 View A 的绘制位置的精确坐标。

我已经能够验证视图 A 中矩形的相对原点是否准确,并且我已经验证金属视图适合矩形。

这是我一直在思考的问题:金属顶点函数的中心坐标系从 -11 的整个宽度和高度如下图所示(除了我只在二维中使用它 space 所以忽略 z 位置):

现在我的问题是:

如果我在金属视图的左上象限 (-0.002, 0.5) 中找到一个点,我将如何利用给定的信息找到它在视图 A 中的位置?我如何 return 视图 A 中点的位置到金属视图占相对定位的矩形?


视觉

这是一个希望澄清的视觉图:

编辑

如果 Metal View 使用以下文本代码占据了 View A 的整个范围,我就能够从 View A 转换为 Metal View:

def normalizedToViewA(x, y):
    x *=  1.0
    y *= -1.0
    x +=  1.0
    y +=  1.0
    return ((x / 2.0) * width, (y / 2.0) * height)

def viewAToNormalized(x, y):
    normalizedX = x / (width / 2.0)
    normalizedY = y / (height / 2.0)
    normalizedX -=  1.0
    normalizedY -=  1.0
    normalizedX *=  1.0
    normalizedY *= -1.0
    return (normalizedX, normalizedY)

但现在我需要计算 Metal View 是否填充了 Rectangle,它只是 View A 的一部分。

我找到了答案并使用了 Python 以便于阅读。

视图 A 为 1270*680。

# View A (Top Left Origin)
width = 1270
height = 680

# Visible Rectangle (Top Left Origin)
#   with an origin as a position in View A
subOriginX = 1000
subOriginY = 400
subWidth = 20
subHeight = 20

# Centered origin converted to top left origin
#   where origin is (0,0)
def normalizedToSubview(x, y):
    x *=  1.0
    y *= -1.0
    x +=  1.0
    y +=  1.0
    return ((x / 2.0) * subWidth, (y / 2.0) * subHeight)

# Top Left origin to centered origin
def subviewToNormalized(x, y):
    normalizedX = x / (subWidth / 2.0)
    normalizedY = y / (subHeight / 2.0)
    normalizedX -=  1.0
    normalizedY -=  1.0
    normalizedX *=  1.0
    normalizedY *= -1.0
    return (normalizedX, normalizedY)

# Relative position of a point within subview
#   but on View A's plane
def subviewToViewA(x, y):
    return (x + subOriginX, y + subOriginY)


# Relative position of a point within View A
#   but on the subview's plane
def viewAToSubView(x, y):
    return (x - subOriginX, y - subOriginY)


# Position within Metal View to a position within View A
normalizedCoord = (0.0, 0.0)
toSubview = normalizedToSubview(*normalizedCoord)
viewACoord = subviewToViewA(*toSubview)

print(f"Converted {normalizedCoord} to {toSubview}")
print(f"Converted {toSubview} to {viewACoord}")
# Converted (0.0, 0.0) to (10.0, 10.0)
# Converted (10.0, 10.0) to (1010.0, 410.0)

# Position within View A to Metal View
backToSubview = viewAToSubView(*viewACoord)
backToNormalized = subviewToNormalized(*backToSubview)
# Converted (1010.0, 410.0) to (10.0, 10.0)
# Converted (10.0, 10.0) to (0.0, -0.0)

print(f"Converted {viewACoord} to {backToSubview}")
print(f"Converted {backToSubview} to {backToNormalized}")

这是一个非常小众的问题,但如果您遇到类似的问题,请发表评论,我会尽力扩展。