Example #1
0
def orthogonal(v):  # Vector.orthogonal isn't present in 2.70
    size = len(v)
    v = (Vector((v[0], v[1], 0.0)) if size == 2 else Vector(v))
    if v.length_squared < 1e-8: return Vector.Fill(size)
    ort = Vector((0, 0, 1)).cross(v).normalized()
    if ort.length_squared < 0.5:
        ort = Vector((0, 1, 0)).cross(v).normalized()
    return (ort.to_2d() if size == 2 else ort)
Example #2
0
def orthogonal(v): # Vector.orthogonal isn't present in 2.70
    size = len(v)
    v = (Vector((v[0], v[1], 0.0)) if size == 2 else Vector(v))
    if v.length_squared < 1e-8: return Vector.Fill(size)
    ort = Vector((0,0,1)).cross(v).normalized()
    if ort.length_squared < 0.5:
        ort = Vector((0,1,0)).cross(v).normalized()
    return (ort.to_2d() if size == 2 else ort)
    def transUvVector(self):
        max_position = 0.
        min_position_x = 0.
        min_position_y = 0.

        # calculate two rotation matrix from normal vector of selected polygons
        vector_nor = self.averageNormal()

        theta_x = self.calcRotAngle('X', vector_nor.x, vector_nor.y,
                                    vector_nor.z)
        mat_rotx = Matrix.Rotation(theta_x, 3, 'X')
        vector_nor.rotate(mat_rotx)

        theta_y = self.calcRotAngle('Y', vector_nor.x, vector_nor.y,
                                    vector_nor.z)
        mat_roty = Matrix.Rotation(theta_y, 3, 'Y')

        # apply two rotation matrix to vertex
        uv_array = self.mesh.uv_layers.active.data
        for poly in self.select_poly:
            for id in range(poly.loop_start,
                            poly.loop_start + poly.loop_total):
                new_vector = Vector((
                    self.mesh.vertices[self.mesh.loops[id].vertex_index].co[0],
                    self.mesh.vertices[self.mesh.loops[id].vertex_index].co[1],
                    self.mesh.vertices[self.mesh.loops[id].vertex_index].co[2]
                ))

                new_vector.rotate(mat_rotx)
                new_vector.rotate(mat_roty)

                uv_array[id].uv = new_vector.to_2d()

                if min_position_x > uv_array[id].uv.x:
                    min_position_x = uv_array[id].uv.x
                if min_position_y > uv_array[id].uv.y:
                    min_position_y = uv_array[id].uv.y

        # recalculate uv position
        for poly in self.select_poly:
            for id in range(poly.loop_start,
                            poly.loop_start + poly.loop_total):
                uv_array[id].uv.x = uv_array[id].uv.x + abs(min_position_x)
                uv_array[id].uv.y = uv_array[id].uv.y + abs(min_position_y)

                if max_position < uv_array[id].uv.x:
                    max_position = uv_array[id].uv.x
                if max_position < uv_array[id].uv.y:
                    max_position = uv_array[id].uv.y

        # scale uv position
        for poly in self.select_poly:
            for id in range(poly.loop_start,
                            poly.loop_start + poly.loop_total):
                uv_array[
                    id].uv.x = uv_array[id].uv.x * MAX_LOCATION / max_position
                uv_array[
                    id].uv.y = uv_array[id].uv.y * MAX_LOCATION / max_position
