bounds.UR.y = _points[1].y;
return bounds;
}
-
- pointf Ellipse::GetFirst() const
- {
- return _points[0];
- }
-
- pointf Ellipse::GetLast() const
- {
- return _points[1];
- }
-
- pointf Ellipse::GetCenter() const
- {
- /* only called for edges, so return a null point */
- pointf center = {0, 0};
- return center;
- }
-
- bool Ellipse::IsConnectable() const
+
+ Connection Ellipse::GetConnection() const
{
- /* cannot be a connector */
- return false;
+ Connection connection;
+ connection.connectable = false;
+ return connection;
}
Path::Path(pointf* points, int pointCount)
return bounds;
}
- pointf Path::GetFirst() const
- {
- return _points[0];
- }
-
- pointf Path::GetLast() const
- {
- return _points[_pointCount - 1];
- }
-
Bezier::Bezier(pointf* points, int pointCount, bool filled):
Path(points, pointCount),
_filled(filled)
{
}
- pointf Bezier::GetCenter() const
+ Connection Bezier::GetConnection() const
{
+ Connection connection;
+ connection.connectable = true;
+ connection.first = _points[0];
+ connection.last = _points[1];
if (_pointCount >= 4 && _pointCount % 2 == 0)
{
/* the central control polygon for the bezier curve */
pointf p3 = _points[_pointCount / 2 + 1];
/* use de Casteljou's algorithm to get a midpoint */
- pointf center;
- center.x = 0.125 * p0.x + 0.375 * p1.x + 0.375 * p2.x + 0.125 * p3.x;
- center.y = 0.125 * p0.y + 0.375 * p1.y + 0.375 * p2.y + 0.125 * p3.y;
- return center;
+ connection.center.x = 0.125 * p0.x + 0.375 * p1.x + 0.375 * p2.x + 0.125 * p3.x;
+ connection.center.y = 0.125 * p0.y + 0.375 * p1.y + 0.375 * p2.y + 0.125 * p3.y;
}
else
- /* just return the middle point */
- return _points[_pointCount / 2];
- }
-
- bool Bezier::IsConnectable() const
- {
- /* can be a connector */
- return true;
+ /* just return the middle point */
+ connection.center = _points[_pointCount / 2];
+
+ return connection;
}
void Bezier::Print(GVJ_t* job, pointf first, pointf last, bool allowCurves) const
{
}
- pointf Polygon::GetCenter() const
+ Connection Polygon::GetConnection() const
{
- /* should not get called, return a null point */
- pointf center = {0, 0};
- return center;
+ Connection connection;
+ connection.connectable = false;
+ return connection;
}
- bool Polygon::IsConnectable() const
- {
- /* cannot be a connector */
- return false;
- }
-
void Polygon::Print(GVJ_t* job, pointf first, pointf last, bool allowCurves) const
{
gvputs(job, "<Geom>\n");
{
}
- pointf Polyline::GetCenter() const
+ Connection Polyline::GetConnection() const
{
- if (_pointCount >= 2 && _pointCount % 2 == 0)
- {
- /* the center two points */
- pointf p0 = _points[_pointCount / 2 - 1];
- pointf p1 = _points[_pointCount / 2];
-
- /* take the midpoint */
- pointf center;
- center.x = (p0.x + p1.x) * 0.5;
- center.y = (p0.y + p1.y) * 0.5;
- return center;
- }
- else
- /* just return the middle point */
- return _points[_pointCount / 2];
- }
-
- bool Polyline::IsConnectable() const
- {
- /* cannot be a connector */
- return false;
+ Connection connection;
+ connection.connectable = false;
+ return connection;
}
void Polyline::Print(GVJ_t* job, pointf first, pointf last, bool allowCurves) const
return _geom->GetBounds();
}
- pointf Graphic::GetFirst() const
+ Connection Graphic::GetConnection() const
{
- return _geom->GetFirst();
+ return _geom->GetConnection();
}
-
- pointf Graphic::GetLast() const
- {
- return _geom->GetLast();
- }
-
- pointf Graphic::GetCenter() const
- {
- return _geom->GetCenter();
- }
-
- bool Graphic::IsConnectable() const
- {
- return _geom->IsConnectable();
- }
-
+
void Graphic::Print(GVJ_t* job, pointf first, pointf last, bool allowCurves) const
{
if (_line)
/* Geom VDX element */
+ struct Connection
+ {
+ bool connectable;
+ pointf first;
+ pointf last;
+ pointf center;
+ };
+
class Geom
{
public:
- virtual boxf GetBounds() const = 0; /* bounding box -- used by node logic */
- virtual pointf GetFirst() const = 0; /* first point -- used by edge logic */
- virtual pointf GetLast() const = 0; /* last point -- used by edge logic */
- virtual pointf GetCenter() const = 0; /* midpoint of the path -- used by text logic */
- virtual bool IsConnectable() const = 0; /* whether this geom can be turned into a connector -- used by edge logic */
+ virtual boxf GetBounds() const = 0; /* bounding box -- used by node logic */
+ virtual Connection GetConnection() const = 0; /* first, last and center points -- used by edge logic */
/* given first (lower left) and last points (upper right), output the geometry */
virtual void Print(GVJ_t* job, pointf first, pointf last, bool allowCurves) const = 0;
Ellipse(pointf* points, bool filled);
virtual boxf GetBounds() const;
- virtual pointf GetFirst() const;
- virtual pointf GetLast() const;
- virtual pointf GetCenter() const;
- virtual bool IsConnectable() const;
+ virtual Connection GetConnection() const;
void Print(GVJ_t* job, pointf first, pointf last, bool allowCurves) const;
~Path();
virtual boxf GetBounds() const;
- virtual pointf GetFirst() const;
- virtual pointf GetLast() const;
protected:
pointf* _points;
public:
Bezier(pointf* points, int pointCount, bool filled);
- virtual pointf GetCenter() const;
- virtual bool IsConnectable() const;
+ virtual Connection GetConnection() const;
virtual void Print(GVJ_t* job, pointf first, pointf last, bool allowCurves) const;
public:
Polygon(pointf* points, int pointCount, bool filled);
- virtual pointf GetCenter() const;
- virtual bool IsConnectable() const;
+ virtual Connection GetConnection() const;
virtual void Print(GVJ_t* job, pointf first, pointf last, bool allowCurves) const;
public:
Polyline(pointf* points, int pointCount);
- virtual pointf GetCenter() const;
- virtual bool IsConnectable() const;
+ virtual Connection GetConnection() const;
void Print(GVJ_t* job, pointf first, pointf last, bool allowCurves) const;
~Graphic();
boxf GetBounds() const;
- pointf GetFirst() const;
- pointf GetLast() const;
- pointf GetCenter() const;
- bool IsConnectable() const;
+ Connection GetConnection() const;
void Print(GVJ_t* job, pointf first, pointf last, bool allowCurves) const;
/* output first connectable shape as an edge shape, all else as regular outer shapes */
bool firstConnector = true;
for (Graphics::const_iterator nextGraphic = _graphics.begin(), lastGraphic = _graphics.end(); nextGraphic != lastGraphic; ++nextGraphic)
- if (firstConnector && (*nextGraphic)->IsConnectable())
- {
- PrintEdgeShape(job,
- _graphics[0],
- beginId == _nodeIds.end() ? 0 : beginId->second,
- endId == _nodeIds.end() ? 0 : endId->second,
- EDGE_TYPE(edge->head->graph->root));
+ if (firstConnector && PrintEdgeShape(job,
+ _graphics[0],
+ beginId == _nodeIds.end() ? 0 : beginId->second,
+ endId == _nodeIds.end() ? 0 : endId->second,
+ EDGE_TYPE(edge->head->graph->root)))
firstConnector = false;
- }
else
PrintOuterShape(job, *nextGraphic);
gvputs(job, "</Shape>\n");
}
- void Render::PrintEdgeShape(GVJ_t* job, Graphic* graphic, unsigned int beginId, unsigned int endId, int edgeType)
+ bool Render::PrintEdgeShape(GVJ_t* job, Graphic* graphic, unsigned int beginId, unsigned int endId, int edgeType)
{
- pointf first = graphic->GetFirst();
- pointf last = graphic->GetLast();
-
- bool zeroWidth = first.x == last.x;
- bool zeroHeight = first.y == last.y;
+ Connection connection = graphic->GetConnection();
+ if (connection.connectable)
+ {
+ bool zeroWidth = connection.first.x == connection.last.x;
+ bool zeroHeight = connection.first.y == connection.last.y;
- gvprintf(job, "<Shape ID='%d' Type='Shape'>\n", ++_shapeId);
-
- /* XForm depends on XForm1D */
- gvputs(job, "<XForm>\n");
- gvputs(job, "<PinX F='GUARD((BeginX+EndX)/2)'/>\n");
- gvputs(job, "<PinY F='GUARD((BeginY+EndY)/2)'/>\n");
- if (zeroWidth)
- gvprintf(job, "<Width F='GUARD(%f)'/>\n", 2 * ZERO_ADJUST); /* if vertical line, expand width to 0.25 inches */
- else
- gvputs(job, "<Width F='GUARD(EndX-BeginX)'/>\n");
- if (zeroHeight)
- gvprintf(job, "<Height F='GUARD(%f)'/>\n", 2 * ZERO_ADJUST); /* if horizontal line, expand height to 0.25 inches */
- else
- gvputs(job, "<Height F='GUARD(EndY-BeginY)'/>\n");
- gvputs(job, "<Angle F='GUARD(0DA)'/>\n");
- gvputs(job, "</XForm>\n");
+ gvprintf(job, "<Shape ID='%d' Type='Shape'>\n", ++_shapeId);
- /* XForm1D walking glue makes connector attach to its nodes */
- gvputs(job, "<XForm1D>\n");
- gvprintf(job, "<BeginX F='_WALKGLUE(BegTrigger,EndTrigger,WalkPreference)'>%f</BeginX>\n", first.x * INCHES_PER_POINT);
- gvprintf(job, "<BeginY F='_WALKGLUE(BegTrigger,EndTrigger,WalkPreference)'>%f</BeginY>\n", first.y * INCHES_PER_POINT);
- gvprintf(job, "<EndX F='_WALKGLUE(EndTrigger,BegTrigger,WalkPreference)'>%f</EndX>\n", last.x * INCHES_PER_POINT);
- gvprintf(job, "<EndY F='_WALKGLUE(EndTrigger,BegTrigger,WalkPreference)'>%f</EndY>\n", last.y * INCHES_PER_POINT);
- gvputs(job, "</XForm1D>\n");
-
- gvputs(job, "<Protection>\n");
- gvputs(job, "<LockHeight>1</LockHeight>\n");
- gvputs(job, "<LockCalcWH>1</LockCalcWH>\n");
- gvputs(job, "</Protection>\n");
-
- gvputs(job, "<Misc>\n");
- gvputs(job, "<NoAlignBox>1</NoAlignBox>\n");
- gvputs(job, "<DynFeedback>2</DynFeedback>\n");
- gvputs(job, "<GlueType>2</GlueType>\n");
- if (beginId && endId)
- {
- gvprintf(job, "<BegTrigger F='_XFTRIGGER(Sheet.%d!EventXFMod)'/>\n", beginId);
- gvprintf(job, "<EndTrigger F='_XFTRIGGER(Sheet.%d!EventXFMod)'/>\n", endId);
- }
- gvputs(job, "<ObjType>2</ObjType>\n");
- gvputs(job, "</Misc>\n");
-
- gvputs(job, "<Layout>\n");
- gvprintf(job, "<ShapeRouteStyle>%d</ShapeRouteStyle>\n", edgeType == ET_LINE ? LORouteCenterToCenter : LORouteRightAngle);
- gvputs(job, "<ConFixedCode>6</ConFixedCode>\n");
- gvprintf(job, "<ConLineRouteExt>%d</ConLineRouteExt>\n", edgeType == ET_LINE || edgeType == ET_PLINE ? LORouteExtStraight : LORouteExtNURBS);
- gvputs(job, "<ShapeSplittable>1</ShapeSplittable>\n");
- gvputs(job, "</Layout>\n");
-
- /* output Hyperlink */
- PrintHyperlinks(job);
+ /* XForm depends on XForm1D */
+ gvputs(job, "<XForm>\n");
+ gvputs(job, "<PinX F='GUARD((BeginX+EndX)/2)'/>\n");
+ gvputs(job, "<PinY F='GUARD((BeginY+EndY)/2)'/>\n");
+ if (zeroWidth)
+ gvprintf(job, "<Width F='GUARD(%f)'/>\n", 2 * ZERO_ADJUST); /* if vertical line, expand width to 0.25 inches */
+ else
+ gvputs(job, "<Width F='GUARD(EndX-BeginX)'/>\n");
+ if (zeroHeight)
+ gvprintf(job, "<Height F='GUARD(%f)'/>\n", 2 * ZERO_ADJUST); /* if horizontal line, expand height to 0.25 inches */
+ else
+ gvputs(job, "<Height F='GUARD(EndY-BeginY)'/>\n");
+ gvputs(job, "<Angle F='GUARD(0DA)'/>\n");
+ gvputs(job, "</XForm>\n");
+
+ /* XForm1D walking glue makes connector attach to its nodes */
+ gvputs(job, "<XForm1D>\n");
+ gvprintf(job, "<BeginX F='_WALKGLUE(BegTrigger,EndTrigger,WalkPreference)'>%f</BeginX>\n", connection.first.x * INCHES_PER_POINT);
+ gvprintf(job, "<BeginY F='_WALKGLUE(BegTrigger,EndTrigger,WalkPreference)'>%f</BeginY>\n", connection.first.y * INCHES_PER_POINT);
+ gvprintf(job, "<EndX F='_WALKGLUE(EndTrigger,BegTrigger,WalkPreference)'>%f</EndX>\n", connection.last.x * INCHES_PER_POINT);
+ gvprintf(job, "<EndY F='_WALKGLUE(EndTrigger,BegTrigger,WalkPreference)'>%f</EndY>\n", connection.last.y * INCHES_PER_POINT);
+ gvputs(job, "</XForm1D>\n");
+
+ gvputs(job, "<Protection>\n");
+ gvputs(job, "<LockHeight>1</LockHeight>\n");
+ gvputs(job, "<LockCalcWH>1</LockCalcWH>\n");
+ gvputs(job, "</Protection>\n");
+
+ gvputs(job, "<Misc>\n");
+ gvputs(job, "<NoAlignBox>1</NoAlignBox>\n");
+ gvputs(job, "<DynFeedback>2</DynFeedback>\n");
+ gvputs(job, "<GlueType>2</GlueType>\n");
+ if (beginId && endId)
+ {
+ gvprintf(job, "<BegTrigger F='_XFTRIGGER(Sheet.%d!EventXFMod)'/>\n", beginId);
+ gvprintf(job, "<EndTrigger F='_XFTRIGGER(Sheet.%d!EventXFMod)'/>\n", endId);
+ }
+ gvputs(job, "<ObjType>2</ObjType>\n");
+ gvputs(job, "</Misc>\n");
+
+ gvputs(job, "<Layout>\n");
+ gvprintf(job, "<ShapeRouteStyle>%d</ShapeRouteStyle>\n", edgeType == ET_LINE ? LORouteCenterToCenter : LORouteRightAngle);
+ gvputs(job, "<ConFixedCode>6</ConFixedCode>\n");
+ gvprintf(job, "<ConLineRouteExt>%d</ConLineRouteExt>\n", edgeType == ET_LINE || edgeType == ET_PLINE ? LORouteExtStraight : LORouteExtNURBS);
+ gvputs(job, "<ShapeSplittable>1</ShapeSplittable>\n");
+ gvputs(job, "</Layout>\n");
+
+ /* output Hyperlink */
+ PrintHyperlinks(job);
- /* TextXForm depends on custom control */
- gvputs(job, "<TextXForm>\n");
- gvputs(job, "<TxtPinX F='SETATREF(Controls.TextPosition)'/>\n");
- gvputs(job, "<TxtPinY F='SETATREF(Controls.TextPosition.Y)'/>\n");
- gvputs(job, "<TxtWidth F='MAX(TEXTWIDTH(TheText),5*Char.Size)'/>\n");
- gvputs(job, "<TxtHeight F='TEXTHEIGHT(TheText,TxtWidth)'/>\n");
- gvputs(job, "</TextXForm>\n");
+ /* TextXForm depends on custom control */
+ gvputs(job, "<TextXForm>\n");
+ gvputs(job, "<TxtPinX F='SETATREF(Controls.TextPosition)'/>\n");
+ gvputs(job, "<TxtPinY F='SETATREF(Controls.TextPosition.Y)'/>\n");
+ gvputs(job, "<TxtWidth F='MAX(TEXTWIDTH(TheText),5*Char.Size)'/>\n");
+ gvputs(job, "<TxtHeight F='TEXTHEIGHT(TheText,TxtWidth)'/>\n");
+ gvputs(job, "</TextXForm>\n");
- if (zeroWidth)
- {
- first.x -= ZERO_ADJUST;
- last.x += ZERO_ADJUST;
- }
- if (zeroHeight)
- {
- first.y -= ZERO_ADJUST;
- last.y += ZERO_ADJUST;
- }
-
- /* compute center to attach text to. if text has been rendered, use overall bounding box center; if not, use the path center */
- pointf textCenter;
- if (_texts.size() > 0)
- {
- boxf outerTextBounds = _texts[0]->GetBounds();
+ if (zeroWidth)
+ {
+ connection.first.x -= ZERO_ADJUST;
+ connection.last.x += ZERO_ADJUST;
+ }
+ if (zeroHeight)
+ {
+ connection.first.y -= ZERO_ADJUST;
+ connection.last.y += ZERO_ADJUST;
+ }
- for (Texts::const_iterator nextText = _texts.begin() + 1, lastText = _texts.end();
- nextText != lastText;
- ++nextText)
+ /* compute center to attach text to. if text has been rendered, use overall bounding box center; if not, use the path center */
+ pointf textCenter;
+ if (_texts.size() > 0)
{
- boxf innerTextBounds = (*nextText)->GetBounds();
- if (outerTextBounds.LL.x > innerTextBounds.LL.x)
- outerTextBounds.LL.x = innerTextBounds.LL.x;
- if (outerTextBounds.LL.y > innerTextBounds.LL.y)
- outerTextBounds.LL.y = innerTextBounds.LL.y;
- if (outerTextBounds.UR.x < innerTextBounds.UR.x)
- outerTextBounds.UR.x = innerTextBounds.UR.x;
- if (outerTextBounds.UR.y < innerTextBounds.UR.y)
- outerTextBounds.UR.y = innerTextBounds.UR.y;
+ boxf outerTextBounds = _texts[0]->GetBounds();
+
+ for (Texts::const_iterator nextText = _texts.begin() + 1, lastText = _texts.end();
+ nextText != lastText;
+ ++nextText)
+ {
+ boxf innerTextBounds = (*nextText)->GetBounds();
+ if (outerTextBounds.LL.x > innerTextBounds.LL.x)
+ outerTextBounds.LL.x = innerTextBounds.LL.x;
+ if (outerTextBounds.LL.y > innerTextBounds.LL.y)
+ outerTextBounds.LL.y = innerTextBounds.LL.y;
+ if (outerTextBounds.UR.x < innerTextBounds.UR.x)
+ outerTextBounds.UR.x = innerTextBounds.UR.x;
+ if (outerTextBounds.UR.y < innerTextBounds.UR.y)
+ outerTextBounds.UR.y = innerTextBounds.UR.y;
+ }
+ textCenter.x = (outerTextBounds.LL.x + outerTextBounds.UR.x) / 2.0;
+ textCenter.y = (outerTextBounds.LL.y + outerTextBounds.UR.y) / 2.0;
}
- textCenter.x = (outerTextBounds.LL.x + outerTextBounds.UR.x) / 2.0;
- textCenter.y = (outerTextBounds.LL.y + outerTextBounds.UR.y) / 2.0;
- }
- else
- textCenter = graphic->GetCenter();
-
- /* Control for positioning text */
- gvputs(job, "<Control NameU='TextPosition'>\n");
- gvprintf(job, "<X>%f</X>\n", (textCenter.x - first.x) * INCHES_PER_POINT);
- gvprintf(job, "<Y>%f</Y>\n", (textCenter.y - first.y) * INCHES_PER_POINT);
- gvputs(job, "<XDyn F='Controls.TextPosition'/>\n");
- gvputs(job, "<YDyn F='Controls.TextPosition.Y'/>\n");
- gvputs(job, "<XCon F='IF(OR(STRSAME(SHAPETEXT(TheText),""),HideText),5,0)'>5</XCon>\n");
- gvputs(job, "<YCon>0</YCon>\n");
- gvputs(job, "</Control>\n");
+ else
+ textCenter = connection.center;
- /* output Para, Char, Text */
- PrintTexts(job);
-
- /* output Line, Fill, Geom */
- graphic->Print(job, first, last, edgeType != ET_LINE && edgeType != ET_PLINE);
-
- gvputs(job, "</Shape>\n");
+ /* Control for positioning text */
+ gvputs(job, "<Control NameU='TextPosition'>\n");
+ gvprintf(job, "<X>%f</X>\n", (textCenter.x - connection.first.x) * INCHES_PER_POINT);
+ gvprintf(job, "<Y>%f</Y>\n", (textCenter.y - connection.first.y) * INCHES_PER_POINT);
+ gvputs(job, "<XDyn F='Controls.TextPosition'/>\n");
+ gvputs(job, "<YDyn F='Controls.TextPosition.Y'/>\n");
+ gvputs(job, "<XCon F='IF(OR(STRSAME(SHAPETEXT(TheText),""),HideText),5,0)'>5</XCon>\n");
+ gvputs(job, "<YCon>0</YCon>\n");
+ gvputs(job, "</Control>\n");
+
+ /* output Para, Char, Text */
+ PrintTexts(job);
+
+ /* output Line, Fill, Geom */
+ graphic->Print(job, connection.first, connection.last, edgeType != ET_LINE && edgeType != ET_PLINE);
+
+ gvputs(job, "</Shape>\n");
+ }
+ return connection.connectable;
}
void Render::PrintTexts(GVJ_t* job)