import math import vsketch import vpype as vp import numpy as np DEBUG = False class KatieHewsonInspiredSketch(vsketch.SketchClass): margin = vsketch.Param(1.0, step=0.1) cloud_coverage = vsketch.Param(0.55, 0, 1, step=0.01) cloud_lines = vsketch.Param(200, 0, 300, step=1) def sky(self, vsk : vsketch.Vsketch, start : tuple, end : tuple)-> None: if DEBUG: vsk.stroke(2) x = np.linspace(start[0], end[0], 200, endpoint=True) y = np.linspace(start[1], end[1], self.cloud_lines, endpoint=True) noise = vsk.noise(x * 0.1, y * 0.1) for i_y, y_val in enumerate(y): # each column, draw a line for every pairs of values start_ = -1 for i_x, x_val in enumerate(x): if noise[i_x, i_y] < self.cloud_coverage: if start_ == -1: start_ = i_x else: if start_ != -1: vsk.line( x[start_], y_val, x[i_x - 1], y_val ) start_ = -1 if start_ != -1: vsk.line( x[start_], y_val, x[-1], y_val ) def mountains(self, vsk: vsketch.Vsketch, start: tuple, end: tuple) -> None: if DEBUG: vsk.stroke(3) # Generate a monotonic random array between start[0] and end[0] x = np.sort(np.random.uniform(start[0], end[0], 200)) x[0] = start[0] x[-1] = end[0] freq = 0.3 # Adjust this value for more or less frequent peaks phase = np.random.uniform(0, 2 * np.pi) y_pure = np.cos(x * freq + phase) * 2 + (end[1] - start[1]) / 2 y = y_pure + vsk.noise(x * 0.5) * 2 x = np.append(x, [end[0], start[0], x[0]]) y = np.append(y, [end[1], end[1], y[0]]) vsk.polygon(x, y) # find where the derivative is zero (peaks) dy = np.diff(y_pure) peaks = np.where(np.diff(np.sign(dy)))[0] + 1 for peak in peaks: vsk.line( x[peak], y[peak], x[peak], end[1] ) def occultation(self, vsk: vsketch.Vsketch) -> None: vsk.vpype("occult -i") def draw(self, vsk: vsketch.Vsketch) -> None: vsk.size("a4", landscape=True) vsk.scale("cm") width_cm = vsk.width / vp.UNITS["cm"] height_cm = vsk.height / vp.UNITS["cm"] vsk.rect( self.margin, self.margin, width_cm - self.margin , height_cm - self.margin ) self.occultation(vsk) self.sky( vsk, (self.margin,self.margin), (width_cm, height_cm) ) self.occultation(vsk) self.mountains( vsk, (self.margin, self.margin), (width_cm, height_cm) ) self.occultation(vsk) def finalize(self, vsk: vsketch.Vsketch) -> None: vsk.vpype("linemerge linesimplify reloop linesort") if __name__ == "__main__": KatieHewsonInspiredSketch.display()