package org.archstudio.bna.utils; import static org.archstudio.sysutils.SystemUtils.castOrNull; import org.archstudio.bna.IBNAView; import org.archstudio.bna.IMutableCoordinateMapper; import org.archstudio.sysutils.SystemUtils; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.widgets.Control; public class FlyToUtils { public static void flyTo(IBNAView view, final Point toWorldPoint) { BNAUtils.checkLock(); //if the given view is not the top-level view, then translate //the world coordinates into world coordinates for the top view. //Then change the view to be the top level view. if (view.getParentView() != null) { IBNAView topLevelView = view.getParentView(); while (topLevelView.getParentView() != null) { topLevelView = topLevelView.getParentView(); } view.getCoordinateMapper().worldToLocal(toWorldPoint); topLevelView.getCoordinateMapper().localToWorld(toWorldPoint); view = topLevelView; } final Control control = view.getBNAUI().getComposite(); if (control == null) { return; } final IMutableCoordinateMapper cm = castOrNull(view.getCoordinateMapper(), IMutableCoordinateMapper.class); if (cm == null) { return; } final double originalScale = cm.getLocalScale(); final Point localSize = control.getSize(); final Point localCenter = new Point(localSize.x / 2, localSize.y / 2); Thread flyThread = new Thread(FlyToUtils.class.getName()) { @Override public void run() { try { Point worldStart = cm.localToWorld(localCenter); Point worldEnd = BNAUtils.clone(toWorldPoint); Point worldDiff = new Point(worldEnd.x - worldStart.x, worldEnd.y - worldStart.y); long duration = 1000; long startTime = System.currentTimeMillis(); long currentTime; long endTime = startTime + duration; while ((currentTime = System.currentTimeMillis()) < endTime) { double d = Math.PI / 2 * (currentTime - startTime) / duration; double transposeFactor = Math.sin(d); final Point worldIntermediate = new Point(// worldStart.x + SystemUtils.round(worldDiff.x * transposeFactor),// worldStart.y + SystemUtils.round(worldDiff.y * transposeFactor)); final double intermediateScale = Math.max(0.0001, originalScale - originalScale * 0.7 * Math.sin(d * 2)); cm.setLocalScaleAndAlign(intermediateScale, localCenter, worldIntermediate); } } finally { // finally, set the cm to the correct scale and position cm.setLocalScaleAndAlign(originalScale, localCenter, toWorldPoint); } } }; flyThread.start(); } }