You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
89 lines
1.8 KiB
89 lines
1.8 KiB
#include "CircleRecognizer.h" |
|
|
|
#include "Inertia.h" |
|
#include "ShapeRecognizerConfig.h" |
|
#include "model/Stroke.h" |
|
|
|
#include <math.h> |
|
|
|
/** |
|
* Create circle stroke for inertia |
|
*/ |
|
Stroke* CircleRecognizer::makeCircleShape(Stroke* originalStroke, Inertia& inertia) |
|
{ |
|
int npts = (int) (2 * inertia.rad()); |
|
if (npts < 12) |
|
{ |
|
npts = 12; // min. number of points |
|
} |
|
|
|
Stroke* s = new Stroke(); |
|
s->applyStyleFrom(originalStroke); |
|
|
|
for (int i = 0; i <= npts; i++) |
|
{ |
|
double x = inertia.centerX() + inertia.rad() * cos((2 * M_PI * i) / npts); |
|
double y = inertia.centerY() + inertia.rad() * sin((2 * M_PI * i) / npts); |
|
s->addPoint(Point(x, y)); |
|
} |
|
|
|
return s; |
|
} |
|
|
|
/** |
|
* Test if we have a circle; inertia has been precomputed by caller |
|
*/ |
|
double CircleRecognizer::scoreCircle(Stroke* s, Inertia& inertia) |
|
{ |
|
if (inertia.getMass() == 0.0) |
|
{ |
|
return 0; |
|
} |
|
|
|
double sum = 0.0; |
|
double x0 = inertia.centerX(); |
|
double y0 = inertia.centerY(); |
|
double r0 = inertia.rad(); |
|
|
|
ArrayIterator<Point> it = s->pointIterator(); |
|
|
|
if (!it.hasNext()) |
|
{ |
|
return 0; |
|
} |
|
|
|
Point p1 = it.next(); |
|
|
|
while (it.hasNext()) |
|
{ |
|
Point p2 = it.next(); |
|
|
|
double dm = hypot(p2.x - p1.x, p2.y - p1.y); |
|
double deltar = hypot(p1.x - x0, p1.y - y0) - r0; |
|
sum += dm * fabs(deltar); |
|
|
|
p1 = p2; |
|
} |
|
|
|
return sum / (inertia.getMass() * r0); |
|
} |
|
|
|
Stroke* CircleRecognizer::recognize(Stroke* stroke) |
|
{ |
|
Inertia s; |
|
s.calc(stroke->getPoints(), 0, stroke->getPointCount()); |
|
RDEBUG("Mass=%.0f, Center=(%.1f,%.1f), I=(%.0f,%.0f, %.0f), Rad=%.2f, Det=%.4f", |
|
s.getMass(), s.centerX(), s.centerY(), s.xx(), s.yy(), s.xy(), s.rad(), s.det()); |
|
|
|
if (s.det() > CIRCLE_MIN_DET) |
|
{ |
|
double score = CircleRecognizer::scoreCircle(stroke, s); |
|
RDEBUG("Circle score: %.2f", score); |
|
if (score < CIRCLE_MAX_SCORE) |
|
{ |
|
return CircleRecognizer::makeCircleShape(stroke, s); |
|
} |
|
} |
|
|
|
return NULL; |
|
}
|
|
|