检测圆形(非精确圆)路径算法?

我收到一个路径 – 来自touchevent的x,y坐标列表。 如何检测此路径形成圆形路径(不是完整或精确的圆)? 是否有任何算法或方法来检测这个?

这是一篇论文,总结了各种方法,使圈子适合数据: http : //www.cs.bsu.edu/homepages/kerryj/kjones/circles.pdf

我会做这样的事情:

假设我有一个半圆的点:

val angles180 = (0 to 180 by 45).map(_ / 180.0 * Pi) val points = angles180.map { a => (math.cos(a), math.sin(a)) } 

我可以使用3个元素组合子集:

 val pointsList = points.combinations(3).toList 

对于pointsList每个子集,在圆圈上只给出三个点,找到圆的中心和半径 :

 val circles = for { p <- pointsList } yield calculateCircle(p) 

哪里:

 case class Circle(x: Double, y: Double, r: Double) def calculateCircle(points: Seq[(Double, Double)]): Circle = { val Seq((x1, y1), (x2, y2), (x3, y3)) = points val mr = (y2 - y1) / (x2 - x1) val mt = (y3 - y2) / (x3 - x2) val x0 = (mr * mt * (y3 - y1) + mr * (x2 + x3) - mt * (x1 + x2)) / (2 * (mr - mt)) val y0 = -1.0 / mr * (x0 - (x1 + x2) / 2) + (y1 + y2) / 2 val r = math.sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0)) Circle(x0, y0, r) } 

你应该检查无效的圈子(也许这些点是共线的,并给出无效的结果):

 def isInvalid(circle: Circle) = (circle.x.isNaN || circle.y.isNaN || circle.r.isNaN) val validCircles = circles.filterNot(isInvalid) 

虽然有效,但这些圈子可以(将)具有不同的数据。 您应该看看计算的圆圈是否彼此相似。

一种方法是查看它们的数据是否落在(m - x . s, m + x . s)的区间内,其中m是平均值, s是标准偏差。 对于x == 2.58 %的数据位于区间内。 您可以检查每个圆圈数据是否位于内部,如果不存在,则不是圆圈。 请记住,我们对圆心和x半径的xy位置都这样做,只有这三个都是好的才行。

 def looksLikeACircle(circles: Seq[Circle]) = { val resultsLists = circles.map { c => List(cx, cy, cr) }.transpose val cis = resultsLists.map(interval99) val good = resultsLists.zip(cis).map { case (values, ci) => withinInterval(values, ci) } val allGood = good.reduceLeft { (acc, v) => acc && v } allGood } val allGood = looksLikeACircle(validCircles) 

哪里:

 def mean(values: Seq[Double]) = values.sum / values.size def standardDeviation(values: Seq[Double]) = { val m = mean(values) math.sqrt(values.map { v => (v - m) * (v - m) }.sum / (values.size - 1)) } def interval99(values: Seq[Double]) = { val m = mean(values) val d = (2.58 * standardDeviation(values)) (m - d, m + d) } def withinInterval(values: Seq[Double], ci: (Double, Double)) = values.forall { v => ci._1 <= v && v <= ci._2 } 

好吧,它看起来像是一个圆圈,但也许它只是数学。 给定足够大的半径,真正的圆可以在窗口中显示为直线。 问题是:用户是否可以在窗口中创建带有这些点的圆圈?

您可以检查平均圆是否在窗口边界内:

 case class Window(x: Double, y: Double, w: Double, h: Double) def calculateMeanCircle(circles: Seq[Circle]) = { val resultsLists = circles.map { c => List(cx, cy, cr) }.transpose val Seq(xm, ym, rm) = resultsLists.map(mean) Circle(xm, ym, rm) } def isCircleFit(circle: Circle, window: Window) = { def isWithinBounds(value: Double, bounds: (Double, Double)) = { bounds._1 <= value && value <= bounds._2 } val (xMin, xMax) = (circle.x - circle.r, circle.x + circle.r) val (yMin, yMax) = (circle.y - circle.r, circle.y + circle.r) val horizontalBounds = (window.x, window.x + window.w) val verticalBounds = (window.y, window.y + window.h) val isInside = isWithinBounds(xMin, horizontalBounds) && isWithinBounds(xMax, horizontalBounds) && isWithinBounds(yMin, verticalBounds) && isWithinBounds(yMax, verticalBounds) isInside } val meanCircle = calculateMeanCircle(validCircles) 

最后,对于这篇长篇文章的开头(希望你还在这里)和一个window

 val window = Window(0, 0, 600, 800) println("Looks like a circle? " + allGood) println(meanCircle) println(window) println("Is mean circle fit? " + isCircleFit(meanCircle, window)) 

我们得到:

 Looks like a circle? true Circle(-8.088567489053774E-18,4.4408920985006264E-17,1.0) Window(0.0,0.0,600.0,800.0) Is mean circle fit? false 

那么在这个窗口内这些点可以绘制一个象限,所以不合适。

如果:

 val points5 = angles180.map { a => (window.w / 2 + math.cos(a), window.h / 2 + math.sin(a)) } 

它现在更好(它位于窗口的中心):

 Looks like a circle? true Circle(300.0,400.0,1.0000000000000144) Window(0.0,0.0,600.0,800.0) Is mean circle fit? true 

这些点几乎形成一个圆心,中心位于(0, 0) ,半径r == 1

 val points = Seq( ( 1.0, 0.0), ( 0.0, 1.1), (-0.9, 0.0), (-0.1, -1.0) ) 

嗯,它看起来像一个,但它当然不适合(但你明白了这一点):

 Looks like a circle? true Circle(0.05805243445692886,0.07674497786857344,1.0288200278337032) Window(0.0,0.0,600.0,800.0) Is mean circle fit? false 

你需要彻底测试它,因为我没有,也许可以调整一下(或很多),但你可以从这里开始,我希望。

此外,我认为其中一个标签为java ,但我认为你不应该很难转换它。