| /****************************************************************************** |
| * Copyright (c) 2005, 2006 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); |
| 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; |
| } |
| } |