Untitled
unknown
python
4 years ago
4.9 kB
4
Indexable
import bpy def print(data): for window in bpy.context.window_manager.windows: screen = window.screen for area in screen.areas: if area.type == 'CONSOLE': override = {'window': window, 'screen': screen, 'area': area} bpy.ops.console.scrollback_append(override, text=str(data), type="OUTPUT") # load image bpy.ops.image.open(filepath='/Users/stas/Downloads/concentric_circles.png') img = bpy.data.images['concentric_circles.png'] width, height = img.size def set_pix_col(x, y, col): global img base_i = (width * y + x) * 4 for i in range(base_i, min(base_i + len(col), len(img.pixels))): img.pixels[i] = col[i - base_i] def get_pix_col(x, y): global img base_i = (width * y + x) * 4 return img.pixels[base_i:base_i+4] def is_black(x, y): col = get_pix_col(x, y) return sum(col[0:3]) == 0 and col[3] == 1 # values are 0-1 instead of 0-255 def in_bounds(x, y): global width, height return 0 <= x < width and 0 <= y < height # process pixels to remove extra corners dirs = [[[1, 0], [1, 1]], [[1, 0], [1, -1]], [[0, 1], [1, 1]], [[0, 1], [-1, 1]], [[-1, 0], [-1, 1]], [[-1, 0], [-1, -1]], [[0, -1], [1, -1]], [[0, -1], [-1, -1]]] for y in range(height): for x in range(width): if is_black(x, y): for d in dirs: nx1, ny1 = [x + d[0][0], y + d[0][1]] nx2, ny2 = [x + d[1][0], y + d[1][1]] if in_bounds(nx1, ny1) and in_bounds(nx2, ny2): if is_black(nx1, ny1) and is_black(nx2, ny2): set_pix_col(nx1, ny1, [1, 1, 1, 0]) # get rings checked = [] for y in range(height): checked.append([False] * width) dirs = [[1, 0], [0, 1], [-1, 0], [0, -1], [1, 1], [1, -1], [-1, 1], [-1, -1]] rings = [] for y in range(height): for x in range(width): if is_black(x, y): if not checked[y][x]: ring = [] buffer = [[x, y]] while len(buffer) > 0: cx, cy = buffer[0] ring.append([cx, cy]) for d in dirs: nx, ny = cx + d[0], cy + d[1] if in_bounds(nx, ny): if is_black(nx, ny): if not checked[ny][nx]: checked[ny][nx] = True buffer.append([nx, ny]) break buffer.pop(0) rings.append(ring) rings.sort(key=len) rings.reverse() from math import sqrt, inf def mag(v1, v2): return sqrt((v1[0] - v2[0]) ** 2 + (v1[1] - v2[1]) ** 2) print("begun calculating connections") # calculate connections con = [] for i in range(len(rings) - 1): cring, nring = rings[i], rings[i + 1] con.append([-1] * len(cring)) # greedy algo for finding nearest point: # we can guess that the closest point to ring[i] is min(con[ring[i - 1]], con[ring[i - 1]]) # since points on circles are consecutive # first one needs to be calculated honestly closest_i = -1 min_dst = inf for k in range(len(nring)): dst = mag(cring[0], nring[k]) if dst < min_dst: min_dst = dst closest_i = k con[i][0] = closest_i print("calculated closest") for j in range(1, len(cring)): cdst = mag(nring[con[i][j - 1]], cring[k]) ndst = mag(nring[(con[i][j - 1] + 1) % len(con[i])], cring[k]) if ndst < cdst: con[i][k] = (con[i][j - 1] + 1) % len(con[i]) else: con[i][k] = con[i][j - 1] print("calculating verts") # put vertices in bucket, layered verts = [] for i in range(len(rings)): for part in rings[i]: verts.append([part[0], part[1], i]) print("calculating ssum") # get size sum to use vertice bucket ssum = [] s = 0 for ring in rings: s += len(ring) ssum.append(s) # if same point is closest, we can keep connecting to that, after that need to do downwards triangle faces = [] print("calculating faces") for i in range(len(con)): ccon = con[i] for j in range(len(con[i])): base_off = ssum[i - 1] if i != 0 else 0 if ccon[j] == ccon[j - 1]: faces.append([(j - 1) % len(con[i]) + base_off, ccon[j] + ssum[i], j + base_off]) else: faces.append([j + base_off, ccon[j - 1] + ssum[i], ccon[j]]) print("creating mesh") mesh = bpy.data.meshes.new("myBeautifulMesh") # add the new mesh obj = bpy.data.objects.new(mesh.name, mesh) col = bpy.data.collections.get("Collection") col.objects.link(obj) bpy.context.view_layer.objects.active = obj mesh.from_pydata(verts, [], faces)
Editor is loading...