blob: fd6a3a5ea743383c3587e6aaaca80c9188492cda [file] [log] [blame]
/******************************************************************************
* 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;
}
}