绘制铅笔式算法 - 填补空白,减少线条中的点

时间:2014-03-19 12:58:50

标签: android algorithm drawing paint

使用MotionEvents轻松跟踪屏幕上的移动,获取您手指所在的所有点。但是,如何轻松识别绘图模式,以便无论何时放置手指都不必是一个点?

截至目前,每当用户触摸我的应用中的屏幕时,我都会画一个点。但是,如果我从左上角快速拖动到右下角,那么"在"之间空地。

是否有任何好的算法,方法可用于计算在屏幕上放下手指之间需要多少点,直到您释放它并在任何需要的地方填补空白。

假设我画了100%的直线,它最有可能只有2分,或者不需要有任何"任何东西"超过X,Y坐标的那两个点。开始坐标和结束坐标。

用一百万个点来跟随用户的移动似乎是浪费,而且价格昂贵,因为在不需要的时候屏幕上会有这么多的点。

铅笔式绘画风格。

截至目前,我正在为Android工作。但我认为这更像是一个普遍的问题。

1 个答案:

答案 0 :(得分:0)

您正在寻找的是一种删除连续路径中冗余点的方法,作为优化用户在屏幕上绘制的路径的一种方法。

对此有一些简单的解决方案,并且有很复杂的方法可以做到这一点。让我们采用一种非常有效的简单方法。

将您的点排列成数组或其他有序结构。请考虑以下几点:

A - > B - > C - > D - > E - > ˚F

要确定“C”是否属于列表,我们需要使用C和它的两个邻居B和D.这三个点定义了两行 - BC和CD。我们想知道的是这两条线是否共线(即它们是否位于同一条直线上。)

为了确定它们是否是共线的,我们只需要在两个向量BC和CD的法线之间执行点积,其中C是中点。如果它们都在同一条线上,那么中间点(C)是多余的并且可以被移除。如果仔细遍历整个列表,您将能够删除所有冗余点。

这是一些伪代码。为清楚起见,三个输入参数将命名为B,C和D以匹配上述描述。结果将是一个数值,我将向您展示如何使用:

double linearDotProduct(point B, point C, point D)
{
    // create our first vector (B->C) - we can use a point structure for this
    point BC(C.x - B.x, C.y - B.y)

    // normalize BC
    double lenBC = sqrt(BC.x * BC.x + BC.y * BC.y)
    BC.x /= lenBC
    BC.y /= lenBC

    // create our second vector (C->D) - we can use a point structure for this
    point CD(D.x - C.x, D.y - C.y)

    // normalize CD
    double lenCD = sqrt(CD.x * CD.x + CD.y * CD.y)
    CD.x /= lenCD
    CD.y /= lenCD

    // Perform a dot product
    double dot = BC.x * CD.x + BC.y * CD.y

    return dot
}

使用您的三个点调用此函数将返回-1 ... +1范围内的数字。值+1意味着线段AB和BC沿着相同的精确线行进。但是,因为我们正在进行浮点数学运算,所以你不应该只检查== 1.0,因为几乎不会出现这种情况(浮点精度误差。)

更好的解决方案是使用它:

double Epsilon = 0.00001 // Some small number greater than zero

if (linearDotProduct(B, C, D) > (1.0 - Epsilon))
{
    // safe to remove point B
}

您可以通过Epsilon进行游戏来调整优化量。 epsilon值越大,您允许的容差越大。换句话说,较大的epsilon值将允许您删除“几乎但不完全是直的”点。这使您可以从中获得更多优化。和epsilon一起玩,找到你满意的结果。

这是一种天真的做法。其他方法类似地工作,但是在一定距离上考虑更多的点以便确定整个片段如何匹配用户的整体手势。我不会在这里介绍它们,因为它听起来并不像你需要的那样,但只是想让你知道所呈现的局限性。