/****************************************************************************** * Copyright (c) 2005, 2009 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation ****************************************************************************/ package org.eclipse.gmf.runtime.diagram.ui.internal.figures; import org.eclipse.draw2d.Connection; import org.eclipse.draw2d.IFigure; import org.eclipse.draw2d.geometry.Point; import org.eclipse.draw2d.geometry.PointList; import org.eclipse.draw2d.geometry.Rectangle; import org.eclipse.gmf.runtime.draw2d.ui.geometry.LineSeg; import org.eclipse.gmf.runtime.draw2d.ui.geometry.PointListUtilities; /** * Helper class to convert the label coordinates from an offset value * from a keypoint to real draw2d coordinate * * @author sshaw * */ public class LabelHelper { /** * Calculates the label offset from the reference point given the label bounds. * * @param label the <code>IFigure</code> to calculate the offset for * @param bounds the <code>Rectangle</code> that is the bounding box of the label. * @param ref the <code>Point</code> that is the reference point that the offset * is based on. * @return a <code>Point</code> which represents a value offset from the <code>ref</code> * point oriented based on the nearest line segment. */ static public Point offsetFromRelativeCoordinate(IFigure label, Rectangle bounds, Point ref) { return offsetFromRelativeCoordinate(label, bounds, getParentPointList(label), ref); } /** * Calculates the label offset from the reference point given the label bounds and a points list. * * @param label the <code>IFigure</code> to calculate the offset for * @param bounds the <code>Rectangle</code> that is the bounding box of the label. * @param points the <code>PointList</code> that contains that the label offset is relative to. * @param ref the <code>Point</code> that is the reference point that the offset * is based on. * @return a <code>Point</code> which represents a value offset from the <code>ref</code> * point oriented based on the nearest line segment. */ static private Point offsetFromRelativeCoordinate(IFigure label, Rectangle bounds, PointList points, Point ref) { Rectangle rect = new Rectangle(bounds); //Componsate for the fact that we are using the // figure center rect.translate(rect.width /2, rect.height /2); Point normalPoint = normalizeRelativePointToPointOnLine(points, ref, new Point(rect.x - ref.x, rect.y - ref.y)); return normalPoint; } /** * Calculates the relative coordinate that is equivalent to the offset from the reference * point, that can be used to set the label location. * * @param label the <code>IFigure</code> to calculate the relative coordinate for * @param ref a <code>Point</code> located on the parent which the offset value * is relative to. * @param offset a <code>Point</code> which represents a value offset from the <code>ref</code> * point oriented based on the nearest line segment. * @return a <code>Point</code> that is the relative coordinate of the label that can be * used to set it's location. */ static public Point relativeCoordinateFromOffset(IFigure label, Point ref, Point offset) { return relativeCoordinateFromOffset(label, getParentPointList(label), ref, offset); } /** * Calculates the relative coordinate that is equivalent to the offset from the reference * point, that can be used to set the label location. * * @param label the <code>IFigure</code> to calculate the relative coordinate for * @param points the <code>PointList</code> that contains that the label offset is relative to. * @param ref a <code>Point</code> located on the parent which the offset value * is relative to. * @param offset a <code>Point</code> which represents a value offset from the <code>ref</code> * point oriented based on the nearest line segment. * @return a <code>Point</code> that is the relative coordinate of the label that can be * used to set it's location. */ static private Point relativeCoordinateFromOffset(IFigure label, PointList points, Point ref, Point offset) { Point location = calculatePointRelativeToPointOnLine(points, ref, offset); location.translate(-1 * label.getBounds().width /2, -1 * label.getBounds().height /2); return location; } /** * gets the point list using the passed figure to get the parent * * @param label the <code>IFigure</code> to use to retrieve the parent points * @return List of points */ static private PointList getParentPointList(IFigure label) { IFigure parent = label.getParent(); if (parent instanceof Connection) { return ((Connection) parent).getPoints(); } else { PointList ptList = new PointList(); ptList.addPoint(parent.getBounds().getLocation()); return ptList; } } /** * Returns a point located relative to the line by the given offset. * * @param ptLst the point * @param ptOnLine * @param offset * @return the relative point given the line angle */ protected static Point calculatePointRelativeToPointOnLine(PointList ptLst, Point ptOnLine, Point offset) { // Calculate slope of line if (ptLst.size() == 1) { // This is a node... return ptLst.getFirstPoint().getTranslated(offset); } else if (ptLst.size() >= 2){ // This is a edge... int index = PointListUtilities.findNearestLineSegIndexOfPoint(ptLst, ptOnLine); if (index < 1) { return ptLst.getFirstPoint().getTranslated(offset); } LineSeg segment = (LineSeg) PointListUtilities.getLineSegments(ptLst).get(index - 1); Point relativeOffset = null; if (segment != null) { if (segment.isHorizontal()) { if (segment.getOrigin().x > segment.getTerminus().x) { relativeOffset = ptOnLine.getTranslated(offset.getNegated()); //System.out.println("1. Relative offset: " + relativeOffset);//$NON-NLS-1$ return relativeOffset; } else { relativeOffset = ptOnLine.getTranslated(offset); //System.out.println("2. Relative offset: " + relativeOffset);//$NON-NLS-1$ return relativeOffset; } } else if (segment.isVertical()) { if (segment.getOrigin().y > segment.getTerminus().y) { relativeOffset = ptOnLine.getTranslated(offset.getCopy().scale(-1, 1).transpose()); //System.out.println("3. Relative offset: " + relativeOffset);//$NON-NLS-1$ return relativeOffset; } else { relativeOffset = ptOnLine.getTranslated(offset.getCopy().scale(1, -1).transpose()); //System.out.println("4. Relative offset: " + relativeOffset);//$NON-NLS-1$ return relativeOffset; } } else { double slope = segment.slope(); double theta = Math.atan(slope); Point normalizedOffset = new Point(offset); Point calculatedOffset = new Point(); if (segment.getOrigin().x > segment.getTerminus().x) { normalizedOffset = offset.getCopy().scale(-1, -1); } calculatedOffset = new Point(normalizedOffset.x * Math.cos(theta) - normalizedOffset.y * Math.sin(theta), normalizedOffset.x * Math.sin(theta) + normalizedOffset.y * Math.cos(theta)); relativeOffset = ptOnLine.getTranslated(calculatedOffset); //System.out.println("5. Relative offset: " + relativeOffset);//$NON-NLS-1$ return relativeOffset; } } } return null; } /** * Calculates the normalized offset from a point on a <code>Connection</code>'s point list to an point. * * @param ptLst * @param ptOnLine * @param offset * @return the normalized offset */ private static Point normalizeRelativePointToPointOnLine(PointList ptLst, Point ptOnLine, Point offset) { // Calculate slope of line if (ptLst.size() == 1) { // This is a node... return offset; } else if (ptLst.size() >= 2){ // This is a edge... int index = PointListUtilities.findNearestLineSegIndexOfPoint(ptLst, ptOnLine); LineSeg segment = (LineSeg) PointListUtilities.getLineSegments(ptLst).get(index - 1); Point normalOffset = null; if (segment != null) { if (segment.isHorizontal()) { if (segment.getOrigin().x > segment.getTerminus().x) { normalOffset = offset.getNegated(); //System.out.println("1. Normal offset: " + normalOffset);//$NON-NLS-1$ return normalOffset; } else { normalOffset = offset; //System.out.println("2. Normal offset: " + normalOffset);//$NON-NLS-1$ return normalOffset; } } else if (segment.isVertical()) { if (segment.getOrigin().y < segment.getTerminus().y) { normalOffset = offset.scale(-1, 1).transpose(); //System.out.println("3. Normal offset: " + normalOffset);//$NON-NLS-1$ return normalOffset; } else { normalOffset = offset.scale(1, -1).transpose(); //System.out.println("4. Normal offset: " + normalOffset);//$NON-NLS-1$ return normalOffset; } } else { Point p = ptOnLine.getTranslated(offset); normalOffset = getOrthogonalDistances(segment, ptOnLine, p); //System.out.println("5. Normal offset: " + normalOffset);//$NON-NLS-1$ return normalOffset; } } } return null; } /** * Calculates distances from a <code>Point</code> on a <code>LineSeg</code> to * another <code>Point</code>. The sign of the distances indicate direction. * * @param lineSeg * @param ptOnLine * @param refPoint * @return the distance from <code>Point</code> on a <code>LineSeg</code> to another <code>Point</code> */ private static Point getOrthogonalDistances(LineSeg lineSeg, Point ptOnLine, Point refPoint) { LineSeg parallelSeg = lineSeg.getParallelLineSegThroughPoint(refPoint); Point p1 = parallelSeg.perpIntersect(ptOnLine.x, ptOnLine.y); double dx = p1.getDistance(refPoint) * ((p1.x > refPoint.x) ? -1 : 1); double dy = p1.getDistance(ptOnLine) * ((p1.y < ptOnLine.y) ? -1 : 1); Point orth = new Point(dx, dy); // Reflection in the y axis if (lineSeg.getOrigin().x > lineSeg.getTerminus().x) orth = orth.scale(-1, -1); return orth; } }