1

我正在为认知心理学写一个实验。我需要生成对一些属性进行任意控制的类似涂鸦的图形。

  • 图形永远不会自相交
  • 它必须关闭
  • 它必须占据大部分绘图表面/画布
  • 我必须能够将其导出为一系列点

此外,我需要在一定程度上控制它的复杂性。

到目前为止,我的一般方法是这样做:

  1. 将画布分成象限并沿每个轴生成交点。这通过确保图形必须进入每个象限来保证图形占据大部分区域。
  2. 我在每个象限中生成随机数量的点。
  3. 我随机选择一条线或一条曲线并按顺序连接每个点

这行得通,但是,它对自相交的控制为零,而且我已经知道我可能对此进行控制的方法是愚蠢的、蛮力的方法。我已经包含了代码,但是对于 SO 来说有点冗长。此外,我绝不会特别关注这个一般过程,这只是我自己能够梦想的。欢迎对我的逻辑提出任何建议/策略/批评。

import numpy as np
import aggdraw
from random import choice
from PIL import ImageDraw, Image
from PIL import ImagePath

# there are a few functions used here, like "angle_between" that I've not included for brevity; they're all just simple functions that do what they say, usually some trig

def generate_segment_positions(seg_count, x_offset, y_offset, avg_dist, dist_variance):
    # this just ensures that the points I choose fall within  the desired
    # quadrant and are within certain distances of each other

    min_pt_dist = avg_dist - dist_variance
    max_pt_dist = avg_dist + dist_variance
    q_pts_x = []
    q_pts_y = []

    while not len(q_pts_x) == seg_count:
        x = from_range(x_offset, x_offset + 400)
        try:
            if not (x in range(q_pts_x[-1] - min_pt_dist, q_pts_x[-1] + min_pt_dist)):
                q_pts_x.append(x)
        except IndexError:
            q_pts_x.append(x)
    while not len(q_pts_y) == seg_count:
        y = from_range(y_offset, y_offset + 400)
        try:
            if not (y in range(q_pts_y[-1] - min_pt_dist, q_pts_y[-1] + min_pt_dist)):
                q_pts_y.append(y)
        except IndexError:
            q_pts_y.append(y)
    q_points = []
    for p in q_pts_x:
        q_points.append((p, q_pts_y[q_pts_x.index(p)]))
    return q_points

def generate_arc_controls(dest, origin, quadrant):
    # this is.. my attempting to work out some control over whether or not
    # the curves I create go all over hell and creation... it doesn't work
    # but I'm hoping it offers some insight into what I'm trying to do

        m = midpoint(dest, origin)
        rotation = int(angle_between(dest, origin))
        angle_1 =  int(np.random.normal(90, 10)) + rotation
        angle_2 =  int(np.random.normal(90, 10)) + rotation
        quad_offset = 0
        if quadrant == 0:
            quad_offset = 180
        if quadrant == 1:
            quad_offset = 90
        if quadrant == 3:
            quad_offset += 270
        angle_1 += quad_offset
        angle_2 += quad_offset
        mp_len = int(line_segment_len(dest, m))
        amplitude_1 = from_range(mp_len // 2, mp_len)
        amplitude_2 = from_range(mp_len // 2, mp_len)
        c1 = point_pos(dest[0], dest[1], amplitude_1, angle_1)
        c2 = point_pos(origin[0], origin[1], amplitude_2, angle_2)
        if any(i for i in c1 + c2) < 0:
            return generate_arc_controls(dest, origin, quadrant)
        d_dest_c1 = line_segment_len(dest, c1)
        d_dest_c2 = line_segment_len(dest, c2)
        return [c1, c2] if d_dest_c1 > d_dest_c2 else [c2, c1]

   def generate_figure(self):
        BOT_L = 0
        TOP_L = 1
        TOP_R = 2
        initial_position = (400, from_range(450, 750))
        segments = []
        min_segments_per_q = 2
        max_segments_per_q = 4
        quadrant_intersects = [(random.choice(range(50, 350)), 400),
                        (400, random.choice(range(50, 350))),
                        (random.choice(range(450, 750), 400), initial_position)]
        avg_dist = 150      # used to give some control
        dist_variance = 50  # over the points I later join
        for quad in range(0,4):
            seg_count = from_range(min_segments_per_q, max_segments_per_q)
            x_offset = 0 if quad in [BOT_L, TOP_L] else 400
            y_offset = 0 if quad in [TOP_L, TOP_R] else 400
            origin = None
            for j in range(0, seg_count):
                # generate start and end points for each segment in the quadrant
                q_points = self.generate_segment_positions(seg_count, x_offset, y_offset, avg_dist, dist_variance)

                # set origin to the destination of previous segment
                o = initial_position if origin is None else origin

                # assign destination point; quadrant intersect for last segment of each quadrant
                d = q_points[j] if j < seg_count - 1 else quadrant_intersects[quad]

                # choose a segment type
                s = random.choice(['arc', 'line'])
                if s == 'line':
                    segments.append(['line', [d, o]])
                if s == 'arc':
                    c = self.generate_arc_controls(d, o, quad)
                    segments.append(['arc', [c[0], c[1], d]])
                origin = d

        surf = aggdraw.Draw("RGBA", (800, 800), (255,255,255,255))
        p_str = "M{0} {1}".format(*initial_position)
        for s in segments:
            if s[0] == 'line':
                p_str += " L{0} {1}".format(*s[1][0])
            if s[0] ==  'arc':
                pts = s[1][0] + s[1][2]
                p_str += " Q {0} {1} {2} {3}".format(*pts)
        sym = aggdraw.Symbol(p_str)
        surf.symbol((0,0), sym, aggdraw.Pen((255,0,0), 1, 255))

        return surf
4

0 回答 0