1   
28  package demo.layout.labeling;
29  
30  import y.geom.YPoint;
31  import y.geom.YVector;
32  import y.layout.PreferredPlacementDescriptor;
33  import y.view.DefaultLabelConfiguration;
34  import y.view.EdgeLabel;
35  import y.view.YLabel;
36  import y.view.YRenderingHints;
37  
38  import java.awt.Color;
39  import java.awt.Font;
40  import java.awt.GradientPaint;
41  import java.awt.Graphics2D;
42  import java.awt.Paint;
43  import java.awt.geom.Arc2D;
44  import java.awt.geom.GeneralPath;
45  import java.awt.geom.Line2D;
46  
47  
50  class VisualizingDescriptorLabelConfiguration extends DefaultLabelConfiguration {
51  
52    private static final Color COLOR_ROTATION = new Color(51, 102, 153);
53    private static final Color COLOR_DISTANCE = new Color(102,204,51);
54    private static final Color COLOR_PREFERRED_SIDE = new Color(204, 153, 51);
55    private static final Color COLOR_ADDITIONAL_ROTATION = new Color(153, 51, 51);
56    private static final double TWO_PI = Math.PI * 2;
57  
58    private static Font smallFont;
59  
60    public void paintContent(YLabel label, Graphics2D gfx, double x, double y, double width, double height) {
61          final boolean flipText = label.getOrientedBox().getUpY() > 0;
63      try {
64        if (flipText) {
65          gfx.rotate(Math.PI, x + width/2-2, y + height/2);
66        }
67  
68        super.paintContent(label, gfx, x, y, width, height);
69      } finally {
70        if (flipText) {
71          gfx.rotate(Math.PI, x + width/2-2, y + height/2);
72        }
73      }
74    }
75  
76    public void paintBox(YLabel label, Graphics2D gfx, double x, double y, double width, double height) {
77      if (label instanceof EdgeLabel) {
78        final Color oldColor = gfx.getColor();
79        final Paint oldPaint = gfx.getPaint();
80        final Font oldFont = gfx.getFont();
81  
82        try {
83          final double x2 = x + width;
84          final double y2 = y + height;
85          final double cx = x + width / 2;
86          final double cy = y + height / 2;
87  
88          final PreferredPlacementDescriptor placementDescriptor = ((EdgeLabel) label).getPreferredPlacementDescriptor();
89          final double dist = Math.max(1, placementDescriptor.getDistanceToEdge());
90  
91                  final boolean labelFlowIsFlipped =
93            placementDescriptor.isRightOfEdge() && placementDescriptor.isAngleOffsetOnRightSide180();
94          final boolean angleRotationIsFlipped =
95            placementDescriptor.isRightOfEdge() && placementDescriptor.isAngleOnRightSideCounterRotating();
96  
97          double angle = placementDescriptor.getAngle();
98          if (angleRotationIsFlipped) {
99            angle = -angle;
100         }
101 
102         final double angleWithoutOffset = angle;
103         if (labelFlowIsFlipped) {
104           angle += Math.PI;
105         }
106 
107                 final GeneralPath labelShapePath = new GeneralPath();
109         labelShapePath.moveTo((float) x, (float) y);
110         labelShapePath.lineTo((float) (x2 - height / 4), (float) y);
111         labelShapePath.lineTo((float) x2, (float) cy);
112         labelShapePath.lineTo((float) (x2 - height / 4), (float) y2);
113         labelShapePath.lineTo((float) x, (float) y2);
114 
115                 gfx.setPaint(
117           new GradientPaint(
118             (float) x,
119             (float) y,
120             Color.white,
121             (float) (x + width + height / 2),
122             (float) y, COLOR_ROTATION, true));
123         gfx.fill(labelShapePath);
124 
125         YVector rightVector = new YVector(width, 0);
126         rightVector = rightVector.rotate(-angle);
127 
128                 if (placementDescriptor.isAngleRelativeToEdgeFlow() && !placementDescriptor.isOnEdge()) {
130                     
133                     double edgeAngle = -label.getOrientedBox().getAngle() - angle;
135           edgeAngle = normalizeAngle(edgeAngle);
136 
137           final boolean labelIsLeftOfEdgeInFlow = isLabelLeftOfEdgeInFlow(placementDescriptor, edgeAngle);
138                     final boolean bottomSideIsCloserToEdge = placementDescriptor.isLeftOfEdge()
140                   ? labelIsLeftOfEdgeInFlow
141                   : labelIsLeftOfEdgeInFlow ^ labelFlowIsFlipped;
142 
143           final double yValue = bottomSideIsCloserToEdge ? y + height : y;
144                     final YPoint cLabelBorder = new YPoint(cx, yValue);
146 
147           final double distToEdge =
148             dist             + Math.abs(rightVector.getY() / 2)             - 0.5;           YVector lineToEdge = new YVector(0, labelIsLeftOfEdgeInFlow ? distToEdge : -distToEdge);
152           lineToEdge = lineToEdge.rotate(-angle);
153 
154                     final YPoint cEdge = new YPoint(cLabelBorder.getX() + lineToEdge.getX(), cLabelBorder.getY() + lineToEdge.getY());
156 
157           gfx.setColor(COLOR_DISTANCE);
158           gfx.fill(new Arc2D.Double(cLabelBorder.getX() - 2, cLabelBorder.getY() - 2, 4, 4, bottomSideIsCloserToEdge ? 0 : 180, -180, Arc2D.CHORD));
159 
160           gfx.draw(new Line2D.Double(cLabelBorder.getX(), cLabelBorder.getY(), cEdge.getX(), cEdge.getY()));
161 
162           gfx.fill(new Arc2D.Double(cEdge.getX() - 2, cEdge.getY() - 2, 4, 4, Math.toDegrees(angle), labelIsLeftOfEdgeInFlow ? 180 : -180, Arc2D.CHORD));
163         }
164 
165                 if (angleWithoutOffset != 0) {
167                               gfx.setColor(COLOR_ROTATION);
170           if (labelFlowIsFlipped) {
171             gfx.draw(new Line2D.Double(x, y, x - rightVector.getX(), y - rightVector.getY()));
172           } else {
173             gfx.draw(new Line2D.Double(x, y, x + rightVector.getX(), y + rightVector.getY()));
174           }
175                     gfx.draw(new Arc2D.Double(x - 10, y - 10, 20, 20, 0, angleWithoutOffset, Arc2D.OPEN));
177         }
178 
179                 if (labelFlowIsFlipped) {
181                               gfx.setColor(COLOR_ADDITIONAL_ROTATION);
184           gfx.draw(new Line2D.Double(x, y, x + rightVector.getX()/2, y + rightVector.getY()/2));
185                               gfx.draw(new Arc2D.Double(x - 5, y - 5, 10, 10, Math.toDegrees(angle), -180, Arc2D.OPEN));
188         }
189 
190                 gfx.setColor(COLOR_PREFERRED_SIDE);
192         gfx.setFont(getSmallFont(gfx));
193         gfx.rotate(-Math.PI/2, x, y);
194         final String position = isOnAnySide(placementDescriptor) ? "Any"
195             : placementDescriptor.isLeftOfEdge() ? "Left"
196             : placementDescriptor.isRightOfEdge() ? "Right"
197             : "OnEdge";
198         gfx.drawString(position, (float) (x - height + 1), (float) (y - 1));
199         gfx.rotate(Math.PI/2, x, y);
200 
201                 if (useSelectionStyle(label, gfx)) {
203           gfx.setColor(Color.RED);
204           gfx.draw(labelShapePath);
205         }
206       } finally {
207                 gfx.setFont(oldFont);
209         gfx.setColor(oldColor);
210         gfx.setPaint(oldPaint);
211       }
212     }
213   }
214 
215   private static double normalizeAngle(final double angle) {
216     return angle - TWO_PI * Math.floor(angle / TWO_PI);
217   }
218 
219 
220   private boolean isOnAnySide(final PreferredPlacementDescriptor placementDescriptor) {
221     return placementDescriptor.getSideOfEdge() ==
222            (PreferredPlacementDescriptor.PLACE_LEFT_OF_EDGE |
223             PreferredPlacementDescriptor.PLACE_ON_EDGE |
224             PreferredPlacementDescriptor.PLACE_RIGHT_OF_EDGE);
225   }
226 
227   private boolean isLabelLeftOfEdgeInFlow(final PreferredPlacementDescriptor placementDescriptor, final double edgeAngle) {
228     if (placementDescriptor.isSideRelativeToEdgeFlow()) {
229       return placementDescriptor.isLeftOfEdge();
230     } else if (0 < edgeAngle && edgeAngle < Math.PI) {
231             return placementDescriptor.isRightOfEdge();
233     } else if (Math.PI < edgeAngle && edgeAngle < 2 * Math.PI) {
234             return placementDescriptor.isLeftOfEdge();
236     } else if (edgeAngle == 0) {
237             return placementDescriptor.isLeftOfEdge() ^ placementDescriptor.isSideAbsoluteWithRightInNorth();
239     } else {
240             return placementDescriptor.isLeftOfEdge() ^ placementDescriptor.isSideAbsoluteWithLeftInNorth();
242     }
243   }
244 
245   private boolean useSelectionStyle(final YLabel label, final Graphics2D gfx) {
246     return label.isSelected() && YRenderingHints.isSelectionPaintingEnabled(gfx);
247   }
248 
249   private Font getSmallFont(final Graphics2D gfx) {
250     if (smallFont == null) {
251       final Font font = gfx.getFont();
252       smallFont = new Font(font.getName(), font.getStyle(), 6);
253     }
254     return smallFont;
255   }
256 }
257