0001: /**
0002: * <copyright></copyright> $Id: ViewportModelImpl.java 25737 2007-06-05 09:45:54Z jeichar $
0003: */package net.refractions.udig.project.internal.render.impl;
0004:
0005: import java.awt.Dimension;
0006: import java.awt.Point;
0007: import java.awt.geom.AffineTransform;
0008: import java.awt.geom.Point2D;
0009: import java.io.IOException;
0010: import java.util.List;
0011: import java.util.concurrent.CopyOnWriteArraySet;
0012:
0013: import net.refractions.udig.project.ILayer;
0014: import net.refractions.udig.project.IMap;
0015: import net.refractions.udig.project.internal.Map;
0016: import net.refractions.udig.project.internal.ProjectPackage;
0017: import net.refractions.udig.project.internal.ProjectPlugin;
0018: import net.refractions.udig.project.internal.Trace;
0019: import net.refractions.udig.project.internal.render.RenderFactory;
0020: import net.refractions.udig.project.internal.render.RenderManager;
0021: import net.refractions.udig.project.internal.render.RenderPackage;
0022: import net.refractions.udig.project.internal.render.ViewportModel;
0023: import net.refractions.udig.project.preferences.PreferenceConstants;
0024: import net.refractions.udig.project.render.IViewportModelListener;
0025: import net.refractions.udig.project.render.ViewportModelEvent;
0026: import net.refractions.udig.project.render.ViewportModelEvent.EventType;
0027: import net.refractions.udig.project.render.displayAdapter.IMapDisplay;
0028: import net.refractions.udig.project.render.displayAdapter.MapDisplayEvent;
0029: import net.refractions.udig.ui.ProgressManager;
0030:
0031: import org.eclipse.core.runtime.NullProgressMonitor;
0032: import org.eclipse.emf.common.notify.Notification;
0033: import org.eclipse.emf.common.notify.NotificationChain;
0034: import org.eclipse.emf.common.notify.impl.AdapterImpl;
0035: import org.eclipse.emf.ecore.EClass;
0036: import org.eclipse.emf.ecore.EObject;
0037: import org.eclipse.emf.ecore.EStructuralFeature;
0038: import org.eclipse.emf.ecore.InternalEObject;
0039: import org.eclipse.emf.ecore.impl.ENotificationImpl;
0040: import org.eclipse.emf.ecore.impl.EObjectImpl;
0041: import org.eclipse.emf.ecore.util.EcoreUtil;
0042: import org.eclipse.jface.preference.IPreferenceStore;
0043: import org.geotools.factory.Hints;
0044: import org.geotools.geometry.jts.JTS;
0045: import org.geotools.geometry.jts.ReferencedEnvelope;
0046: import org.geotools.referencing.CRS;
0047: import org.geotools.referencing.FactoryFinder;
0048: import org.geotools.referencing.GeodeticCalculator;
0049: import org.geotools.referencing.crs.DefaultGeographicCRS;
0050: import org.opengis.referencing.FactoryException;
0051: import org.opengis.referencing.NoSuchAuthorityCodeException;
0052: import org.opengis.referencing.crs.CoordinateReferenceSystem;
0053: import org.opengis.referencing.operation.CoordinateOperationFactory;
0054: import org.opengis.referencing.operation.MathTransform;
0055: import org.opengis.referencing.operation.TransformException;
0056:
0057: import com.vividsolutions.jts.geom.Coordinate;
0058: import com.vividsolutions.jts.geom.Envelope;
0059:
0060: /**
0061: * TODO Purpose of net.refractions.udig.project.internal.render.impl
0062: * <p>
0063: * </p>
0064: *
0065: * @author Jesse
0066: * @since 1.0.0
0067: * @generated
0068: */
0069: public class ViewportModelImpl extends EObjectImpl implements
0070: ViewportModel {
0071: /**
0072: * <!-- begin-user-doc --> <!-- end-user-doc -->
0073: *
0074: * @generated
0075: */
0076: public static final String copyright = "uDig - User Friendly Desktop Internet GIS client http://udig.refractions.net (C) 2004, Refractions Research Inc. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; version 2.1 of the License. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details."; //$NON-NLS-1$
0077:
0078: /**
0079: * The default value of the '{@link #getCRS() <em>CRS</em>}' attribute. <!-- begin-user-doc
0080: * --> <!-- end-user-doc -->
0081: *
0082: * @see #getCRS()
0083: * @generated NOT
0084: * @ordered
0085: */
0086: public static final CoordinateReferenceSystem CRS_EDEFAULT = null;
0087:
0088: /**
0089: * The cached value of the '{@link #getCRS() <em>CRS</em>}' attribute. <!-- begin-user-doc -->
0090: * <!-- end-user-doc -->
0091: *
0092: * @see #getCRS()
0093: * @generated
0094: * @ordered
0095: */
0096: protected CoordinateReferenceSystem cRS = getDefaultCRS();
0097:
0098: /**
0099: * This is true if the CRS attribute has been set. <!-- begin-user-doc --> <!-- end-user-doc -->
0100: *
0101: * @generated false
0102: * @ordered
0103: */
0104: protected boolean cRSESet = false;
0105:
0106: /**
0107: * The default value of the '{@link #getBounds() <em>Bounds</em>}' attribute. <!--
0108: * begin-user-doc --> <!-- end-user-doc -->
0109: *
0110: * @see #getBounds()
0111: * @generated
0112: * @ordered
0113: */
0114: protected static final Envelope BOUNDS_EDEFAULT = (Envelope) RenderFactory.eINSTANCE
0115: .createFromString(RenderPackage.eINSTANCE.getEnvelope(), ""); //$NON-NLS-1$
0116:
0117: /**
0118: * The cached value of the '{@link #getBounds() <em>Bounds</em>}' attribute. <!--
0119: * begin-user-doc --> <!-- end-user-doc -->
0120: *
0121: * @see #getBounds()
0122: * @generated
0123: * @ordered
0124: */
0125: protected Envelope bounds = BOUNDS_EDEFAULT;
0126:
0127: /**
0128: * The default value of the '{@link #getCenter() <em>Center</em>}' attribute. <!--
0129: * begin-user-doc --> <!-- end-user-doc -->
0130: *
0131: * @see #getCenter()
0132: * @generated
0133: * @ordered
0134: */
0135: protected static final Coordinate CENTER_EDEFAULT = null;
0136:
0137: /**
0138: * The default value of the '{@link #getHeight() <em>Height</em>}' attribute. <!--
0139: * begin-user-doc --> <!-- end-user-doc -->
0140: *
0141: * @see #getHeight()
0142: * @generated
0143: * @ordered
0144: */
0145: protected static final double HEIGHT_EDEFAULT = 0.0;
0146:
0147: /**
0148: * The default value of the '{@link #getWidth() <em>Width</em>}' attribute. <!--
0149: * begin-user-doc --> <!-- end-user-doc -->
0150: *
0151: * @see #getWidth()
0152: * @generated
0153: * @ordered
0154: */
0155: protected static final double WIDTH_EDEFAULT = 0.0;
0156:
0157: /**
0158: * The default value of the '{@link #getAspectRatio() <em>Aspect Ratio</em>}' attribute. <!--
0159: * begin-user-doc --> <!-- end-user-doc -->
0160: *
0161: * @see #getAspectRatio()
0162: * @generated
0163: * @ordered
0164: */
0165: protected static final double ASPECT_RATIO_EDEFAULT = 0.0;
0166:
0167: /**
0168: * The default value of the '{@link #getPixelSize() <em>Pixel Size</em>}' attribute. <!--
0169: * begin-user-doc --> <!-- end-user-doc -->
0170: *
0171: * @see #getPixelSize()
0172: * @generated
0173: * @ordered
0174: */
0175: protected static final Coordinate PIXEL_SIZE_EDEFAULT = null;
0176:
0177: /**
0178: * The cached value of the '{@link #getRenderManagerInternal() <em>Render Manager Internal</em>}'
0179: * reference. <!-- begin-user-doc --> <!-- end-user-doc -->
0180: *
0181: * @see #getRenderManagerInternal()
0182: * @generated
0183: * @ordered
0184: */
0185: protected RenderManager renderManagerInternal = null;
0186:
0187: AdapterImpl renderManagerListener = new AdapterImpl() {
0188: /**
0189: * @see org.eclipse.emf.common.notify.impl.AdapterImpl#notifyChanged(org.eclipse.emf.common.notify.Notification)
0190: */
0191: public void notifyChanged(Notification msg) {
0192: switch (msg.getFeatureID(RenderManager.class)) {
0193: case RenderPackage.RENDER_MANAGER__MAP_DISPLAY:
0194: // sizeChanged(new MapDisplayEvent(getRenderManagerInternal().getMapDisplay(), msg
0195: // .getOldValue() == null ? null : ((IMapDisplay) msg.getOldValue())
0196: // .getDisplaySize(), ((IMapDisplay) msg.getNewValue()).getDisplaySize()));
0197: break;
0198:
0199: default:
0200: break;
0201: }
0202: }
0203: };
0204:
0205: /**
0206: * <!-- begin-user-doc --> <!-- end-user-doc -->
0207: *
0208: * @generated NOT
0209: */
0210: @SuppressWarnings("unchecked")
0211: protected ViewportModelImpl() {
0212: super ();
0213: eAdapters().add(new AdapterImpl() {
0214: /**
0215: * @see org.eclipse.emf.common.notify.impl.AdapterImpl#notifyChanged(org.eclipse.emf.common.notify.Notification)
0216: */
0217: public void notifyChanged(Notification msg) {
0218: switch (msg.getFeatureID(ViewportModel.class)) {
0219: case RenderPackage.VIEWPORT_MODEL__RENDER_MANAGER_INTERNAL: {
0220: if (msg.getOldValue() != null)
0221: ((RenderManager) msg.getOldValue()).eAdapters()
0222: .remove(renderManagerListener);
0223: if (msg.getNewValue() != null)
0224: ((RenderManager) msg.getNewValue()).eAdapters()
0225: .add(renderManagerListener);
0226: break;
0227: }// case
0228: }// switch
0229: }
0230: });
0231: }
0232:
0233: /**
0234: * <!-- begin-user-doc --> <!-- end-user-doc -->
0235: *
0236: * @generated
0237: */
0238: protected EClass eStaticClass() {
0239: return RenderPackage.eINSTANCE.getViewportModel();
0240: }
0241:
0242: /**
0243: * <!-- begin-user-doc --> <!-- end-user-doc -->
0244: *
0245: * @generated
0246: */
0247: public CoordinateReferenceSystem getCRS() {
0248: return cRS;
0249: }
0250:
0251: /**
0252: * @see net.refractions.udig.project.internal.render.ViewportModel#setCRS(org.opengis.referencing.crs.CoordinateReferenceSystem)
0253: * @uml.property name="cRS"
0254: */
0255: public void setCRS(CoordinateReferenceSystem newCRS) {
0256: if (newCRS == null)
0257: throw new IllegalArgumentException("A CRS cannot be null"); //$NON-NLS-1$
0258: if (newCRS.equals(cRS))
0259: return;
0260: CoordinateReferenceSystem oldCRS = getCRS();
0261: if (getBounds().isNull()) {
0262: setCRSGen(newCRS);
0263:
0264: if (eNotificationRequired())
0265: eNotify(new ENotificationImpl(this , Notification.SET,
0266: RenderPackage.VIEWPORT_MODEL__CRS, oldCRS, cRS));
0267: } else {
0268: try {
0269: setCRSGen(newCRS);
0270: MathTransform transform = CRS.findMathTransform(oldCRS,
0271: newCRS, true);
0272: // FIXME need to ensure that new bounds is a valid area.
0273: zoomToBox(org.geotools.geometry.jts.JTS.transform(
0274: bounds, null, transform, 8));
0275: } catch (FactoryException e) {
0276: zoomToExtent();
0277: } catch (TransformException e) {
0278: zoomToExtent();
0279: }
0280: }
0281: if (eNotificationRequired()) {
0282: notifyListeners(new ViewportModelEvent(this , EventType.CRS,
0283: cRS, oldCRS));
0284: }
0285: }
0286:
0287: /**
0288: * @generated
0289: */
0290: public void setCRSGen(CoordinateReferenceSystem newCRS) {
0291: CoordinateReferenceSystem oldCRS = cRS;
0292: cRS = newCRS;
0293: boolean oldCRSESet = cRSESet;
0294: cRSESet = true;
0295: if (eNotificationRequired())
0296: eNotify(new ENotificationImpl(this , Notification.SET,
0297: RenderPackage.VIEWPORT_MODEL__CRS, oldCRS, cRS,
0298: !oldCRSESet));
0299: }
0300:
0301: /**
0302: * <!-- begin-user-doc --> <!-- end-user-doc -->
0303: *
0304: * @generated NOT
0305: */
0306: public void unsetCRS() {
0307: CoordinateReferenceSystem oldCRS = cRS;
0308: boolean oldCRSESet = cRSESet;
0309: cRS = getDefaultCRS();
0310: cRSESet = false;
0311: if (eNotificationRequired())
0312: eNotify(new ENotificationImpl(this , Notification.UNSET,
0313: RenderPackage.VIEWPORT_MODEL__CRS, oldCRS,
0314: getDefaultCRS(), oldCRSESet));
0315: }
0316:
0317: /**
0318: * <!-- begin-user-doc --> <!-- end-user-doc -->
0319: *
0320: * @generated
0321: */
0322: public boolean isSetCRS() {
0323: return cRSESet;
0324: }
0325:
0326: /**
0327: * <!-- begin-user-doc --> <!-- end-user-doc -->
0328: *
0329: * @generated
0330: */
0331: public ReferencedEnvelope getBounds() {
0332: if (bounds instanceof ReferencedEnvelope) {
0333: ReferencedEnvelope env = (ReferencedEnvelope) bounds;
0334: if (getCRS().equals(env.getCoordinateReferenceSystem())) {
0335: return env;
0336: }
0337: }
0338: bounds = new ReferencedEnvelope(bounds, getCRS());
0339: return (ReferencedEnvelope) bounds;
0340: }
0341:
0342: /**
0343: * <!-- begin-user-doc --> <!-- end-user-doc -->
0344: *
0345: * @uml.property name="bounds"
0346: * @generated NOT
0347: */
0348: public void setBounds(Envelope newBounds) {
0349: Envelope oldBounds = bounds == null ? new Envelope() : bounds;
0350: if (!getBounds().isNull() && !Double.isNaN(getAspectRatio())
0351: && !Double.isNaN(newBounds.getWidth())
0352: && !Double.isNaN(newBounds.getHeight())) {
0353: double nRatio = newBounds.getWidth()
0354: / newBounds.getHeight();
0355: if (Double.isNaN(nRatio))
0356: nRatio = 0.0;
0357: double dRatio = getAspectRatio();
0358: if (Math.abs(nRatio - dRatio) > ACCURACY) {
0359: // Returning the same newBounds box is ok, but sometimes causes an infinite loop if
0360: // zoomToBox's calculations don't affect the size. Making this arbitrary change to
0361: // the
0362: // x-axis solves the problem.
0363: newBounds.init(newBounds.getMinX() - 2 * ACCURACY,
0364: newBounds.getMaxX() + 2 * ACCURACY, newBounds
0365: .getMinY(), newBounds.getMaxY());
0366:
0367: zoomToBox(newBounds);
0368: return;
0369: }
0370: }
0371: bounds = newBounds;
0372: fireNotification(oldBounds);
0373: }
0374:
0375: /**
0376: * <!-- begin-user-doc --> <!-- end-user-doc -->
0377: *
0378: * @generated NOT
0379: */
0380: public Coordinate getCenter() {
0381: return new Coordinate(bounds.getMinX() + bounds.getWidth() / 2,
0382: bounds.getMinY() + bounds.getHeight() / 2);
0383: }
0384:
0385: /**
0386: * <!-- begin-user-doc --> <!-- end-user-doc -->
0387: *
0388: * @generated NOT
0389: */
0390: public void setCenter(Coordinate newCenter) {
0391: // Coordinate center=getCenter();
0392: double dw = getBounds().getWidth() / 2, dh = getBounds()
0393: .getHeight() / 2;
0394: setBounds(new Envelope(newCenter.x - dw, newCenter.x + dw,
0395: newCenter.y - dh, newCenter.y + dh));
0396: }
0397:
0398: /**
0399: * <!-- begin-user-doc --> <!-- end-user-doc -->
0400: *
0401: * @generated NOT
0402: */
0403: public double getHeight() {
0404: return bounds.getHeight();
0405: }
0406:
0407: /**
0408: * <!-- begin-user-doc --> <!-- end-user-doc -->
0409: *
0410: * @generated NOT
0411: */
0412: public void setHeight(double newHeight) {
0413: zoom(getHeight() / newHeight);
0414: }
0415:
0416: /**
0417: * <!-- begin-user-doc --> <!-- end-user-doc -->
0418: *
0419: * @generated NOT
0420: */
0421: public double getWidth() {
0422: return getBounds().getWidth();
0423: }
0424:
0425: /**
0426: * <!-- begin-user-doc --> <!-- end-user-doc -->
0427: *
0428: * @generated NOT
0429: */
0430: public void setWidth(double newWidth) {
0431: zoom(getWidth() / newWidth);
0432: }
0433:
0434: /**
0435: * <!-- begin-user-doc --> <!-- end-user-doc -->
0436: *
0437: * @generated NOT
0438: */
0439: public double getAspectRatio() {
0440: if (!validState())
0441: return Double.NaN;
0442: return getRenderManagerInternal().getMapDisplay().getWidth()
0443: / (double) getRenderManagerInternal().getMapDisplay()
0444: .getHeight();
0445: }
0446:
0447: /**
0448: * TODO summary sentence for validState ...
0449: *
0450: * @return validState
0451: */
0452: private boolean validState() {
0453: return getRenderManagerInternal() != null
0454: && getRenderManagerInternal().getMapDisplay() != null
0455: && getRenderManagerInternal().getMapDisplay()
0456: .getDisplaySize() != null;
0457: }
0458:
0459: /**
0460: * <!-- begin-user-doc --> <!-- end-user-doc -->
0461: *
0462: * @generated
0463: */
0464: public Map getMapInternal() {
0465: if (eContainerFeatureID != RenderPackage.VIEWPORT_MODEL__MAP_INTERNAL)
0466: return null;
0467: return (Map) eContainer;
0468: }
0469:
0470: /**
0471: * <!-- begin-user-doc --> <!-- end-user-doc -->
0472: *
0473: * @generated
0474: */
0475: public void setMapInternalGen(Map newMapInternal) {
0476: if (newMapInternal != eContainer
0477: || (eContainerFeatureID != RenderPackage.VIEWPORT_MODEL__MAP_INTERNAL && newMapInternal != null)) {
0478: if (EcoreUtil.isAncestor(this , (EObject) newMapInternal))
0479: throw new IllegalArgumentException(
0480: "Recursive containment not allowed for " + toString()); //$NON-NLS-1$
0481: NotificationChain msgs = null;
0482: if (eContainer != null)
0483: msgs = eBasicRemoveFromContainer(msgs);
0484: if (newMapInternal != null)
0485: msgs = ((InternalEObject) newMapInternal).eInverseAdd(
0486: this ,
0487: ProjectPackage.MAP__VIEWPORT_MODEL_INTERNAL,
0488: Map.class, msgs);
0489: msgs = eBasicSetContainer((InternalEObject) newMapInternal,
0490: RenderPackage.VIEWPORT_MODEL__MAP_INTERNAL, msgs);
0491: if (msgs != null)
0492: msgs.dispatch();
0493: } else if (eNotificationRequired())
0494: eNotify(new ENotificationImpl(this , Notification.SET,
0495: RenderPackage.VIEWPORT_MODEL__MAP_INTERNAL,
0496: newMapInternal, newMapInternal));
0497: }
0498:
0499: boolean viewer = false;
0500:
0501: private static final double ACCURACY = 0.0000001;
0502:
0503: private boolean initialized;
0504:
0505: /**
0506: * @return Returns the viewer.
0507: * @uml.property name="viewer"
0508: */
0509: public boolean isViewer() {
0510: return viewer;
0511: }
0512:
0513: /**
0514: * @param viewer The viewer to set.
0515: * @uml.property name="viewer"
0516: */
0517: public void setViewer(boolean viewer) {
0518: this .viewer = viewer;
0519: }
0520:
0521: /**
0522: * @see net.refractions.udig.project.internal.render.RenderManager#setMap(IMap)
0523: */
0524: public void setMapInternal(Map newMap) {
0525: if (isViewer()) {
0526: eBasicSetContainer((InternalEObject) newMap,
0527: RenderPackage.VIEWPORT_MODEL__MAP_INTERNAL);
0528: } else
0529: setMapInternalGen(newMap);
0530: }
0531:
0532: /**
0533: * <!-- begin-user-doc --> <!-- end-user-doc -->
0534: *
0535: * @generated
0536: */
0537: public RenderManager getRenderManagerInternal() {
0538: return renderManagerInternal;
0539: }
0540:
0541: /**
0542: * <!-- begin-user-doc --> <!-- end-user-doc -->
0543: *
0544: * @generated
0545: */
0546: public NotificationChain basicSetRenderManagerInternal(
0547: RenderManager newRenderManagerInternal,
0548: NotificationChain msgs) {
0549: RenderManager oldRenderManagerInternal = renderManagerInternal;
0550: renderManagerInternal = newRenderManagerInternal;
0551: if (eNotificationRequired()) {
0552: ENotificationImpl notification = new ENotificationImpl(
0553: this ,
0554: Notification.SET,
0555: RenderPackage.VIEWPORT_MODEL__RENDER_MANAGER_INTERNAL,
0556: oldRenderManagerInternal, newRenderManagerInternal);
0557: if (msgs == null)
0558: msgs = notification;
0559: else
0560: msgs.add(notification);
0561: }
0562: return msgs;
0563: }
0564:
0565: /**
0566: * <!-- begin-user-doc --> <!-- end-user-doc -->
0567: *
0568: * @generated
0569: */
0570: public void setRenderManagerInternal(
0571: RenderManager newRenderManagerInternal) {
0572: if (newRenderManagerInternal != renderManagerInternal) {
0573: NotificationChain msgs = null;
0574: if (renderManagerInternal != null)
0575: msgs = ((InternalEObject) renderManagerInternal)
0576: .eInverseRemove(
0577: this ,
0578: RenderPackage.RENDER_MANAGER__VIEWPORT_MODEL_INTERNAL,
0579: RenderManager.class, msgs);
0580: if (newRenderManagerInternal != null)
0581: msgs = ((InternalEObject) newRenderManagerInternal)
0582: .eInverseAdd(
0583: this ,
0584: RenderPackage.RENDER_MANAGER__VIEWPORT_MODEL_INTERNAL,
0585: RenderManager.class, msgs);
0586: msgs = basicSetRenderManagerInternal(
0587: newRenderManagerInternal, msgs);
0588: if (msgs != null)
0589: msgs.dispatch();
0590: } else if (eNotificationRequired())
0591: eNotify(new ENotificationImpl(
0592: this ,
0593: Notification.SET,
0594: RenderPackage.VIEWPORT_MODEL__RENDER_MANAGER_INTERNAL,
0595: newRenderManagerInternal, newRenderManagerInternal));
0596: }
0597:
0598: /**
0599: * <!-- begin-user-doc --> <!-- end-user-doc -->
0600: *
0601: * @generated NOT
0602: */
0603: public Coordinate getPixelSize() {
0604: return new Coordinate(getXPixelToWorldScale(),
0605: getYPixelToWorldScale());
0606: }
0607:
0608: private double getXPixelToWorldScale() {
0609: if (!validState())
0610: return Double.NaN;
0611: return getWidth()
0612: / getRenderManagerInternal().getMapDisplay().getWidth();
0613: }
0614:
0615: private double getYPixelToWorldScale() {
0616: if (!validState())
0617: return Double.NaN;
0618: return getHeight()
0619: / getRenderManagerInternal().getMapDisplay()
0620: .getHeight();
0621: }
0622:
0623: /**
0624: * <!-- begin-user-doc --> <!-- end-user-doc -->
0625: *
0626: * @generated NOT
0627: */
0628: public void setBounds(double minx, double maxx, double miny,
0629: double maxy) {
0630: setBounds(new Envelope(minx, maxx, miny, maxy));
0631: }
0632:
0633: /**
0634: * <!-- begin-user-doc --> <!-- end-user-doc -->
0635: *
0636: * @generated NOT
0637: */
0638: public AffineTransform worldToScreenTransform() {
0639: if (!validState())
0640: return null;
0641: // set up the affine transform and calculate scale values
0642: return worldToScreenTransform(getBounds(),
0643: getRenderManagerInternal().getMapDisplay()
0644: .getDisplaySize());
0645: }
0646:
0647: /**
0648: * @see ViewportModel#worldToScreenTransform(Envelope, Dimension)
0649: */
0650: public AffineTransform worldToScreenTransform(Envelope mapExtent,
0651: Dimension screenSize) {
0652: double scaleX = screenSize.getWidth() / mapExtent.getWidth();
0653: double scaleY = screenSize.getHeight() / mapExtent.getHeight();
0654:
0655: double tx = -mapExtent.getMinX() * scaleX;
0656: double ty = (mapExtent.getMinY() * scaleY)
0657: + screenSize.getHeight();
0658:
0659: AffineTransform at = new AffineTransform(scaleX, 0.0d, 0.0d,
0660: -scaleY, tx, ty);
0661:
0662: return at;
0663: }
0664:
0665: /**
0666: * <!-- begin-user-doc --> <!-- end-user-doc -->
0667: *
0668: * @generated NOT
0669: */
0670: public Point worldToPixel(Coordinate coord) {
0671: if (!validState())
0672: return null;
0673: Point2D w = new Point2D.Double(coord.x, coord.y);
0674: AffineTransform at = worldToScreenTransform();
0675: Point2D p = at.transform(w, new Point2D.Double());
0676: return new Point((int) p.getX(), (int) p.getY());
0677: }
0678:
0679: /**
0680: * <!-- begin-user-doc --> <!-- end-user-doc -->
0681: *
0682: * @generated NOT
0683: */
0684: public Coordinate pixelToWorld(int x, int y) {
0685: if (!validState())
0686: return null;
0687: // set up the affine transform and calculate scale values
0688: AffineTransform at = worldToScreenTransform(getBounds(),
0689: getRenderManagerInternal().getMapDisplay()
0690: .getDisplaySize());
0691:
0692: try {
0693: Point2D result = at.inverseTransform(
0694: new java.awt.geom.Point2D.Double(x, y),
0695: new java.awt.geom.Point2D.Double());
0696: Coordinate c = new Coordinate(result.getX(), result.getY());
0697:
0698: return c;
0699: } catch (Exception e) {
0700: // TODO
0701: e.printStackTrace();
0702: }
0703:
0704: return null;
0705: }
0706:
0707: /**
0708: * <!-- begin-user-doc --> <!-- end-user-doc -->
0709: *
0710: * @generated NOT
0711: */
0712: public ViewportModel panUsingScreenCoords(int xpixels, int ypixels) {
0713: if (!validState())
0714: return this ;
0715: panUsingWorldCoords(xpixels * getXPixelToWorldScale(), -ypixels
0716: * getYPixelToWorldScale());
0717: return this ;
0718: }
0719:
0720: /**
0721: * <!-- begin-user-doc --> <!-- end-user-doc -->
0722: *
0723: * @generated NOT
0724: */
0725: public ViewportModel panUsingWorldCoords(double x, double y) {
0726: Envelope bounds = getBounds();
0727: setBounds(bounds.getMinX() + x, bounds.getMaxX() + x, bounds
0728: .getMinY()
0729: + y, bounds.getMaxY() + y);
0730: return this ;
0731: }
0732:
0733: /**
0734: * <!-- begin-user-doc --> <!-- end-user-doc -->
0735: *
0736: * @generated NOT
0737: */
0738: public ViewportModel zoom(double zoom) {
0739: Coordinate center = getCenter();
0740: double height = getHeight() / zoom, width = getWidth() / zoom;
0741: double dh = height / 2, dw = width / 2;
0742: setBounds(center.x - dw, center.x + dw, center.y - dh, center.y
0743: + dh);
0744: return this ;
0745: }
0746:
0747: /**
0748: * <!-- begin-user-doc --> <!-- end-user-doc -->
0749: *
0750: * @generated NOT
0751: */
0752: public void zoomToExtent() {
0753: try {
0754: if (!validState())
0755: return;
0756:
0757: ReferencedEnvelope bounds2 = new ReferencedEnvelope(
0758: getCRS());
0759: boolean hasVisibleLayer = false;
0760: // search the map for visible layers and construct a bounds from those layers.
0761: // otherwise default to what the map's extent is.
0762: List<ILayer> layers = getMap().getMapLayers();
0763: for (ILayer layer : layers) {
0764: ReferencedEnvelope layerBounds = layer.getBounds(
0765: ProgressManager.instance().get(), getCRS());
0766: if (layer.isVisible() && !layerBounds.isNull()) {
0767: hasVisibleLayer = true;
0768: if (bounds2.isNull()) {
0769: bounds2.init(layerBounds);
0770: } else {
0771: bounds2.expandToInclude(layerBounds);
0772: }
0773: }
0774: }
0775:
0776: if (!hasVisibleLayer) {
0777: bounds2 = getMap().getBounds(
0778: ProgressManager.instance().get());
0779: }
0780:
0781: if (bounds2.getCoordinateReferenceSystem() == null
0782: || getCRS() == null
0783: || bounds2.getCoordinateReferenceSystem().equals(
0784: getCRS())) {
0785: zoomToBox(bounds2);
0786: } else {
0787: MathTransform transform = null;
0788: transform = CRS
0789: .findMathTransform(bounds2
0790: .getCoordinateReferenceSystem(),
0791: getCRS(), true);
0792: zoomToBox(JTS.transform(bounds2, transform));
0793: }
0794:
0795: } catch (IOException e2) {
0796: zoomToBox(new Envelope(-180, 180, -90, 90));
0797: } catch (FactoryException e) {
0798: zoomToBox(new Envelope(-180, 180, -90, 90));
0799: } catch (TransformException e) {
0800: zoomToBox(new Envelope(-180, 180, -90, 90));
0801: }
0802: }
0803:
0804: /**
0805: * <!-- begin-user-doc --> <!-- end-user-doc -->
0806: *
0807: * @generated
0808: */
0809: public NotificationChain eInverseAdd(InternalEObject otherEnd,
0810: int featureID, Class baseClass, NotificationChain msgs) {
0811: if (featureID >= 0) {
0812: switch (eDerivedStructuralFeatureID(featureID, baseClass)) {
0813: case RenderPackage.VIEWPORT_MODEL__MAP_INTERNAL:
0814: if (eContainer != null)
0815: msgs = eBasicRemoveFromContainer(msgs);
0816: return eBasicSetContainer(otherEnd,
0817: RenderPackage.VIEWPORT_MODEL__MAP_INTERNAL,
0818: msgs);
0819: case RenderPackage.VIEWPORT_MODEL__RENDER_MANAGER_INTERNAL:
0820: if (renderManagerInternal != null)
0821: msgs = ((InternalEObject) renderManagerInternal)
0822: .eInverseRemove(
0823: this ,
0824: RenderPackage.RENDER_MANAGER__VIEWPORT_MODEL_INTERNAL,
0825: RenderManager.class, msgs);
0826: return basicSetRenderManagerInternal(
0827: (RenderManager) otherEnd, msgs);
0828: default:
0829: return eDynamicInverseAdd(otherEnd, featureID,
0830: baseClass, msgs);
0831: }
0832: }
0833: if (eContainer != null)
0834: msgs = eBasicRemoveFromContainer(msgs);
0835: return eBasicSetContainer(otherEnd, featureID, msgs);
0836: }
0837:
0838: /**
0839: * <!-- begin-user-doc --> <!-- end-user-doc -->
0840: *
0841: * @generated
0842: */
0843: public NotificationChain eInverseRemove(InternalEObject otherEnd,
0844: int featureID, Class baseClass, NotificationChain msgs) {
0845: if (featureID >= 0) {
0846: switch (eDerivedStructuralFeatureID(featureID, baseClass)) {
0847: case RenderPackage.VIEWPORT_MODEL__MAP_INTERNAL:
0848: return eBasicSetContainer(null,
0849: RenderPackage.VIEWPORT_MODEL__MAP_INTERNAL,
0850: msgs);
0851: case RenderPackage.VIEWPORT_MODEL__RENDER_MANAGER_INTERNAL:
0852: return basicSetRenderManagerInternal(null, msgs);
0853: default:
0854: return eDynamicInverseRemove(otherEnd, featureID,
0855: baseClass, msgs);
0856: }
0857: }
0858: return eBasicSetContainer(null, featureID, msgs);
0859: }
0860:
0861: /**
0862: * <!-- begin-user-doc --> <!-- end-user-doc -->
0863: *
0864: * @generated
0865: */
0866: public NotificationChain eBasicRemoveFromContainer(
0867: NotificationChain msgs) {
0868: if (eContainerFeatureID >= 0) {
0869: switch (eContainerFeatureID) {
0870: case RenderPackage.VIEWPORT_MODEL__MAP_INTERNAL:
0871: return eContainer.eInverseRemove(this ,
0872: ProjectPackage.MAP__VIEWPORT_MODEL_INTERNAL,
0873: Map.class, msgs);
0874: default:
0875: return eDynamicBasicRemoveFromContainer(msgs);
0876: }
0877: }
0878: return eContainer.eInverseRemove(this , EOPPOSITE_FEATURE_BASE
0879: - eContainerFeatureID, null, msgs);
0880: }
0881:
0882: /**
0883: * <!-- begin-user-doc --> <!-- end-user-doc -->
0884: *
0885: * @generated
0886: */
0887: public Object eGet(EStructuralFeature eFeature, boolean resolve) {
0888: switch (eDerivedStructuralFeatureID(eFeature)) {
0889: case RenderPackage.VIEWPORT_MODEL__CRS:
0890: return getCRS();
0891: case RenderPackage.VIEWPORT_MODEL__BOUNDS:
0892: return getBounds();
0893: case RenderPackage.VIEWPORT_MODEL__CENTER:
0894: return getCenter();
0895: case RenderPackage.VIEWPORT_MODEL__HEIGHT:
0896: return new Double(getHeight());
0897: case RenderPackage.VIEWPORT_MODEL__WIDTH:
0898: return new Double(getWidth());
0899: case RenderPackage.VIEWPORT_MODEL__ASPECT_RATIO:
0900: return new Double(getAspectRatio());
0901: case RenderPackage.VIEWPORT_MODEL__PIXEL_SIZE:
0902: return getPixelSize();
0903: case RenderPackage.VIEWPORT_MODEL__MAP_INTERNAL:
0904: return getMapInternal();
0905: case RenderPackage.VIEWPORT_MODEL__RENDER_MANAGER_INTERNAL:
0906: return getRenderManagerInternal();
0907: }
0908: return eDynamicGet(eFeature, resolve);
0909: }
0910:
0911: /**
0912: * <!-- begin-user-doc --> <!-- end-user-doc -->
0913: *
0914: * @generated
0915: */
0916: public void eSet(EStructuralFeature eFeature, Object newValue) {
0917: switch (eDerivedStructuralFeatureID(eFeature)) {
0918: case RenderPackage.VIEWPORT_MODEL__CRS:
0919: setCRS((CoordinateReferenceSystem) newValue);
0920: return;
0921: case RenderPackage.VIEWPORT_MODEL__BOUNDS:
0922: setBounds((Envelope) newValue);
0923: return;
0924: case RenderPackage.VIEWPORT_MODEL__CENTER:
0925: setCenter((Coordinate) newValue);
0926: return;
0927: case RenderPackage.VIEWPORT_MODEL__HEIGHT:
0928: setHeight(((Double) newValue).doubleValue());
0929: return;
0930: case RenderPackage.VIEWPORT_MODEL__WIDTH:
0931: setWidth(((Double) newValue).doubleValue());
0932: return;
0933: case RenderPackage.VIEWPORT_MODEL__MAP_INTERNAL:
0934: setMapInternal((Map) newValue);
0935: return;
0936: case RenderPackage.VIEWPORT_MODEL__RENDER_MANAGER_INTERNAL:
0937: setRenderManagerInternal((RenderManager) newValue);
0938: return;
0939: }
0940: eDynamicSet(eFeature, newValue);
0941: }
0942:
0943: /**
0944: * <!-- begin-user-doc --> <!-- end-user-doc -->
0945: *
0946: * @generated
0947: */
0948: public void eUnset(EStructuralFeature eFeature) {
0949: switch (eDerivedStructuralFeatureID(eFeature)) {
0950: case RenderPackage.VIEWPORT_MODEL__CRS:
0951: unsetCRS();
0952: return;
0953: case RenderPackage.VIEWPORT_MODEL__BOUNDS:
0954: setBounds(BOUNDS_EDEFAULT);
0955: return;
0956: case RenderPackage.VIEWPORT_MODEL__CENTER:
0957: setCenter(CENTER_EDEFAULT);
0958: return;
0959: case RenderPackage.VIEWPORT_MODEL__HEIGHT:
0960: setHeight(HEIGHT_EDEFAULT);
0961: return;
0962: case RenderPackage.VIEWPORT_MODEL__WIDTH:
0963: setWidth(WIDTH_EDEFAULT);
0964: return;
0965: case RenderPackage.VIEWPORT_MODEL__MAP_INTERNAL:
0966: setMapInternal((Map) null);
0967: return;
0968: case RenderPackage.VIEWPORT_MODEL__RENDER_MANAGER_INTERNAL:
0969: setRenderManagerInternal((RenderManager) null);
0970: return;
0971: }
0972: eDynamicUnset(eFeature);
0973: }
0974:
0975: /**
0976: * <!-- begin-user-doc --> <!-- end-user-doc -->
0977: *
0978: * @generated
0979: */
0980: public boolean eIsSet(EStructuralFeature eFeature) {
0981: switch (eDerivedStructuralFeatureID(eFeature)) {
0982: case RenderPackage.VIEWPORT_MODEL__CRS:
0983: return isSetCRS();
0984: case RenderPackage.VIEWPORT_MODEL__BOUNDS:
0985: return BOUNDS_EDEFAULT == null ? bounds != null
0986: : !BOUNDS_EDEFAULT.equals(bounds);
0987: case RenderPackage.VIEWPORT_MODEL__CENTER:
0988: return CENTER_EDEFAULT == null ? getCenter() != null
0989: : !CENTER_EDEFAULT.equals(getCenter());
0990: case RenderPackage.VIEWPORT_MODEL__HEIGHT:
0991: return getHeight() != HEIGHT_EDEFAULT;
0992: case RenderPackage.VIEWPORT_MODEL__WIDTH:
0993: return getWidth() != WIDTH_EDEFAULT;
0994: case RenderPackage.VIEWPORT_MODEL__ASPECT_RATIO:
0995: return getAspectRatio() != ASPECT_RATIO_EDEFAULT;
0996: case RenderPackage.VIEWPORT_MODEL__PIXEL_SIZE:
0997: return PIXEL_SIZE_EDEFAULT == null ? getPixelSize() != null
0998: : !PIXEL_SIZE_EDEFAULT.equals(getPixelSize());
0999: case RenderPackage.VIEWPORT_MODEL__MAP_INTERNAL:
1000: return getMapInternal() != null;
1001: case RenderPackage.VIEWPORT_MODEL__RENDER_MANAGER_INTERNAL:
1002: return renderManagerInternal != null;
1003: }
1004: return eDynamicIsSet(eFeature);
1005: }
1006:
1007: /**
1008: * <!-- begin-user-doc --> <!-- end-user-doc -->
1009: *
1010: * @generated
1011: */
1012: public String toString() {
1013: if (eIsProxy())
1014: return super .toString();
1015:
1016: StringBuffer result = new StringBuffer(super .toString());
1017: result.append(" (cRS: "); //$NON-NLS-1$
1018: if (cRSESet)
1019: result.append(cRS);
1020: else
1021: result.append("<unset>"); //$NON-NLS-1$
1022: result.append(", bounds: "); //$NON-NLS-1$
1023: result.append(bounds);
1024: result.append(')');
1025: return result.toString();
1026: }
1027:
1028: /**
1029: * @see net.refractions.udig.project.render.displayAdapter.IMapDisplayListener#sizeChanged(net.refractions.udig.project.render.displayAdapter.MapDisplayEvent)
1030: */
1031: public void sizeChanged(MapDisplayEvent event) {
1032: if (event.getSize().width < 1 || event.getSize().height < 1)
1033: return;
1034:
1035: Envelope oldBounds = getBounds();
1036:
1037: if (newSizeIsSmaller(event)) {
1038: calculateNewBounds(event, oldBounds);
1039: return;
1040: }
1041:
1042: if (oldBounds.isNull()) {
1043: zoomToExtent();
1044: } else {
1045: if (oldSizeIsValid(event)) {
1046: calculateNewBounds(event, oldBounds);
1047: fireNotification(oldBounds);
1048: } else {
1049: zoomToBox(getBounds());
1050: }
1051: }
1052: }
1053:
1054: private void fireNotification(Envelope oldBounds) {
1055: if (eNotificationRequired()) {
1056: eNotify(new ENotificationImpl(this , Notification.SET,
1057: RenderPackage.VIEWPORT_MODEL__BOUNDS, oldBounds,
1058: bounds));
1059:
1060: notifyListeners(new ViewportModelEvent(this , EventType.CRS,
1061: bounds, oldBounds));
1062: }
1063: }
1064:
1065: private void calculateNewBounds(MapDisplayEvent event,
1066: Envelope oldBounds) {
1067: double oldXscale = getWidth() / event.getOldSize().width;
1068: double oldYscale = getHeight() / event.getOldSize().height;
1069: double minx = oldBounds.getMinX();
1070: double maxy = oldBounds.getMaxY();
1071: double maxx = minx + (event.getSize().width * oldXscale);
1072: double miny = maxy - (event.getSize().height * oldYscale);
1073: this .bounds = new Envelope(minx, maxx, miny, maxy);
1074: }
1075:
1076: private boolean oldSizeIsValid(MapDisplayEvent event) {
1077: return event.getOldSize() != null
1078: && event.getOldSize().width != 0
1079: && event.getOldSize().height != 0;
1080: }
1081:
1082: private boolean newSizeIsSmaller(MapDisplayEvent event) {
1083: if (event.getOldSize() == null)
1084: return false;
1085: return event.getOldSize().width > event.getSize().width
1086: && event.getOldSize().height > event.getSize().height;
1087: }
1088:
1089: /**
1090: * @see net.refractions.udig.project.internal.render.ViewportModel#zoomToBox(com.vividsolutions.jts.geom.Envelope)
1091: */
1092: public void zoomToBox(Envelope newbbox) {
1093: setInitialized(true);
1094: if (Math.abs(newbbox.getWidth() / newbbox.getHeight()
1095: - this .getAspectRatio()) > ACCURACY) {
1096: IMapDisplay display = this .getRenderManagerInternal()
1097: .getMapDisplay();
1098: double scaley = newbbox.getHeight() / display.getHeight();
1099: double scalex = newbbox.getWidth() / display.getWidth();
1100: double scale;
1101: if (scalex > scaley)
1102: scale = scalex;
1103: else
1104: scale = scaley;
1105:
1106: double height = display.getHeight() * scale;
1107: double width = display.getWidth() * scale;
1108:
1109: double dw = width / 2, dh = height / 2;
1110: Envelope mapBounds = newbbox;
1111: double x = (mapBounds.getMaxX() + mapBounds.getMinX()) / 2;
1112: double y = (mapBounds.getMaxY() + mapBounds.getMinY()) / 2;
1113: newbbox.init(x - dw, x + dw, y - dh, y + dh);
1114: // newbbox.init(validateEnvelope(newbbox));
1115: }
1116: this .setBounds(newbbox);
1117: }
1118:
1119: /**
1120: * Returns the system wide default CRS
1121: */
1122: public static CoordinateReferenceSystem getDefaultCRS() {
1123: try {
1124: IPreferenceStore store = ProjectPlugin.getPlugin()
1125: .getPreferenceStore();
1126: int i = store.getInt(PreferenceConstants.P_DEFAULT_CRS);
1127: if (i == -1)
1128: return CRS.decode("EPSG:4326");//$NON-NLS-1$
1129: return CRS.decode("EPSG:" + i); //$NON-NLS-1$
1130: } catch (NoSuchAuthorityCodeException e) {
1131: try {
1132: return CRS.decode("EPSG:4326"); //$NON-NLS-1$
1133: } catch (NoSuchAuthorityCodeException e2) {
1134: return DefaultGeographicCRS.WGS84;
1135: }
1136: }
1137: }
1138:
1139: /**
1140: * FIXME, This method was added as a work around for the fact that we do not have the ability to
1141: * chain or batch commands.
1142: *
1143: * @param firing
1144: */
1145: public void setFiringEvents(boolean firing) {
1146: if (firing) {
1147: eFlags |= EDELIVER;
1148: } else {
1149: eFlags &= ~EDELIVER;
1150:
1151: }
1152: }
1153:
1154: /**
1155: * @see net.refractions.udig.project.internal.render.ViewportModel#isInitialized()
1156: * @uml.property name="initialized"
1157: */
1158: public boolean isInitialized() {
1159: return initialized;
1160: }
1161:
1162: /**
1163: * @param initialized The initialized to set.
1164: * @uml.property name="initialized"
1165: */
1166: public void setInitialized(boolean initialized) {
1167: this .initialized = initialized;
1168: }
1169:
1170: /**
1171: * @see net.refractions.udig.project.render.IViewportModel#getMap()
1172: */
1173: public IMap getMap() {
1174: return getMapInternal();
1175: }
1176:
1177: public double getScaleDenominator() {
1178: if (getRenderManagerInternal() == null
1179: || getRenderManagerInternal().getMapDisplay() == null)
1180: return -1;
1181:
1182: Envelope translatedBounds = getBounds();
1183: Envelope world = new Envelope(-180, 180, -90, 90);
1184: try {
1185: if (!getBounds().getCoordinateReferenceSystem().equals(
1186: DefaultGeographicCRS.WGS84))
1187: translatedBounds = getBounds().transform(
1188: DefaultGeographicCRS.WGS84, true);
1189: } catch (Exception e1) {
1190: ProjectPlugin
1191: .trace(
1192: Trace.MODEL,
1193: getClass(),
1194: "Error transforming " + getCRS().getName() + " to WGS84", e1); //$NON-NLS-1$ //$NON-NLS-2$
1195: try {
1196: world = getMap().getBounds(new NullProgressMonitor());
1197: } catch (IOException e) {
1198: ProjectPlugin.log("Error getting map bounds", e); //$NON-NLS-1$
1199: return -1;
1200: }
1201: }
1202: if (world.contains(translatedBounds)) {
1203: Point2D displaySize = new Point2D.Double(
1204: getRenderManagerInternal().getMapDisplay()
1205: .getWidth(), getRenderManagerInternal()
1206: .getMapDisplay().getHeight());
1207: return calculateScale(translatedBounds, displaySize);
1208: } else {
1209: Point2D screenDimension = new Point2D.Double();
1210: Envelope scaledBounds = calculateScaledBounds(
1211: translatedBounds, screenDimension);
1212:
1213: return calculateScale(scaledBounds, screenDimension);
1214: }
1215: }
1216:
1217: private Envelope calculateScaledBounds(Envelope translatedBounds,
1218: Point2D screenDimension) {
1219: Envelope result;
1220: Envelope world = new Envelope(-180, 180, -90, 90);
1221: double width = translatedBounds.getWidth();
1222: double xratio = world.getWidth() / width;
1223: double yratio = world.getHeight()
1224: / translatedBounds.getHeight();
1225: if (xratio < yratio) {
1226: // ratio between widths is greater so the scaled instance should be based on
1227: // width.
1228: result = new Envelope(-180, 180, -90, -90
1229: + translatedBounds.getHeight() * xratio);
1230: screenDimension.setLocation(
1231: ((double) getRenderManagerInternal()
1232: .getMapDisplay().getWidth())
1233: * xratio,
1234: ((double) getRenderManagerInternal()
1235: .getMapDisplay().getHeight())
1236: * xratio);
1237: } else {
1238: // ratio between widths is greater so the scaled instance should be based on
1239: // width.
1240: result = new Envelope(-180, -180 + width * yratio, -90, 90);
1241: screenDimension.setLocation(
1242: ((double) getRenderManagerInternal()
1243: .getMapDisplay().getWidth())
1244: * yratio,
1245: ((double) getRenderManagerInternal()
1246: .getMapDisplay().getHeight())
1247: * yratio);
1248:
1249: }
1250: return result;
1251: }
1252:
1253: private double calculateScale(Envelope restrictedBounds,
1254: Point2D screenDimension) {
1255: double diagonalGroundDistance;
1256: try {
1257: diagonalGroundDistance = DefaultGeographicCRS.WGS84
1258: .distance(
1259: new double[] { restrictedBounds.getMinX(),
1260: restrictedBounds.getMinY() },
1261: new double[] { restrictedBounds.getMaxX(),
1262: restrictedBounds.getMaxY() })
1263: .doubleValue();
1264: } catch (Exception e) {
1265: ProjectPlugin.log("Error calculating ground distance", e); //$NON-NLS-1$
1266: return -1;
1267: }
1268:
1269: double displayWidth = screenDimension.getX();
1270: double displayHeight = screenDimension.getY();
1271:
1272: // pythagorean theorem
1273: double diagonalPixelDistancePixels = Math.sqrt(displayWidth
1274: * displayWidth + displayHeight * displayHeight);
1275: // 2.54 = cm/inch, 100= cm/m
1276: double diagonalPixelDistanceMeters = (diagonalPixelDistancePixels * 2.54)
1277: / (90 * 100);
1278:
1279: // remember, this is the denominator, not the actual scale
1280: return diagonalGroundDistance / diagonalPixelDistanceMeters;
1281: }
1282:
1283: private final static CoordinateOperationFactory distanceOperationFactory;
1284: static {
1285: Hints hints = new Hints(Hints.LENIENT_DATUM_SHIFT, Boolean.TRUE);
1286: distanceOperationFactory = FactoryFinder
1287: .getCoordinateOperationFactory(hints);
1288: }
1289:
1290: public void setScale(double scaleDenominator) {
1291: double displayWidth = getRenderManagerInternal()
1292: .getMapDisplay().getWidth();
1293: double displayHeight = getRenderManagerInternal()
1294: .getMapDisplay().getHeight();
1295:
1296: // pythagorean theorem
1297: double diagonalPixelDistancePixels = Math.sqrt(displayWidth
1298: * displayWidth + displayHeight * displayHeight);
1299: double diagonalPixelDistanceMeters = diagonalPixelDistancePixels / 90 * 2.54 / 100; // 2.54 = cm/inch, 100= cm/m
1300:
1301: double groundDistance = scaleDenominator
1302: * diagonalPixelDistanceMeters;
1303:
1304: GeodeticCalculator gc = new GeodeticCalculator();
1305: double[] cs = new double[4];
1306: double[] csLatLong = new double[4];
1307:
1308: try {
1309: cs[0] = Math.max(getBounds().getMinX(), getMap().getBounds(
1310: null).getMinX());
1311: cs[1] = Math.max(getBounds().getMinX(), getMap().getBounds(
1312: null).getMinX());
1313:
1314: MathTransform transform = distanceOperationFactory
1315: .createOperation(getCRS(),
1316: DefaultGeographicCRS.WGS84)
1317: .getMathTransform();
1318: transform.transform(cs, 0, csLatLong, 0, 1);
1319: gc.setAnchorPoint(csLatLong[0], csLatLong[1]);
1320:
1321: gc.setDirection(45, groundDistance);
1322: Point2D latLongPosition = gc.getDestinationPoint();
1323: csLatLong[0] = latLongPosition.getX();
1324: csLatLong[1] = latLongPosition.getY();
1325: transform.inverse().transform(csLatLong, 0, cs, 2, 1);
1326:
1327: // calculate amount to zoom
1328: setWidth(cs[2] - cs[0]);
1329: } catch (Exception e) {
1330: ProjectPlugin.log("", e); //$NON-NLS-1$
1331: }
1332:
1333: }
1334:
1335: CopyOnWriteArraySet<IViewportModelListener> listeners = new CopyOnWriteArraySet<IViewportModelListener>();
1336:
1337: public void addViewportModelListener(IViewportModelListener listener) {
1338: listeners.add(listener);
1339: }
1340:
1341: public void removeViewportModelListener(
1342: IViewportModelListener listener) {
1343: listeners.remove(listener);
1344: }
1345:
1346: private void notifyListeners(ViewportModelEvent event) {
1347: for (IViewportModelListener listener : listeners) {
1348: try {
1349: listener.changed(event);
1350: } catch (Throwable t) {
1351: ProjectPlugin.log("", t); //$NON-NLS-1$
1352: }
1353: }
1354: }
1355:
1356: }
|