Example #4
0
def func_constrain_axis_mmb(self, context, key, value, angle):
    if len(self.tab) > 1:
        angle = 0
    if key == 'MIDDLEMOUSE':
        if value == 'PRESS':
            if self.handle_axes == None:
                args = (self, context, angle)
                self.handle_axes = bpy.types.SpaceSequenceEditor.draw_handler_add(
                    draw_axes, args, 'PREVIEW', 'POST_PIXEL')
            self.choose_axis = True
            self.pos_clic = self.mouse_pos
        if value == 'RELEASE':
            self.choose_axis = False
            if self.pos_clic == self.mouse_pos:
                self.axis_x = self.axis_y = True
                if self.handle_axes:
                    bpy.types.SpaceSequenceEditor.draw_handler_remove(
                        self.handle_axes, 'PREVIEW')
                    self.handle_axes = None
    if self.choose_axis:
        vec_axis_z = Vector((0, 0, 1))
        vec_axis_x = Vector((1, 0, 0))
        vec_axis_x.rotate(Quaternion(vec_axis_z, math.radians(angle)))
        vec_axis_x = vec_axis_x.to_2d()
        vec_axis_y = Vector((0, 1, 0))
        vec_axis_y.rotate(Quaternion(vec_axis_z, math.radians(angle)))
        vec_axis_y = vec_axis_y.to_2d()

        ang_x = math.degrees(
            vec_axis_x.angle(self.mouse_pos - self.center_area))
        ang_y = math.degrees(
            vec_axis_y.angle(self.mouse_pos - self.center_area))

        if ang_x > 90:
            ang_x = 180 - ang_x
        if ang_y > 90:
            ang_y = 180 - ang_y

        if ang_x < ang_y:
            self.axis_x = True
            self.axis_y = False
        else:
            self.axis_x = False
            self.axis_y = True
Example #5
0
def _get_check_pattern():
    pattern = []
    rays_rows = 16  # 128 rays
    rays_cols = 8
    for i in range(rays_rows):
        angle = radians(360.0 / rays_rows * i)
        for j in range(rays_cols):
            mat_rotation = Matrix.Rotation(angle, 3, 'Z')
            p1 = Vector((1.0, 0.0, 0.0))
            p1.rotate(mat_rotation)
            pattern.append(p1.to_2d() * (1.0 / rays_cols * j))
    pattern.append(Vector((0.0, 0.0)))
    return pattern
    def transUvVector(self):
        max_position = 0.
        min_position_x = 0.
        min_position_y = 0.

        # calculate two rotation matrix from normal vector of selected polygons
        vector_nor = self.averageNormal()

        theta_x = self.calcRotAngle('X', vector_nor.x, vector_nor.y, vector_nor.z)
        mat_rotx = Matrix.Rotation(theta_x, 3, 'X')
        vector_nor.rotate(mat_rotx)

        theta_y = self.calcRotAngle('Y', vector_nor.x, vector_nor.y, vector_nor.z)
        mat_roty = Matrix.Rotation(theta_y, 3, 'Y')

        # apply two rotation matrix to vertex
        uv_array = self.mesh.uv_layers.active.data
        for poly in self.select_poly:
            for id in range(poly.loop_start, poly.loop_start + poly.loop_total):
                new_vector = Vector((self.mesh.vertices[self.mesh.loops[id].vertex_index].co[0],
                                     self.mesh.vertices[self.mesh.loops[id].vertex_index].co[1],
                                     self.mesh.vertices[self.mesh.loops[id].vertex_index].co[2]))

                new_vector.rotate(mat_rotx)
                new_vector.rotate(mat_roty)

                uv_array[id].uv = new_vector.to_2d()

                if min_position_x > uv_array[id].uv.x:
                    min_position_x = uv_array[id].uv.x
                if min_position_y > uv_array[id].uv.y:
                    min_position_y = uv_array[id].uv.y

        # recalculate uv position
        for poly in self.select_poly:
            for id in range(poly.loop_start, poly.loop_start + poly.loop_total):
                uv_array[id].uv.x = uv_array[id].uv.x + abs(min_position_x)
                uv_array[id].uv.y = uv_array[id].uv.y + abs(min_position_y)

                if max_position < uv_array[id].uv.x:
                    max_position = uv_array[id].uv.x
                if max_position < uv_array[id].uv.y:
                    max_position = uv_array[id].uv.y

        # scale uv position
        for poly in self.select_poly:
            for id in range(poly.loop_start, poly.loop_start + poly.loop_total):
                uv_array[id].uv.x = uv_array[id].uv.x * MAX_LOCATION / max_position
                uv_array[id].uv.y = uv_array[id].uv.y * MAX_LOCATION / max_position
