blob: b6fb4d0b4ccdcbcb70d9bdb62068ac143dac15e1 [file] [log] [blame]
/******************************************************************************
* Copyright (c) 2003, 2010 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.geoshapes.internal.draw2d.figures;
import org.eclipse.draw2d.Graphics;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.PointList;
import org.eclipse.draw2d.geometry.PrecisionPoint;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gmf.runtime.draw2d.ui.figures.IPolygonAnchorableFigure;
import org.eclipse.gmf.runtime.draw2d.ui.figures.PolylineConnectionEx;
import org.eclipse.gmf.runtime.draw2d.ui.geometry.LineSeg;
import org.eclipse.gmf.runtime.draw2d.ui.geometry.PointListUtilities;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Path;
/**
* @author jschofie
*
* This Figure represents a Cylinder Figure
*/
public class GeoShapeCylinderFigure extends GeoShapeFigure implements IPolygonAnchorableFigure {
// cache the anchor border point list since the calculation is costly.
private PointList anchorBorderPointList;
/**
* Constructor - Creates a cylinder with a given Default size
*
* @param width initial width of figure
* @param height initial height of the figure
* @param spacing <code>int</code> that is the margin between children in logical units
*/
public GeoShapeCylinderFigure(int width, int height, int spacing) {
super(width, height, spacing);
}
/* (non-Javadoc)
* @see org.eclipse.draw2d.Figure#paintFigure(org.eclipse.draw2d.Graphics)
*/
protected void paintFigure(Graphics g) {
g.pushState();
// don't apply transparency to the outline
applyTransparency(g);
if (!isUsingGradient()) {
// Fill cylinder with fill color
g.setFillRule(SWT.FILL_WINDING);
Path path = getPath();
try {
g.fillPath(path);
} finally {
path.dispose();
}
} else {
// Use gradient info to fill the cylinder with gradient
fillGradient(g, SWT.FILL_WINDING);
}
g.popState();
// Now draw the border
Rectangle r = getBounds().getCopy();
r.shrink(getLineWidth() / 2, getLineWidth() / 2);
int height = getTopHeight(r);
Rectangle ellipse = new Rectangle(r.x, r.y, r.width, height + 1);
Rectangle middle = new Rectangle(r.x, r.y + (height / 2), r.width,
r.height - height);
Rectangle lowerArc = new Rectangle(r.x, r.y + r.height - height - 1,
r.width - 1, height);
// set the line type and line width
g.setLineStyle(getLineStyle());
g.setLineWidth(getLineWidth());
// Draw the ellipse outline
g.drawOval(ellipse.x, ellipse.y, ellipse.width - 1, ellipse.height - 1);
// Draw the middle section
g.drawLine(middle.x, middle.y, middle.x, middle.y + middle.height);
// Draw the lower arc outline
g.drawLine(middle.x + middle.width - 1, middle.y, middle.x
+ middle.width - 1, middle.y + middle.height);
g.drawArc(lowerArc, 180, 180);
}
/**
* Estimate the anchor intersection points by using a polyline smoothed
* with bezier curves for the rounded top and bottom arcs.
*
* @return PointList of the border of the cylinder shape
*/
protected PointList getAnchorBorderPointList() {
Rectangle rBounds = getBounds();
if (rBounds.isEmpty()) {
return new PointList(new int[]{rBounds.x, rBounds.y});
}
// similar calculations as those made in paintFigure()
int height = (int) (rBounds.height * 0.25);
Rectangle rUpperEllipse = new Rectangle( rBounds.x,rBounds.y, rBounds.width, height );
Rectangle rMiddle = new Rectangle( rBounds.x, rBounds.y + height/2, rBounds.width, rBounds.height - height + 1 );
Rectangle rLowerEllipse = new Rectangle( rBounds.x, rBounds.y + rBounds.height - height - 1, rBounds.width, height );
// working our way counter-clockwise, find key points.
Point keyPoint1 = new PrecisionPoint(rMiddle.getTopLeft().x, rMiddle.getTopLeft().y);
Point keyPoint2 = new PrecisionPoint(rMiddle.getBottomLeft().x, rMiddle.getBottomLeft().y);
Point keyPoint3 = new PrecisionPoint(rMiddle.getBottomRight().x, rMiddle.getBottomRight().y);
Point keyPoint4 = new PrecisionPoint(rMiddle.getTopRight().x, rMiddle.getTopRight().y);
// build point list for upper ellipse
PointList upperPointList = new PointList();
upperPointList.addPoint(keyPoint4); // top-right
// Intermediate segments to estimate the top arc
LineSeg lineSeg = new LineSeg(new PrecisionPoint(rUpperEllipse.getTopRight().x - rUpperEllipse.width/32, rUpperEllipse.getTopRight().y ),
new PrecisionPoint(rUpperEllipse.getBottomRight().x - rUpperEllipse.width/32, rUpperEllipse.getCenter().y) );
upperPointList.addPoint(lineSeg.getLineIntersectionsWithEllipse(rUpperEllipse).getLastPoint());
lineSeg = new LineSeg(new PrecisionPoint(rUpperEllipse.getTopRight().x - rUpperEllipse.width/12, rUpperEllipse.getTopRight().y ),
new PrecisionPoint(rUpperEllipse.getBottomRight().x - rUpperEllipse.width/12, rUpperEllipse.getCenter().y) );
upperPointList.addPoint(lineSeg.getLineIntersectionsWithEllipse(rUpperEllipse).getLastPoint());
lineSeg = new LineSeg(new PrecisionPoint(rUpperEllipse.getTopRight().x - rUpperEllipse.width/8, rUpperEllipse.getTopRight().y ),
new PrecisionPoint(rUpperEllipse.getBottomRight().x - rUpperEllipse.width/8, rUpperEllipse.getCenter().y) );
upperPointList.addPoint(lineSeg.getLineIntersectionsWithEllipse(rUpperEllipse).getLastPoint());
lineSeg = new LineSeg(new PrecisionPoint(rUpperEllipse.getTopRight().x - rUpperEllipse.width/4, rUpperEllipse.getTopRight().y ),
new PrecisionPoint(rUpperEllipse.getBottomRight().x - rUpperEllipse.width/4, rUpperEllipse.getCenter().y) );
upperPointList.addPoint(lineSeg.getLineIntersectionsWithEllipse(rUpperEllipse).getLastPoint());
upperPointList.addPoint(rUpperEllipse.getCenter().x , rUpperEllipse.getCenter().y - rUpperEllipse.height/2); // center.
lineSeg = new LineSeg(new Point(rUpperEllipse.getTopLeft().x + rUpperEllipse.width/4, rUpperEllipse.getTopRight().y ),
new PrecisionPoint(rUpperEllipse.getTopLeft().x + rUpperEllipse.width/4, rUpperEllipse.getCenter().y) );
upperPointList.addPoint(lineSeg.getLineIntersectionsWithEllipse(rUpperEllipse).getLastPoint());
lineSeg = new LineSeg(new PrecisionPoint(rUpperEllipse.getTopLeft().x + rUpperEllipse.width/8, rUpperEllipse.getTopRight().y ),
new PrecisionPoint(rUpperEllipse.getTopLeft().x + rUpperEllipse.width/8, rUpperEllipse.getCenter().y) );
upperPointList.addPoint(lineSeg.getLineIntersectionsWithEllipse(rUpperEllipse).getLastPoint());
lineSeg = new LineSeg(new PrecisionPoint(rUpperEllipse.getTopLeft().x + rUpperEllipse.width/12, rUpperEllipse.getTopRight().y ),
new PrecisionPoint(rUpperEllipse.getTopLeft().x + rUpperEllipse.width/12, rUpperEllipse.getCenter().y) );
upperPointList.addPoint(lineSeg.getLineIntersectionsWithEllipse(rUpperEllipse).getLastPoint());
lineSeg = new LineSeg(new PrecisionPoint(rUpperEllipse.getTopLeft().x + rUpperEllipse.width/32, rUpperEllipse.getTopRight().y ),
new PrecisionPoint(rUpperEllipse.getTopLeft().x + rUpperEllipse.width/32, rUpperEllipse.getCenter().y) );
upperPointList.addPoint(lineSeg.getLineIntersectionsWithEllipse(rUpperEllipse).getLastPoint());
upperPointList.addPoint(keyPoint1); // top-left
// build point list for lower ellipse
PointList lowerPointList = new PointList();
lowerPointList.addPoint(keyPoint2); // bottom-left
// intermediate segments to estimate the bottom arc
lineSeg = new LineSeg(new PrecisionPoint(rUpperEllipse.getBottomLeft().x + rUpperEllipse.width/32, rLowerEllipse.getCenter().y ),
new PrecisionPoint(rUpperEllipse.getBottomLeft().x + rUpperEllipse.width/32, rLowerEllipse.getBottomLeft().y) );
lowerPointList.addPoint(lineSeg.getLineIntersectionsWithEllipse(rLowerEllipse).getFirstPoint());
lineSeg = new LineSeg(new PrecisionPoint(rUpperEllipse.getBottomLeft().x + rUpperEllipse.width/12, rLowerEllipse.getCenter().y ),
new PrecisionPoint(rUpperEllipse.getBottomLeft().x + rUpperEllipse.width/12, rLowerEllipse.getBottomLeft().y) );
lowerPointList.addPoint(lineSeg.getLineIntersectionsWithEllipse(rLowerEllipse).getFirstPoint());
lineSeg = new LineSeg(new PrecisionPoint(rUpperEllipse.getBottomLeft().x + rUpperEllipse.width/8, rLowerEllipse.getCenter().y ),
new PrecisionPoint(rUpperEllipse.getBottomLeft().x + rUpperEllipse.width/8, rLowerEllipse.getBottomLeft().y) );
lowerPointList.addPoint(lineSeg.getLineIntersectionsWithEllipse(rLowerEllipse).getFirstPoint());
lineSeg = new LineSeg(new PrecisionPoint(rUpperEllipse.getBottomLeft().x + rUpperEllipse.width/4, rLowerEllipse.getCenter().y ),
new PrecisionPoint(rUpperEllipse.getBottomLeft().x + rUpperEllipse.width/4, rLowerEllipse.getBottomLeft().y) );
lowerPointList.addPoint(lineSeg.getLineIntersectionsWithEllipse(rLowerEllipse).getFirstPoint());
lowerPointList.addPoint(rLowerEllipse.getCenter().x , rLowerEllipse.getCenter().y + rLowerEllipse.height/2); // center.
lineSeg = new LineSeg(new PrecisionPoint(rUpperEllipse.getBottomRight().x - rUpperEllipse.width/4, rLowerEllipse.getCenter().y ),
new PrecisionPoint(rUpperEllipse.getBottomRight().x - rUpperEllipse.width/4, rLowerEllipse.getBottomRight().y) );
lowerPointList.addPoint(lineSeg.getLineIntersectionsWithEllipse(rLowerEllipse).getFirstPoint());
lineSeg = new LineSeg(new PrecisionPoint(rUpperEllipse.getBottomRight().x - rUpperEllipse.width/8, rLowerEllipse.getCenter().y ),
new PrecisionPoint(rUpperEllipse.getBottomRight().x - rUpperEllipse.width/8, rLowerEllipse.getBottomRight().y) );
lowerPointList.addPoint(lineSeg.getLineIntersectionsWithEllipse(rLowerEllipse).getFirstPoint());
lineSeg = new LineSeg(new PrecisionPoint(rUpperEllipse.getBottomRight().x - rUpperEllipse.width/12, rLowerEllipse.getCenter().y ),
new PrecisionPoint(rUpperEllipse.getBottomRight().x - rUpperEllipse.width/12, rLowerEllipse.getBottomRight().y) );
lowerPointList.addPoint(lineSeg.getLineIntersectionsWithEllipse(rLowerEllipse).getFirstPoint());
lineSeg = new LineSeg(new PrecisionPoint(rUpperEllipse.getBottomRight().x - rUpperEllipse.width/32, rLowerEllipse.getCenter().y ),
new PrecisionPoint(rUpperEllipse.getBottomRight().x - rUpperEllipse.width/32, rLowerEllipse.getBottomRight().y) );
lowerPointList.addPoint(lineSeg.getLineIntersectionsWithEllipse(rLowerEllipse).getFirstPoint());
lowerPointList.addPoint(keyPoint3); // bottom-right
// combine all the points and close the polyline moving counter clockwise
PointList combinedPointList = new PointList();
combinedPointList.addPoint(keyPoint1);
combinedPointList.addPoint(keyPoint2);
combinedPointList.addAll(PointListUtilities.calcSmoothPolyline(
lowerPointList, PolylineConnectionEx.SMOOTH_MORE,
PointListUtilities.DEFAULT_BEZIERLINES));
combinedPointList.addPoint(keyPoint3);
combinedPointList.addPoint(keyPoint4);
combinedPointList.addAll(PointListUtilities.calcSmoothPolyline(
upperPointList, PolylineConnectionEx.SMOOTH_MORE,
PointListUtilities.DEFAULT_BEZIERLINES));
combinedPointList.addPoint(keyPoint1);
PointListUtilities.normalizeSegments(combinedPointList);
return combinedPointList;
}
/*
* (non-Javadoc)
* @see org.eclipse.draw2d.Figure#setBounds(org.eclipse.draw2d.geometry.Rectangle)
*/
public void setBounds(Rectangle rect) {
super.setBounds(rect);
anchorBorderPointList = null;
}
/*
* @see org.eclipse.gmf.runtime.draw2d.ui.figures.IPolygonAnchorableFigure#getPolygonPoints()
*/
public PointList getPolygonPoints() {
if (anchorBorderPointList == null) {
anchorBorderPointList = getAnchorBorderPointList();
}
return anchorBorderPointList.getCopy();
}
/* (non-Javadoc)
* @see org.eclipse.gmf.runtime.gef.ui.figures.NodeFigure#getPath()
* @since 1.2
*/
protected Path getPath() {
Rectangle r = getBounds().getCopy();
r.shrink(getLineWidth() / 2, getLineWidth() / 2);
int height = getTopHeight(r);
Path path = new Path(null);
path.addArc(r.x, r.y, r.width, height, 0, -360);
path.addRectangle(r.x, r.y + (height / 2), r.width, r.height - height
- 1);
path.addArc(r.x, r.y + r.height - height - 1, r.width - 1, height, 0,
-360);
return path;
}
/**
* @param r
* @return
* @since 1.2
*/
private int getTopHeight(Rectangle r) {
return (int) (r.height * 0.25);
}
}