Skip to content

Commit

Permalink
Improved type annotations for operator_func module with Pyright. Upda…
Browse files Browse the repository at this point in the history
…ted the sqlite_bedrock_packs module.
  • Loading branch information
Nusiq committed Aug 29, 2023
1 parent d498e9e commit 3db7654
Show file tree
Hide file tree
Showing 11 changed files with 193 additions and 120 deletions.
7 changes: 4 additions & 3 deletions mcblend/operator_func/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ def import_model(data: Dict, geometry_name: str, context: Context) -> List[str]:
model_loader = ModelLoader(data, geometry_name)
geometry = ImportGeometry(model_loader)
armature = geometry.build_with_armature(context)
model_properties = armature.mcblend
model_properties = get_mcblend(armature)

model_properties.texture_width = geometry.texture_width
model_properties.texture_height = geometry.texture_height
Expand Down Expand Up @@ -551,7 +551,7 @@ def import_model_form_project(
armature = geometry.build_with_armature(context)

# 2.1. Set proper textures resolution and model bounds
model_properties = armature.mcblend
model_properties = get_mcblend(armature)
model_properties = cast(
MCBLEND_ObjectProperties, model_properties)

Expand All @@ -571,7 +571,7 @@ def import_model_form_project(

# 2.2. Save render controller properties in the armature
for rc_stack_item in rc_stack:
armature_rc = armature.mcblend.\
armature_rc = get_mcblend(armature).\
render_controllers.add()
if rc_stack_item.texture is not None:
armature_rc.texture = rc_stack_item.texture.name
Expand Down Expand Up @@ -752,6 +752,7 @@ def prepare_physics_simulation(context: Context) -> Dict:
if not child.mctype == MCObjType.CUBE:
continue
new_obj = child.thisobj.copy()
new_obj = cast(Object, new_obj)
new_obj.data = child.obj_data.copy()
new_obj.animation_data_clear()
get_objects(context.collection).link(new_obj)
Expand Down
28 changes: 14 additions & 14 deletions mcblend/operator_func/animation.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
from __future__ import annotations

from typing import NamedTuple, Dict, Optional, List, Tuple, Set, cast
import math
import math # pyright: ignore[reportShadowedImports]
from dataclasses import dataclass, field
from itertools import tee, islice
from itertools import tee, islice # pyright: ignore[reportShadowedImports]

import bpy
from bpy.types import Action, Context
Expand All @@ -15,19 +15,19 @@
import numpy as np

from .typed_bpy_access import (
get_fcurves, get_keyframe_points, get_nla_tracks, get_selected_objects,
get_fcurves, get_keyframe_points, get_nla_tracks,
get_strips, get_timeline_markers)
from .json_tools import get_vect_json
from .common import (
AnimationLoopType, MINECRAFT_SCALE_FACTOR, MCObjType, McblendObjectGroup,
ANIMATION_TIMESTAMP_PRECISION,
ANIMATION_TIMESTAMP_PRECISION, NumpyTable
)


def _pick_closest_rotation(
base: np.ndarray, close_to: np.ndarray,
original_rotation: Optional[np.ndarray] = None
) -> np.ndarray:
base: NumpyTable, close_to: NumpyTable,
original_rotation: Optional[NumpyTable] = None
) -> NumpyTable:
'''
Takes two arrays with euler rotations in degrees. Looks for rotations
that result in same orientation ad the base rotation. Picks the vector
Expand All @@ -37,7 +37,7 @@ def _pick_closest_rotation(
bones rotated before the animation. Issue #25 on Github describes the
problem in detail.
:base: np.ndarray: the base rotation. Function is looking for different
:base: NumpyTable: the base rotation. Function is looking for different
representations of this orientation.
:param close_to: target rotation. Function returns the result as close
as possible to this vector.
Expand All @@ -50,9 +50,9 @@ def _pick_closest_rotation(
original_rotation = np.array([0.0, 0.0, 0.0])

def _pick_closet_location(
base: np.ndarray, close_to: np.ndarray
) -> Tuple[float, np.ndarray]:
choice: np.ndarray = base
base: NumpyTable, close_to: NumpyTable
) -> Tuple[float, NumpyTable]:
choice: NumpyTable = base
distance = np.linalg.norm(choice - close_to)

for i in range(3): # Adds removes 360 to all 3 axis (picks the best)
Expand Down Expand Up @@ -175,9 +175,9 @@ def get_action_keyframes(action: Action) -> List[float]:
class PoseBone(NamedTuple):
'''Properties of a pose of single bone.'''
name: str
location: np.ndarray
rotation: np.ndarray
scale: np.ndarray
location: NumpyTable
rotation: NumpyTable
scale: NumpyTable
parent_name: Optional[str] = None

def relative(self, original: PoseBone) -> PoseBone:
Expand Down
82 changes: 53 additions & 29 deletions mcblend/operator_func/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@
from enum import Enum
from typing import (
Deque, Dict, Iterator, NamedTuple, List, Optional, Tuple, Any, Iterable,
Sequence, cast)
Sequence, cast, TypeAlias, Literal, ClassVar)
from collections import deque

import numpy as np
import numpy.typing as npt

import bpy
from bpy.types import MeshUVLoopLayer, Object, MeshPolygon, PoseBone, Context
Expand All @@ -26,7 +27,9 @@
from .texture_generator import Mask, ColorMask, get_masks_from_side
from .exception import ExporterException

MINECRAFT_SCALE_FACTOR = 16
NumpyTable: TypeAlias = npt.NDArray[np.float64]

MINECRAFT_SCALE_FACTOR = 16.0
'''The scale convertion from blender to minecraft (16 units == 1 meter).'''

ANIMATION_TIMESTAMP_PRECISION = 2
Expand Down Expand Up @@ -89,15 +92,22 @@ class McblendObject:
:param group: The :class:`McblendObjectGroup` that stores all of the
:class:`McblendObject`s being processed with this object.
'''
thisobj_id: ObjectId
thisobj: Object
parentobj_id: ObjectId | None
children_ids: list[ObjectId]
mctype: MCObjType
group: McblendObjectGroup

def __init__(
self, thisobj_id: ObjectId, thisobj: Object,
parentobj_id: Optional[ObjectId], children_ids: List[ObjectId],
parentobj_id: ObjectId | None, children_ids: list[ObjectId],
mctype: MCObjType, group: McblendObjectGroup):
self.thisobj_id = thisobj_id
self.thisobj: Object = thisobj
self.parentobj_id: Optional[ObjectId] = parentobj_id
self.children_ids: List[ObjectId] = children_ids
self.mctype: MCObjType = mctype
self.thisobj = thisobj
self.parentobj_id = parentobj_id
self.children_ids = children_ids
self.mctype = mctype
self.group = group

@property
Expand Down Expand Up @@ -132,13 +142,13 @@ def inflate(self, inflate: float):
get_mcblend(self.thisobj).inflate = inflate

@property
def min_uv_size(self) -> np.ndarray:
def min_uv_size(self) -> NumpyTable:
'''The lower UV size limit of this object.'''
return np.array(
get_mcblend(self.thisobj).min_uv_size)

@min_uv_size.setter
def min_uv_size(self, min_uv_size: np.ndarray):
def min_uv_size(self, min_uv_size: NumpyTable):
get_mcblend(self.thisobj).min_uv_size = cast(
tuple[int, int, int],min_uv_size)

Expand Down Expand Up @@ -226,7 +236,7 @@ def obj_matrix_world(self) -> Matrix:
return this_obj_matrix_world

@property
def mcube_size(self) -> np.ndarray:
def mcube_size(self) -> NumpyTable:
'''
The cube size in Minecraft format based on the bounding box of the
blender object wrapped inside this object.
Expand All @@ -236,15 +246,15 @@ def mcube_size(self) -> np.ndarray:
return (np.array(bound_box[6]) - np.array(bound_box[0]))[[0, 2, 1]]

@property
def mccube_position(self) -> np.ndarray:
def mccube_position(self) -> NumpyTable:
'''
The cube position in Minecraft format based on the bounding box of
the blender object wrapped inside this object.
'''
return np.array(self.obj_bound_box[0])[[0, 2, 1]]

@property
def mcpivot(self) -> np.ndarray:
def mcpivot(self) -> NumpyTable:
'''
The pivot point of Minecraft object exported using this object.
'''
Expand Down Expand Up @@ -298,7 +308,7 @@ def get_local_matrix(

def get_mcrotation(
self, other: Optional[McblendObject] = None
) -> np.ndarray:
) -> NumpyTable:
'''
Returns the Minecraft rotation of this object optionally in relation
to the other :class:`McblendObject`.
Expand All @@ -324,7 +334,7 @@ def local_rotation(
)
else:
result_euler = to_euler(self.obj_matrix_world, 'XZY')
result: np.ndarray = np.array(result_euler)[[0, 2, 1]]
result: NumpyTable = np.array(result_euler)[[0, 2, 1]]
result = result * np.array([1, -1, 1])
result = result * 180/math.pi # math.degrees() for array
return result
Expand Down Expand Up @@ -450,6 +460,11 @@ def find_lose_parts(self) -> Tuple[int, ...]:
aptr.value = min(a, b)
return tuple(i.value for i in groups)

FaceName: TypeAlias = Literal[
'north', 'east', 'south', 'west', 'up', 'down']
FacePattern: TypeAlias = Literal[
'---', '+--', '-+-', '++-', '--+', '+-+', '-++', '+++']

# TODO - CubePolygonsSolver, CubePolygons and CubePolygon is a messy structure
# maybe CubePolygonsSolver should be removed
class CubePolygonsSolver:
Expand All @@ -465,18 +480,21 @@ class CubePolygonsSolver:
- solution - a list of assigned positions of vertices (list of names like
'+++').
'''
FACE_PATTERNS = [
FACE_PATTERNS: ClassVar[list[list[FacePattern]]] = [
['---', '+--', '+-+', '--+'], # Cube Front (north)
['--+', '-++', '-+-', '---'], # Cube Right (east)
['-++', '+++', '++-', '-+-'], # Cube Back (south)
['+--', '++-', '+++', '+-+'], # Cube Left (west)
['--+', '+-+', '+++', '-++'], # Cube Up (up)
['-+-', '++-', '+--', '---'], # Cube Down (down)
]
FACE_NAMES = ['north', 'east', 'south', 'west', 'up', 'down']
FACE_NAMES: ClassVar[list[FaceName]] = [
'north', 'east', 'south', 'west', 'up', 'down']

# key (side, is_mirrored) : value (names of the vertices)
MC_MAPPING_UV_ORDERS = {
MC_MAPPING_UV_ORDERS: ClassVar[
dict[tuple[FaceName, bool], tuple[str, str, str, str]]
] = {
('east', False) :('-+-', '---', '--+', '-++'),
('north', False) :('---', '+--', '+-+', '--+'),
('west', False) :('+--', '++-', '+++', '+-+'),
Expand All @@ -491,17 +509,22 @@ class CubePolygonsSolver:
('down', True) :('++-', '-+-', '---', '+--'),
}

p_options: list[list[str]]
polygons: Iterable[MeshPolygon]
solved: bool
solution: list[str | None]

def __init__(
self, p_options: List[List[str]],
polygons: Iterable[MeshPolygon]):
self.p_options = p_options
self.polygons = polygons
self.solved = False
self.solution: List[Optional[str]] = [None] * 8
self.solution = [None] * 8

@staticmethod
def _get_vertices_order(
name: str, mirror: bool,
name: FaceName, mirror: bool,
bound_box_vertices: List[str | None]
) -> Tuple[int, int, int, int]:
'''Gets the order of vertices for given cube polygon'''
Expand Down Expand Up @@ -547,7 +570,7 @@ def is_valid(self):
'''
used_face_patterns = [False]*6
for polygon in self.polygons:
complete_face = [None]*4
complete_face: list[str | None] = [None]*4
for i, vertex_index in enumerate(polygon.vertices):
complete_face[i] = self.solution[vertex_index]
if None in complete_face:
Expand Down Expand Up @@ -690,7 +713,7 @@ class CubePolygon(NamedTuple):
order: Tuple[int, int, int, int]

def uv_layer_coordinates(
self, uv_layer: MeshUVLoopLayer) -> np.ndarray:
self, uv_layer: MeshUVLoopLayer) -> NumpyTable:
'''
Returns 4x2 numpy array with UV coordinates of this cube polygon loops
from the uv_layer. The order of the coordinates in the array is
Expand All @@ -702,7 +725,7 @@ def uv_layer_coordinates(
return crds

@staticmethod
def validate_rectangle_uv(crds: np.ndarray) -> Tuple[bool, bool, bool]:
def validate_rectangle_uv(crds: NumpyTable) -> Tuple[bool, bool, bool]:
'''
Takes an 4x2 array with UV coordinates of 4 points (left bottom,
right bottom, right top, left top) and checks if they're mapped to
Expand Down Expand Up @@ -758,12 +781,13 @@ class McblendObjectGroup:
transformation space of the animation. Animating that object is
equivalent to animating everything else in opposite way.
'''
def __init__(
self, armature: Object,
world_origin: Optional[Object]):
self.data: Dict[ObjectId, McblendObject] = {}
data: dict[ObjectId, McblendObject]
world_origin: Object | None

def __init__(self, armature: Object, world_origin: Optional[Object]):
self.data = {}
'''the content of the group.'''
self.world_origin: Optional[Object] = world_origin
self.world_origin = world_origin
self._load_objects(armature)

def get_world_origin_matrix(self):
Expand Down Expand Up @@ -853,7 +877,7 @@ def _load_objects(self, armature: Object):
children_ids=[], mctype=MCObjType.LOCATOR, group=self)
self.data[parentobj_id].children_ids.append(obj_id)

def cyclic_equiv(u: List, v: List) -> bool:
def cyclic_equiv(u: list[Any], v: list[Any]) -> bool:
'''
Compare cyclic equivalency of two lists.
Expand Down Expand Up @@ -950,7 +974,7 @@ def fix_cube_rotation(obj: Object):
set_matrix_local(obj, matmul_chain(
loc_mat, counter_rotation, rot_mat, scl_mat))

def get_vect_json(arr: Iterable) -> List[float]:
def get_vect_json(arr: Iterable) -> list[float]:
'''
Changes the iterable of numbers into basic python list of floats.
Values from the original iterable are rounded to the 3rd deimal
Expand Down
Loading

0 comments on commit 3db7654

Please sign in to comment.