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 / ArcGraphE.C < prev    next >
C/C++ Source or Header  |  1998-08-03  |  9KB  |  348 lines

  1. // $Id: ArcGraphE.C,v 1.17 1998/08/03 12:59:25 zeller Exp $ -*- C++ -*-
  2. // Arc edges
  3.  
  4. // Copyright (C) 1997 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 ArcGraphEdge_rcsid[] = 
  30.     "$Id: ArcGraphE.C,v 1.17 1998/08/03 12:59:25 zeller Exp $";
  31.  
  32. #ifdef __GNUG__
  33. #pragma implementation
  34. #endif
  35.  
  36. #include "ArcGraphE.h"
  37. #include "HintGraphN.h"
  38. #include "misc.h"
  39. #include "printBox.h"
  40.  
  41. #include <math.h>
  42. #include <stdlib.h>
  43. #include "pi.h"
  44. #include "hypot.h"
  45.  
  46. #include <X11/X.h>
  47. #include <X11/Xlib.h>
  48. #include <X11/Intrinsic.h>
  49.  
  50. DEFINE_TYPE_INFO_1(ArcGraphEdge, LineGraphEdge);
  51.  
  52. inline double hypot(const BoxPoint& p)
  53. {
  54.     return hypot(p[X], p[Y]);
  55. }
  56.  
  57. // Compute the center of the arc enclosing P1, P2, and P3.
  58. // Return false iff P1, P2, and P3 form a line (i.e. there is no arc)
  59. bool ArcGraphEdge::center(const BoxPoint& p1, const BoxPoint& p2, 
  60.               const BoxPoint& p3, double& x, double& y)
  61. {
  62.     if (p1[X] == p3[X] && p1[Y] == p3[Y])
  63.     return false;
  64.  
  65.     BoxPoint d12 = p1 - p2;
  66.     BoxPoint d13 = p1 - p3;
  67.  
  68.     double s12 = asin(d12[Y] / hypot(d12));
  69.     double s13 = asin(d13[Y] / hypot(d13));
  70.     const double epsilon = 0.01;
  71.     if (fabs(s12 - s13) < epsilon)
  72.     return false;
  73.  
  74.     double l1 = p1[X] * p1[X] + p1[Y] * p1[Y];
  75.     double l2 = p2[X] * p2[X] + p2[Y] * p2[Y];
  76.     double l3 = p3[X] * p3[X] + p3[Y] * p3[Y];
  77.  
  78.     y = (d12[X] * (l3 - l1) - d13[X] * (l2 - l1))
  79.     / (2.0 * (d13[X] * d12[Y] - d12[X] * d13[Y]));
  80.  
  81.     if (p1[X] != p3[X])
  82.     x = (l3 + 2.0 * y * d13[Y] - l1) / (2.0 * -d13[X]);
  83.     else
  84.     x = (l2 + 2.0 * y * d12[Y] - l1) / (2.0 * -d12[X]);
  85.  
  86.     return true;
  87. }
  88.  
  89. void ArcGraphEdge::drawLine(Widget w, 
  90.                 const BoxRegion& exposed, 
  91.                 const GraphGC& gc) const
  92. {
  93.     makeLine(w, exposed, cout, gc);
  94. }
  95.  
  96. void ArcGraphEdge::_print(ostream& os,
  97.               const GraphGC& gc) const
  98. {
  99.     makeLine(0, BoxRegion(), os, gc);
  100. }
  101.  
  102. void ArcGraphEdge::makeLine(Widget w,
  103.                 const BoxRegion& exposed,
  104.                 ostream& os,
  105.                 const GraphGC& gc) const
  106. {
  107.     HintGraphNode   *arc_hint = 0;
  108.     RegionGraphNode *arc_from = 0;
  109.     RegionGraphNode *arc_to   = 0;
  110.  
  111.     bool make_arc = true;
  112.     if (from()->isHint() && to()->isHint())
  113.     {
  114.     // Edge between two hints
  115.     make_arc = false;
  116.     }
  117.     else if (from()->isHint() && from()->firstTo() != 0)
  118.     {
  119.     arc_hint = ptr_cast(HintGraphNode, from());
  120.     arc_from = ptr_cast(RegionGraphNode, arc_hint->firstTo()->from());
  121.     arc_to   = ptr_cast(RegionGraphNode, to());
  122.  
  123.     if (arc_hint == 0 || arc_from == 0 || arc_to == 0 
  124.         || arc_hint->nextTo(arc_hint->firstTo()) != 0)
  125.     {
  126.         // Bad nodes or hint with multiple edges
  127.         make_arc = false;
  128.     }
  129.     }
  130.     else if (to()->isHint() && to()->firstFrom() != 0)
  131.     {
  132.     arc_hint = ptr_cast(HintGraphNode, to());
  133.     arc_to   = ptr_cast(RegionGraphNode, arc_hint->firstFrom()->to());
  134.     arc_from = ptr_cast(RegionGraphNode, from());
  135.  
  136.     if (arc_hint == 0 || arc_from == 0 || arc_to == 0
  137.         || arc_hint->nextFrom(arc_hint->firstFrom()) != 0)
  138.     {
  139.         // Bad nodes or hint with multiple edges
  140.         make_arc = false;
  141.     }
  142.     }
  143.     else
  144.     {
  145.     // Edge between two ordinary nodes
  146.     make_arc = false;
  147.     }
  148.  
  149.     if (!make_arc)
  150.     {
  151.      if (w != 0)
  152.         LineGraphEdge::drawLine(w, exposed, gc);
  153.     else
  154.         LineGraphEdge::_print(os, gc);
  155.     return;
  156.     }
  157.  
  158.     BoxPoint pos_from     = arc_from->pos();
  159.     BoxRegion region_from = arc_from->region(gc);
  160.     if (arc_from->selected())
  161.     {
  162.     pos_from             += gc.offsetIfSelected;
  163.     region_from.origin() += gc.offsetIfSelected;
  164.     }
  165.  
  166.     BoxPoint pos_to     = arc_to->pos();
  167.     BoxRegion region_to = arc_to->region(gc);
  168.     if (arc_to->selected())
  169.     {
  170.     pos_to             += gc.offsetIfSelected;
  171.     region_to.origin() += gc.offsetIfSelected;
  172.     }
  173.  
  174.     BoxPoint pos_hint     = arc_hint->pos();
  175.     BoxRegion region_hint = arc_hint->region(gc);
  176.     if (arc_hint->selected())
  177.     {
  178.     pos_hint             += gc.offsetIfSelected;
  179.     region_hint.origin() += gc.offsetIfSelected;
  180.     }
  181.  
  182.     if (pos_hint <= region_from || pos_hint <= region_to)
  183.     {
  184.     // Hint within region
  185.      if (w != 0)
  186.         LineGraphEdge::drawLine(w, exposed, gc);
  187.     else
  188.         LineGraphEdge::_print(os, gc);
  189.     return;
  190.     }
  191.  
  192.     BoxPoint new_pos_from, new_pos_to, dummy;
  193.     findLine(pos_from, pos_hint, region_from, region_hint,
  194.          new_pos_from, dummy, gc);
  195.     findLine(pos_hint, pos_to, region_hint, region_to,
  196.          dummy, new_pos_to, gc);
  197.     pos_from = new_pos_from;
  198.     pos_to   = new_pos_to;
  199.  
  200.     // Draw circle segment POS_FROM -> POS_HINT or POS_HINT -> POS_TO
  201.  
  202.     // Determine the arc center
  203.     double cx, cy;
  204.     bool ok = center(pos_from, pos_hint, pos_to, cx, cy);
  205.     if (!ok)
  206.     {
  207.     // Nodes form a line
  208.      if (w != 0)
  209.         LineGraphEdge::drawLine(w, exposed, gc);
  210.     else
  211.         LineGraphEdge::_print(os, gc);
  212.     return;
  213.     }
  214.  
  215.     // Determine radius (easy when you have the center)
  216.     double radius = hypot(cx - pos_to[X], cy - pos_to[Y]);
  217.  
  218.     // Determine start and path of arc
  219.     double alpha_from = -atan2(pos_from[Y] - cy, pos_from[X] - cx);
  220.     double alpha_hint = -atan2(pos_hint[Y] - cy, pos_hint[X] - cx);
  221.     double alpha_to   = -atan2(pos_to[Y]   - cy, pos_to[X]   - cx);
  222.  
  223.     const int base = 360 * 64;
  224.  
  225.     int angle_from = (int(alpha_from * base / (PI * 2.0)) + base) % base;
  226.     int angle_to   = (int(alpha_to   * base / (PI * 2.0)) + base) % base;
  227.     int angle_hint = (int(alpha_hint * base / (PI * 2.0)) + base) % base;
  228.  
  229.     int path_from_hint = (base + angle_hint - angle_from) % base;
  230.     int path_hint_to   = (base + angle_to - angle_hint) % base;
  231.  
  232.     if (abs(path_from_hint) > base / 2)
  233.     path_from_hint = (path_from_hint - base) % base;
  234.     if (abs(path_hint_to) > base / 2)
  235.     path_hint_to = (path_hint_to - base) % base;
  236.  
  237.     if (sgn(path_from_hint) * sgn(path_hint_to) == -1)
  238.     {
  239.     // Hint is not between FROM and TO
  240.      if (w != 0)
  241.         LineGraphEdge::drawLine(w, exposed, gc);
  242.     else
  243.         LineGraphEdge::_print(os, gc);
  244.     return;
  245.     }
  246.  
  247.     int angle, path;
  248.     if (to()->isHint())
  249.     {
  250.     angle = angle_from;
  251.     path  = path_from_hint;
  252.     }
  253.     else
  254.     {
  255.     angle = angle_hint;
  256.     path  = path_hint_to;
  257.     }
  258.  
  259.     if (w != 0)
  260.     {
  261.     XDrawArc(XtDisplay(w), XtWindow(w), gc.edgeGC,
  262.          int(cx - radius), int(cy - radius),
  263.          unsigned(radius) * 2, unsigned(radius) * 2, angle, path);
  264.     }
  265.     else if (gc.printGC->isPostScript())
  266.     {
  267.     BoxCoordinate line_width = 1;
  268.  
  269.     int arc_start  = angle / 64;
  270.     int arc_extend = path / 64;
  271.  
  272.     int start, end;
  273.     if (arc_extend > 0)
  274.     {
  275.         start = (720 - arc_start - arc_extend) % 360;
  276.         end   = (720 - arc_start) % 360;
  277.     }
  278.     else
  279.     {
  280.         start = (720 - arc_start) % 360;
  281.         end   = (720 - arc_start - arc_extend) % 360;
  282.     }
  283.  
  284.     os << start << " " << end << " " 
  285.        << int(radius) << " " << int(radius) << " "
  286.        << int(cx) << " " << int(cy) << " " << line_width << " arc*\n";
  287.     }
  288.     else if (gc.printGC->isFig())
  289.     {
  290.     // We draw the entire arc in one stroke.
  291.     if (from()->isHint())
  292.     {
  293.         BoxCoordinate line_width = 1;
  294.  
  295.         os << ARCARROWHEAD1 << line_width << ARCARROWHEAD2;
  296.         if (path > 0)
  297.         os << ARCCOUNTERCLOCKWISE;
  298.         else
  299.         os << ARCCLOCKWISE;
  300.         os << ARCARROWHEAD3
  301.            << cx << " " << cy << " "
  302.            << pos_from[X] << " " << pos_from[Y] << " "
  303.            << pos_hint[X] << " " << pos_hint[Y] << " "
  304.            << pos_to[X]   << " " << pos_to[Y]   << " "
  305.            << ARCARROWHEAD4;
  306.     }
  307.     }
  308.  
  309.     if (from()->isHint())
  310.     {
  311.     // Draw arrow head at POS_TO
  312.     double alpha = atan2(pos_to[Y] - cy, pos_to[X] - cx);
  313.  
  314.     if (w != 0)
  315.     {
  316.         if (path > 0)
  317.         alpha += PI / 2.0;
  318.         else
  319.         alpha -= PI / 2.0;
  320.  
  321.         drawArrowHead(w, exposed, gc, pos_to, alpha);
  322.     }
  323.     else if (gc.printGC->isPostScript())
  324.     {
  325.         if (path > 0)
  326.         alpha -= PI / 2.0;
  327.         else
  328.         alpha += PI / 2.0;
  329.  
  330.         os << gc.arrowAngle << " " << gc.arrowLength << " " 
  331.            << (360 + int(alpha * 360.0 / (PI * 2.0))) % 360 << " "
  332.            << pos_to[X] << " " << pos_to[Y] << " arrowhead*\n";
  333.     }
  334.     }
  335.  
  336.     if (to()->isHint() && annotation() != 0)
  337.     {
  338.     if (w != 0)
  339.     {
  340.         annotation()->draw(w, to()->pos(), exposed, gc);
  341.     }
  342.     else
  343.     {
  344.         annotation()->_print(os, to()->pos(), gc);
  345.     }
  346.     }
  347. }
  348.