/** * Return the number of corners in the specified stroke. This calls numCorners with threshold * values either initialized in the constructor or specified by the user. * * <p>First check to see if this feature already exists in the stroke's property table (access * using PROPERTY_KEY). If so, return that value (cast to double). Otherwise call numCorners to * compute and cache the result in the table. * * <p> */ public double apply(TimedStroke s) { Integer num = (Integer) s.getProperty(PROPERTY_KEY); if (num == null) { int val = numCorners(s, _threshDot, _threshMagRatio, _threshRelaxedDot); s.setProperty(PROPERTY_KEY, new Integer(val)); return (double) val; } else { return num.doubleValue(); } }
/** * Return the indices where the corners occur in the given stroke. Return null if no corners exist * in the stroke. Iterate over the points in the stroke, for every three points (p1, p2, p3) we * form two vectors, (p1,p2) and (p2, p3). If the dot product of these two vectors is less than * threshDot, then there is definitely an angle at p2. If the dot product is greater than * threshDot but less than threshRelaxedDot, it is likely that there is an angle at p2, but we're * not sure. In this case, the magnitudes of both vectors are calculated, m1 and m2. Let 'plen' be * the stroke path length, we calculate r1 = m1/plen and r2 = m2/plen. If either r1 or r2 is * greater than threshMagRatio, then we say that there is a corner. If both vectors are really * short (r1<threshMagRatio && r2<threshMagRatio), then they are not significant enough to be used * to determine a corner. They are more likely to be noise due to the pen/tablet hardware. */ public static final int[] cornerIndices( TimedStroke s, double threshMagRatio, double threshDot, double threshRelaxedDot) { if (s == null) { return null; } else if (s.getVertexCount() < 3) { return null; } else { int numPoints = s.getVertexCount(); ArrayList cornerIndices = new ArrayList(); double pathLength = PathLengthFE.pathLength(s); double x1, y1, x2, y2, x3, y3; for (int i = 0; i < numPoints - 2; i++) { x1 = s.getX(i); y1 = s.getY(i); x2 = s.getX(i + 1); y2 = s.getY(i + 1); x3 = s.getX(i + 2); y3 = s.getY(i + 2); double dot = FEUtilities.dotProduct(x1, y1, x2, y2, x3, y3); if (dot < threshDot) { // definitely an angle double angle = Math.acos(dot); angle = Math.toDegrees(angle); int j = i + 1; cornerIndices.add(new Integer(j)); // numCorners++; } else if (dot < threshRelaxedDot) { // likely to be an angle double l1 = FEUtilities.distance(x1, y1, x2, y2); double l2 = FEUtilities.distance(x2, y2, x3, y3); l1 = l1 / pathLength; l2 = l2 / pathLength; if ((l1 > threshMagRatio) || (l2 > threshMagRatio)) { double angle = Math.acos(dot); angle = Math.toDegrees(angle); // numCorners++; int j = i + 1; cornerIndices.add(new Integer(j)); } } } if (cornerIndices.size() == 0) { return null; } else { int arr[] = new int[cornerIndices.size()]; // System.out.println("Corner indices:-----"); int k = 0; for (Iterator i = cornerIndices.iterator(); i.hasNext(); ) { Integer index = (Integer) i.next(); int val = index.intValue(); arr[k++] = val; // System.out.println(val+":("+s.getX(val)+", "+s.getY(val)+")"); } // System.out.println("--------------------"); return arr; } } }
/** Treat the current stroke as a lasso selection if it is mostly closed. */ public void actionPerformed(ActionEvent evt) { _interp.removeCurrentSymbol(); TimedStroke stroke = _interp.getCurrentStroke(); int num = stroke.getVertexCount(); /* double length = PathLengthFE.pathLength(stroke); double dist = FEUtilities.distance(stroke.getX(0), stroke.getY(0), stroke.getX(num-1), stroke.getY(num-1)); double ratio = dist/length; if(ratio <= CLOSE_PROPORTION){ */ Polygon2D poly = new Polygon2D.Float(); poly.moveTo(stroke.getX(0), stroke.getY(0)); for (int i = 1; i < num; i++) { poly.lineTo(stroke.getX(i), stroke.getY(i)); } poly.closePath(); Iterator iter = _interp.getController().containedSketchFigures(poly); ArrayList hitFigures = new ArrayList(); while (iter.hasNext()) { Figure f = (Figure) iter.next(); if (f instanceof FigureDecorator) { f = ((FigureDecorator) f).getDecoratedFigure(); } hitFigures.add(f); } // } toggleSelection(hitFigures); }
/** Normalize an individual stroke to time increments given by timestep. */ public static TimedStroke interpolate(TimedStroke s, int timestep) { long t0 = s.getTimestamp(0); long tN = s.getTimestamp(s.getVertexCount() - 1); int nsteps = (int) ((tN - t0) / timestep); TimedStroke out = new TimedStroke(); long tcur = t0; int j = 0; for (int i = 0; i < nsteps; i++) { while (j < s.getVertexCount() && s.getTimestamp(j) <= tcur) { j++; } if (j >= s.getVertexCount()) { throw new RuntimeException("not enough points!"); } else { long tplus = s.getTimestamp(j); long tminus = s.getTimestamp(j - 1); double xcur = (tplus - tcur) * s.getX(j - 1) + (tcur - tminus) * s.getX(j); xcur = xcur / (tplus - tminus); double ycur = (tplus - tcur) * s.getY(j - 1) + (tcur - tminus) * s.getY(j); ycur = ycur / (tplus - tminus); out.addVertex((float) xcur, (float) ycur, tcur); tcur += timestep; } } return out; }