def place_tiles_along_chains(chains, angles_0to180, half_tile, RAND_SIZE, MAX_ANGLE, A0, plot=[]): # construct tiles along ductus chain RAND_EXTRA = int(round(half_tile * RAND_SIZE)) polygons = [] t0 = time.time() delta_i = int(half_tile * 2) # width of standard tile (i.e. on straight lines) for ik, chain in enumerate(chains): # consider existing polygons next to the new lane (reason: speed) search_area = LineString(np.array(chain)[:, ::-1]).buffer(2.1 * half_tile) preselected_nearby_polygons = [ poly for poly in polygons if poly.intersects(search_area) ] for i in range(len(chain)): y, x = chain[i] winkel = angles_0to180[y, x] if i == 0: # at the beginning save the first side of the future polygon i_start = i rand_i = random.randint(-RAND_EXTRA, +RAND_EXTRA) # a<=x<=b winkel_start = winkel line_start = LineString([(x, y - half_tile), (x, y + half_tile)]) line_start = affinity.rotate(line_start, -winkel_start) # Draw polygon as soon as one of the three conditions is fullfilled: draw_polygon = False # 1. end of chain is reached if i == len(chain) - 1: draw_polygon = True else: y_next, x_next = chain[i + 1] winkel_next = angles_0to180[y_next, x_next] winkeldelta = winkel_next - winkel_start winkeldelta = min(180 - abs(winkeldelta), abs(winkeldelta)) # 2. with the NEXT point a large angle would be reached => draw now if winkeldelta > MAX_ANGLE: draw_polygon = True # 3. goal width is reached if i - i_start == delta_i + rand_i: draw_polygon = True if draw_polygon: line = LineString([(x, y - half_tile), (x, y + half_tile)]) line = affinity.rotate(line, -winkel) # construct new tile p = MultiPoint([ line_start.coords[0], line_start.coords[1], line.coords[0], line.coords[1] ]) p = p.convex_hull line_start = line winkel_start = winkel # do not draw very thin polygon, but set as new starting point (line_start) to skip critical area if i - i_start <= 2: i_start = i continue i_start = i rand_i = random.randint(-RAND_EXTRA, +RAND_EXTRA) # a<=x<=b # cut off areas that overlap with already existing tiles nearby_polygons = [ poly for poly in preselected_nearby_polygons if p.disjoint(poly) == False ] p = fit_in_polygon(p, nearby_polygons) # Sort out small tiles if p.area >= 0.08 * A0 and p.geom_type == 'Polygon' and p.is_valid: polygons += [p] preselected_nearby_polygons += [p] print(f'Placed {len(polygons)} tiles along guidelines', f'{time.time()-t0:.1f}s') if 'polygons_chains' in plot: plotting.draw_tiles(polygons, None, h=0, w=0, background_brightness=0.2, return_svg=False, chains=chains, axis_off=True) return polygons