コード例 #1
0
ファイル: tiles.py プロジェクト: pavlinb/mosaic
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