@@ -89,8 +89,8 @@ namespace ogdf { |
89 | 89 | } |
90 | 90 | } |
91 | 91 |
|
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) { |
94 | 94 | const double epsilon = 1e-6; |
95 | 95 | const double trapeziumWidthOffset = vSize.m_x * 0.275; |
96 | 96 | GenericPolyline<DPoint> polygon; |
@@ -101,8 +101,8 @@ namespace ogdf { |
101 | 101 | DPoint edgePt2 = v + *polygon.get((i + 1) % polygon.size()); |
102 | 102 |
|
103 | 103 | 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) { |
106 | 106 | return false; |
107 | 107 | } |
108 | 108 | } |
@@ -113,81 +113,82 @@ namespace ogdf { |
113 | 113 | polygon.clear(); |
114 | 114 | double radius = (max(vSize.m_x, vSize.m_y) / 2.0); |
115 | 115 | 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) { |
117 | 117 | polygon.pushBack(DPoint(radius * cos(angle), radius * sin(angle))); |
118 | 118 | } |
119 | 119 | return isInConvexCCWPolygon(); |
120 | 120 | }; |
121 | 121 |
|
122 | 122 | 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; |
181 | 181 | } |
182 | 182 | } |
183 | 183 |
|
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) { |
185 | 186 | // math visualised: https://www.desmos.com/calculator/j6iktd7fs4 |
186 | 187 | double nOffset = floor((angle - rotationOffset) / (2 * Math::pi / n)) * 2 * Math::pi / n; |
187 | 188 | double polyLineStartAngle = rotationOffset + nOffset; |
188 | 189 | double polyLineEndAngle = polyLineStartAngle + 2 * Math::pi / n; |
189 | 190 | DLine polyLine = DLine(-cos(polyLineStartAngle), -sin(polyLineStartAngle), |
190 | | - -cos(polyLineEndAngle), -sin(polyLineEndAngle)); |
| 191 | + -cos(polyLineEndAngle), -sin(polyLineEndAngle)); |
191 | 192 |
|
192 | 193 | DLine originLine = DLine(0, 0, cos(angle), sin(angle)); |
193 | 194 |
|
@@ -197,81 +198,76 @@ namespace ogdf { |
197 | 198 | return intersectionPoint + center; |
198 | 199 | } |
199 | 200 |
|
200 | | - DPoint contourPointFromAngle(double angle, Shape shape, DPoint center, DPoint vSize) { |
| 201 | + DPoint contourPointFromAngle(double angle, Shape shape, const DPoint& center, const DPoint& vSize) { |
201 | 202 | angle = std::fmod(angle, 2 * Math::pi); |
202 | 203 | if (angle < 0) { |
203 | 204 | angle += Math::pi * 2; |
204 | 205 | } |
205 | 206 |
|
206 | 207 | 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); |
271 | 240 | } |
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; |
275 | 271 | } |
276 | 272 | } |
277 | 273 |
|
@@ -327,40 +323,52 @@ namespace ogdf { |
327 | 323 | const double dy = end.m_y - start.m_y; |
328 | 324 | const double size = getArrowSize(m_attr, adj); |
329 | 325 | node v = adj->theNode(); |
330 | | - |
| 326 | + |
331 | 327 | DPolyline poly; |
332 | 328 | if (dx == 0) { |
333 | 329 | int sign = dy > 0 ? 1 : -1; |
334 | 330 | double y = m_attr.y(v) - m_attr.height(v) / 2 * sign; |
335 | 331 | 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); |
338 | 335 | } else { |
339 | 336 | // 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 | + |
348 | 354 | // 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); |
364 | 372 | } |
365 | 373 |
|
366 | 374 | return poly; |
|