计算直线的斜率(如果它是无穷大)

Calculating slopes of a line if it is infinity

我正在 Java(特别是 Android)中制作显示如下内容的内容:

用户可以拖动框的角,正如预期的那样,虚线应相应移动,始终有 3 条水平线(一条在中间,一条在顶部和底部之间,一条在 25% 处,一条在 75% 处) 和 3 条垂直线。但是,如果左边缘或右边缘是无穷大(当用户第一次看到屏幕时),它看起来像这样:

如何更改我的代码,以便考虑无限斜率边缘并仍然显示所需的屏幕?这是我的代码,用于检测虚线的位置、斜率,最后绘制到屏幕上。

//get edge slopes to calculate dashed lines
//c1X is the top left corner X position, c2X is for the top right corner, etc.
            float topLineSlope = (c2Y - c1Y)/(c2X - c1X);
            float rightLineSlope = (c3Y - c2Y)/(c3X - c2X);
            float bottomLineSlope = (c4Y - c3Y)/(c4X - c3X);
            float leftLineSlope = (c1Y - c4Y)/(c1X - c4X);


            //b in y=mx+b
            float topLineB = c1Y - (topLineSlope * c1X);
            float rightLineB = c2Y - (rightLineSlope * c2X);
            float bottomLineB = c3Y - (bottomLineSlope * c3X);
            float leftLineB = c4Y - (leftLineSlope * c4X);

            //final dashed line coordinates
            float topLineMiddleX = (c1X + c2X) / 2.0f;
            float topLineMiddleY = topLineSlope * topLineMiddleX + topLineB;
            float bottomLineMiddleX = (c3X + c4X) / 2.0f;
            float bottomLineMiddleY = bottomLineSlope * bottomLineMiddleX + bottomLineB;
            float leftLineMiddleX = (c4X + c1X) / 2.0f;
            float leftLineMiddleY = leftLineSlope * leftLineMiddleX + leftLineB;
            float rightLineMiddleX = (c2X + c3X) / 2.0f;
            float rightLineMiddleY = rightLineSlope * rightLineMiddleX + rightLineB;

            float topLineLeftX = (c1X + topLineMiddleX) / 2.0f;
            float topLineLeftY = topLineSlope * topLineLeftX + topLineB;
            float bottomLineLeftX = (c4X + bottomLineMiddleX) / 2.0f;
            float bottomLineLeftY = bottomLineSlope * bottomLineLeftX + bottomLineB;
            float topLineRightX = (topLineMiddleX + c2X) / 2.0f;
            float topLineRightY = topLineSlope * topLineRightX + topLineB;
            float bottomLineRightX = (c3X + bottomLineMiddleX) / 2.0f;
            float bottomLineRightY = bottomLineSlope * bottomLineRightX + bottomLineB;

            float leftLineTopX = (c1X + leftLineMiddleX) / 2.0f;
            float leftLineTopY = leftLineSlope * leftLineTopX + leftLineB;
            float rightLineTopX = (c2X + rightLineMiddleX) / 2.0f;
            float rightLineTopY = rightLineSlope * rightLineTopX + rightLineB;
            float leftLineBottomX = (leftLineMiddleX + c4X) / 2.0f;
            float leftLineBottomY = leftLineSlope * leftLineBottomX + leftLineB;
            float rightLineBottomX = (c3X + rightLineMiddleX) / 2.0f;
            float rightLineBottomY = rightLineSlope * rightLineBottomX + rightLineB;

            canvas.drawLine(topLineMiddleX, topLineMiddleY, bottomLineMiddleX, bottomLineMiddleY, dashedLine);
            canvas.drawLine(leftLineMiddleX, leftLineMiddleY, rightLineMiddleX, rightLineMiddleY, dashedLine);
            canvas.drawLine(topLineLeftX, topLineLeftY, bottomLineLeftX, bottomLineLeftY, dashedLine);
            canvas.drawLine(topLineRightX, topLineRightY, bottomLineRightX, bottomLineRightY, dashedLine);
            canvas.drawLine(leftLineTopX, leftLineTopY, rightLineTopX, rightLineTopY, dashedLine);
            canvas.drawLine(leftLineBottomX, leftLineBottomY, rightLineBottomX, rightLineBottomY, dashedLine);

如果一直是一个底边完全水平的矩形,你根本不需要使用斜坡,你只需在内部的两个层次上从左到右画一条水平线,例如:

bottom +     (top - bottom) / 3
bottom + 2 * (top - bottom) / 3

