public void FitTest(Recognizer m_features, bool useEndpoints = false) { // if only two points then we have a line with no error if (m_features.getNumPoints() <= 2) { //log.debug("LineFit: stroke contains " + m_features.getNumPoints() // + " points"); m_err = 0.0; m_lsqe = 0.0; m_passed = true; return; } // ideal line (just connect the endpoints) if (useEndpoints) { m_shape = new Line2D.Double(m_features.getFirstOrigPoint().X, m_features.getFirstOrigPoint().Y, m_features .getLastOrigPoint().X, m_features .getLastOrigPoint().Y); } else { m_shape = m_features.getMajorAxis(); } // test 1: least squares error between the stroke points and the line // formed by the endpoints m_lsqe = LeastSquares.error(m_features.getPoints(), (Line2D)m_shape); m_ratio = m_features.getEndptStrokeLengthRatio(); if (m_features.getStrokeLength() > 25.0) { if (m_lsqe / m_features.getStrokeLength() > 1.4) { m_passed = false; m_fail = 0; // if line test was close and endpt ratio is high then go ahead // and pass if (m_lsqe / m_features.getStrokeLength() < M_LINE_LS_ERROR_FROM_ENDPTS + 0.1 && m_ratio > 0.98) { m_passed = true; } } if (m_lsqe / m_features.getStrokeLength() > 1.25 && m_ratio < 0.75 && m_features.getNumRevolutions() <= 0.5) { m_passed = false; m_fail = 1; } } else { if (m_lsqe / m_features.getStrokeLength() > 1.5 && m_ratio < 0.732) { m_passed = false; m_fail = 2; } if (m_lsqe / m_features.getStrokeLength() > 1.25 && m_ratio < 0.7 && m_features.getNumRevolutions() < 0.15) { m_passed = false; m_fail = 3; } } // test 2: verify that stroke is not overtraced if (m_features.isOvertraced()) { m_passed = false; m_fail = 4; } // test 3: test feature area (use as error for fit) m_err = FeatureArea.toLine(m_features.getPoints(), (Line2D)m_shape) / m_features.getStrokeLength(); if (m_err > M_LINE_FEATURE_AREA) { m_passed = false; m_fail = 5; } // test 4: ratio must be near 1.0 //if (m_ratio > 0.99) // definitely a line // m_passed = true; if (m_ratio < 0.3) { // definitely not a line m_passed = false; m_fail = 6; } lineLength = m_features.getStrokeLength(); // compute beautified shape try { //computeBeautified(); } catch (Exception e) { //log.error("Could not create shape object: " + e.getMessage()); } //log.debug("LineFit: passed = " + m_passed + "(" + m_fail // + ") least sq error = " // + (m_lsqe / m_features.getStrokeLength()) + " overtraced = " // + m_features.isOvertraced() + " feature area error = " + m_err // + " endpts = (" + ((Line2D)m_shape).getX1() + "," // + ((Line2D)m_shape).getY1() + ") (" // + ((Line2D)m_shape).getX2() + "," + ((Line2D)m_shape).getY2() // + // /* ") corners = " + m_features.numFinalCorners() + */ // " best fit = (" + m_features.getBestFitLine().getX1() + "," // + m_features.getBestFitLine().getY1() + ") (" // + m_features.getBestFitLine().getX2() + "," // + m_features.getBestFitLine().getY2() + ") is closed = " // + m_features.isClosed() + " ratio = " + m_ratio + " length = " // + m_features.getStrokeLength() + " revs = " // + m_features.getNumRevolutions()); }