[Uml-devel] branches/KDE/3.5/kdesdk/umbrello/umbrello

Oliver Kellogg okellogg at users.sourceforge.net
Sun Dec 11 12:37:00 UTC 2005


SVN commit 487751 by okellogg:

constrainTextPos(): Snapping the text position to the circle midpoint
in case of a constraint violation creates unpleasant visual jitter.
Rather, let's project the text position onto the closest point on the
circle.


 M  +55 -3     associationwidget.cpp  


--- branches/KDE/3.5/kdesdk/umbrello/umbrello/associationwidget.cpp #487750:487751
@@ -1888,15 +1888,67 @@
     double r = sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0)) / 2;
     if (textWidth > r)
         r = textWidth;
-    const int relX = textCenterY - midP.x();  // NB: text{X,Y} are swapped to
-    const int relY = textCenterX - midP.y();  //     convert from Qt coord.system.
-    // circle equation:  x*x + y*y - r*r = 0
+    // swap textCenter{X,Y} to convert from Qt coord.system.
+    const QPoint origTextCenter(textCenterY, textCenterX);
+    const int relX = abs(origTextCenter.x() - midP.x());
+    const int relY = abs(origTextCenter.y() - midP.y());
     const double negativeWhenInsideCircle = relX * relX + relY * relY - r * r;
     if (negativeWhenInsideCircle <= 0.0) {
         return;
     }
+    /*
+     The original constraint was to snap the text position to the
+     midpoint but that creates unpleasant visual jitter:
     textX = midP.y() - textWidth / 2;   // go back to Qt coord.sys.
     textY = midP.x() - textHeight / 2;  // go back to Qt coord.sys.
+
+     Rather, we project the text position onto the closest point
+     on the circle:
+
+     Circle equation:
+       relX^2 + relY^2 - r^2 = 0   , or in other words
+       relY^2 = r^2 - relX^2       , or
+       relY = sqrt(r^2 - relX^2)
+     Line equation:
+       relY = a * relX + b
+         We can omit "b" because relX and relY are already relative to
+         the circle origin, therefore we can also write:
+       a = relY / relX
+     To obtain the point of intersection between the circle of radius r
+     and the line connecting the circle origin with the point (relX, relY),
+     we equate the relY:
+       a * x = sqrt(r^2 - x^2)     , or in other words
+       a^2 * x^2 = r^2 - x^2       , or
+       x^2 * (a^2 + 1) = r^2       , or
+       x^2 = r^2 / (a^2 + 1)       , or
+       x = sqrt(r^2 / (a^2 + 1))
+     and then
+       y = a * x
+     The resulting x and y are relative to the circle origin so we just add
+     the circle origin (X,Y) to obtain the constrained (textX,textY).
+     */
+    // Handle the special case, relX = 0.
+    if (relX == 0) {
+        if (origTextCenter.y() > midP.y())
+            textX = midP.y() + (int)r;   // go back to Qt coord.sys.
+        else
+            textX = midP.y() - (int)r;   // go back to Qt coord.sys.
+        textX -= textWidth / 2;
+        return;
+    }
+    const double a = (double)relY / (double)relX;
+    const double x = sqrt(r*r / (a*a + 1));
+    const double y = a * x;
+    if (origTextCenter.x() > midP.x())
+        textY = midP.x() + (int)x;   // go back to Qt coord.sys.
+    else
+        textY = midP.x() - (int)x;   // go back to Qt coord.sys.
+    textY -= textHeight / 2;
+    if (origTextCenter.y() > midP.y())
+        textX = midP.y() + (int)y;   // go back to Qt coord.sys.
+    else
+        textX = midP.y() - (int)y;   // go back to Qt coord.sys.
+    textX -= textWidth / 2;
 }
 
 void AssociationWidget::calculateNameTextSegment() {




More information about the umbrello-devel mailing list