Untitled
unknown
python
5 years ago
4.9 kB
7
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...