Example #7
0
class MouseCoordinate:
    '''
    origin, current, shiftからrelativeを求める。
    relativeをorigin -> lockのベクトルに正射影。

    exptargetsの例:
    exptargets = {'dist': [(self.mc, 'dist', self, 'dist', 0.0),
                           (self.mc.exp, 0, self, 'dist', Null())],
                  'fac': [(self.mc, 'fac', self, 'dist', 0.0),
                          (self.mc.exp, 0, self, 'dist', Null())]}
    set_values()
        引数無しの場合:
            self.exptargetsを全て処理。
        引数をタプルとして受けとった場合:
            例 set_values(self.mc, 'dist', self, 'dist', 0.0)
            これのみ処理。
        引数を辞書として受け取った場合:
            例 set_values(default=False, fac=True)
            キーが存在したらそれを真偽によって処理、
            その他の真偽はdefault(キーが無ければ真)。
    '''

    def __init__(self, context=None, event=None, recalcDPBU=True, dpf=200,
                 expnames=('Dist {exp}',)):
        self.shift = None  # *0.1. type:Vector. relativeに影響。
        self.lock = None  # lock direction. type:Vector. relativeに影響。
        self.snap = False  # type:Bool
        self.origin = Vector()  # Rキーで変更
        self.current = Vector()  # (event.mouse_region_x, event.mouse_region_y, 0)
        self.relative = Vector()  # shift,lockを考慮
        self.dpbu = 1.0  # 初期化時、及びupdateの際に指定した場合に更新。
        self.unit_pow = 1.0 # 上記と同様
        self.dist = 0.0  # relativesnapを考慮
        self.fac = 0.0

        self.inputexp = False
        self.exp = InputExpression(names=expnames)
        #self.finaldist = 0.0  # exp等を考慮した最終的な値
        self.exptargets = {}

        self.shortcuts = []

        if event:
            self.origin = Vector((event.mouse_region_x, event.mouse_region_y, \
                                  0.0))
        self.dpf = dpf  # dot per fac
        self.update(context, event, recalcDPBU)

    def set_exptargets(self, exptargets):
        self.exptargets = exptargets

    def set_shortcuts(self, shortcuts):
        ''' default: SC = Shortcut
        shortcuts = [SC('lock', 'MIDDLEMOUSE'),
                     SC('reset', 'R'),
        '''
        self.shortcuts = shortcuts

    def set_values(self, *target, **kw):
        if target:
            self.exptargets['targetonly'] = target[0]
        for key, values in self.exptargets.items():
            if target:
                if key != 'targetonly':
                    continue
            elif kw:
                if key in kw:
                    if not kw[key]:
                        continue
                elif 'default' in kw:
                    if not kw['default']:
                        continue
            for obj, attr, tagobj, tagattr, err in values:
                # read
                if obj == self.exp:  # (self.exp, index)
                    if not self.inputexp:
                        continue
                    val = self.exp.get_exp_value(attr)
                    if val is None:
                        if isinstance(err, Null):
                            continue
                        val = err
                else:
                    if isinstance(attr, str):
                        val = getattr(obj, attr)
                    else:
                        val = obj[attr]
                # set
                if isinstance(tagattr, str):
                    setattr(tagobj, tagattr, val)
                else:
                    tagobj[tagattr] = val
        if target:
            del(self.exptargets['targetonly'])

    def handling_event(self, context, event):
        mouseco = Vector((event.mouse_region_x, event.mouse_region_y, 0.0))

        handled = True
        EXECUTE = True  # execute等を実行後、すぐにreturn {'RUNNING_MODAL'}
        if self.inputexp:  # evalの式の入力
            if event.value == 'PRESS':
                handled_by_exp = self.exp.input(event)
                if handled_by_exp:
                    self.set_values()
                    return handled, EXECUTE

        shortcut_name = check_shortcuts(self.shortcuts, event)

        if event.type == 'TAB' and event.value == 'PRESS':
            # <Input Expression>
            if self.inputexp and (event.shift or event.ctrl):
                self.inputexp = False
                self.update(context, event)
                self.set_values()
            elif not self.inputexp and not (event.shift or event.ctrl):
                self.inputexp = True
                self.set_values()
            else:
                handled = False
        elif event.type in ('ESC', 'RIGHTMOUSE') and event.value == 'PRESS':
            if self.inputexp:
                self.inputexp = False
                self.update(context, event)
                self.set_values()
            else:
                handled = False
        elif event.type in ('LEFT_SHIFT', 'RIGHT_SHIFT'):
            if event.value == 'PRESS':
                self.shift = mouseco.copy()
            elif event.value == 'RELEASE':
                self.shift = None
                self.update(context, event)
                self.set_values()
            else:
                handled = False
        elif event.type in ('LEFT_CTRL', 'RIGHT_CTRL'):
            if event.value == 'PRESS':
                self.snap = True
            elif event.value == 'RELEASE':
                self.snap = False
            self.update(context, event)
            self.set_values()
        elif event.type == 'MOUSEMOVE':
            # <Move Mouse>
            self.update(context, event)
            self.set_values()
        elif shortcut_name == 'lock':
            # <Lock Trans Axis>
            if self.lock is None:
                self.lock = mouseco.copy()
            else:
                self.lock = None
        elif shortcut_name == 'reset':
            # <Reset>
            if self.lock:
                self.lock = self.lock - self.origin + mouseco
            self.origin = mouseco.copy()
            self.update(context, event)
            self.set_values()
        else:
            handled = False
        return handled, False

    def update(self, context=None, event=None, recalcDPBU=False):
        shift = self.shift
        snap = self.snap
        lock = self.lock
        origin = self.origin

        if event:
            current = Vector((event.mouse_region_x, event.mouse_region_y, 0.0))
        else:
            current = self.current
        if shift:
            relative = shift - origin + (current - shift) * 0.1
        else:
            relative = current - origin
        if lock:
            origin_lock = lock - origin
            if origin_lock.length >= MIN_NUMBER:
                if relative.length >= MIN_NUMBER:
                    relative = relative.project(origin_lock)
            else:
                self.lock = None
        if context and recalcDPBU:
            dpbu, dx, unit_pow = get_DPBU_dx_unit_pow(context.region)
        else:
            dpbu, unit_pow = self.dpbu, self.unit_pow

        dist = relative.length / dpbu
        fac = relative.length / self.dpf
        if lock:
            if relative.dot(origin_lock) < 0.0:
                dist = -dist
                fac = -fac
        if snap:
            grid = 10 ** unit_pow
            gridf = 0.1
            if shift:
                grid /= 10
                gridf /= 10
            dist = grid * math.floor(0.5 + dist / grid)
            fac = gridf * math.floor(0.5 + fac / gridf)

        self.current = current
        self.relative = relative
        self.dpbu = dpbu
        self.unit_pow = unit_pow
        self.dist = dist
        self.fac = fac

    def draw_origin(self, radius=5, raydirections=[], raylength=5):
        draw_sun(self.origin[0], self.origin[1], radius, 16, \
                 raydirections, raylength)

    def draw_relative(self, radius=5):
        #if self.shift:
        draw_circle(self.origin[0] + self.relative[0], \
                    self.origin[1] + self.relative[1], radius, 16)

    def draw_lock_arrow(self, length=10, angle=math.radians(110)):
        if self.lock is not None:
            lock = self.lock.to_2d()
            origin = self.origin.to_2d()
            vec = (origin - lock).normalized()
            vec *= 20
            vecn = lock + vec
            draw_arrow(vecn[0], vecn[1], lock[0], lock[1], \
                       headlength=length, headangle=angle, headonly=True)

    def draw_factor_circle(self, subdivide=64):
        draw_circle(self.origin[0], self.origin[1], self.dpf, subdivide)
