Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthew Khouzam2017-11-21 01:34:52 +0000
committerMatthew Khouzam2018-01-18 20:57:04 +0000
commit604622674087d0fd04e7a28da77bc4bccad0d512 (patch)
tree8f9f5f1d99fe0abc5829c4f294ce522b288aed1e
parent15cc26c41fce096c26eb12a6b14cd8b19f0dd4f5 (diff)
downloadorg.eclipse.tracecompass-604622674087d0fd04e7a28da77bc4bccad0d512.tar.gz
org.eclipse.tracecompass-604622674087d0fd04e7a28da77bc4bccad0d512.tar.xz
org.eclipse.tracecompass-604622674087d0fd04e7a28da77bc4bccad0d512.zip
tmf.ui: fix line thickness bug on arrows.
Use the Cohen Sutherland algorithm to clip lines properly. Adds a log(n) compute time, but fixes the bug in Linux's LibCairo gtk library. Bug 470115 Change-Id: Ic4ce13398b25c2c2628283a0017419fe5bdbbb02 Signed-off-by: Matthew Khouzam <matthew.khouzam@ericsson.com> Reviewed-on: https://git.eclipse.org/r/111937 Tested-by: Hudson CI Reviewed-by: Loic Prieur-Drevon <loic.prieurdrevon@gmail.com>
-rw-r--r--tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/widgets/timegraph/widgets/TimeGraphControl.java130
1 files changed, 128 insertions, 2 deletions
diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/widgets/timegraph/widgets/TimeGraphControl.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/widgets/timegraph/widgets/TimeGraphControl.java
index d7da4ee7ed..8ceb64c811 100644
--- a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/widgets/timegraph/widgets/TimeGraphControl.java
+++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/widgets/timegraph/widgets/TimeGraphControl.java
@@ -36,6 +36,7 @@ import java.util.Queue;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jface.action.IStatusLineManager;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.resource.LocalResourceManager;
@@ -121,6 +122,15 @@ public class TimeGraphControl extends TimeGraphBaseControl
MenuDetectListener, ITmfTimeGraphDrawingHelper, ITimeGraphColorListener, Listener {
/**
+ * Quadrant bitmaks for Cohen Sutherland
+ */
+ private static final int DOWN = 1 << 4;
+ private static final int UP = 1 << 3;
+ private static final int RIGHT = 1 << 2;
+ private static final int LEFT = 1 << 1;
+ private static final int INSIDE = 0;
+
+ /**
* Constant indicating that all levels of the time graph should be expanded
*/
public static final int ALL_LEVELS = AbstractTreeViewer.ALL_LEVELS;
@@ -2264,7 +2274,7 @@ public class TimeGraphControl extends TimeGraphBaseControl
drawArrow(getColorScheme(), event, getArrowRectangle(bounds, event), gc);
}
- private Rectangle getArrowRectangle(Rectangle bounds, ILinkEvent event) {
+ private @Nullable Rectangle getArrowRectangle(Rectangle bounds, ILinkEvent event) {
int srcIndex = fItemData.findItemIndex(event.getEntry());
int destIndex = fItemData.findItemIndex(event.getDestinationEntry());
@@ -2286,7 +2296,123 @@ public class TimeGraphControl extends TimeGraphBaseControl
int y0 = src.y + src.height / 2;
int y1 = dst.y + dst.height / 2;
- return new Rectangle(x0, y0, x1 - x0, y1 - y0);
+ return cohenSutherlandClipped(bounds, x0, y0, x1, y1);
+ }
+
+ /**
+ * Computer graphics algorithm used for line clipping, workaround for Cairo bug
+ *
+ * https://bugs.eclipse.org/bugs/show_bug.cgi?id=470115
+ *
+ * https://bugs.freedesktop.org/show_bug.cgi?id=103840
+ *
+ * @param bounds
+ * the clipping rectangle
+ * @param x0
+ * point 0 x
+ * @param y0
+ * point 0 y
+ * @param x1
+ * point 1 x
+ * @param y1
+ * point 1 y
+ * @return
+ */
+ private static Rectangle cohenSutherlandClipped(Rectangle bounds, int x0, int y0, int x1, int y1) {
+ int quadrant0 = computeQuadrant(x0, y0, bounds);
+ int quadrant1 = computeQuadrant(x1, y1, bounds);
+ if (quadrant0 == 0 && quadrant1 == 0) {
+ return new Rectangle(x0, y0, x1 - x0, y1 - y0);
+ }
+ if ((quadrant0 & quadrant1) != 0 || bounds.width == 0 || bounds.height == 0) {
+ return null;
+ }
+ long deltaY = (long) y1 - (long) y0;
+ long deltaX = (long) x1 - (long) x0;
+ double slope = deltaY / (double) deltaX;
+ double antiSlope = deltaX / (double) deltaY;
+ int newX0 = x0;
+ int newY0 = y0;
+ int newX1 = x1;
+ int newY1 = y1;
+ // log n iterations
+ while (quadrant0 != 0) {
+ if ((quadrant0 & UP) != 0) {
+ newX0 = (int) (newX0 + antiSlope * (bounds.y - newY0));
+ newY0 = bounds.height + bounds.y;
+ } else if ((quadrant0 & DOWN) != 0) {
+ newX0 = (int) (newX0 + antiSlope * (bounds.y + bounds.height - newY0));
+ newY0 = bounds.y;
+ } else if ((quadrant0 & RIGHT) != 0) {
+ newY0 = (int) (newY0 + slope * (bounds.x + bounds.width - newX0));
+ newX0 = bounds.x + bounds.width;
+ } else {
+ newY0 = (int) (newY0 + slope * (bounds.x - newX0));
+ newX0 = bounds.x;
+ }
+ quadrant0 = computeQuadrant(newX0, newY0, bounds);
+ }
+ // ditto
+ while (quadrant1 != 0) {
+ if ((quadrant1 & UP) != 0) {
+ newX1 = (int) (newX0 + antiSlope * (bounds.y - newY0));
+ newY1 = bounds.height + bounds.y;
+ } else if ((quadrant1 & DOWN) != 0) {
+ newX1 = (int) (newX0 + antiSlope * (bounds.y + bounds.height - newY0));
+ newY1 = bounds.y;
+ } else if ((quadrant1 & RIGHT) != 0) {
+ newY1 = (int) (newY0 + slope * (bounds.x + bounds.width - newX0));
+ newX1 = bounds.x + bounds.width;
+ } else {
+ newY1 = (int) (newY0 + slope * (bounds.x - newX0));
+ newX1 = bounds.x;
+ }
+ quadrant1 = computeQuadrant(newX1, newY1, bounds);
+ }
+ return new Rectangle(newX0, newY0, newX1 - newX0, newY1 - newY0);
+ }
+
+ /**
+ * Cohen Sutherland compute algorithm
+ * <table>
+ * <tr>
+ * <th>0101</th>
+ * <th>0100</th>
+ * <th>0110</th>
+ * </tr>
+ * <tr>
+ * <th>0001</th>
+ * <th>0000</th>
+ * <th>0010</th>
+ * </tr>
+ * <tr>
+ * <th>1001</th>
+ * <th>1000</th>
+ * <th>1010</th>
+ * </tr>
+ * </table>
+ *
+ * @param x
+ * point x
+ * @param y
+ * point y
+ * @param bounds
+ * bounds rectangle
+ * @return a quadrant
+ */
+ private static int computeQuadrant(int x, int y, Rectangle bounds) {
+ int retCode = INSIDE;
+ if (x < bounds.x) {
+ retCode |= LEFT;
+ } else if (x > (bounds.x + bounds.width)) {
+ retCode |= RIGHT;
+ }
+ if (y < bounds.y) {
+ retCode |= UP;
+ } else if (y > (bounds.y + bounds.height)) {
+ retCode |= DOWN;
+ }
+ return retCode;
}
/**

Back to the top