clip_path.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. from __future__ import (absolute_import, division, print_function,
  2. unicode_literals)
  3. import six
  4. from six.moves import zip
  5. import numpy as np
  6. from math import degrees
  7. import math
  8. import warnings
  9. def atan2(dy, dx):
  10. if dx == 0 and dy == 0:
  11. warnings.warn("dx and dy is 0")
  12. return 0
  13. else:
  14. return math.atan2(dy, dx)
  15. # FIXME : The current algorithm seems to return incorrect angle when the line
  16. # ends at the boundary.
  17. def clip(xlines, ylines, x0, clip="right", xdir=True, ydir=True):
  18. clipped_xlines = []
  19. clipped_ylines = []
  20. _pos_angles = []
  21. if xdir:
  22. xsign = 1
  23. else:
  24. xsign = -1
  25. if ydir:
  26. ysign = 1
  27. else:
  28. ysign = -1
  29. for x, y in zip(xlines, ylines):
  30. if clip in ["up", "right"]:
  31. b = (x < x0).astype("i")
  32. db = b[1:] - b[:-1]
  33. else:
  34. b = (x > x0).astype("i")
  35. db = b[1:] - b[:-1]
  36. if b[0]:
  37. ns = 0
  38. else:
  39. ns = -1
  40. segx, segy = [], []
  41. for (i,) in np.argwhere(db!=0):
  42. c = db[i]
  43. if c == -1:
  44. dx = (x0 - x[i])
  45. dy = (y[i+1] - y[i]) * (dx/ (x[i+1] - x[i]))
  46. y0 = y[i] + dy
  47. clipped_xlines.append(np.concatenate([segx, x[ns:i+1], [x0]]))
  48. clipped_ylines.append(np.concatenate([segy, y[ns:i+1], [y0]]))
  49. ns = -1
  50. segx, segy = [], []
  51. if dx == 0. and dy == 0:
  52. dx = x[i+1] - x[i]
  53. dy = y[i+1] - y[i]
  54. a = degrees(atan2(ysign*dy, xsign*dx))
  55. _pos_angles.append((x0, y0, a))
  56. elif c == 1:
  57. dx = (x0 - x[i])
  58. dy = (y[i+1] - y[i]) * (dx / (x[i+1] - x[i]))
  59. y0 = y[i] + dy
  60. segx, segy = [x0], [y0]
  61. ns = i+1
  62. if dx == 0. and dy == 0:
  63. dx = x[i+1] - x[i]
  64. dy = y[i+1] - y[i]
  65. a = degrees(atan2(ysign*dy, xsign*dx))
  66. _pos_angles.append((x0, y0, a))
  67. if ns != -1:
  68. clipped_xlines.append(np.concatenate([segx, x[ns:]]))
  69. clipped_ylines.append(np.concatenate([segy, y[ns:]]))
  70. #clipped_pos_angles.append(_pos_angles)
  71. return clipped_xlines, clipped_ylines, _pos_angles
  72. def clip_line_to_rect(xline, yline, bbox):
  73. x0, y0, x1, y1 = bbox.extents
  74. xdir = x1 > x0
  75. ydir = y1 > y0
  76. if x1 > x0:
  77. lx1, ly1, c_right_ = clip([xline], [yline], x1, clip="right", xdir=xdir, ydir=ydir)
  78. lx2, ly2, c_left_ = clip(lx1, ly1, x0, clip="left", xdir=xdir, ydir=ydir)
  79. else:
  80. lx1, ly1, c_right_ = clip([xline], [yline], x0, clip="right", xdir=xdir, ydir=ydir)
  81. lx2, ly2, c_left_ = clip(lx1, ly1, x1, clip="left", xdir=xdir, ydir=ydir)
  82. if y1 > y0:
  83. ly3, lx3, c_top_ = clip(ly2, lx2, y1, clip="right", xdir=ydir, ydir=xdir)
  84. ly4, lx4, c_bottom_ = clip(ly3, lx3, y0, clip="left", xdir=ydir, ydir=xdir)
  85. else:
  86. ly3, lx3, c_top_ = clip(ly2, lx2, y0, clip="right", xdir=ydir, ydir=xdir)
  87. ly4, lx4, c_bottom_ = clip(ly3, lx3, y1, clip="left", xdir=ydir, ydir=xdir)
  88. # lx1, ly1, c_right_ = clip([xline], [yline], x1, clip="right")
  89. # lx2, ly2, c_left_ = clip(lx1, ly1, x0, clip="left")
  90. # ly3, lx3, c_top_ = clip(ly2, lx2, y1, clip="right")
  91. # ly4, lx4, c_bottom_ = clip(ly3, lx3, y0, clip="left")
  92. #c_left = [((x, y), (a+90)%180-180) for (x, y, a) in c_left_ \
  93. # if bbox.containsy(y)]
  94. c_left = [((x, y), (a+90)%180-90) for (x, y, a) in c_left_
  95. if bbox.containsy(y)]
  96. c_bottom = [((x, y), (90 - a)%180) for (y, x, a) in c_bottom_
  97. if bbox.containsx(x)]
  98. c_right = [((x, y), (a+90)%180+90) for (x, y, a) in c_right_
  99. if bbox.containsy(y)]
  100. c_top = [((x, y), (90 - a)%180+180) for (y, x, a) in c_top_
  101. if bbox.containsx(x)]
  102. return list(zip(lx4, ly4)), [c_left, c_bottom, c_right, c_top]