Example #8
0
class GlLine(GlBaseLine):
    """
        2d/3d Line
    """
    def __init__(self, d=3, p=None, v=None, p0=None, p1=None, z_axis=None):
        """
            d=3 use 3d coords, d=2 use 2d pixels coords
            Init by either
            p: Vector or tuple origin
            v: Vector or tuple size and direction
            or
            p0: Vector or tuple 1 point location
            p1: Vector or tuple 2 point location
            Will convert any into Vector 3d
            both optionnals
        """
        if p is not None and v is not None:
            self.p = Vector(p)
            self.v = Vector(v)
        elif p0 is not None and p1 is not None:
            self.p = Vector(p0)
            self.v = Vector(p1) - self.p
        else:
            self.p = Vector((0, 0, 0))
            self.v = Vector((0, 0, 0))
        if z_axis is not None:
            self.z_axis = z_axis
        else:
            self.z_axis = Vector((0, 0, 1))
        GlBaseLine.__init__(self, d)

    @property
    def p0(self):
        return self.p

    @property
    def p1(self):
        return self.p + self.v

    @p0.setter
    def p0(self, p0):
        """
            Note: setting p0
            move p0 only
        """
        p1 = self.p1
        self.p = Vector(p0)
        self.v = p1 - p0

    @p1.setter
    def p1(self, p1):
        """
            Note: setting p1
            move p1 only
        """
        self.v = Vector(p1) - self.p

    @property
    def length(self):
        return self.v.length

    @property
    def angle(self):
        return atan2(self.v.y, self.v.x)

    @property
    def cross(self):
        """
            Vector perpendicular on plane defined by z_axis
            lie on the right side
            p1
            |--x
            p0
        """
        return self.v.cross(self.z_axis)

    def normal(self, t=0):
        """
            Line perpendicular on plane defined by z_axis
            lie on the right side
            p1
            |--x
            p0
        """
        n = GlLine()
        n.p = self.lerp(t)
        n.v = self.cross
        return n

    def sized_normal(self, t, size):
        """
            GlLine perpendicular on plane defined by z_axis and of given size
            positionned at t in current line
            lie on the right side
            p1
            |--x
            p0
        """
        n = GlLine()
        n.p = self.lerp(t)
        n.v = size * self.cross.normalized()
        return n

    def lerp(self, t):
        """
            Interpolate along segment
            t parameter [0, 1] where 0 is start of arc and 1 is end
        """
        return self.p + self.v * t

    def offset(self, offset):
        """
            offset > 0 on the right part
        """
        self.p += offset * self.cross.normalized()

    def point_sur_segment(self, pt):
        """ point_sur_segment (2d)
            point: Vector 3d
            t: param t de l'intersection sur le segment courant
            d: distance laterale perpendiculaire positif a droite
        """
        dp = (pt - self.p).to_2d()
        v2d = self.v.to_2d()
        dl = v2d.length
        d = (self.v.x * dp.y - self.v.y * dp.x) / dl
        t = (v2d * dp) / (dl * dl)
        return t > 0 and t < 1, d, t

    @property
    def pts(self):
        return [self.p0, self.p1]
