Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » GMF (Graphical Modeling Framework) » Rotation and skew of Figures
Rotation and skew of Figures [message #208043] Wed, 08 October 2008 09:52 Go to next message
Gerrit  is currently offline Gerrit Friend
Messages: 30
Registered: July 2009
Member
I would like to implement a 2D compositing application with GEF, where you
can not only move and resize a Figure (as with normal diagrams), but also
rotate and skew it, creating an arbitrary AffineTransform.

Are there any implementations of this so far? I'd be happy to start with
just the rotation... The only hint I found are the GMF IRotatableEditPart
and RotatableShapeEditPolicy. There is this old thread that discusses them

http://dev.eclipse.org/newslists/news.eclipse.modeling.gmf/m sg02705.html

but I haven't found any code examples on how to use them. Do you know any?
Are these classes a good starting point? If not, what GEF / GMF classes
would help me best?

Thanks in advance!
Gerrit
Re: Rotation and skew of Figures [message #208453 is a reply to message #208043] Mon, 13 October 2008 14:54 Go to previous messageGo to next message
Tatiana Fesenko is currently offline Tatiana FesenkoFriend
Messages: 530
Registered: July 2009
Senior Member
Hello Gerrit,

I know an example of rotating a simple figure. Its Fork/Join nodes in Activity
diagram editor provided by MDT UML2Tools.
Fork/Join nodes are shown as black filled vertical rectangle. Rotate action
allows us to turn it horizontally and back. So, the action makes horizontal
rectangle from vertical one, and back - it makes vertical rectangle from
horizontal. If you are interested in this sample, you can find details in
RotateAction class from org.eclipse.uml2.diagram.common plugin.

However, as I understand, you want to implement more sophisticated cases.
In this case, playing with graphics.rotate(..) in Figure#paintFigure(Graphics
graphics) can help.

Best wishes,
Tatiana.

> I would like to implement a 2D compositing application with GEF, where
> you can not only move and resize a Figure (as with normal diagrams),
> but also rotate and skew it, creating an arbitrary AffineTransform.
>
> Are there any implementations of this so far? I'd be happy to start
> with just the rotation... The only hint I found are the GMF
> IRotatableEditPart and RotatableShapeEditPolicy. There is this old
> thread that discusses them
>
> http://dev.eclipse.org/newslists/news.eclipse.modeling.gmf/m sg02705.ht
> ml
>
> but I haven't found any code examples on how to use them. Do you know
> any? Are these classes a good starting point? If not, what GEF / GMF
> classes would help me best?
>
> Thanks in advance!
> Gerrit
Re: Rotation and skew of Figures [message #211096 is a reply to message #208453] Thu, 13 November 2008 10:22 Go to previous message
Gerrit  is currently offline Gerrit Friend
Messages: 30
Registered: July 2009
Member
Thanks for the suggestions. I managed to create an EditPolicy subclass
which interprets resize input as rotation and skew and produces
AffineTransforms. These need a special Figure subclass to be displayed
since normal figures don't seem to accept free transforms. Right now, the
transform is only shown as feedback.

Later, I'll probably move the transform calculation code to a subclass of
ResizeTracker. Most likely, I'll also have to subclass Handle, Request and
Command.

Now I'd like to have the normal resize along with rotation and skew. Most
vector graphics editors (e.g. Inkscape) implement this by having the
handles flip between resize and rotate/skew every time the user reselects
a shape. However, it seems that in GEF the SelectEditPartTracker
intercepts the selections and does not count re-selection as an action.
The SelectEditPartTracker is controlled by the EditPartViewer.

Here's my new question: What is the most efficient way to implement
re-selection handling and alternating tools in GEF? ("Efficient" here
means involving a minimal amount of subclassing.)

I post my code below in case anyone is interested.



public class FreeTransformEditPolicy extends ResizableEditPolicy {

@Override
protected IFigure createDragSourceFeedbackFigure() {
Rectangle bounds = getInitialFeedbackBounds();
int width = bounds.width / 2;
int height = bounds.height / 2;

TransformablePolygon p = new TransformablePolygon();

PointList points = new PointList();
points.addPoint(-width,-height);
points.addPoint(width,-height);
points.addPoint(width,height);
points.addPoint(-width,height);
p.setPoints(points);

FigureUtilities.makeGhostShape(p);
p.setLineStyle(Graphics.LINE_DOT);
p.setForegroundColor(ColorConstants.white);

addFeedback(p);
return p;
}


@Override
protected void showChangeBoundsFeedback(ChangeBoundsRequest request) {

// Test if figure accepts transforms.
IFigure feedback = getDragSourceFeedbackFigure();
if( ! (feedback instanceof TransformablePolygon) ) {
super.showChangeBoundsFeedback(request);
return;
}

// Cast to transformable figure.
TransformablePolygon polygon = (TransformablePolygon) feedback;

int direction = request.getResizeDirection();

// Test for simple drag.
if( direction == PositionConstants.NONE ) {
showDragFeedback(request, polygon);
return;
}

// Calc delta from center of figure to current mouse location.
Rectangle startRectangle = getInitialFeedbackBounds();
Point center = startRectangle.getCenter();
Dimension toCurrent = request.getLocation().getDifference( center );

AffineTransform transform;

switch (direction) {

case PositionConstants.NORTH_EAST:
case PositionConstants.NORTH_WEST:
case PositionConstants.SOUTH_EAST:
case PositionConstants.SOUTH_WEST:
// Calc delta from center of figure to mouse starting location.
Dimension toStart = getPosition(startRectangle,
direction).getDifference( center );
// Calc rotation transform.
transform = getRotationTransform(direction, toStart, toCurrent);
break;

case PositionConstants.NORTH:
case PositionConstants.EAST:
case PositionConstants.SOUTH:
case PositionConstants.WEST:
// Calc skew transform.
transform = getSkewTransform(direction, toCurrent);
break;

case PositionConstants.NONE:
default:
transform = new AffineTransform();
break;
}

// Apply translation to transform.
// (No need for matrix calculations, since rotate and skew translation
is 0.)
double[] m = new double[4];
transform.getMatrix(m);
transform.setTransform(m[0], m[1], m[2], m[3], center.x, center.y);
// Apply transform to figure.
polygon.setTransform(transform);
}


protected void showDragFeedback(ChangeBoundsRequest request,
TransformablePolygon polygon) {
Point currentCenter = request.getTransformedRectangle(
getInitialFeedbackBounds() ).getCenter();
polygon.setTransform(AffineTransform.getTranslateInstance(cu rrentCenter.x,
currentCenter.y));
}

protected AffineTransform getRotationTransform(int direction, Dimension
toStart, Dimension toCurrent) {
double angle;

if(toStart.width==0&&toStart.height==0 ||
toCurrent.width==0&&toCurrent.height==0)
angle = 0;
else
angle = Math.atan2(toStart.width, toStart.height) -
Math.atan2(toCurrent.width, toCurrent.height);

return AffineTransform.getRotateInstance(angle);
}

protected AffineTransform getSkewTransform(int direction, Dimension
delta) {
double dx = delta.width;
double dy = delta.height;

double skewX = 0;
double skewY = 0;

switch (direction) {

case PositionConstants.NORTH:
case PositionConstants.SOUTH:
if( dy != 0 )
skewX = dx / dy;
break;
case PositionConstants.EAST:
case PositionConstants.WEST:
if( dx != 0 )
skewY = dy / dx;
break;

default:
break;
}

return AffineTransform.getShearInstance(skewX, skewY);
}

public static Point getPosition(Rectangle rect, int position) {
switch (position) {

case PositionConstants.NORTH_EAST:
return rect.getTopRight();
case PositionConstants.NORTH_WEST:
return rect.getTopLeft();
case PositionConstants.SOUTH_EAST:
return rect.getBottomRight();
case PositionConstants.SOUTH_WEST:
return rect.getBottomLeft();

case PositionConstants.NORTH:
return rect.getTop();
case PositionConstants.EAST:
return rect.getRight();
case PositionConstants.SOUTH:
return rect.getBottom();
case PositionConstants.WEST:
return rect.getLeft();

case PositionConstants.CENTER:
return rect.getCenter();

default:
return null;
}
}
}


public class TransformablePolygon extends Shape {

protected PointList points = new PointList();
public PointList getPoints() {
return points;
}

protected AffineTransform transform =
AffineTransform.getRotateInstance(Math.PI/4.0);

protected PointList transformedPoints = new PointList();
protected Rectangle transformedBounds = new Rectangle();

private Point min = new Point();
private Point max = new Point();
private Point2D.Double awtPoint = new Point2D.Double();
private Point draw2dPoint = new Point();

public void setTransform(AffineTransform transform) {
this.transform = transform;
calcTransformedPoints();
setBounds(transformedBounds);
}


protected void calcTransformedPoints() {
PointList points = getPoints();
transformedPoints.setSize(points.size());
for (int i=0; i<points.size(); i++) {
awtPoint.x = points.getPoint(i).x;
awtPoint.y = points.getPoint(i).y;
transform.transform(awtPoint, awtPoint);
draw2dPoint.x = (int) awtPoint.getX();
draw2dPoint.y = (int) awtPoint.getY();
transformedPoints.setPoint(draw2dPoint,i);
}
calcBounds(transformedBounds, transformedPoints);
}

private void calcBounds(Rectangle transformedBounds, PointList points) {
if( points.size() == 0 ) {
transformedBounds.setLocation(0, 0);
transformedBounds.setSize(0, 0);
return;
}
min.setLocation( points.getFirstPoint() );
max.setLocation( points.getFirstPoint() );
for (int i=1; i<points.size(); i++) {
Point point = points.getPoint(i);
if( point.x < min.x )
min.x = point.x;
else if( point.x > max.x )
max.x = point.x;
if( point.y < min.y )
min.y = point.y;
else if( point.y > max.y )
max.y = point.y;
}
transformedBounds.setLocation(min.x, min.y);
transformedBounds.setSize(max.x-min.x, max.y-min.y);
int lineWidth = (getLineWidth()+1) / 2;
transformedBounds.expand(lineWidth, lineWidth);
}

public TransformablePolygon() {
}

public void setPoints(PointList points) {
this.points = points;
}

@Override
protected void fillShape(Graphics graphics) {
graphics.fillPolygon(transformedPoints);
}

@Override
protected void outlineShape(Graphics graphics) {
graphics.drawPolygon(transformedPoints);
}
}
Previous Topic:[Announce] GMF 2.2.0M3 is available
Next Topic:TAIPAN
Goto Forum:
  


Current Time: Thu Apr 25 04:18:46 GMT 2024

Powered by FUDForum. Page generated in 0.03118 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software

Back to the top