| 320 | } |
| 321 | |
| 322 | static Point |
| 323 | postdir(const BezierCPs& cps, |
| 324 | double time, |
| 325 | double t) |
| 326 | { |
| 327 | Point dir; |
| 328 | Point p2, p3, p2p3, p3p2; |
| 329 | |
| 330 | p2 = getPointAt(cps, time, t); |
| 331 | p2p3 = getRightPointAt(cps, time, t); |
| 332 | p3 = getPointAt(cps, time, t + 1); |
| 333 | p3p2 = getLeftPointAt(cps, time, t + 1); |
| 334 | dir.x = 3. * (p2p3.x - p2.x); |
| 335 | dir.y = 3. * (p2p3.y - p2.y); |
| 336 | double epsilon = norm(p2, p2p3, p3p2, p3); |
| 337 | double predirNormSquared = dir.x * dir.x + dir.y * dir.y; |
| 338 | |
| 339 | if (predirNormSquared > epsilon) { |
| 340 | double normDir = std::sqrt(predirNormSquared); |
| 341 | assert(normDir != 0); |
| 342 | Point ret; |
| 343 | ret.x = dir.x / normDir; |
| 344 | ret.y = dir.y / normDir; |
| 345 | |
| 346 | return ret; |
| 347 | } |
| 348 | dir.x = p2.x - 2 * p2p3.x + p3p2.x; |
| 349 | dir.y = p2.y - 2 * p2p3.y + p3p2.y; |
| 350 | predirNormSquared = dir.x * dir.x + dir.y * dir.y; |
| 351 | if (predirNormSquared > epsilon) { |
| 352 | double normDir = std::sqrt(predirNormSquared); |
| 353 | assert(normDir != 0); |
| 354 | |
| 355 | Point ret; |
| 356 | ret.x = dir.x / normDir; |
| 357 | ret.y = dir.y / normDir; |
| 358 | |
| 359 | return ret; |
| 360 | } |
| 361 | dir.x = p3.x - p2.x + 3. * (p2p3.x - p3p2.x); |
| 362 | dir.y = p3.y - p2.y + 3. * (p2p3.y - p3p2.y); |
| 363 | predirNormSquared = dir.x * dir.x + dir.y * dir.y; |
| 364 | double normDir = std::sqrt(predirNormSquared); |
| 365 | assert(normDir != 0); |
| 366 | Point ret; |
| 367 | ret.x = dir.x / normDir; |
| 368 | ret.y = dir.y / normDir; |
| 369 | |
| 370 | return ret; |
| 371 | } |
| 372 | |
| 373 | static Point |
| 374 | dirVect(const BezierCPs& cps, |
no test coverage detected