Example #9
0
class MouseCoordinate:
    '''
    origin, current, shiftからrelativeを求める。
    relativeをorigin -> lockのベクトルに正射影。

    exptargetsの例:
    exptargets = {'dist': [(self.mc, 'dist', self, 'dist', 0.0),
                           (self.mc.exp, 0, self, 'dist', Null())],
                  'fac': [(self.mc, 'fac', self, 'dist', 0.0),
                          (self.mc.exp, 0, self, 'dist', Null())]}
    set_values()
        引数無しの場合:
            self.exptargetsを全て処理。
        引数をタプルとして受けとった場合:
            例 set_values(self.mc, 'dist', self, 'dist', 0.0)
            これのみ処理。
        引数を辞書として受け取った場合:
            例 set_values(default=False, fac=True)
            キーが存在したらそれを真偽によって処理、
            その他の真偽はdefault(キーが無ければ真)。
    '''
    def __init__(self,
                 context=None,
                 event=None,
                 recalcDPBU=True,
                 dpf=200,
                 expnames=('Dist {exp}', )):
        self.shift = None  # *0.1. type:Vector. relativeに影響。
        self.lock = None  # lock direction. type:Vector. relativeに影響。
        self.snap = False  # type:Bool
        self.origin = Vector()  # Rキーで変更
        self.current = Vector(
        )  # (event.mouse_region_x, event.mouse_region_y, 0)
        self.relative = Vector()  # shift,lockを考慮
        self.dpbu = 1.0  # 初期化時、及びupdateの際に指定した場合に更新。
        self.unit_pow = 1.0  # 上記と同様
        self.dist = 0.0  # relativesnapを考慮
        self.fac = 0.0

        self.inputexp = False
        self.exp = InputExpression(names=expnames)
        #self.finaldist = 0.0  # exp等を考慮した最終的な値
        self.exptargets = {}

        self.shortcuts = []

        if event:
            self.origin = Vector((event.mouse_region_x, event.mouse_region_y, \
                                  0.0))
        self.dpf = dpf  # dot per fac
        self.update(context, event, recalcDPBU)

    def set_exptargets(self, exptargets):
        self.exptargets = exptargets

    def set_shortcuts(self, shortcuts):
        ''' default: SC = Shortcut
        shortcuts = [SC('lock', 'MIDDLEMOUSE'),
                     SC('reset', 'R'),
        '''
        self.shortcuts = shortcuts

    def set_values(self, *target, **kw):
        if target:
            self.exptargets['targetonly'] = target[0]
        for key, values in self.exptargets.items():
            if target:
                if key != 'targetonly':
                    continue
            elif kw:
                if key in kw:
                    if not kw[key]:
                        continue
                elif 'default' in kw:
                    if not kw['default']:
                        continue
            for obj, attr, tagobj, tagattr, err in values:
                # read
                if obj == self.exp:  # (self.exp, index)
                    if not self.inputexp:
                        continue
                    val = self.exp.get_exp_value(attr)
                    if val is None:
                        if isinstance(err, Null):
                            continue
                        val = err
                else:
                    if isinstance(attr, str):
                        val = getattr(obj, attr)
                    else:
                        val = obj[attr]
                # set
                if isinstance(tagattr, str):
                    setattr(tagobj, tagattr, val)
                else:
                    tagobj[tagattr] = val
        if target:
            del (self.exptargets['targetonly'])

    def handling_event(self, context, event):
        mouseco = Vector((event.mouse_region_x, event.mouse_region_y, 0.0))

        handled = True
        EXECUTE = True  # execute等を実行後、すぐにreturn {'RUNNING_MODAL'}
        if self.inputexp:  # evalの式の入力
            if event.value == 'PRESS':
                handled_by_exp = self.exp.input(event)
                if handled_by_exp:
                    self.set_values()
                    return handled, EXECUTE

        shortcut_name = check_shortcuts(self.shortcuts, event)

        if event.type == 'TAB' and event.value == 'PRESS':
            # <Input Expression>
            if self.inputexp and (event.shift or event.ctrl):
                self.inputexp = False
                self.update(context, event)
                self.set_values()
            elif not self.inputexp and not (event.shift or event.ctrl):
                self.inputexp = True
                self.set_values()
            else:
                handled = False
        elif event.type in ('ESC', 'RIGHTMOUSE') and event.value == 'PRESS':
            if self.inputexp:
                self.inputexp = False
                self.update(context, event)
                self.set_values()
            else:
                handled = False
        elif event.type in ('LEFT_SHIFT', 'RIGHT_SHIFT'):
            if event.value == 'PRESS':
                self.shift = mouseco.copy()
            elif event.value == 'RELEASE':
                self.shift = None
                self.update(context, event)
                self.set_values()
            else:
                handled = False
        elif event.type in ('LEFT_CTRL', 'RIGHT_CTRL'):
            if event.value == 'PRESS':
                self.snap = True
            elif event.value == 'RELEASE':
                self.snap = False
            self.update(context, event)
            self.set_values()
        elif event.type == 'MOUSEMOVE':
            # <Move Mouse>
            self.update(context, event)
            self.set_values()
        elif shortcut_name == 'lock':
            # <Lock Trans Axis>
            if self.lock is None:
                self.lock = mouseco.copy()
            else:
                self.lock = None
        elif shortcut_name == 'reset':
            # <Reset>
            if self.lock:
                self.lock = self.lock - self.origin + mouseco
            self.origin = mouseco.copy()
            self.update(context, event)
            self.set_values()
        else:
            handled = False
        return handled, False

    def update(self, context=None, event=None, recalcDPBU=False):
        shift = self.shift
        snap = self.snap
        lock = self.lock
        origin = self.origin

        if event:
            current = Vector((event.mouse_region_x, event.mouse_region_y, 0.0))
        else:
            current = self.current
        if shift:
            relative = shift - origin + (current - shift) * 0.1
        else:
            relative = current - origin
        if lock:
            origin_lock = lock - origin
            if origin_lock.length >= MIN_NUMBER:
                if relative.length >= MIN_NUMBER:
                    relative = relative.project(origin_lock)
            else:
                self.lock = None
        if context and recalcDPBU:
            dpbu, dx, unit_pow = get_DPBU_dx_unit_pow(context.region)
        else:
            dpbu, unit_pow = self.dpbu, self.unit_pow

        dist = relative.length / dpbu
        fac = relative.length / self.dpf
        if lock:
            if relative.dot(origin_lock) < 0.0:
                dist = -dist
                fac = -fac
        if snap:
            grid = 10**unit_pow
            gridf = 0.1
            if shift:
                grid /= 10
                gridf /= 10
            dist = grid * math.floor(0.5 + dist / grid)
            fac = gridf * math.floor(0.5 + fac / gridf)

        self.current = current
        self.relative = relative
        self.dpbu = dpbu
        self.unit_pow = unit_pow
        self.dist = dist
        self.fac = fac

    def draw_origin(self, radius=5, raydirections=[], raylength=5):
        draw_sun(self.origin[0], self.origin[1], radius, 16, \
                 raydirections, raylength)

    def draw_relative(self, radius=5):
        #if self.shift:
        draw_circle(self.origin[0] + self.relative[0], \
                    self.origin[1] + self.relative[1], radius, 16)

    def draw_lock_arrow(self, length=10, angle=math.radians(110)):
        if self.lock is not None:
            lock = self.lock.to_2d()
            origin = self.origin.to_2d()
            vec = (origin - lock).normalized()
            vec *= 20
            vecn = lock + vec
            draw_arrow(vecn[0], vecn[1], lock[0], lock[1], \
                       headlength=length, headangle=angle, headonly=True)

    def draw_factor_circle(self, subdivide=64):
        draw_circle(self.origin[0], self.origin[1], self.dpf, subdivide)
