如何正确缩放和规范化(x,y)坐标从一个窗口大小到另一个窗口大小

问题描述 投票:0回答:2

我正在创建一个聊天程序,允许用户在聊天室中自由移动他们的头像。首次加载程序时,默认聊天窗口大小为(996,496),这是窗口可以达到的最小大小。用户可以调整程序的大小,因此该窗口将根据他们的喜好调整大小。

我试图确保每个客户端都能够正确渲染用户头像的位置,无论其他用户的屏幕尺寸如何。最终,目标是让所有客户端的所有化身都处于大致位置。

为了实现这一点,我在客户端重新定位头像时提出了以下解决方案:

  • 将当前头像的 (x,y) 坐标标准化为 [0,1] 之间的百分比。在这种情况下,相对坐标 (0,0) = 房间窗口的左上角,(1,1) 的相对坐标将是房间窗口的右下角。

  • 我想使用这些标准化的(x,y)坐标将头像放置在客户房间窗户的正确位置,以适应其特定的窗口尺寸。

  • 在这种情况下,如果新的 x 坐标 > 房间窗口宽度,那么我会将新的 x 坐标设置为(房间窗口宽度 - 头像宽度)。同样,如果新的 y 坐标 > 房间窗户高度,那么我会将新的 y 坐标设置为(房间窗户高度 - 头像高度)。这应该可以防止头像超出可视房间区域

这种方法几乎有效,但我遇到了一个问题,如果房间窗口在客户端上调整为更大的尺寸,那么头像将无法正确更新其位置。例如,如果我将头像放在右下角(相对位置1,1),然后最大化房间窗口,头像并没有像我期望的那样移动到右下角。

为了尝试解决这个问题,我添加了一个缩放因子。我的假设是使用(新房间大小/原始房间大小)来计算比例。这确实使得角色在房间窗户增大后尝试去到正确的位置,但实际的新坐标值小于预期值,因此角色没有准确到达它需要的位置。此外,当房间窗户增大时,当头像移动到房间的任何部分(角落除外)时,它现在会到达错误的位置。

您可以在此处查看我为尝试实现此目的而编写的代码:

    int avatarX = roomUser.UserAvatarX; // current X coordinate
    int avatarY = roomUser.UserAvatarY; // current Y coordinate
    int avatarWidth = roomUser.UserAvatar.Width; 
    int avatarHeight = roomUser.UserAvatar.Height;
    int roomWidth = FrmClient.formClient.WebBrowser.Width; // Client room width
    int roomHeight = FrmClient.formClient.WebBrowser.Height; // Client room height
    int originalRoomWidth = 996;
    int originalRoomHeight = 496;

    // Compute the scale factor to account for difference in room sizes
    double scaleX = roomWidth / (double)originalRoomWidth;
    double scaleY = roomHeight / (double)originalRoomHeight;

    // Compute the X coordinate as a percentage of the room width
    double relativeX = avatarX / (double)(roomWidth - avatarWidth);

    // Compute the Y coordinate as a percentage of the room height
    double relativeY = avatarY / (double)(roomHeight - avatarHeight);
   
    // Calculate the actual X coordinate based on the percentage, room size, and scale factor
    int actualX = (int)(relativeX * (roomWidth - avatarWidth) * scaleX + 0.5);

    // Calculate the actual Y coordinate based on the percentage, room size, and scale factor
    int actualY = (int)(relativeY * (roomHeight - avatarHeight) * scaleY + 0.5);


    // Adjust the avatar position if necessary
    if (actualX + avatarWidth > roomWidth)
    {
      actualX = roomWidth - avatarWidth;
    }

    if (actualY + avatarHeight > roomHeight)
    {
      actualY = roomHeight - avatarHeight;
    }

    // Update the position of the avatar control in the room
    roomUser.UserAvatar.Location = new Point(actualX, actualY);

这是我得到的结果与我期望的结果的具体示例:

  • 当房间窗户尺寸为:(996,496)时

  • 我希望右下角是(1,1)的标准化位置(有效)

  • 我希望这会转化为右下角:(796, 296)(有效)

到目前为止,该程序的运行效果符合我的预期。我什至可以在房间窗户的任何部分自由移动头像,没有任何问题。然而...

  • 我现在将房间窗口的大小调整为:(1495, 663)

  • 我希望右下角标准化为(1,1)的位置(有效)

  • 我希望这会转化为右下角:(1295, 463),所以我希望我的头像现在移动到这个新位置,但事实并非如此。 (失败)

  • 实际发生的情况是,我的头像被放置在位置 (1195, 396),而不是去 (1295, 463)。事实上,随着窗口尺寸的增加,每当我将头像移动到房间内的任何位置时,头像都会移动到错误的位置。

最后,这里是每个标准化坐标对应对应的角的列表,只是为了更具体地说明我如何尝试标准化坐标:

> (0, 0) = top left
> (0, 1) = bottom left
> (1, 0) = top right
> (1, 1) = bottom right
c# math geometry
2个回答
0
投票

这是带有硬编码测试值的代码,其中包括头像尺寸的缩放:

int avatarX = 1395; // current X coordinate
int avatarY = 563; // current Y coordinate
int avatarWidth = 100;
int avatarHeight = 100;
int roomWidth = 1495; // Client room width
int roomHeight = 663; // Client room height
int originalRoomWidth = 996;
int originalRoomHeight = 496;

// Compute the scale factor to account for difference in room sizes
double scaleX = roomWidth / (double)originalRoomWidth;
double scaleY = roomHeight / (double)originalRoomHeight;

// Compute the X coordinate as a percentage of the room width
double actualX = avatarX * scaleX;

// Compute the Y coordinate as a percentage of the room height
double actualY = avatarY * scaleY;


double scaledWidth = (double)avatarWidth * scaleX;
double scaledHeight = (double)avatarHeight * scaleY;

// Adjust the avatar position if necessary
if (actualX + scaledWidth > roomWidth)
{
    actualX = roomWidth - scaledWidth;
}

if (actualY + scaledHeight > roomHeight)
{
    actualY = roomHeight - scaledHeight;
}

// assuming there is a set accessor:
roomUser.UserAvatar.Width = scaledWidth;
roomUser.UserAvatar.Height = scaledHeight;

0
投票

让我纠正一些计算:

// Compute the X coordinate as a percentage of the room width
//NO    double relativeX = avatarX / (double)(roomWidth - avatarWidth);
// avatarX: last coordinate (pixel) before a size change
double relativeX = avatarX / (double)previousRoomWidth;
//Same for relativeY
double relativeY = avatarY / (double)previousRoomHeight;

// Calculate the actual X,Y coordinates based on the percentage and new room size.
int actualX = (int)(relativeX * roomWidth);
int actualY = (int)(relativeY * roomHeight);

所有这些都是针对调整窗口大小而在左侧没有看到新内容的情况。我的意思是,X,Y 原点没有改变。

例如,如果原点更改为

noX, noY
,那么最后两行必须是

int actualX = noX + (int)(relativeX * roomWidth);
int actualY = noY + (int)(relativeY * roomHeight);

请注意,不需要比例因子。如果您也希望调整头像大小,则可能会这样。

为了不将头像定位+/-1像素,也许你想将

avatarX, avatarY
存储到
double
中,并在绘制它们的函数中将它们转换为像素(
int
)。

© www.soinside.com 2019 - 2024. All rights reserved.