home *** CD-ROM | disk | FTP | other *** search
- // $Id: LineGraphE.C,v 1.26 1998/08/03 12:59:26 zeller Exp $
- // class LineGraphEdge
-
- // Copyright (C) 1995 Technische Universitaet Braunschweig, Germany.
- // Written by Andreas Zeller <zeller@ips.cs.tu-bs.de>.
- //
- // This file is part of DDD.
- //
- // DDD is free software; you can redistribute it and/or
- // modify it under the terms of the GNU General Public
- // License as published by the Free Software Foundation; either
- // version 2 of the License, or (at your option) any later version.
- //
- // DDD is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- // See the GNU General Public License for more details.
- //
- // You should have received a copy of the GNU General Public
- // License along with DDD -- see the file COPYING.
- // If not, write to the Free Software Foundation, Inc.,
- // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- //
- // DDD is the data display debugger.
- // For details, see the DDD World-Wide-Web page,
- // `http://www.cs.tu-bs.de/softech/ddd/',
- // or send a mail to the DDD developers <ddd@ips.cs.tu-bs.de>.
-
- char LineGraphEdge_rcsid[] =
- "$Id: LineGraphE.C,v 1.26 1998/08/03 12:59:26 zeller Exp $";
-
- #ifdef __GNUG__
- #pragma implementation
- #endif
-
-
- #include "LineGraphE.h"
-
- #include "assert.h"
-
- #include <math.h>
- #include "pi.h"
- #include "hypot.h"
- #include <limits.h>
- #include <string.h>
- #include <stdlib.h>
-
- #include <X11/X.h>
- #include <X11/Xlib.h>
- #include <X11/Intrinsic.h>
-
- #include "GraphNode.h"
- #include "LineGESI.h"
- #include "printBox.h"
-
-
- DEFINE_TYPE_INFO_1(LineGraphEdge, GraphEdge)
-
- // Find the points to draw line at
-
- // Clip point P to side SIDE of region B.
- void LineGraphEdge::moveToSide(const BoxRegion& b, int side,
- BoxPoint& p, const BoxPoint&)
- {
- assert(side == North || side == South || side == East || side == West);
-
- p = b.origin();
-
- // Fetch points
- if (side & (North | South))
- {
- p[X] += b.space(X) / 2;
- if (side & South)
- p[Y] += b.space(Y);
- }
-
- if (side & (East | West))
- {
- p[Y] += b.space(Y) / 2;
- if (side & East)
- p[X] += b.space(X);
- }
- }
-
-
- // Clip point P to side SIDE of region B centered around C.
- void LineGraphEdge::clipToSide(const BoxRegion& b, int side,
- BoxPoint& p, const BoxPoint& c)
- {
- assert(side == North || side == South || side == East || side == West);
-
- BoxDimension d1, d2;
-
- if (side & (North | South))
- d1 = X, d2 = Y;
- else
- d1 = Y, d2 = X;
-
- int offset;
- if (side & (North | West))
- offset = -1;
- else
- offset = 1;
-
- if (c[d1] != p[d1] && c[d2] != p[d2])
- p[d1] += offset * (b.space(d2) / 2) * (c[d1] - p[d1])
- / (c[d2] - p[d2]);
- p[d2] += offset * b.space(d2) / 2;
- }
-
-
- // Clip point P to side SIDE of region B centered around C. Assume
- // that B contains a circle.
- void LineGraphEdge::clipToCircle(const BoxRegion& b, int /* side */,
- BoxPoint& p, const BoxPoint& c)
- {
- // assert(side == North || side == South || side == East || side == West);
-
- double radius = max(b.space(X), b.space(Y)) / 2;
- if (radius > 0.0)
- {
- double hyp = hypot(c[X] - p[X], c[Y] - p[Y]);
-
- p[X] += BoxCoordinate((radius * (c[X] - p[X])) / hyp);
- p[Y] += BoxCoordinate((radius * (c[Y] - p[Y])) / hyp);
- }
- }
-
- // Find line from region B1 centered around C1 to region B2 centered
- // around C2. Resulting line shall be drawn from P1 to P2
- void LineGraphEdge::findLine(const BoxPoint& c1, const BoxPoint& c2,
- const BoxRegion& b1, const BoxRegion& b2,
- BoxPoint& p1, BoxPoint& p2,
- const GraphGC& gc)
- {
- // allow all sizes to begin
- int side1 = North | South | East | West;
- int side2 = North | South | East | West;
-
- // exclude opposite side
- if (c2[X] > c1[X]) { side1 &= ~West; side2 &= ~East; }
- else { side1 &= ~East; side2 &= ~West; }
-
- if (c2[Y] > c1[Y]) { side1 &= ~North; side2 &= ~South; }
- else { side1 &= ~South; side2 &= ~North; }
-
- // find edge cutting the line between the two center points c1, c2
- BoxCoordinate dx = abs(c1[X] - c2[X]);
- BoxCoordinate dy = abs(c1[Y] - c2[Y]);
-
- if (b1.space(Y) * dx > b1.space(X) * dy) side1 &= ~(North | South);
- else side1 &= ~(East | West);
-
- if (b2.space(Y) * dx > b2.space(X) * dy) side2 &= ~(North | South);
- else side2 &= ~(East | West);
-
- p1 = c1;
- p2 = c2;
-
- // Select appropriate clipping procedure
- typedef void (*ClipProc)(const BoxRegion& b, int side,
- BoxPoint& p, const BoxPoint& c);
-
- struct ClipMapRec {
- EdgeAttachMode mode;
- ClipProc proc;
- };
-
- static const ClipMapRec clipMap[] =
- {
- {Straight, LineGraphEdge::clipToSide},
- {Circle, LineGraphEdge::clipToCircle},
- {Centered, LineGraphEdge::moveToSide},
- {Straight, 0}
- };
-
- for (int i = 0; clipMap[i].proc != 0; i++)
- if (gc.edgeAttachMode == clipMap[i].mode)
- {
- clipMap[i].proc(b1, side1, p1, c2);
- clipMap[i].proc(b2, side2, p2, c1);
-
- return;
- }
-
- assert(0);
- }
-
-
- // Draw
-
- void LineGraphEdge::_draw(Widget w,
- const BoxRegion& exposed,
- const GraphGC& gc) const
- {
- if (from() == to())
- drawSelf(w, exposed, gc);
- else
- drawLine(w, exposed, gc);
- }
-
- void LineGraphEdge::drawLine(Widget w,
- const BoxRegion& exposed,
- const GraphGC& gc) const
- {
- // Get node starting points
- BoxPoint pos1 = from()->pos();
- BoxRegion region1 = from()->region(gc);
- if (from()->selected())
- {
- pos1 += gc.offsetIfSelected;
- region1.origin() += gc.offsetIfSelected;
- }
-
- BoxPoint pos2 = to()->pos();
- BoxRegion region2 = to()->region(gc);
- if (to()->selected())
- {
- pos2 += gc.offsetIfSelected;
- region2.origin() += gc.offsetIfSelected;
- }
-
- // If nodes overlap, don't draw the edge.
- if (region1 <= region2)
- return;
-
- // Get the line points
- BoxPoint l1, l2;
- findLine(pos1, pos2, region1, region2, l1, l2, gc);
-
- // If there is no edge (adjacent nodes), don't draw it.
- if (l1 == l2)
- return;
-
- XDrawLine(XtDisplay(w), XtWindow(w), gc.edgeGC,
- l1[X], l1[Y], l2[X], l2[Y]);
-
- // Draw annotation
- BoxPoint anno_pos = annotationPosition(gc);
- if (annotation() != 0 && anno_pos.isValid())
- {
- annotation()->draw(w, anno_pos, exposed, gc);
- }
-
- // Get arrow angle
- double alpha = atan2(double(l1[Y] - l2[Y]), double(l1[X] - l2[X]));
-
- // Draw arrow head at L2
- drawArrowHead(w, exposed, gc, l2, alpha);
- }
-
-
- // Draw arrow head at POS
- void LineGraphEdge::drawArrowHead(Widget w,
- const BoxRegion& /* exposed */,
- const GraphGC& gc,
- const BoxPoint& pos,
- double alpha) const
- {
- if (!gc.drawArrowHeads || to()->isHint())
- return;
-
- const double offset = gc.arrowAngle * PI / 180; // Angle
- const int length = gc.arrowLength; // Length
-
- // Get coordinates
- XPoint points[3];
- points[0].x = pos[X];
- points[0].y = pos[Y];
- points[1].x = short(pos[X] + length * cos(alpha + offset / 2));
- points[1].y = short(pos[Y] + length * sin(alpha + offset / 2));
- points[2].x = short(pos[X] + length * cos(alpha - offset / 2));
- points[2].y = short(pos[Y] + length * sin(alpha - offset / 2));
-
- #if 0
- clog << "\nangle = " << (alpha / (PI * 2.0)) * 360.0 << "\n";
- for (int i = 0; i < 3; i++)
- clog << "points[" << i << "] = "
- << BoxPoint(points[i].x, points[i].y) << "\n";
- #endif
-
- XFillPolygon(XtDisplay(w), XtWindow(w), gc.edgeGC, points,
- XtNumber(points), Convex, CoordModeOrigin);
- }
-
-
- // Region occupied by edge
- BoxRegion LineGraphEdge::region(const GraphGC& gc) const
- {
- BoxRegion r;
- if (gc.drawAnnotations && annotation() != 0)
- {
- BoxPoint anno_pos = annotationPosition(gc);
- if (anno_pos.isValid())
- {
- BoxRegion anno_region = annotation()->region(anno_pos, gc);
- if (r.origin().isValid())
- r = r | anno_region;
- else
- r = anno_region;
- }
- }
-
- if (from() == to())
- {
- BoxRegion region = from()->region(gc);
- if (from()->selected())
- region.origin() += gc.offsetIfSelected;
-
- LineGraphEdgeSelfInfo info(region, gc);
-
- BoxRegion self_region(info.arc_pos,
- BoxSize(info.diameter, info.diameter));
-
- if (r.origin().isValid())
- r = r | self_region;
- else
- r = self_region;
- }
-
- return r;
- }
-
-
- // Draw self edge
- void LineGraphEdge::drawSelf(Widget w,
- const BoxRegion& exposed,
- const GraphGC& gc) const
- {
- assert(from() == to());
-
- // Get region
- BoxRegion region = from()->region(gc);
- if (from()->selected())
- region.origin() += gc.offsetIfSelected;
-
- LineGraphEdgeSelfInfo info(region, gc);
-
- XDrawArc(XtDisplay(w), XtWindow(w), gc.edgeGC, info.arc_pos[X],
- info.arc_pos[Y], info.diameter, info.diameter,
- info.arc_start * 64, info.arc_extend * 64);
-
- if (annotation() != 0)
- {
- // Draw annotation
- annotation()->draw(w, info.anno_pos, exposed, gc);
- }
-
- // Find arrow angle
- drawArrowHead(w, exposed, gc, info.arrow_pos, info.arrow_alpha);
- }
-
- void LineGraphEdge::printSelf(ostream& os, const GraphGC &gc) const
- {
- assert(from() == to());
-
- // Get region
- BoxRegion region = from()->region(gc);
- if (from()->selected())
- region.origin() += gc.offsetIfSelected;
-
- LineGraphEdgeSelfInfo info(region, gc);
-
- if (gc.printGC->isPostScript())
- {
- int start = (720 - info.arc_start - info.arc_extend) % 360 ;
- int end = (720 - info.arc_start) % 360 ;
-
- BoxCoordinate line_width = 1;
-
- // Draw arc
- os << start << " " << end << " "
- << info.radius << " " << info.radius << " "
- << info.arc_center[X] << " " << info.arc_center[Y] << " "
- << line_width << " arc*\n";
-
- // Now draw the arrow head
- int angle = (720 - info.arrow_angle) % 360;
-
- os << gc.arrowAngle << " " << gc.arrowLength << " " << angle << " "
- << info.arrow_pos[X] << " " << info.arrow_pos[Y] << " arrowhead*\n";
- }
- else if (gc.printGC->isFig())
- {
- BoxCoordinate line_width = 1;
-
- os << ARCARROWHEAD1 << line_width << ARCARROWHEAD2;
- switch (gc.selfEdgeDirection)
- {
- case Clockwise:
- os << ARCCLOCKWISE;
- break;
- case Counterclockwise:
- os << ARCCOUNTERCLOCKWISE;
- break;
- }
- os << ARCARROWHEAD3
- << float(info.arc_center[X]) << " "
- << float(info.arc_center[Y]) << " ";
- for (int i = 0; i < 3; i++)
- os << info.fig_pos[i][X] << " " << info.fig_pos[i][Y] << " ";
- os << ARCARROWHEAD4;
- }
-
- if (annotation() != 0)
- {
- // Print annotation
- annotation()->_print(os, info.anno_pos, gc);
- }
- }
-
- BoxPoint LineGraphEdge::annotationPosition(const GraphGC &gc) const
- {
- if (from() == to())
- {
- BoxRegion region = from()->region(gc);
- if (from()->selected())
- region.origin() += gc.offsetIfSelected;
-
- LineGraphEdgeSelfInfo info(region, gc);
- return info.anno_pos;
- }
-
- BoxPoint pos1 = from()->pos();
- BoxRegion region1 = from()->region(gc);
-
- BoxPoint pos2 = to()->pos();
- BoxRegion region2 = to()->region(gc);
-
- BoxPoint l1, l2;
- findLine(pos1, pos2, region1, region2, l1, l2, gc);
-
- if (from()->isHint() && to()->isHint())
- {
- // Between two hints -- don't draw anything
- return BoxPoint();
- }
-
- if (to()->isHint())
- {
- // Draw at hint position
- return to()->pos();
- }
-
- // Draw at mid-distance
- return l1 + (l2 - l1) / 2;
- }
-
- void LineGraphEdge::_print(ostream& os, const GraphGC &gc) const
- {
- if (from() == to())
- {
- printSelf(os, gc);
- return;
- }
-
- GraphEdge::_print(os, gc);
-
- // Print annotation
- if (annotation() != 0)
- {
- BoxPoint anno_pos = annotationPosition(gc);
- if (anno_pos.isValid())
- {
- annotation()->_print(os, anno_pos, gc);
- }
- }
- }
-