|
417 | 417 | polysmooth(points::Vector{Point}, radius; action = :none, debug = false, close = true) = |
418 | 418 | polysmooth(points, radius, action; debug = debug, close = close) |
419 | 419 |
|
| 420 | +""" |
| 421 | + roundcorner(p1::Point, cornerpoint::Point, p2::Point, radius) |
| 422 | +
|
| 423 | +Given a corner `cornerpoint` defined by the three points `p1`, `cornerpoint`, and `p2`, |
| 424 | +calculate the intersection points and centerpoint for a smooth rounded corner. |
| 425 | + |
| 426 | +Returns |
| 427 | + |
| 428 | + `p1_cross`, `circlepoint`, `p2_cross`, `clockwise` |
| 429 | + |
| 430 | +The corner can be drawn as: |
| 431 | +
|
| 432 | + p1 -> p1_cross -> arc2r(circlepoint, p1_cross, p2_cross) -> p2_cross -> p2 |
| 433 | +
|
| 434 | +`clockwise` is true if the arc is to drawn clockwise. |
| 435 | +""" |
| 436 | +function roundcorner(p1::Point, cornerpoint::Point, p2::Point, radius) |
| 437 | + if isapprox(radius, 0.0) |
| 438 | + throw(error("roundcorner: impossibly small radius $radius")) |
| 439 | + end |
| 440 | + dx1 = cornerpoint.x - p1.x # vector 1 |
| 441 | + dy1 = cornerpoint.y - p1.y |
| 442 | + dx2 = cornerpoint.x - p2.x # vector 2 |
| 443 | + dy2 = cornerpoint.y - p2.y |
| 444 | + |
| 445 | + # Angle between vector 1 and vector 2 divided by 2 |
| 446 | + angle2 = (atan(dy1, dx1) - atan(dy2, dx2)) / 2 |
| 447 | + |
| 448 | + # length of segment between corner point and the |
| 449 | + # points of intersection with the circle of a given radius |
| 450 | + t = abs(tan(angle2)) |
| 451 | + segment = radius / t |
| 452 | + |
| 453 | + # Check the segment |
| 454 | + length1 = hypot(dx1, dy1) |
| 455 | + length2 = hypot(dx2, dy2) |
| 456 | + seglength = min(length1, length2) |
| 457 | + if segment > seglength |
| 458 | + segment = seglength |
| 459 | + radius = seglength * t |
| 460 | + end |
| 461 | + |
| 462 | + # points of intersection are calculated by the proportion between |
| 463 | + # the coordinates of the vector, length of vector and the length of the segment. |
| 464 | + p1_cross = Luxor.getproportionpoint(cornerpoint, segment, length1, dx1, dy1) |
| 465 | + p2_cross = Luxor.getproportionpoint(cornerpoint, segment, length2, dx2, dy2) |
| 466 | + |
| 467 | + # calculation of the coordinates of the circle's center by the addition of angular vectors |
| 468 | + dx = cornerpoint.x * 2 - p1_cross.x - p2_cross.x |
| 469 | + dy = cornerpoint.y * 2 - p1_cross.y - p2_cross.y |
| 470 | + L = hypot(dx, dy) |
| 471 | + d = hypot(segment, radius) |
| 472 | + # this prevents impossible constructions; Cairo will crash if L is 0 |
| 473 | + if isapprox(L, 0.0) |
| 474 | + L = 0.01 |
| 475 | + end |
| 476 | + circlepoint = Luxor.getproportionpoint(cornerpoint, d, L, dx, dy) |
| 477 | + |
| 478 | + # start angle and end engle of arc |
| 479 | + startangle = atan(p1_cross.y - circlepoint.y, p1_cross.x - circlepoint.x) |
| 480 | + endangle = atan(p2_cross.y - circlepoint.y, p2_cross.x - circlepoint.x) |
| 481 | + |
| 482 | + if endangle < 0 |
| 483 | + endangle = 2π + endangle |
| 484 | + end |
| 485 | + if startangle < 0 |
| 486 | + startangle = 2π + startangle |
| 487 | + end |
| 488 | + sweepangle = endangle - startangle |
| 489 | + |
| 490 | + if abs(sweepangle) > π |
| 491 | + if startangle < endangle |
| 492 | + clockwise = false |
| 493 | + else |
| 494 | + clockwise = true |
| 495 | + end |
| 496 | + else |
| 497 | + if startangle < endangle |
| 498 | + clockwise = true |
| 499 | + else |
| 500 | + clockwise = false |
| 501 | + end |
| 502 | + end |
| 503 | + return p1_cross, circlepoint, p2_cross, clockwise |
| 504 | +end |
| 505 | + |
420 | 506 | """ |
421 | 507 | offsetpoly(plist::Vector{Point}, d::T) where T<:Number |
422 | 508 |
|
|
0 commit comments