This is a small tutorial for the GEF4 Geometry API.
You can find all the figures in the org.eclipse.gef4.geometry.planar package. In the majority of cases, you will get along with those predeclared figures. If you feel the need of another one that is not provided there, you can draw the joker (Path) which can be used to work with complicated composed shapes and curves. But we will begin by demonstrating the other classes first.
The constructor methods of the curves and shapes are overloaded to provide either raw data to create the object from:
Point p1 = new Point(100, 100); Point p2 = new Point(200, 200); Line line = new Line(100, 100, 200, 200);
Or to create it from existing curves/shapes:
Line line = new Line(p1, p2); QuadraticCurve qc = new QuadraticCurve(p2, new Point(300, 200), new Point(300, 100));
Each shape can bake a copy of its own via its
Line line2 = line.getCopy();
If you want to transform a shape, there are several ways to do this. You may use...
- ...the general AffineTransform class using the
- ...short-cut methods for the individual transformations
You can easily rotate a Rectangle by calling its
Rectangle quad = new Rectangle(100, 100, 100, 100); Polygon rhomb = quad.getRotatedCCW(Angle.fromDeg(45));
Rectangle rect = new Rectangle(100, 100, 200, 50); Rectangle rotated = rect.getRotatedCCW(Angle.fromDeg(90)).getBounds();
You may wonder why the rotation method is called
getRotatedCCW() and not just
getRotated(). This is to assure, that the direction of rotation is correct. The postfix indicates whether you want to rotate counter-clock-wise (CCW) or clock-wise (CW). Another small assistance is the Angle class. It prevents you from mixing up degrees and radians in rotation calculations.
Translation and scaling are directly available on each form, too:
Rectangle rect = new Rectangle(100, 100, 200, 50); Rectangle big = rect.getScaled(2); Rectangle small = rect.getScaled(0.5); Rectangle quad = rect.getScaled(0.5, 2); Rectangle translated = rect.getTranslated(-50, 50); //...
Rotation and scaling do always use a relative point to rotate around and scale away from, respectively. If you omit it, the transformation will use the mid-point of the IGeometry as the relative point for the transformation. This behavior is considered to be least surprising, although some people might expect the scaling and the rotation to be relative to (0, 0) which is the default behavior for Points and Vectors.
Relation between geometric objects
Curves and shapes can interact with each other. You can test them for intersection or overlap, and you can compute the points of intersection of two curves/shapes and the overlapping section of two curves.
To do so, the ICurve and IShape interfaces provide various methods, namely touches(), contains(), overlaps(), intersects(), getIntersections() and getOverlap() which return information on the relationship of two shapes.
For example, you may wish to compute the points of intersection between an ellipse and a line:
Ellipse e = new Ellipse(100, 100, 100, 100); Point intersections = e.getIntersections(new Line(100, 100, 200, 200));
Or you are dealing with two overlapping cubic Bézier curves and you want to get the overlap: (which is a very rare case)
CubicCurve c1 = new CubicCurve(100, 100, 420, 420, 164, 484, 253.6, 292); CubicCurve c2 = new CubicCurve(246.4, 292, 336, 484, 80, 420, 400, 100); CubicCurve overlap = c1.getOverlap(c2).toCubic();
[REPL Note: To make the overlap visible, delete the variables c1 and c2. You can delete a variable by right-clicking it in the list of variables and selecting "delete".]
Presumably, you will mostly use the touches(), contains() and intersects() methods as they perform the basic tests on the geometric objects. The IGeometry.touches(IGeometry) method tests two geometric objects for at least one common point, so you can use it for collision detection. The IShape.contains(IGeometry) method tests if the passed geometric object is fully contained in the invoking shape. Finally, the ICurve.intersects(ICurve) method tests the two curves for a finite number of intersection points. If you want to test two curves for an infinite number of intersection points, you can use the ICurve.overlaps(ICurve) method.
Interaction with SWT
The GEF4 Geometry API is an independent module. To integrate it into your SWT applications you can convert the individual geometric objects to their SWT counterparts or close-matches vià particular toSWT*() methods. At least, any geometric object of the GEF4 Geometry API can be converted to a Path using its toPath() method. And you can obtain a SWT PathData representation of any Path by calling its toSWTPathData() method.
Normally, you do not have to keep track of both, the GEF4 and the SWT objects. It suffices to generate appropriate SWT pendants if the need arises. For example, this is how your code could look like, if you would want to display your curves and shapes using a org.eclipse.graphics.GC:
gc.drawPolyline(line.toSWTPointArray()); gc.drawRectangle(rect.toSWTRectangle()); // in most cases, you are going to use the path: gc.drawPath(new org.eclipse.swt.graphics.Path(Display.getCurrent(), ellipse.toPath().toSWTPathData()));
Region & Ring
Analogous to the SWT Region, the GEF4 Geometry API provides a Region class that can be used to compose several Rectangles and address them as a single unit. For the API to be complete, you need to be able to rotate such a Region just like any other geometric object. This is one reason we decided to include another IPolyShape, namely the Ring. A Ring is a combination of several Polygons.
Region region = new Region(new Rectangle(50, 50, 50, 200), new Rectangle(50, 200, 200, 50)); Ring ring = region.getRotatedCCW(Angle.fromDeg(45), new Point());
Constructive Area Geometry
TODO... delegates to Path.