如果线是无穷大,则计算线的斜率

时间:2015-01-07 03:50:13

标签: java android canvas line paint

我在Java(特别是Android)中创建了一些显示如下内容的东西:

enter image description here

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

enter image description here

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

//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);

3 个答案:

答案 0 :(得分:1)

如果不使用直线或斜率方程,这很容易。你所做的是通过找到x坐标对的平均值来计算所有x坐标。然后,您已将这些x坐标替换为边的方程。正如您所知,如果斜坡是无限的,这将不起作用。有一个非常简单的解决方案。您所要做的就是以与计算x坐标完全相同的方式计算y坐标,问题就消失了。

答案 1 :(得分:0)

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

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)

(“图形”的道歉),最上面的水平线可以画成:

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

这是我an earlier answer的更广义形式,可以找到给定线的中点。

因此,在这两种情况下,你所需要的只是一个基于起点和终点(你已经拥有)的线条绘制原语,没有可能无限斜率的混乱。

答案 2 :(得分:0)

在不了解该计划的情况下,我无法明确回答。也就是说,我对你可以尝试的事情有一些想法,但我有各自的问题:

  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 / Fragment。
    2. 运行该方法的Activity / Fragment生命周期的哪个部分?如果您在onResume()中运行它,请尝试在周期的早期运行它的各个方面,或提前进行特殊计算。更具体地说:

      • a)使用静态预先计算的角度和手动传递的给定坐标计算循环早期部分的特殊线斜率,直到其余部分完全加载为止。满载后,计算实际斜率。在初始加载时 - 第一次使用应用程序时 - 提供默认值。在此后的每个出口处,存储坐标,坡度等值,并在再次加载该屏幕时检索它们。
      • b)仅在屏幕完成加载后进行计算并生成框 - 即将其作为最后一步,并且仅由依赖于完成的任务触发。
      • c)在生成框之前,检查左边和右边是否等于无穷大。使用一个监听器(我认为它是窗口对象?)来监视左右边缘值的变化。
        • ...或使用asynctask只是一直检查边缘值,直到它们都不是无穷大,然后在满足这个条件后立即退出。
      • 就那个说明......你是在片段或活动中运行它吗?
  2. 您是否能够提供启动它的完整活动或片段以及方法的其余部分?

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