static Side crosside (BoxRegion ®ion, BoxPoint &p) { BoxPoint center = region.origin() + (region.space() / BoxPoint(2)) ; BoxPoint delta = center - p ; int side = North | South | East | West ; // exclude opposite side if (p[X] > center[X]) side &= ~West ; else side &= ~East ; if (p[Y] > center[Y]) side &= ~North ; else side &= ~South ; delta[X] = abs(delta[X]); delta[Y] = abs(delta[Y]); if (region.space(Y) * delta[X] > region.space(X) * delta[Y]) side &= ~(North | South); else side &= ~(East | West); return Side(side); }
// Draw void LineBox::_draw(Widget w, const BoxRegion& r, const BoxRegion& exposed, GC gc, bool context_selected) const { XGCValues gcvalues; // Set width and cap style; project beyond end point up to 1/2 // line thickness gcvalues.line_width = _linethickness; gcvalues.cap_style = CapProjecting; XChangeGC(XtDisplay(w), gc, GCLineWidth | GCCapStyle, &gcvalues); // Keep an empty frame of 1/2 line thickness around R (X may cross // R's boundaries otherwise) BoxPoint origin = r.origin(); BoxSize space = r.space(); origin += _linethickness / 2; space -= _linethickness; // Draw children __draw(w, BoxRegion(origin, space), exposed, gc, context_selected); // Attention: We leave LINE_WIDTH and CAP_STYLE changed! // (Works within Box::draw(), but the used GC may be changed) }
// Draw RuleBox void RuleBox::_draw(Widget w, const BoxRegion& r, const BoxRegion&, GC gc, bool) const { BoxSize space = r.space(); BoxPoint origin = r.origin(); BoxPoint width(extend(X) ? space[X] : size(X), extend(Y) ? space[Y] : size(Y)); if (width[Y] == 1) { // Horizontal line XDrawLine(XtDisplay(w), XtWindow(w), gc, origin[X], origin[Y], origin[X] + width[X], origin[Y]); } else if (width[X] == 1) { // Vertical line XDrawLine(XtDisplay(w), XtWindow(w), gc, origin[X], origin[Y], origin[X], origin[Y] + width[Y]); } else { // Rectangle XFillRectangle(XtDisplay(w), XtWindow(w), gc, origin[X], origin[Y], width[X], width[Y]); } }
// 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); }
// cleanRegion // clean a region with white ink // static void cleanRegion (std::ostream& os, const GraphGC& gc, BoxRegion region) { BoxPoint origin = region.origin(); BoxPoint width = region.space(); if (gc.printGC->isPostScript()) { os << origin[X] << " " << origin[Y] << " "; os << origin[X] + width[X] << " " << origin[Y]; os << " "; os << origin[X] + width[X] << " "; os << origin[Y] + width[Y] << " "; os << origin[X] << " " << origin[Y] + width[Y]; os << " clean*\n"; } else if (gc.printGC->isFig()) { os << CLEANHEAD; os << origin[X] << " " << origin[Y] << " "; os << origin[X] + width[X] << " " << origin[Y]; os << " "; os << origin[X] + width[X] << " "; os << origin[Y] + width[Y] << " "; os << origin[X] << " " << origin[Y] + width[Y]; os << " "; os << origin[X] << " "<< origin[Y] << " 9999 9999\n"; } }
static BoxPoint crosspoint (BoxRegion ®ion, BoxPoint &p) { int side = crosside (region, p); BoxDimension d1, d2; BoxPoint center = region.origin() + (region.space() / BoxPoint(2)) ; BoxPoint cross = center; int offset; offset = (side & (North | West)? -1 : 1) ; if (side & (North | South)) { d1 = X ; d2 = Y ; } else { d1 = Y ; d2 = X ; } if (center[d1] != p[d1] && center[d2] != p[d2]) { cross[d1] += offset * (region.space(d2) / 2) * ( center[d1] - p[d1]) / ( center[d2] - p[d2] ) ; } cross[d2] += offset * region.space(d2) / 2; return cross ; }
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); } }
// mark the following objects as one XFIG compound object static void startCompound(std::ostream& os, BoxRegion region) { BoxPoint origin = region.origin(); BoxPoint width = region.space(); os << CMPHEAD; os << origin[X] + width[X] + 1 << " " << origin[Y] - 1 << " "; os << origin[X] - 1 << " " << origin[Y] + width[Y] + 1 << "\n"; }
// Draw void RiseBox::__draw(Widget w, const BoxRegion& r, const BoxRegion&, GC gc, bool) const { BoxSize space = r.space(); BoxPoint origin = r.origin(); XDrawLine(XtDisplay(w), XtWindow(w), gc, origin[X], origin[Y] + space[Y], origin[X] + space[X], origin[Y]); }
// Print void HatBox::_print(std::ostream& os, const BoxRegion& region, const PrintGC& gc) const { BoxRegion childRegion = region; if (extend(X) == 0) childRegion.space(X) = size(X); if (extend(Y) == 0) childRegion.space(Y) = size(Y); _box->_print(os, childRegion, gc); }
// 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); } }
// Draw void HatBox::_draw(Widget w, const BoxRegion& r, const BoxRegion& exposed, GC gc, bool context_selected) const { BoxRegion childRegion = r; // If not extensible, shrink to minimal size if (extend(X) == 0) childRegion.space(X) = size(X); if (extend(Y) == 0) childRegion.space(Y) = size(Y); _box->draw(w, childRegion, exposed, gc, context_selected); }
// Print void RiseBox::_print(std::ostream& os, const BoxRegion& region, const PrintGC& gc) const { BoxPoint origin = region.origin(); BoxPoint space = region.space(); if (gc.isFig()) { os << LINEHEAD1 ; os << linethickness() << LINEHEAD2 ; os << origin[X] << " " << origin[Y] + space[Y] << " " ; os << origin[X] + space[X] << " " << origin[Y] << " " ; os << "9999 9999\n" ; } else if (gc.isPostScript()) { os << origin[X] << " " << origin[Y] + space[Y] << " " ; os << origin[X] + space[X] << " " << origin[Y] << " " ; os << linethickness() << " line*\n"; } }
// Draw a BoxGraphNode void BoxGraphNode::forceDraw(Widget w, const BoxRegion& /* exposed */, const GraphGC& gc) const { assert(box() != 0); // assert(box()->OK()); // We do not check for exposures here -- // boxes are usually small and partial display // doesn't work well with scrolling static BoxRegion exposed(BoxPoint(0, 0), BoxSize(INT_MAX, INT_MAX)); if (selected() && highlight()) { box()->draw(w, region(gc), exposed, gc.nodeGC, false); bool use_color = ColorBox::use_color; ColorBox::use_color = false; BoxRegion r = highlightRegion(gc); if (r <= exposed) { XFillRectangle(XtDisplay(w), XtWindow(w), gc.clearGC, r.origin(X), r.origin(Y), r.space(X), r.space(Y)); highlight()->draw(w, r, r, gc.nodeGC, false); } ColorBox::use_color = use_color; } else if (selected()) { bool use_color = ColorBox::use_color; ColorBox::use_color = false; box()->draw(w, region(gc), exposed, gc.nodeGC, false); ColorBox::use_color = use_color; } else { box()->draw(w, region(gc), exposed, gc.nodeGC, false); } }
// 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); } }
// Draw void StringBox::_draw(Widget w, const BoxRegion& r, const BoxRegion&, GC gc, bool) const { BoxPoint origin = r.origin(); if (_font != 0) XSetFont(XtDisplay(w), gc, _font->fid); XDrawString(XtDisplay(w), XtWindow(w), gc, origin[X], origin[Y] + _ascent, _string.chars(), _string.length()); }
// 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; }
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; }
// Draw DiagBox void DiagBox::_draw(Widget w, const BoxRegion& r, const BoxRegion& exposed, GC gc, bool context_selected) const { const BoxSize space = r.space(); const BoxPoint origin = r.origin(); // Draw a 10-pixel-grid BoxCoordinate i; for (i = 0; i < space[X]; i += 10) XDrawLine(XtDisplay(w), XtWindow(w), gc, origin[X] + i, origin[Y], origin[X] + i, origin[Y] + space[Y]); for (i = 0; i < space[Y]; i += 10) XDrawLine(XtDisplay(w), XtWindow(w), gc, origin[X], origin[Y] + i, origin[X] + space[X], origin[Y] + i); // Make space info std::ostringstream oss; oss << space << '\0'; const string ss(oss); // Draw it (centered) StringBox *s = new StringBox(ss); const BoxSize stringSize = s->size(); const BoxPoint stringOrigin = origin + space/2 - stringSize/2; XClearArea(XtDisplay(w), XtWindow(w), stringOrigin[X], stringOrigin[Y], stringSize[X], stringSize[Y], False); s->draw(w, BoxRegion(stringOrigin, stringSize), exposed, gc, context_selected); s->unlink(); }
void GraphEdge::_print(std::ostream& os, const GraphGC &gc) const { // Don't print if we're hidden if (hidden()) return; // Fetch the regions BoxRegion start = from()->region(gc); BoxRegion end = to()->region(gc); // Don't print edges with zero length if (start <= end) return; BoxPoint startc = start.origin() + (start.space() / BoxPoint(2)); BoxPoint endc = end.origin() + (end.space() / BoxPoint(2)); BoxPoint startp = crosspoint (start, endc); BoxPoint endp = crosspoint (end, startc); // This should come from gc.edgeGC BoxCoordinate line_width = 1; if (gc.printGC->isFig()) { if (!gc.drawArrowHeads || to()->isHint()) { os << EDGEHEAD1 << line_width; os << EDGEHEAD2 ; os << startp[X] << " " << startp[Y] << " " ; os << endp[X] << " " << endp[Y] << " " ; os << "9999 9999\n" ; } else { os << ARROWHEAD1 << line_width; os << ARROWHEAD2 ; os << startp[X] << " " << startp[Y] << " " ; os << endp[X] << " " << endp[Y] << " " ; os << "9999 9999\n" ; } } else if (gc.printGC->isPostScript()) { if (!gc.drawArrowHeads || to()->isHint()) { os << startp[X] << " " << startp[Y] << " " ; os << endp[X] << " " << endp[Y] << " " ; os << line_width << " line*\n"; } else { os << gc.arrowAngle << " " << gc.arrowLength << " "; os << startp[X] << " " << startp[Y] << " " ; os << endp[X] << " " << endp[Y] << " " ; os << line_width << " arrowline*\n"; } } }
void StringBox::_print(std::ostream& os, const BoxRegion& region, const PrintGC& gc) const { // Don't draw empty strings if (str().empty()) return; BoxPoint origin = region.origin() ; const FONTMAP *fmap = matchFont (fontName_c()); if (gc.isFig()) { os << TEXTHEAD1 << fmap->figfont << " " << size(Y) - 3 << " " << TEXTHEAD2 << size(X) << " " << size(Y) << " " << origin[X] << " " << origin [Y] + size(Y) - 2 << " " << str() << "\001\n"; } else if (gc.isPostScript()) { os << fmap->psfont << " " << size(X) << " " << size(Y) << " " << origin[X] << " " << origin[Y] + size(Y) << " " << "(" << pscook(str()) << ") text*\n"; } }
// 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); }
void Box::epsHeader (std::ostream& os, const BoxRegion& region, const PostScriptPrintGC& gc) { // check size of graph BoxPoint space = region.space(); BoxPoint origin = region.origin(); BoxPoint size; switch (gc.orientation) { case PostScriptPrintGC::PORTRAIT: size = BoxPoint(gc.hsize, gc.vsize); break; case PostScriptPrintGC::LANDSCAPE: size = BoxPoint(gc.vsize, gc.hsize); break; } double scale = 1.0; if (space > size) { // Scale down ... double hscale = double(size[X]) / region.space(X); double vscale = double(size[Y]) / region.space(Y); scale = (hscale < vscale ? hscale : vscale); space[X] = int(double(space[X]) * scale + 0.5); space[Y] = int(double(space[Y]) * scale + 0.5); origin[X] = int(double(origin[X]) * scale + 0.5); origin[Y] = int(double(origin[Y]) * scale + 0.5); } // Determine bounding box BoxPoint llcorner, urcorner; switch (gc.orientation) { case PostScriptPrintGC::PORTRAIT: llcorner = BoxPoint(gc.hoffset, gc.voffset); urcorner = BoxPoint(gc.hoffset + space[X], gc.voffset + space[Y]); break; case PostScriptPrintGC::LANDSCAPE: llcorner = BoxPoint(gc.hsize - space[Y] + gc.hoffset - gc.voffset, gc.hoffset); urcorner = BoxPoint(gc.hsize + gc.hoffset - gc.voffset, gc.hoffset + space[X]); break; } os << EPSHEAD << CREATOR << BOUND << llcorner[X] << " " << llcorner[Y] << " " << urcorner[X] << " " << urcorner[Y] << "\n" << PAGES << ENDC << "\ngsave\n"; // Write rotation if (gc.orientation == PostScriptPrintGC::LANDSCAPE) os << gc.hsize + gc.hoffset << " 0 translate 90 rotate\n"; // Write scaling int hmove = gc.hoffset - origin[X]; int vmove = gc.voffset + space[Y] + origin[Y]; os << hmove << " " << vmove << " translate\n" << scale << " " << -scale << " scale\n"; }
void RuleBox::_print(std::ostream& os, const BoxRegion& region, const PrintGC& gc) const { BoxSize space = region.space(); BoxPoint origin = region.origin(); BoxPoint width ; width = BoxPoint ( extend(X) ? space[X] : size(X) , extend(Y) ? space[Y] : size(Y) ); if (width == BoxPoint (0,1) || width == BoxPoint (1,0)) { return ; } if (width[X] && width[X] < 3 && gc.isFig()) { // // vertical Line // os << LINEHEAD1 ; os << width[X] << LINEHEAD2 ; os << origin[X] + width[X]/2 << " " << origin[Y] ; os << " " ; os << origin[X] + width[X]/2 << " " ; os << origin[Y] + width[Y] << " " ; os << "9999 9999\n" ; } else if (width[Y] && width[Y] < 3 && gc.isFig()) { // // horizontal line // os << LINEHEAD1 ; os << width[Y] << LINEHEAD2 ; os << origin[X] << " " << origin[Y]+width[Y]/2 ; os << " " ; os << origin[X] + width[X] << " " ; os << origin[Y] + width[Y]/2 << " " ; os << "9999 9999\n" ; } else { // // filled rectangle // if (gc.isFig()) { os << RULEHEAD ; os << origin[X] << " " << origin[Y] << " " ; os << origin[X] + width[X] << " " << origin[Y] ; os << " " ; os << origin[X] + width[X] << " " ; os << origin[Y] + width[Y] << " "; os << origin[X] << " " << origin[Y] + width[Y] ; os << " " ; os << origin[X] << " "<< origin[Y] << " 9999 9999\n" ; } else if (gc.isPostScript()) { os << origin[X] << " " << origin[Y] << " " ; os << origin[X] + width[X] << " " << origin[Y] ; os << " " ; os << origin[X] + width[X] << " " ; os << origin[Y] + width[Y] << " "; os << origin[X] << " " << origin[Y] + width[Y] ; os << " box*" << " %" << region << "\n"; ; } } }