GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — updated arrow rendering code · ogdf/ogdf-python@b187c50

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
  • src/ogdf_python/matplotlib
    • rendering.h
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎src/ogdf_python/matplotlib/rendering.h‎

Copy file name to clipboardExpand all lines: src/ogdf_python/matplotlib/rendering.h
+167-159Lines changed: 167 additions & 159 deletions
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,8 @@ namespace ogdf {
8989
}
9090
}
9191

92-
bool isPointCoveredByNode(const DPoint &point, const DPoint &v, const DPoint &vSize,
93-
const Shape &shape) {
92+
bool isPointCoveredByNode(const DPoint& point, const DPoint& v, const DPoint& vSize,
93+
const Shape& shape) {
9494
const double epsilon = 1e-6;
9595
const double trapeziumWidthOffset = vSize.m_x * 0.275;
9696
GenericPolyline<DPoint> polygon;
@@ -101,8 +101,8 @@ namespace ogdf {
101101
DPoint edgePt2 = v + *polygon.get((i + 1) % polygon.size());
102102

103103
if ((edgePt2.m_x - edgePt1.m_x) * (point.m_y - edgePt1.m_y)
104-
- (edgePt2.m_y - edgePt1.m_y) * (point.m_x - edgePt1.m_x)
105-
< -epsilon) {
104+
- (edgePt2.m_y - edgePt1.m_y) * (point.m_x - edgePt1.m_x)
105+
< -epsilon) {
106106
return false;
107107
}
108108
}
@@ -113,81 +113,82 @@ namespace ogdf {
113113
polygon.clear();
114114
double radius = (max(vSize.m_x, vSize.m_y) / 2.0);
115115
for (double angle = -(Math::pi / 2) + Math::pi / sides; angle < 1.5 * Math::pi;
116-
angle += 2.0 * Math::pi / sides) {
116+
angle += 2.0 * Math::pi / sides) {
117117
polygon.pushBack(DPoint(radius * cos(angle), radius * sin(angle)));
118118
}
119119
return isInConvexCCWPolygon();
120120
};
121121

122122
switch (shape) {
123-
// currently these tikz polygons are only supported as regular polygons, i.e. width=height
124-
case Shape::Pentagon:
125-
return isInRegularPolygon(5);
126-
case Shape::Hexagon:
127-
return isInRegularPolygon(6);
128-
case Shape::Octagon:
129-
return isInRegularPolygon(8);
130-
case Shape::Triangle:
131-
return isInRegularPolygon(3);
132-
// Non-regular polygons
133-
case Shape::InvTriangle:
134-
polygon.pushBack(DPoint(0, -vSize.m_y * 2.0 / 3.0));
135-
polygon.pushBack(DPoint(vSize.m_x / 2.0, vSize.m_y * 1.0 / 3.0));
136-
polygon.pushBack(DPoint(-vSize.m_x / 2.0, vSize.m_y * 1.0 / 3.0));
137-
return isInConvexCCWPolygon();
138-
case Shape::Rhomb:
139-
polygon.pushBack(DPoint(vSize.m_x / 2.0, 0));
140-
polygon.pushBack(DPoint(0, vSize.m_y / 2.0));
141-
polygon.pushBack(DPoint(-vSize.m_x / 2.0, 0));
142-
polygon.pushBack(DPoint(0, -vSize.m_y / 2.0));
143-
return isInConvexCCWPolygon();
144-
case Shape::Trapeze:
145-
polygon.pushBack(DPoint(-vSize.m_x / 2.0, -vSize.m_y / 2.0));
146-
polygon.pushBack(DPoint(vSize.m_x / 2.0, -vSize.m_y / 2.0));
147-
polygon.pushBack(DPoint(vSize.m_x / 2.0 - trapeziumWidthOffset, +vSize.m_y / 2.0));
148-
polygon.pushBack(DPoint(-vSize.m_x / 2.0 + trapeziumWidthOffset, +vSize.m_y / 2.0));
149-
return isInConvexCCWPolygon();
150-
case Shape::InvTrapeze:
151-
polygon.pushBack(DPoint(vSize.m_x / 2.0, vSize.m_y / 2.0));
152-
polygon.pushBack(DPoint(-vSize.m_x / 2.0, vSize.m_y / 2.0));
153-
polygon.pushBack(DPoint(-vSize.m_x / 2.0 + trapeziumWidthOffset, -vSize.m_y / 2.0));
154-
polygon.pushBack(DPoint(vSize.m_x / 2.0 - trapeziumWidthOffset, -vSize.m_y / 2.0));
155-
return isInConvexCCWPolygon();
156-
case Shape::Parallelogram:
157-
polygon.pushBack(DPoint(-vSize.m_x / 2.0, -vSize.m_y / 2.0));
158-
polygon.pushBack(DPoint(vSize.m_x / 2.0 - trapeziumWidthOffset, -vSize.m_y / 2.0));
159-
polygon.pushBack(DPoint(vSize.m_x / 2.0, +vSize.m_y / 2.0));
160-
polygon.pushBack(DPoint(-vSize.m_x / 2.0 + trapeziumWidthOffset, +vSize.m_y / 2.0));
161-
return isInConvexCCWPolygon();
162-
case Shape::InvParallelogram:
163-
polygon.pushBack(DPoint(-vSize.m_x / 2.0 + trapeziumWidthOffset, -vSize.m_y / 2.0));
164-
polygon.pushBack(DPoint(vSize.m_x / 2.0, -vSize.m_y / 2.0));
165-
polygon.pushBack(DPoint(vSize.m_x / 2.0 - trapeziumWidthOffset, vSize.m_y / 2.0));
166-
polygon.pushBack(DPoint(-vSize.m_x / 2.0, vSize.m_y / 2.0));
167-
return isInConvexCCWPolygon();
168-
// Ellipse
169-
case Shape::Ellipse:
170-
return pow((point.m_x - v.m_x) / (vSize.m_x * 0.5), 2)
171-
+ pow((point.m_y - v.m_y) / (vSize.m_y * 0.5), 2)
172-
< 1;
173-
// Simple x y comparison
174-
case Shape::Rect:
175-
case Shape::RoundedRect:
176-
default:
177-
return point.m_x + epsilon >= v.m_x - vSize.m_x / 2.0
178-
&& point.m_x - epsilon <= v.m_x + vSize.m_x / 2.0
179-
&& point.m_y + epsilon >= v.m_y - vSize.m_y / 2.0
180-
&& point.m_y - epsilon <= v.m_y + vSize.m_y / 2.0;
123+
// currently these tikz polygons are only supported as regular polygons, i.e. width=height
124+
case Shape::Pentagon:
125+
return isInRegularPolygon(5);
126+
case Shape::Hexagon:
127+
return isInRegularPolygon(6);
128+
case Shape::Octagon:
129+
return isInRegularPolygon(8);
130+
case Shape::Triangle:
131+
return isInRegularPolygon(3);
132+
// Non-regular polygons
133+
case Shape::InvTriangle:
134+
polygon.pushBack(DPoint(0, -vSize.m_y * 2.0 / 3.0));
135+
polygon.pushBack(DPoint(vSize.m_x / 2.0, vSize.m_y * 1.0 / 3.0));
136+
polygon.pushBack(DPoint(-vSize.m_x / 2.0, vSize.m_y * 1.0 / 3.0));
137+
return isInConvexCCWPolygon();
138+
case Shape::Rhomb:
139+
polygon.pushBack(DPoint(vSize.m_x / 2.0, 0));
140+
polygon.pushBack(DPoint(0, vSize.m_y / 2.0));
141+
polygon.pushBack(DPoint(-vSize.m_x / 2.0, 0));
142+
polygon.pushBack(DPoint(0, -vSize.m_y / 2.0));
143+
return isInConvexCCWPolygon();
144+
case Shape::Trapeze:
145+
polygon.pushBack(DPoint(-vSize.m_x / 2.0, -vSize.m_y / 2.0));
146+
polygon.pushBack(DPoint(vSize.m_x / 2.0, -vSize.m_y / 2.0));
147+
polygon.pushBack(DPoint(vSize.m_x / 2.0 - trapeziumWidthOffset, +vSize.m_y / 2.0));
148+
polygon.pushBack(DPoint(-vSize.m_x / 2.0 + trapeziumWidthOffset, +vSize.m_y / 2.0));
149+
return isInConvexCCWPolygon();
150+
case Shape::InvTrapeze:
151+
polygon.pushBack(DPoint(vSize.m_x / 2.0, vSize.m_y / 2.0));
152+
polygon.pushBack(DPoint(-vSize.m_x / 2.0, vSize.m_y / 2.0));
153+
polygon.pushBack(DPoint(-vSize.m_x / 2.0 + trapeziumWidthOffset, -vSize.m_y / 2.0));
154+
polygon.pushBack(DPoint(vSize.m_x / 2.0 - trapeziumWidthOffset, -vSize.m_y / 2.0));
155+
return isInConvexCCWPolygon();
156+
case Shape::Parallelogram:
157+
polygon.pushBack(DPoint(-vSize.m_x / 2.0, -vSize.m_y / 2.0));
158+
polygon.pushBack(DPoint(vSize.m_x / 2.0 - trapeziumWidthOffset, -vSize.m_y / 2.0));
159+
polygon.pushBack(DPoint(vSize.m_x / 2.0, +vSize.m_y / 2.0));
160+
polygon.pushBack(DPoint(-vSize.m_x / 2.0 + trapeziumWidthOffset, +vSize.m_y / 2.0));
161+
return isInConvexCCWPolygon();
162+
case Shape::InvParallelogram:
163+
polygon.pushBack(DPoint(-vSize.m_x / 2.0 + trapeziumWidthOffset, -vSize.m_y / 2.0));
164+
polygon.pushBack(DPoint(vSize.m_x / 2.0, -vSize.m_y / 2.0));
165+
polygon.pushBack(DPoint(vSize.m_x / 2.0 - trapeziumWidthOffset, vSize.m_y / 2.0));
166+
polygon.pushBack(DPoint(-vSize.m_x / 2.0, vSize.m_y / 2.0));
167+
return isInConvexCCWPolygon();
168+
// Ellipse
169+
case Shape::Ellipse:
170+
return pow((point.m_x - v.m_x) / (vSize.m_x * 0.5), 2)
171+
+ pow((point.m_y - v.m_y) / (vSize.m_y * 0.5), 2)
172+
< 1;
173+
// Simple x y comparison
174+
case Shape::Rect:
175+
case Shape::RoundedRect:
176+
default:
177+
return point.m_x + epsilon >= v.m_x - vSize.m_x / 2.0
178+
&& point.m_x - epsilon <= v.m_x + vSize.m_x / 2.0
179+
&& point.m_y + epsilon >= v.m_y - vSize.m_y / 2.0
180+
&& point.m_y - epsilon <= v.m_y + vSize.m_y / 2.0;
181181
}
182182
}
183183

184-
DPoint contourPointFromAngle(double angle, int n, double rotationOffset, DPoint center, DPoint vSize) {
184+
DPoint contourPointFromAngle(double angle, int n, double rotationOffset, const DPoint& center,
185+
const DPoint& vSize) {
185186
// math visualised: https://www.desmos.com/calculator/j6iktd7fs4
186187
double nOffset = floor((angle - rotationOffset) / (2 * Math::pi / n)) * 2 * Math::pi / n;
187188
double polyLineStartAngle = rotationOffset + nOffset;
188189
double polyLineEndAngle = polyLineStartAngle + 2 * Math::pi / n;
189190
DLine polyLine = DLine(-cos(polyLineStartAngle), -sin(polyLineStartAngle),
190-
-cos(polyLineEndAngle), -sin(polyLineEndAngle));
191+
-cos(polyLineEndAngle), -sin(polyLineEndAngle));
191192

192193
DLine originLine = DLine(0, 0, cos(angle), sin(angle));
193194

@@ -197,81 +198,76 @@ namespace ogdf {
197198
return intersectionPoint + center;
198199
}
199200

200-
DPoint contourPointFromAngle(double angle, Shape shape, DPoint center, DPoint vSize) {
201+
DPoint contourPointFromAngle(double angle, Shape shape, const DPoint& center, const DPoint& vSize) {
201202
angle = std::fmod(angle, 2 * Math::pi);
202203
if (angle < 0) {
203204
angle += Math::pi * 2;
204205
}
205206

206207
switch (shape) {
207-
case Shape::Triangle:
208-
return contourPointFromAngle(angle, 3, Math::pi / 2, center, vSize);
209-
case Shape::InvTriangle:
210-
return contourPointFromAngle(angle + Math::pi, Shape::Triangle, DPoint(), vSize) * -1
211-
+ center;
212-
case Shape::Image:
213-
case Shape::RoundedRect:
214-
case Shape::Rect:
215-
return contourPointFromAngle(angle, 4, Math::pi / 4, center, vSize / sqrt(2));
216-
case Shape::Pentagon:
217-
return contourPointFromAngle(angle, 5, Math::pi / 2, center, vSize);
218-
case Shape::Hexagon:
219-
return contourPointFromAngle(angle, 6, 0, center, vSize);
220-
case Shape::Octagon:
221-
return contourPointFromAngle(angle, 8, Math::pi / 8, center, vSize);
222-
case Shape::Rhomb:
223-
return contourPointFromAngle(angle, 4, Math::pi / 2, center, vSize);
224-
case Shape::Trapeze:
225-
if (angle < atan(2) || angle >= Math::pi * 7 / 4) {
226-
DPoint other = contourPointFromAngle(Math::pi - angle, Shape::Trapeze, DPoint(), vSize);
227-
other.m_x *= -1;
228-
return other + center;
229-
} else if (angle < Math::pi - atan(2)) {
230-
return contourPointFromAngle(angle, Shape::Rect, center, vSize);
231-
} else if (angle < Math::pi * 5 / 4) {
232-
DLine tLine = DLine(.5, -1, 1, 1);
233-
DLine eLine = DLine(0, 0, 2 * cos(angle), 2 * sin(angle));
234-
DPoint iPoint;
235-
tLine.intersection(eLine, iPoint);
236-
iPoint = DPoint(iPoint.m_x * vSize.m_x, iPoint.m_y * vSize.m_y);
237-
return iPoint + center;
238-
}
239-
if (angle < Math::pi * 7 / 4) {
240-
return contourPointFromAngle(angle, Shape::Rect, center, vSize);
241-
}
242-
return DPoint(); // Execution will never reach this point but it reduces warnings.
243-
case Shape::InvTrapeze:
244-
return contourPointFromAngle(angle + Math::pi, Shape::Trapeze, DPoint(), vSize) * -1 + center;
245-
case Shape::Parallelogram:
246-
if (angle < atan(2) || angle > Math::pi * 7 / 4) {
247-
DLine tLine = DLine(-.5, -1, -1, 1);
248-
DLine eLine = DLine(0, 0, 2 * cos(angle), 2 * sin(angle));
249-
DPoint iPoint;
250-
tLine.intersection(eLine, iPoint);
251-
iPoint = DPoint(iPoint.m_x * vSize.m_x, iPoint.m_y * vSize.m_y);
252-
return iPoint + center;
253-
} else if (angle < Math::pi * 3 / 4) {
254-
return contourPointFromAngle(angle, Shape::Rect, center, vSize);
255-
} else if (angle < Math::pi + atan(2)) {
256-
DLine tLine = DLine(.5, 1, 1, -1);
257-
DLine eLine = DLine(0, 0, 2 * cos(angle), 2 * sin(angle));
258-
DPoint iPoint;
259-
tLine.intersection(eLine, iPoint);
260-
iPoint = DPoint(iPoint.m_x * vSize.m_x, iPoint.m_y * vSize.m_y);
261-
return iPoint + center;
262-
}
263-
if (angle < Math::pi * 7 / 4) {
264-
return contourPointFromAngle(angle, Shape::Rect, center, vSize);
265-
}
266-
return DPoint(); // Execution will never reach this point but it reduces warnings.
267-
case Shape::InvParallelogram: {
268-
DPoint p = contourPointFromAngle(Math::pi - angle, Shape::Parallelogram, DPoint(), vSize);
269-
p.m_x *= -1;
270-
return p + center;
208+
case Shape::Triangle:
209+
return contourPointFromAngle(angle, 3, Math::pi / 2, center, vSize * .5);
210+
case Shape::InvTriangle:
211+
return center - contourPointFromAngle(angle + Math::pi, Shape::Triangle, DPoint(), vSize);
212+
case Shape::Image:
213+
case Shape::RoundedRect:
214+
case Shape::Rect:
215+
return contourPointFromAngle(angle, 4, Math::pi / 4, center, vSize / sqrt(2));
216+
case Shape::Pentagon:
217+
return contourPointFromAngle(angle, 5, Math::pi / 2, center, vSize / 2);
218+
case Shape::Hexagon:
219+
return contourPointFromAngle(angle, 6, 0, center, vSize / 2);
220+
case Shape::Octagon:
221+
return contourPointFromAngle(angle, 8, Math::pi / 8, center, vSize / 2);
222+
case Shape::Rhomb:
223+
return contourPointFromAngle(angle, 4, Math::pi / 2, center, vSize / 2);
224+
case Shape::Trapeze:
225+
if (angle < atan(2) || angle >= Math::pi * 7 / 4) {
226+
DPoint other = contourPointFromAngle(Math::pi - angle, Shape::Trapeze, DPoint(), vSize);
227+
other.m_x *= -1;
228+
return other + center;
229+
} else if (angle < Math::pi - atan(2)) {
230+
return contourPointFromAngle(angle, Shape::Rect, center, vSize);
231+
} else if (angle < Math::pi * 5 / 4) {
232+
DLine tLine = DLine(.5, -1, 1, 1);
233+
DLine eLine = DLine(0, 0, 2 * cos(angle), 2 * sin(angle));
234+
DPoint iPoint;
235+
tLine.intersection(eLine, iPoint);
236+
iPoint = DPoint(iPoint.m_x * vSize.m_x * .5, iPoint.m_y * vSize.m_y * .5);
237+
return iPoint + center;
238+
} else { // angle < Math::pi * 7 / 4
239+
return contourPointFromAngle(angle, Shape::Rect, center, vSize);
271240
}
272-
case Shape::Ellipse:
273-
default:
274-
return DPoint(-vSize.m_x * cos(angle), -vSize.m_y * sin(angle)) + center;
241+
case Shape::InvTrapeze:
242+
return center - contourPointFromAngle(angle + Math::pi, Shape::Trapeze, DPoint(), vSize);
243+
case Shape::Parallelogram:
244+
if (angle < atan(2) || angle > Math::pi * 7 / 4) {
245+
DLine tLine = DLine(-.5, -1, -1, 1);
246+
DLine eLine = DLine(0, 0, 2 * cos(angle), 2 * sin(angle));
247+
DPoint iPoint;
248+
tLine.intersection(eLine, iPoint);
249+
iPoint = DPoint(iPoint.m_x * vSize.m_x * .5, iPoint.m_y * vSize.m_y * .5);
250+
return iPoint + center;
251+
} else if (angle < Math::pi * 3 / 4) {
252+
return contourPointFromAngle(angle, Shape::Rect, center, vSize);
253+
} else if (angle < Math::pi + atan(2)) {
254+
DLine tLine = DLine(.5, 1, 1, -1);
255+
DLine eLine = DLine(0, 0, 2 * cos(angle), 2 * sin(angle));
256+
DPoint iPoint;
257+
tLine.intersection(eLine, iPoint);
258+
iPoint = DPoint(iPoint.m_x * vSize.m_x * .5, iPoint.m_y * vSize.m_y * .5);
259+
return iPoint + center;
260+
} else { // angle < Math::pi * 7 / 4
261+
return contourPointFromAngle(angle, Shape::Rect, center, vSize);
262+
}
263+
case Shape::InvParallelogram: {
264+
DPoint p = contourPointFromAngle(Math::pi - angle, Shape::Parallelogram, DPoint(), vSize);
265+
p.m_x *= -1;
266+
return p + center;
267+
}
268+
case Shape::Ellipse:
269+
default:
270+
return DPoint(-vSize.m_x * .5 * cos(angle), -vSize.m_y * .5 * sin(angle)) + center;
275271
}
276272
}
277273

@@ -327,40 +323,52 @@ namespace ogdf {
327323
const double dy = end.m_y - start.m_y;
328324
const double size = getArrowSize(m_attr, adj);
329325
node v = adj->theNode();
330-
326+
331327
DPolyline poly;
332328
if (dx == 0) {
333329
int sign = dy > 0 ? 1 : -1;
334330
double y = m_attr.y(v) - m_attr.height(v) / 2 * sign;
335331
end.m_y = y - sign * size;
336-
337-
append({end.m_x, y, end.m_x - size / 4, end.m_y, end.m_x + size / 4, end.m_y}, poly);
332+
333+
append({end.m_x, y, end.m_x - size / 4, y - size * sign,
334+
end.m_x + size / 4, y - size * sign}, poly);
338335
} else {
339336
// identify the position of the tip
340-
float angle = atan(dy / dx) + (dx < 0 ? Math::pi : 0);
341-
DPoint head = contourPointFromAngle(angle, m_attr.shape(v),
342-
DPoint(m_attr.x(v), m_attr.y(v)),
343-
DPoint(m_attr.width(v), m_attr.height(v)));
344-
345-
end.m_x = head.m_x;
346-
end.m_y = head.m_y;
347-
337+
double slope = dy / dx;
338+
int sign = dx > 0 ? 1 : -1;
339+
340+
double x = m_attr.x(v) - m_attr.width(v) / 2 * sign;
341+
double delta = x - start.m_x;
342+
double y = start.m_y + delta * slope;
343+
344+
if (!isCoveredBy(m_attr, DPoint(x, y), adj)) {
345+
sign = dy > 0 ? 1 : -1;
346+
y = m_attr.y(v) - m_attr.height(v) / 2 * sign;
347+
delta = y - start.m_y;
348+
x = start.m_x + delta / slope;
349+
}
350+
351+
end.m_x = x;
352+
end.m_y = y;
353+
348354
// draw the actual arrow head
349-
350-
double length = std::sqrt(dx * dx + dy * dy);
351-
double dx_norm = dx / length;
352-
double dy_norm = dy / length;
353-
354-
double mx = head.m_x - size * dx_norm;
355-
double my = head.m_y - size * dy_norm;
356-
357-
double x2 = mx - size / 4 * dy_norm;
358-
double y2 = my + size / 4 * dx_norm;
359-
360-
double x3 = mx + size / 4 * dy_norm;
361-
double y3 = my - size / 4 * dx_norm;
362-
363-
append({head.m_x, head.m_y, x2, y2, x3, y3}, poly);
355+
356+
double dx2 = end.m_x - start.m_x;
357+
double dy2 = end.m_y - start.m_y;
358+
double length = std::sqrt(dx2 * dx2 + dy2 * dy2);
359+
dx2 /= length;
360+
dy2 /= length;
361+
362+
double mx = end.m_x - size * dx2;
363+
double my = end.m_y - size * dy2;
364+
365+
double x2 = mx - size / 4 * dy2;
366+
double y2 = my + size / 4 * dx2;
367+
368+
double x3 = mx + size / 4 * dy2;
369+
double y3 = my - size / 4 * dx2;
370+
371+
append({end.m_x, end.m_y, x2, y2, x3, y3}, poly);
364372
}
365373

366374
return poly;

0 commit comments

Comments
0 (0)
You are visitor 01402520 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.