Example #10
0
    def execute(self, context):
        current = context.scene.frame_current + 1
        # context.scene.frame_current = current
        bpy.context.scene.frame_set(current)

        SPL = bpy.context.active_object

        Voronoi_collection = bpy.data.collections["Voronoi Diagram"]

        samples = []
        VPLs = []
        invalid_VPLs = []
        face_obs = []

        for VPL in bpy.data.collections['Indirect Lights'].all_objects.values(
        ):
            if (VPL.hide_viewport):
                invalid_VPLs += [VPL]
            else:
                VPLs += [VPL]

        # determine the validity of each VPL
        for VPL in VPLs:
            sample_direction = validateVPL(VPL, SPL)
            if (sample_direction):
                samples += [sample_direction]
            else:
                invalid_VPLs += [VPL]
                VPL.hide_viewport = True

        # Remove all invalid VPLs and Possibly a number of valid ones to imporvement the distribution
        for iVPL in invalid_VPLs:
            if iVPL in VPLs:
                VPLs.remove(iVPL)

        if (invalid_VPLs == []):
            return {'FINISHED'}

        # Create new VPLs accroding to allotted budget.

        # delete all old Voronoi face
        bpy.ops.object.select_all(action='DESELECT')
        for ob in Voronoi_collection.all_objects:
            ob.select_set(True)
        bpy.ops.object.delete()
        # create new Voronoi face
        sample_2d = []
        for sample in samples:
            sample_2d += [sample.to_2d().to_3d()]

        # createPointCloud(context, Voronoi_collection, name="Sample_Points", points=sample_2d, dim='2D')
        voronoi_faces, vo_verts = createVoronoiDiagramByCircle(
            context,
            Voronoi_collection,
            sample_2d,
            "Voronoi_face",
            circle_radius=sin(SPL.data.spot_size * 0.5))
        for face in voronoi_faces.values():
            createCustomProperty(context, face, "Type", 'Voronoi_Face',
                                 "face of Voronoi Diagram")

        # search min distance in all voronoi vertices
        distances = {}
        for vert in vo_verts:
            v = Vector(vert).to_3d()
            s = 0.0
            for sample in sample_2d:
                s += (sample - v).length
            distances[s] = v
        sort_vo_verts = [distances[k] for k in sorted(distances.keys())]

        # maximum number for try to add
        add_VPL_max = 10
        i = 0
        while (True):
            if (invalid_VPLs == []):
                break
            if (i >= add_VPL_max):
                break
            if (sort_vo_verts == []):
                break

            iVPL = invalid_VPLs[0]

            vert = sort_vo_verts.pop()
            # have numerical error
            if (vert.length_squared < 1.0):
                local_v = Vector(
                    (vert.x, vert.y, -math.sqrt(1.0 - vert.length_squared)))
            else:
                local_v = Vector((vert.x, vert.y, 0.0))

            world_v = SPL.matrix_world @ local_v

            intersection, intersect_ob = rayCastingMeshObjects(
                bpy.data.objects, [], SPL.location, world_v - SPL.location)

            if (intersection):
                # valid
                iVPL.hide_viewport = False
                # modify VPL
                iVPL.location = intersection
                iVPL["Hit_Object"] = intersect_ob
                invalid_VPLs.remove(iVPL)

                samples += [local_v]
                sample_2d += [local_v.to_2d().to_3d()]
                VPLs += [iVPL]
                i += 1

        # delete all old Voronoi face
        bpy.ops.object.select_all(action='DESELECT')
        for face in Voronoi_collection.all_objects:
            face.select_set(True)
        bpy.ops.object.delete()
        # recompute Voronoi Diagram and intersect by a circle
        createPointCloud(context,
                         Voronoi_collection,
                         name="Sample_Points",
                         points=sample_2d,
                         dim='2D')
        voronoi_faces, vo_verts = createVoronoiDiagramByCircle(
            context,
            Voronoi_collection,
            sample_2d,
            "Voronoi_face",
            circle_radius=sin(SPL.data.spot_size * 0.5))

        for face in voronoi_faces.values():
            createCustomProperty(context, face, "Type", 'Voronoi_Face',
                                 "face of Voronoi Diagram")

        # link and recompute area
        for sample_idx in range(len(VPLs)):
            VPLs[sample_idx]["Area"] = voronoi_faces[sample_idx]
            createCustomProperty(context, VPLs[sample_idx], "Area",
                                 voronoi_faces[sample_idx], "Voronoi Face")

        # Compute intensities for VPLs.
        area_sum = 0.0
        for VPL in VPLs:
            if (len(VPL['Area'].data.polygons) > 0):
                area_sum += VPL['Area'].data.polygons[0].area

        SPL_color = Color(SPL.data.color)
        SPL_energy = SPL.data.energy
        for VPL in VPLs:
            area = 0
            if (len(VPL['Area'].data.polygons) > 0):
                area = VPL['Area'].data.polygons[0].area
            ob_color = Color(VPL['Hit_Object'].material_slots[0].material.
                             diffuse_color[0:3])
            VPL.data.color = [
                SPL_color.r * ob_color.r, SPL_color.g * ob_color.g,
                SPL_color.b * ob_color.b
            ]
            # VPL.data.color = [ob_color.r, ob_color.g, ob_color.b]
            VPL.data.energy = SPL_energy * (area / area_sum)

        # keyframe insert
        for VPL in bpy.data.collections['Indirect Lights'].all_objects.values(
        ):
            VPL.keyframe_insert(data_path='hide_viewport', frame=current)
            VPL.keyframe_insert(data_path='location', frame=current)
            VPL.data.keyframe_insert(data_path='color', frame=current)
            VPL.data.keyframe_insert(data_path='energy', frame=current)

        bpy.ops.object.select_all(action='DESELECT')
        SPL.select_set(True)
        context.view_layer.objects.active = SPL

        return {'FINISHED'}