Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save BenedictWilkins/5d43bf17dbe5ef452e219a61a5352447 to your computer and use it in GitHub Desktop.
Save BenedictWilkins/5d43bf17dbe5ef452e219a61a5352447 to your computer and use it in GitHub Desktop.
Implementation of hatching for an axis aligned rectangle.
def line_intersection(line1, line2):
"""
Find the intersection of two lines.
Each line is defined by a pair of points (x1, y1) and (x2, y2).
"""
x1, y1, x2, y2 = line1
x3, y3, x4, y4 = line2
denominator = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4)
if denominator == 0:
return None # Lines are parallel
px = ((x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4)) / denominator
py = ((x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4)) / denominator
return px, py
def clip_line_to_rect(x_start, y_start, x_end, y_end, xmin, xmax, ymin, ymax):
"""
Clip a line to the boundaries of a rectangle.
"""
rect_lines = [
(xmin, ymin, xmin, ymax), # Left edge
(xmin, ymax, xmax, ymax), # Top edge
(xmax, ymax, xmax, ymin), # Right edge
(xmax, ymin, xmin, ymin) # Bottom edge
]
clipped_line = []
for rect_line in rect_lines:
intersection = line_intersection((x_start, y_start, x_end, y_end), rect_line)
if intersection and xmin <= intersection[0] <= xmax and ymin <= intersection[1] <= ymax:
clipped_line.append(intersection)
if len(clipped_line) < 2:
return None # Line does not intersect the rectangle
return clipped_line[0], clipped_line[1]
def custom_hatch(ax, xmin, xmax, ymin, ymax, color='black', angle=45, density=20):
"""
Add custom hatched region to an axis.
Parameters:
ax (matplotlib.axes.Axes): The axis to add the hatched region.
xmin, xmax (float): The x-axis limits of the hatched region.
ymin, ymax (float): The y-axis limits of the hatched region.
color (str): Color of the hatch lines.
angle (float): Angle of the hatch lines in degrees.
density (int): Number of hatch lines.
"""
# Convert angle to radians
angle_rad = np.radians(angle)
# Define the width and height of the rectangle
width = xmax - xmin
height = ymax - ymin
# Calculate the maximum distance required for the lines to cover the rectangle
diag_len = np.sqrt(width**2 + height**2)
# Calculate the step size based on the density and diagonal length
step = diag_len / density
# Calculate the starting points for the lines
x_starts = np.linspace(xmin - diag_len, xmax + diag_len, density + 1)
y_starts = ymin + (x_starts - xmin) * np.tan(angle_rad)
# Calculate the ending points for the lines
x_ends = x_starts + height / np.sin(angle_rad)
y_ends = y_starts - width / np.cos(angle_rad)
# Draw each line, clipping it to the rectangle
for x_start, y_start, x_end, y_end in zip(x_starts, y_starts, x_ends, y_ends):
clipped_line = clip_line_to_rect(x_start, y_start, x_end, y_end, xmin, xmax, ymin, ymax)
if clipped_line:
line_xs, line_ys = zip(*clipped_line)
ax.add_line(plt.Line2D(line_xs, line_ys, linewidth=1, color=color, alpha=0.5, solid_capstyle='butt'))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment