| Summary: | Only ChopboxAnchors should compute the reference point as the center of its GA. | ||
|---|---|---|---|
| Product: | [Modeling] Graphiti | Reporter: | Hernan Gonzalez <hjg.com.ar> |
| Component: | Core | Assignee: | Project Inbox <graphiti-inbox> |
| Status: | CLOSED FIXED | QA Contact: | |
| Severity: | normal | ||
| Priority: | P3 | CC: | matthias.gorning, michael.wenz |
| Version: | 0.8.0 | Flags: | michael.wenz:
juno+
|
| Target Milestone: | 0.9.0 | ||
| Hardware: | All | ||
| OS: | All | ||
| See Also: | https://bugs.eclipse.org/bugs/show_bug.cgi?id=359219 | ||
| Whiteboard: | Juno M4 Theme_bugs | ||
|
Description
Hernan Gonzalez
Not sure if it should be the position of the anchor or rather the center of the GA assigned to the anchor? But definitely not the center of the GA of the shape. (In reply to comment #1) > Not sure if it should be the position of the anchor or rather the center of the > GA assigned to the anchor? I hitnk it should be the position of the anchor. That's conceptually logical (for me), it's what one thinks as the endpoint of the connection. And, elsewhere, it would be impossible to get the desired behaviour, as in the (common) tutorial scenario: an anchor on the border of the parent rectangle, with connections starting precisely from the border. The center of the anchor's GA will be furthermore the "referenceLocation" of the anchor. The "referenceLocation" is the location where connections can start or end. We think that's a good default solution for the most anchors. But we understand your problem. Therefore with this fix you will get a new method on a FixPointAnchor/BoxRelativeAnchor: setUseAnchorLocationAsConnectionEndpoint(boolean value); With this method you can achieve the anchor behaviour what you want. I've also created a bugzilla for the improvement of the anchor documentation. https://bugs.eclipse.org/bugs/show_bug.cgi?id=359219 I'm getting errors on the master branch because of references to a AdvancedAnchor class that is not present - perhaps some incomplete commit? I can see AdvancedAnchor in the master brand (commited 13 days ago). Could ther be a sync issue on your side? Mmmm I got it now. Apparently EGit "compare with" does not show differences if there are new files on the remote? Never mind... The current fix, together with the ChopboxAnchorFixed.getLocation(Point) implementation, is not precise. For example, suppose a define a FixPointAnchor at coordinate (180, 72) (assume it's already translated to absolute), and assume a connection is drawn from remote reference point (15,506) The locationPoint should return (180, 72), but it returns (180,73).
The problem is that the GFChopboxAnchor.getBox() returns (for a
advancedAnchor with isUseAnchorLocationAsConnectionEndpoint() == true) a 1x1 rectangle. Then (in the example), GFChopboxAnchor.getLocation() will assume the center is at (180.5, 72.5), which is not what we want: we want the center at (180, 72).
I propose this fix (works for me)
In GFChopboxAnchor.getBox() , be real, return a 0x0 rectangle:
copy.setHeight(0);
copy.setWidth(0);
In ChopboxAnchorFixed.getLocation(Point) alter the calculation to avoid division by zero:
public Point getLocation(final Point reference) {
Rectangle r = Rectangle.SINGLETON;
r.setBounds(getBox());
getOwner().translateToAbsolute(r);
float centerX = r.x + 0.5f * r.width;
float centerY = r.y + 0.5f * r.height;
float dx = reference.x - centerX;
float dy = reference.y - centerY;
float tmax = Math.max(Math.abs(dx) * r.height, Math.abs(dy) * r.width);
// CHANGED: in case of "nearly zero" (divide-by-zero or
// rounding-problems) would happen: return just the center
if (tmax >= 0.001f) {
float scale = r.width * 0.5f * r.height / tmax;
centerX += dx * scale;
centerY += dy * scale;
}
return new Point(Math.round(centerX), Math.round(centerY));
}
GefService.getChopboxLocationOnBox() and PeServiceImpl.getChopboxLocationOnBox() should be modified analogously - we should never assume that r.width or r.height are non-zero.
We need to check this To ease the testing, and perhaps to reuse in the other methods, we could define a static helper method:
/**
* Computes the "location", i.e. the point at which the line that joins the
* rectangle center with the reference point crosses the rectangle border.
* Works with zero size rectangles.
*/
public static Point computeLocation(Rectangle r, Point reference) {
float centerX = r.x + 0.5f * r.width;
float centerY = r.y + 0.5f * r.height;
float dx = reference.x - centerX;
float dy = reference.y - centerY;
float tmax = Math.max(Math.abs(dx) * r.height, Math.abs(dy) * r.width);
if (tmax >= 0.001f) {
float scale = r.width * 0.5f * r.height / tmax;
centerX += dx * scale;
centerY += dy * scale;
}
return new Point(Math.round(centerX), Math.round(centerY));
}
public Point getLocation(Point reference) {
Rectangle r = Rectangle.SINGLETON;
r.setBounds(getBox());
getOwner().translateToAbsolute(r);
Point location = computeLocation(r, reference);
return location;
}
There is a more basic problem here. This implementation of AdvancedAnchors seems to assume that the anchor is in the corner of its GA. In other words: the position of the Anchor is assumed to be the position of its GA. Say a want my anchor to be inside its GA (a rectangle), not in the border, nor in the center. Currently it's impossible to do that. (In reply to comment #11) > There is a more basic problem here. This implementation of AdvancedAnchors > seems to assume that the anchor is in the corner of its GA. In other words: the > position of the Anchor is assumed to be the position of its GA. Say a want my > anchor to be inside its GA (a rectangle), not in the border, nor in the center. > Currently it's impossible to do that. That's only the default location. You could do something like this to achive what you want (squareShape is a ContainerShape that may have a Rectangle as representation): BoxRelativeAnchor relativeAnchor = createService.createBoxRelativeAnchor(squareShape); relativeAnchor.setRelativeHeight(0.5d); relativeAnchor.setRelativeWidth(0.5d); relativeAnchor.setReferencedGraphicsAlgorithm(squareRectangle); relativeAnchor.setUseAnchorLocationAsConnectionEndpoint(true); Ellipse anchorEllipse = createService.createEllipse(relativeAnchor); layoutService.setLocationAndSize(anchorEllipse, 25, 25, 0, 0); You will get a circle (radius) as connection point and the connection line will point to the center of the square rectangle. (This is taken from the newly checked-in Chess example in AddBoardFeature and defines the anchor in a chess square). (In reply to comment #10) > To ease the testing, and perhaps to reuse in the other methods, we could define > a static helper method: In principle agreed, but not sure if using a 0x0 rectangle is the best solution, as it introduces DivisionByZeroExceptions at various spots (also in GEF) we would need to work around. Feasibility check needed, colleague will check after his vacation. (In reply to comment #12) > That's only the default location. You could do something like this to achive > what you want (squareShape is a ContainerShape that may have a Rectangle as > representation): > BoxRelativeAnchor relativeAnchor = > createService.createBoxRelativeAnchor(squareShape); > relativeAnchor.setRelativeHeight(0.5d); > relativeAnchor.setRelativeWidth(0.5d); > relativeAnchor.setReferencedGraphicsAlgorithm(squareRectangle); > relativeAnchor.setUseAnchorLocationAsConnectionEndpoint(true); > Ellipse anchorEllipse = createService.createEllipse(relativeAnchor); > layoutService.setLocationAndSize(anchorEllipse, 25, 25, 0, 0); > > You will get a circle (radius) as connection point Well, I once had to digest that in Graphiti "a Rectangle is not a Shape", now it seems that an circle can be a point ... ;-) Seriously, this is utterly confusing, I can't understand the concepts related to anchors. You use a "ReferencedGraphicsAlgorithm" and there is stricly zero information in the docs (including source comments) about what a ReferencedGraphicsAlgorithm is supposed to be, I've tried to guess it and failed, I tried to ask and also failed http://www.eclipse.org/forums/index.php/t/254053/ There are three GA involved with an anchor (the parent, the anchor own GA, and the "referenced", it's not clear the meaning of each one, it's not clear the positioning. BTW, in your example layoutService.setLocationAndSize(anchorEllipse, 25, 25, 0, 0); creates a zero sized circle, (it seems strange to me, after noting that zero sized rectangles are dangerous), so that the the "anchor area" or "anchor capture zone" (where the anchor gets activated when attempting a connection creation) result in a single pixel -if I'm not mistaken. I don't want that, I want the anchor to be a (say) 20x10 rectangle and the anchor end-point to be at (say) at the middle of a vertical side. For example ------------------------------------- | | | | | ----------- RA | || | | || | | ||A | | || | | || | | | ----------- | | | | RB ------------ | | | || | | || | | B|| | | || | | || | ------------ | | | | | ------------------------------------- In this example, we have a 200x200 outer rectangle, a RA 60x60 rectangle starting at (0,30) with an anchor point at the middle of its left side (coordinates (0,60) relative to the outer rect) Similarly, the RB rectangle has an anchor point in the middle of its right side I want the rectangles RA RB to act as anchors, i.e., that their areas accepts a connection creation when the mouse is over them. And I want the connection to start at the points A B (In reply to comment #14) > Well, I once had to digest that in Graphiti "a Rectangle is not a Shape", now > it seems that an circle can be a point ... ;-) > Seriously, this is utterly confusing, I can't understand the concepts related > to anchors. You use a "ReferencedGraphicsAlgorithm" and there is stricly zero > information in the docs (including source comments) about what a > ReferencedGraphicsAlgorithm is supposed to be, I've tried to guess it and > failed, I tried to ask and also failed > http://www.eclipse.org/forums/index.php/t/254053/ > There are three GA involved with an anchor (the parent, the anchor own GA, and > the "referenced", it's not clear the meaning of each one, it's not clear the > positioning. Yes, indeed this is confusing and lacks some documentation; Bug 359219 targets exactly that and it should clarify especially the refGA and boxes stuff. Sorry, i somehow missed that forum entry (In reply to comment #15) > BTW, in your example > layoutService.setLocationAndSize(anchorEllipse, 25, 25, 0, 0); > creates a zero sized circle, (it seems strange to me, after noting that zero > sized rectangles are dangerous), so that the the "anchor area" or "anchor > capture zone" > (where the anchor gets activated when attempting a connection creation) result > in a single pixel -if I'm not mistaken. > I don't want that, I want the anchor to be a (say) 20x10 rectangle and the > anchor end-point to be at (say) at the middle of a vertical side. > For example > ------------------------------------- > | | > | | > | ----------- RA | > || | | > || | | > ||A | | > || | | > || | | > | ----------- | > | | > | RB ------------ | > | | || > | | || > | | B|| > | | || > | | || > | ------------ | > | | > | | > ------------------------------------- > In this example, we have a 200x200 outer rectangle, > a RA 60x60 rectangle starting at (0,30) with an anchor point > at the middle of its left side > (coordinates (0,60) relative to the outer rect) > Similarly, the RB rectangle has an anchor point in the > middle of its right side > I want the rectangles RA RB to act as anchors, i.e., > that their areas accepts a connection creation when > the mouse is over them. And I want the connection > to start at the points A B This should be perfectly possible by setting the refGa to the outer rectangle and having rectangles of the appropriate sizes as GAs for the anchors. In the chess example we have a special situation because we have the square visualized as rectangle and the box relative anchor only serving as the anchor the connection is drawn to. For actually attaching a connection to, there is a second chopbox anchor in place. So the visualization using 0 as diameter is ok since the shape is not meant for grabbing. The solution is not really satisfying to me as well but I could not come up with a better one under these circumstances: 1) Attaching a connection shall be possible to the complete square (or piece) shape 2) The connection shall not be clipped at the square (or piece) shape border 3) The GA of the box relative anchor must not overlay the square or piece shape for selection Fixed. Location of an advanced anchor is now precise (only in cases where the location is used as a connection endpoint). commit 55c41afcc6f8a80ad0a5a7e072f439de5401610a Author: mgorning <matthias.gorning@sap.com> 2011-11-28 14:36:58 Committer: mgorning <matthias.gorning@sap.com> 2011-11-28 14:36:58 Parent: 8a058f973e54f8720a0b14e618d21786e92661f3 (Bug 355968 - Only ChopboxAnchors should compute the reference point as the center of its GA / returned location is more precise) Branches: origin/master, master Position does no longer depend on the center of a rectangle but instead directly on the anchor position. Looks good to me. Bookkeeping: Set target release Part of Graphiti 0.9.0 (Eclipse Juno) |