home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1999 mARCH / PCWK3A99.iso / Linux / DDD331 / DDD-3_1_.000 / DDD-3_1_ / ddd-3.1.1 / ddd / LineGraphE.C < prev    next >
C/C++ Source or Header  |  1998-08-03  |  12KB  |  469 lines

  1. // $Id: LineGraphE.C,v 1.26 1998/08/03 12:59:26 zeller Exp $
  2. // class LineGraphEdge
  3.  
  4. // Copyright (C) 1995 Technische Universitaet Braunschweig, Germany.
  5. // Written by Andreas Zeller <zeller@ips.cs.tu-bs.de>.
  6. // 
  7. // This file is part of DDD.
  8. // 
  9. // DDD is free software; you can redistribute it and/or
  10. // modify it under the terms of the GNU General Public
  11. // License as published by the Free Software Foundation; either
  12. // version 2 of the License, or (at your option) any later version.
  13. // 
  14. // DDD is distributed in the hope that it will be useful,
  15. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  17. // See the GNU General Public License for more details.
  18. // 
  19. // You should have received a copy of the GNU General Public
  20. // License along with DDD -- see the file COPYING.
  21. // If not, write to the Free Software Foundation, Inc.,
  22. // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  23. // 
  24. // DDD is the data display debugger.
  25. // For details, see the DDD World-Wide-Web page, 
  26. // `http://www.cs.tu-bs.de/softech/ddd/',
  27. // or send a mail to the DDD developers <ddd@ips.cs.tu-bs.de>.
  28.  
  29. char LineGraphEdge_rcsid[] = 
  30.     "$Id: LineGraphE.C,v 1.26 1998/08/03 12:59:26 zeller Exp $";
  31.  
  32. #ifdef __GNUG__
  33. #pragma implementation
  34. #endif
  35.  
  36.  
  37. #include "LineGraphE.h"
  38.  
  39. #include "assert.h"
  40.  
  41. #include <math.h>
  42. #include "pi.h"
  43. #include "hypot.h"
  44. #include <limits.h>
  45. #include <string.h>
  46. #include <stdlib.h>
  47.  
  48. #include <X11/X.h>
  49. #include <X11/Xlib.h>
  50. #include <X11/Intrinsic.h>
  51.  
  52. #include "GraphNode.h"
  53. #include "LineGESI.h"
  54. #include "printBox.h"
  55.  
  56.  
  57. DEFINE_TYPE_INFO_1(LineGraphEdge, GraphEdge)
  58.  
  59. // Find the points to draw line at
  60.  
  61. // Clip point P to side SIDE of region B.
  62. void LineGraphEdge::moveToSide(const BoxRegion& b, int side, 
  63.                    BoxPoint& p, const BoxPoint&)
  64. {
  65.     assert(side == North || side == South || side == East || side == West);
  66.  
  67.     p = b.origin();
  68.  
  69.     // Fetch points
  70.     if (side & (North | South))
  71.     {
  72.     p[X] += b.space(X) / 2;
  73.     if (side & South)
  74.         p[Y] += b.space(Y);
  75.     }
  76.  
  77.     if (side & (East | West))
  78.     {
  79.     p[Y] += b.space(Y) / 2;
  80.     if (side & East)
  81.         p[X] += b.space(X);
  82.     }
  83. }
  84.  
  85.  
  86. // Clip point P to side SIDE of region B centered around C.
  87. void LineGraphEdge::clipToSide(const BoxRegion& b, int side, 
  88.                    BoxPoint& p, const BoxPoint& c)
  89. {
  90.     assert(side == North || side == South || side == East || side == West);
  91.  
  92.     BoxDimension d1, d2;
  93.  
  94.     if (side & (North | South))
  95.     d1 = X, d2 = Y;
  96.     else
  97.     d1 = Y, d2 = X;
  98.  
  99.     int offset;
  100.     if (side & (North | West))
  101.     offset = -1;
  102.     else
  103.     offset = 1;
  104.  
  105.     if (c[d1] != p[d1] && c[d2] != p[d2])
  106.     p[d1] += offset * (b.space(d2) / 2) * (c[d1] - p[d1]) 
  107.         / (c[d2] - p[d2]);
  108.     p[d2] += offset * b.space(d2) / 2;
  109. }
  110.  
  111.  
  112. // Clip point P to side SIDE of region B centered around C.  Assume
  113. // that B contains a circle.
  114. void LineGraphEdge::clipToCircle(const BoxRegion& b, int /* side */, 
  115.                  BoxPoint& p, const BoxPoint& c)
  116. {
  117.     // assert(side == North || side == South || side == East || side == West);
  118.  
  119.     double radius = max(b.space(X), b.space(Y)) / 2;
  120.     if (radius > 0.0)
  121.     {
  122.     double hyp = hypot(c[X] - p[X], c[Y] - p[Y]);
  123.  
  124.     p[X] += BoxCoordinate((radius * (c[X] - p[X])) / hyp);
  125.     p[Y] += BoxCoordinate((radius * (c[Y] - p[Y])) / hyp);
  126.     }
  127. }
  128.  
  129. // Find line from region B1 centered around C1 to region B2 centered
  130. // around C2.  Resulting line shall be drawn from P1 to P2
  131. void LineGraphEdge::findLine(const BoxPoint& c1, const BoxPoint& c2,
  132.                  const BoxRegion& b1, const BoxRegion& b2, 
  133.                  BoxPoint& p1, BoxPoint& p2, 
  134.                  const GraphGC& gc)
  135. {
  136.     // allow all sizes to begin
  137.     int side1 = North | South | East | West;
  138.     int side2 = North | South | East | West;
  139.  
  140.     // exclude opposite side
  141.     if (c2[X] > c1[X]) { side1 &= ~West; side2 &= ~East; }
  142.     else               { side1 &= ~East; side2 &= ~West; }
  143.  
  144.     if (c2[Y] > c1[Y]) { side1 &= ~North; side2 &= ~South; }
  145.     else               { side1 &= ~South; side2 &= ~North; }
  146.  
  147.     // find edge cutting the line between the two center points c1, c2
  148.     BoxCoordinate dx = abs(c1[X] - c2[X]);
  149.     BoxCoordinate dy = abs(c1[Y] - c2[Y]);
  150.  
  151.     if (b1.space(Y) * dx > b1.space(X) * dy) side1 &= ~(North | South);
  152.     else                                     side1 &= ~(East | West);
  153.  
  154.     if (b2.space(Y) * dx > b2.space(X) * dy) side2 &= ~(North | South);
  155.     else                                     side2 &= ~(East | West);
  156.  
  157.     p1 = c1;
  158.     p2 = c2;
  159.  
  160.     // Select appropriate clipping procedure
  161.     typedef void (*ClipProc)(const BoxRegion& b, int side,
  162.                  BoxPoint& p, const BoxPoint& c);
  163.  
  164.     struct ClipMapRec {
  165.     EdgeAttachMode mode;
  166.     ClipProc       proc;
  167.     };
  168.  
  169.     static const ClipMapRec clipMap[] = 
  170.     {
  171.     {Straight, LineGraphEdge::clipToSide},
  172.     {Circle,   LineGraphEdge::clipToCircle},
  173.     {Centered, LineGraphEdge::moveToSide},
  174.     {Straight, 0}
  175.     };
  176.  
  177.     for (int i = 0; clipMap[i].proc != 0; i++)
  178.     if (gc.edgeAttachMode == clipMap[i].mode)
  179.     {
  180.         clipMap[i].proc(b1, side1, p1, c2);
  181.         clipMap[i].proc(b2, side2, p2, c1);
  182.  
  183.         return;
  184.     }
  185.  
  186.     assert(0);
  187. }
  188.  
  189.  
  190. // Draw
  191.  
  192. void LineGraphEdge::_draw(Widget w, 
  193.               const BoxRegion& exposed, 
  194.               const GraphGC& gc) const
  195. {
  196.     if (from() == to())
  197.     drawSelf(w, exposed, gc);
  198.     else
  199.     drawLine(w, exposed, gc);
  200. }
  201.  
  202. void LineGraphEdge::drawLine(Widget w, 
  203.                  const BoxRegion& exposed, 
  204.                  const GraphGC& gc) const
  205. {
  206.     // Get node starting points
  207.     BoxPoint pos1     = from()->pos();
  208.     BoxRegion region1 = from()->region(gc);
  209.     if (from()->selected())
  210.     {
  211.     pos1             += gc.offsetIfSelected;
  212.     region1.origin() += gc.offsetIfSelected;
  213.     }
  214.  
  215.     BoxPoint pos2     = to()->pos();
  216.     BoxRegion region2 = to()->region(gc);
  217.     if (to()->selected())
  218.     {
  219.     pos2             += gc.offsetIfSelected;
  220.     region2.origin() += gc.offsetIfSelected;
  221.     }
  222.  
  223.     // If nodes overlap, don't draw the edge.
  224.     if (region1 <= region2)
  225.     return;
  226.  
  227.     // Get the line points
  228.     BoxPoint l1, l2;
  229.     findLine(pos1, pos2, region1, region2, l1, l2, gc);
  230.  
  231.     // If there is no edge (adjacent nodes), don't draw it.
  232.     if (l1 == l2)
  233.     return;
  234.  
  235.     XDrawLine(XtDisplay(w), XtWindow(w), gc.edgeGC,
  236.           l1[X], l1[Y], l2[X], l2[Y]);
  237.  
  238.     // Draw annotation
  239.     BoxPoint anno_pos = annotationPosition(gc);
  240.     if (annotation() != 0 && anno_pos.isValid())
  241.     {
  242.     annotation()->draw(w, anno_pos, exposed, gc);
  243.     }
  244.  
  245.     // Get arrow angle
  246.     double alpha = atan2(double(l1[Y] - l2[Y]), double(l1[X] - l2[X]));
  247.  
  248.     // Draw arrow head at L2
  249.     drawArrowHead(w, exposed, gc, l2, alpha);
  250. }
  251.  
  252.  
  253. // Draw arrow head at POS
  254. void LineGraphEdge::drawArrowHead(Widget w,
  255.                   const BoxRegion& /* exposed */,
  256.                   const GraphGC& gc,
  257.                   const BoxPoint& pos,
  258.                   double alpha) const
  259. {
  260.     if (!gc.drawArrowHeads || to()->isHint())
  261.     return;
  262.  
  263.     const double offset = gc.arrowAngle * PI / 180;    // Angle
  264.     const int length    = gc.arrowLength;        // Length
  265.  
  266.     // Get coordinates
  267.     XPoint points[3];
  268.     points[0].x = pos[X];
  269.     points[0].y = pos[Y];
  270.     points[1].x = short(pos[X] + length * cos(alpha + offset / 2));
  271.     points[1].y = short(pos[Y] + length * sin(alpha + offset / 2));
  272.     points[2].x = short(pos[X] + length * cos(alpha - offset / 2));
  273.     points[2].y = short(pos[Y] + length * sin(alpha - offset / 2));
  274.  
  275. #if 0
  276.     clog << "\nangle = " << (alpha / (PI * 2.0)) * 360.0  << "\n";
  277.     for (int i = 0; i < 3; i++)
  278.         clog << "points[" << i << "] = "
  279.          << BoxPoint(points[i].x, points[i].y) << "\n";
  280. #endif
  281.  
  282.     XFillPolygon(XtDisplay(w), XtWindow(w), gc.edgeGC, points,
  283.          XtNumber(points), Convex, CoordModeOrigin);
  284. }
  285.  
  286.  
  287. // Region occupied by edge
  288. BoxRegion LineGraphEdge::region(const GraphGC& gc) const
  289. {
  290.     BoxRegion r;
  291.     if (gc.drawAnnotations && annotation() != 0)
  292.     {
  293.     BoxPoint anno_pos = annotationPosition(gc);
  294.     if (anno_pos.isValid())
  295.     {
  296.         BoxRegion anno_region = annotation()->region(anno_pos, gc);
  297.         if (r.origin().isValid())
  298.         r = r | anno_region;
  299.         else
  300.         r = anno_region;
  301.     }
  302.     }
  303.  
  304.     if (from() == to())
  305.     {
  306.     BoxRegion region = from()->region(gc);
  307.            if (from()->selected())
  308.         region.origin() += gc.offsetIfSelected;
  309.  
  310.     LineGraphEdgeSelfInfo info(region, gc);
  311.  
  312.     BoxRegion self_region(info.arc_pos,
  313.                   BoxSize(info.diameter, info.diameter));
  314.  
  315.     if (r.origin().isValid())
  316.         r = r | self_region;
  317.     else
  318.         r = self_region;
  319.     }
  320.  
  321.     return r;
  322. }
  323.  
  324.  
  325. // Draw self edge
  326. void LineGraphEdge::drawSelf(Widget w,
  327.                  const BoxRegion& exposed,
  328.                  const GraphGC& gc) const
  329. {
  330.     assert(from() == to());
  331.  
  332.     // Get region
  333.     BoxRegion region = from()->region(gc);
  334.     if (from()->selected())
  335.     region.origin() += gc.offsetIfSelected;
  336.  
  337.     LineGraphEdgeSelfInfo info(region, gc);
  338.  
  339.     XDrawArc(XtDisplay(w), XtWindow(w), gc.edgeGC, info.arc_pos[X],
  340.          info.arc_pos[Y], info.diameter, info.diameter,
  341.          info.arc_start * 64, info.arc_extend * 64);
  342.  
  343.     if (annotation() != 0)
  344.     {
  345.     // Draw annotation
  346.     annotation()->draw(w, info.anno_pos, exposed, gc);
  347.     }
  348.  
  349.     // Find arrow angle
  350.     drawArrowHead(w, exposed, gc, info.arrow_pos, info.arrow_alpha);
  351. }
  352.  
  353. void LineGraphEdge::printSelf(ostream& os, const GraphGC &gc) const
  354. {
  355.     assert(from() == to());
  356.  
  357.     // Get region
  358.     BoxRegion region = from()->region(gc);
  359.     if (from()->selected())
  360.     region.origin() += gc.offsetIfSelected;
  361.  
  362.     LineGraphEdgeSelfInfo info(region, gc);
  363.  
  364.     if (gc.printGC->isPostScript())
  365.     {
  366.     int start = (720 - info.arc_start - info.arc_extend) % 360 ;
  367.     int end   = (720 - info.arc_start) % 360 ;
  368.  
  369.     BoxCoordinate line_width = 1;
  370.  
  371.     // Draw arc
  372.     os << start << " " << end << " " 
  373.        << info.radius << " " << info.radius << " "
  374.        << info.arc_center[X] << " " << info.arc_center[Y] << " " 
  375.        << line_width << " arc*\n";
  376.  
  377.     // Now draw the arrow head
  378.     int angle = (720 - info.arrow_angle) % 360;
  379.  
  380.     os << gc.arrowAngle << " " << gc.arrowLength << " " << angle << " "
  381.        << info.arrow_pos[X] << " " << info.arrow_pos[Y] << " arrowhead*\n";
  382.     }
  383.     else if (gc.printGC->isFig())
  384.     {
  385.     BoxCoordinate line_width = 1;
  386.  
  387.     os << ARCARROWHEAD1 << line_width << ARCARROWHEAD2;
  388.     switch (gc.selfEdgeDirection)
  389.     {
  390.     case Clockwise:
  391.         os << ARCCLOCKWISE;
  392.         break;
  393.     case Counterclockwise:
  394.         os << ARCCOUNTERCLOCKWISE;
  395.         break;
  396.     }
  397.     os << ARCARROWHEAD3
  398.        << float(info.arc_center[X]) << " " 
  399.        << float(info.arc_center[Y]) << " ";
  400.     for (int i = 0; i < 3; i++)
  401.         os << info.fig_pos[i][X] << " " << info.fig_pos[i][Y] << " ";
  402.     os << ARCARROWHEAD4;
  403.     }
  404.  
  405.     if (annotation() != 0)
  406.     {
  407.     // Print annotation
  408.     annotation()->_print(os, info.anno_pos, gc);
  409.     }
  410. }
  411.  
  412. BoxPoint LineGraphEdge::annotationPosition(const GraphGC &gc) const
  413. {
  414.     if (from() == to())
  415.     {
  416.     BoxRegion region = from()->region(gc);
  417.     if (from()->selected())
  418.         region.origin() += gc.offsetIfSelected;
  419.  
  420.     LineGraphEdgeSelfInfo info(region, gc);
  421.     return info.anno_pos;
  422.     }
  423.  
  424.     BoxPoint pos1     = from()->pos();
  425.     BoxRegion region1 = from()->region(gc);
  426.  
  427.     BoxPoint pos2     = to()->pos();
  428.     BoxRegion region2 = to()->region(gc);
  429.  
  430.     BoxPoint l1, l2;
  431.     findLine(pos1, pos2, region1, region2, l1, l2, gc);
  432.  
  433.     if (from()->isHint() && to()->isHint())
  434.     {
  435.     // Between two hints -- don't draw anything
  436.     return BoxPoint();
  437.     }
  438.  
  439.     if (to()->isHint())
  440.     {
  441.     // Draw at hint position
  442.     return to()->pos();
  443.     }
  444.  
  445.     // Draw at mid-distance
  446.     return l1 + (l2 - l1) / 2;
  447. }
  448.  
  449. void LineGraphEdge::_print(ostream& os, const GraphGC &gc) const
  450. {
  451.     if (from() == to())
  452.     {
  453.     printSelf(os, gc);
  454.     return;
  455.     }
  456.  
  457.     GraphEdge::_print(os, gc);
  458.  
  459.     // Print annotation
  460.     if (annotation() != 0)
  461.     {
  462.     BoxPoint anno_pos = annotationPosition(gc);
  463.     if (anno_pos.isValid())
  464.     {
  465.         annotation()->_print(os, anno_pos, gc);
  466.     }
  467.     }
  468. }
  469.