/** * Creates a position step with image coordinates. Overridden by ParticleDataTrack. * * @param track the PointMass track * @param n the frame number * @param x the x coordinate * @param y the y coordinate * @return the PositionStep */ protected PositionStep createPositionStep(PointMass track, int n, double x, double y) { PositionStep newStep = new PositionStep(track, n, x, y); newStep.valid = !Double.isNaN(x) && !Double.isNaN(y); return newStep; }
/** Refreshes step positions. */ protected void refreshSteps() { locked = true; if (refreshStepsLater) return; // return if this is an empty dynamic system if (this instanceof DynamicSystem) { DynamicSystem system = (DynamicSystem) this; if (system.particles.length == 0) return; } if (trackerPanel != null) { refreshDerivsLater = trackerPanel.getPlayer().getClipControl().isPlaying(); int n = trackerPanel.getFrameNumber(); VideoClip clip = trackerPanel.getPlayer().getVideoClip(); // determine last frame to be marked (must satisfy both model and clip) int end = Math.min(getEndFrame(), n); while (end > getStartFrame() && !clip.includesFrame(end)) { end--; } if (end <= lastValidFrame) return; if (lastValidFrame == -1) { reset(); // initializes model, sets lastValidFrame to marked frame, if any if (lastValidFrame == -1 || end <= lastValidFrame) return; } int start = lastValidFrame; Tracker.logTime( this.getClass().getSimpleName() + this.hashCode() + " refreshing steps " + start + " to " + end); //$NON-NLS-1$ //$NON-NLS-2$ boolean singleStep = (end - start == 1); // step forward to end ImageCoordSystem coords = trackerPanel.getCoords(); // get underlying coords if appropriate boolean useDefault = isUseDefaultReferenceFrame(); while (useDefault && coords instanceof ReferenceFrame) { coords = ((ReferenceFrame) coords).getCoords(); } double startTime = t0 + dt * tracePtsPerStep * (start - getStartFrame()) / clip.getStepSize(); double stepSize = 1.0 * clip.getStepSize() / tracePtsPerStep; int stepCount = (tracePtsPerStep * (end - start)) / clip.getStepSize(); ParticleModel[] models = getModels(); // prepare larger trace arrays and copy existing points into them for (ParticleModel next : models) { next.locked = false; int traceLength = next.traceX.length + stepCount; next.prevX = next.traceX; next.prevY = next.traceY; next.traceX = new double[traceLength]; next.traceY = new double[traceLength]; System.arraycopy(next.prevX, 0, next.traceX, 0, next.prevX.length); System.arraycopy(next.prevY, 0, next.traceY, 0, next.prevY.length); } for (int i = 0; i < stepCount; i++) { int stepNumber = i + 1; int frameNumber = start + (int) (stepNumber * stepSize); time = startTime + stepNumber * dt; Point2D[] points = getNextTracePositions(); if (points == null) continue; AffineTransform transform = coords.getToImageTransform(frameNumber); for (int j = 0; j < models.length; j++) { transform.transform(points[j], points[j]); // determine if point is invalid due to out of bounds boolean valid = Math.abs(points[j].getX()) < xLimit && Math.abs(points[j].getY()) < yLimit; if (!valid && !invalidWarningShown) { invalidWarningShown = true; Runnable runner = new Runnable() { // avoids deadlock? public void run() { // if (invalidWarningShown) return; JOptionPane.showMessageDialog( trackerPanel, TrackerRes.getString("ParticleModel.Dialog.Offscreen.Message1") + XML.NEW_LINE //$NON-NLS-1$ + TrackerRes.getString( "ParticleModel.Dialog.Offscreen.Message2"), //$NON-NLS-1$ TrackerRes.getString("ParticleModel.Dialog.Offscreen.Title"), // $NON-NLS-1$ JOptionPane.WARNING_MESSAGE); } }; SwingUtilities.invokeLater(runner); } models[j].traceX[models[j].prevX.length + i] = valid ? points[j].getX() : Double.NaN; models[j].traceY[models[j].prevY.length + i] = valid ? points[j].getY() : Double.NaN; if (stepNumber % tracePtsPerStep == 0) { // refresh position step saveState(frameNumber); PositionStep step = (PositionStep) models[j].getStep(frameNumber); if (step == null) { step = createPositionStep(models[j], frameNumber, 0, 0); step.setFootprint(models[j].getFootprint()); models[j].steps.setStep(frameNumber, step); } step.getPosition().setPosition(valid ? points[j] : nan); // this method is fast } } } int count = 4 + (end - start); int startUpdate = start; // step back twice to pick up possible valid derivatives if (startUpdate > clip.getStepSize()) startUpdate -= clip.getStepSize(); if (startUpdate > clip.getStepSize()) startUpdate -= clip.getStepSize(); lastValidFrame = end; for (ParticleModel next : models) { next.steps.setLength(end + 1); coords = trackerPanel.getCoords(); // get active coords // special treatment if this is the origin of current reference frame if (coords instanceof ReferenceFrame && ((ReferenceFrame) coords).getOriginTrack() == next) { // set origins of reference frame boolean prev = next.refreshing; // save refreshing value next.refreshing = true; ((ReferenceFrame) coords).setOrigins(); // then set positions to zero wrt origins for (int i = 0; i < clip.getStepCount(); i++) { int frameNumber = clip.stepToFrame(i); PositionStep step = (PositionStep) next.getStep(frameNumber); if (step == null) continue; AffineTransform transform = coords.getToImageTransform(frameNumber); next.point.setLocation(0, 0); transform.transform(next.point, next.point); step.getPosition().setPosition(next.point); // this method is fast } next.refreshing = prev; // restore refreshing value if (!refreshDerivsLater) { next.updateDerivatives(startUpdate, count); } } else if (!refreshDerivsLater) { next.updateDerivatives(startUpdate, count); } if (next.vAtOrigin) next.vTailsToOriginItem.doClick(); if (next.aAtOrigin) next.aTailsToOriginItem.doClick(); if (!refreshDerivsLater) { if (singleStep) next.support.firePropertyChange("step", null, new Integer(n)); // $NON-NLS-1$ else next.support.firePropertyChange("steps", null, null); // $NON-NLS-1$ } // erase refreshed steps for (int i = start + 1; i <= end; i++) { Step step = next.getStep(i); if (step != null) step.erase(); } next.locked = true; } trackerPanel.repaint(); } }