|
6 | 6 |
|
7 | 7 | from pyglet.math import Vec2, Vec3
|
8 | 8 |
|
9 |
| -from arcade.types import HasAddSubMul, Point, Point2, SupportsRichComparison |
| 9 | +from arcade.types import AsFloat, HasAddSubMul, Point, Point2, SupportsRichComparison |
10 | 10 | from arcade.types.rect import Rect
|
11 | 11 | from arcade.types.vector_like import Point3
|
12 | 12 |
|
@@ -365,6 +365,73 @@ def rotate_point(
|
365 | 365 | return x, y
|
366 | 366 |
|
367 | 367 |
|
| 368 | +# scale around point |
| 369 | + |
| 370 | + |
| 371 | +def rescale_relative_to_point(source: Point2, target: Point2, factor: AsFloat | Point2) -> Point2: |
| 372 | + """ |
| 373 | + Calculate where a point should be when scaled by the factor realtive to the source point. |
| 374 | +
|
| 375 | + Args: |
| 376 | + source: Where to scaled from. |
| 377 | + target: The point being scaled. |
| 378 | + factor: How much to scale by. If factor is less than one, target approaches source. |
| 379 | + Otherwise it moves away. A factor of zero returns source. |
| 380 | +
|
| 381 | + Returns: |
| 382 | + The rescaled point. |
| 383 | + """ |
| 384 | + |
| 385 | + if isinstance(factor, (float, int)): |
| 386 | + if factor == 1.0: |
| 387 | + return target |
| 388 | + scale_x = scale_y = factor |
| 389 | + else: |
| 390 | + try: |
| 391 | + scale_x, scale_y = factor |
| 392 | + if scale_x == 1.0 and scale_y == 1.0: |
| 393 | + return target |
| 394 | + except ValueError: |
| 395 | + raise ValueError( |
| 396 | + "factor must be a float, int, or tuple-like " |
| 397 | + "which unpacks as two float-like values" |
| 398 | + ) |
| 399 | + except TypeError: |
| 400 | + raise TypeError( |
| 401 | + "factor must be a float, int, or tuple-like unpacks as two float-like values" |
| 402 | + ) |
| 403 | + |
| 404 | + dx = target[0] - source[0] |
| 405 | + dy = target[1] - source[1] |
| 406 | + |
| 407 | + return source[0] + dx * scale_x, source[1] + dy * scale_y |
| 408 | + |
| 409 | + |
| 410 | +def rotate_around_point(source: Point2, target: Point2, angle: float): |
| 411 | + """ |
| 412 | + Rotate a point around another point clockwise. |
| 413 | +
|
| 414 | + Args: |
| 415 | + source: The point to rotate around |
| 416 | + target: The point to rotate |
| 417 | + angle: The degrees to rotate the target by. |
| 418 | + """ |
| 419 | + |
| 420 | + if source == target or angle % 360.0 == 0.0: |
| 421 | + return target |
| 422 | + |
| 423 | + diff_x = target[0] - source[0] |
| 424 | + diff_y = target[1] - source[1] |
| 425 | + r = math.radians(angle) |
| 426 | + |
| 427 | + c, s = math.cos(r), math.sin(r) |
| 428 | + |
| 429 | + dx = diff_x * c - diff_y * s |
| 430 | + dy = diff_x * s + diff_y * c |
| 431 | + |
| 432 | + return target[0] + dx, target[1] + dy |
| 433 | + |
| 434 | + |
368 | 435 | def get_angle_degrees(x1: float, y1: float, x2: float, y2: float) -> float:
|
369 | 436 | """
|
370 | 437 | Get the angle in degrees between two points.
|
|
0 commit comments