从上到下的垂直线也是如此。

这基本上只是执行以下操作,假设左下角是离原点最近的点:

hspread = (right - left) / 3
line (top, left +     hspread) - (bottom, left +     hspread)
line (top, left + 2 * hspread) - (bottom, left + 2 * hspread)

vspread = (top - bottom) / 3
line (bottom +     vspread, left) - (bottom +     vspread, right)
line (bottom + 2 * vspread, left) - (bottom + 2 * vspread, right)

如果角可以独立移动(即,它不必是矩形),您仍然不需要让自己参与斜坡。

然后你需要做的是沿着每边找到相当于沿线 1/3 和 2/3 距离的点,并将它们连接起来。对于直线 (x1,y1)-(x2,y2),您可以简单地使用以下命令找到点 4/5

x = x1 + (x2-x1) * 4/5
y = y1 + (y2-y1) * 4/5

例如,如果形状是这样的:

       (x1,y1)            (x2,y2)
                    ___--+
              +----'      \
              |            \
              |             \
              |              \
              |               \
              +----------------+
       (x3,y3)                  (x4,y4)
     :
     :
     :......
(0,0)

(为"graphics"道歉),最上面的水平线可以画成:

line (x3 + (x1-x3) * 2/3, y3 + (y1-y3) * 2/3)
   - (x4 + (x2-x4) * 2/3, y4 + (y2-y4) * 2/3)

这是我的 an earlier answer 的更通用形式,用于查找给定线的中点。

因此,在这两种情况下,您所需要的只是一个基于起点和终点(您已经拥有)的线条图原语,而不用担心潜在的无限斜率。

如果您不使用直线或斜率方程,这将非常容易。您所做的是通过查找 x 坐标对的平均值来计算所有 x 坐标。然后,您将这些 x 坐标代入了边的方程式。正如您所确定的,如果斜率是无限的,这将不起作用。有一个非常简单的解决方案。您所要做的就是按照与计算 x 坐标完全相同的方式计算 y 坐标,问题就会消失。

在不了解该程序的更多信息的情况下,我无法明确回答。也就是说,我对您可以尝试的事情有一些想法,但我对每个想法都有疑问:

  1. 我觉得很奇怪,第一次加载屏幕时左右边缘等于无穷大。你的左右边缘位置是基于什么?它们是提前储存的吗?基于屏幕尺寸和密度?如果它基于屏幕尺寸,则不应出现此问题。如下测量屏幕宽度(可能因 Android 版本而异,但网上有很多教程):

    Display d = getWindowManager().getDefaultDisplay();
    Point point = new Point();
    d.getSize(point);
    int width = point.x;
    int height = point.y;
    

    在计算任何东西之前先拥有这些值。根据屏幕边缘调整初始坐标位置。

    1. 盒子每次都以相同的坐标开始吗?在上面 运行 之前的应用程序中是否有屏幕?如果两者都是这样,则:

      • a) 计算app首次加载时的所有位置,并传递给新的Activity/Fragment;或者
      • b) 在应用程序加载时(在加载图像之前的屏幕中)异步生成实际绘制的 Canvas,然后将实际的 Canvas 传递给新的 Activity /片段.
    2. Activity/Fragment 生命周期的哪一部分是您 运行 中的方法?如果您在 onResume() 中 运行 它,请在周期的早期尝试它的 运行 方面,或者尽早进行特殊计算。更具体地说:

      • a) 在循环的较早部分使用静态预计算角度和手动传递给定坐标计算特殊线斜率,直到其余部分完全加载.满载后,计算实际斜率。在初始加载时 - 当应用程序首次使用时 - 提供默认值。在之后的每个出口,存储坐标、坡度等值,并在您再次加载该屏幕时检索它们。
      • b) 仅在屏幕加载完成后进行计算并生成框 - 即使其成为最后一步,并且仅由依赖于完成的任务触发。
      • c) 生成框前检查左右边缘不等于无穷大。在(我认为是 window 对象?)上使用侦听器来观察左右边缘值的变化。
        • ...或者使用一个异步任务,不断检查边缘值,直到它们都不是无穷大,然后在满足此条件时立即退出。
      • 在那张纸条上......你是 运行 它在片段中,还是在 Activity 中?

您能否提供完整的 Activity 或启动它的片段以及方法的其余部分?

请注意,我只是简单地查看了数学本身并没有发现任何问题,所以我假设它没问题,因为你说加载完成后没有问题。