Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions declarations.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ class Operators(str, Enum):
AddRatio = "view3d.slvs_add_ratio"
AddRectangle = "view3d.slvs_add_rectangle"
AddSketch = "view3d.slvs_add_sketch"
AddSketchFace = "view3d.slvs_add_sketch_face"
ProjectInclude = "view3d.slvs_project_include"
AddTangent = "view3d.slvs_add_tangent"
AddVertical = "view3d.slvs_add_vertical"
AddWorkPlane = "view3d.slvs_add_workplane"
Expand Down Expand Up @@ -106,8 +108,10 @@ class WorkSpaceTools(str, Enum):
AddPoint2D = "sketcher.slvs_add_point2d"
AddPoint3D = "sketcher.slvs_add_point3d"
AddRectangle = "sketcher.slvs_add_rectangle"
AddSketchFace = "sketcher.slvs_add_sketch_face"
AddWorkplane = "sketcher.slvs_add_workplane"
AddWorkplaneFace = "sketcher.slvs_add_workplane_face"
ProjectInclude = "sketcher.slvs_project_include"
Offset = "sketcher.slvs_offset"
Select = "sketcher.slvs_select"
Trim = "sketcher.slvs_trim"
Expand Down
11 changes: 6 additions & 5 deletions keymaps.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,11 @@
WorkSpaceTools.AddCircle2D,
Operators.AddCircle2D,
),
tool_invoke_kmi(
"I",
WorkSpaceTools.ProjectInclude,
Operators.ProjectInclude,
),
tool_invoke_kmi(
"A",
WorkSpaceTools.AddArc2D,
Expand All @@ -166,11 +171,7 @@
WorkSpaceTools.Bevel,
Operators.Bevel,
),
tool_invoke_kmi(
"O",
WorkSpaceTools.Offset,
Operators.Offset
),
tool_invoke_kmi("O", WorkSpaceTools.Offset, Operators.Offset),
(
Operators.AddSketch,
{"type": "S", "value": "PRESS"},
Expand Down
3 changes: 2 additions & 1 deletion operators/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from ..utilities.register import module_register_factory
from ..stateful_operator.utilities.register import register_stateops_factory
from ..utilities.register import module_register_factory

modules = [
"select",
Expand Down Expand Up @@ -36,6 +36,7 @@
"add_geometric_constraints",
"align_workplane",
"align_view",
"project_include",
"modifiers",
"move",
"duplicate",
Expand Down
7 changes: 3 additions & 4 deletions operators/add_sketch.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
import logging

import bpy
from bpy.types import Operator, Context, Event
from bpy.types import Context, Event, Operator

from ..model.types import SlvsWorkplane
from ..declarations import Operators
from ..stateful_operator.utilities.register import register_stateops_factory
from ..model.types import SlvsWorkplane
from ..stateful_operator.state import state_from_args
from ..stateful_operator.utilities.register import register_stateops_factory
from .base_3d import Operator3d
from .utilities import activate_sketch, switch_sketch_mode


logger = logging.getLogger(__name__)


Expand Down
15 changes: 7 additions & 8 deletions operators/add_workplane.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
import logging

import bpy
from bpy.types import Operator, Context
from bpy.types import Context, Operator

from .. import global_data
from ..model.types import SlvsNormal3D
from ..model.categories import NORMAL3D

from ..utilities.geometry import get_face_orientation
from ..declarations import Operators
from ..stateful_operator.utilities.register import register_stateops_factory
from ..model.categories import NORMAL3D
from ..model.types import SlvsNormal3D
from ..solver import solve_system
from ..stateful_operator.state import state_from_args
from ..stateful_operator.utilities.geometry import get_evaluated_obj, get_mesh_element
from ..solver import solve_system
from ..stateful_operator.utilities.register import register_stateops_factory
from ..utilities.geometry import get_face_orientation
from ..utilities.view import get_placement_pos
from .base_3d import Operator3d
from .constants import types_point_3d
from .utilities import ignore_hover
from ..utilities.view import get_placement_pos

logger = logging.getLogger(__name__)

Expand Down
5 changes: 2 additions & 3 deletions operators/base_2d.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,11 @@
from bpy.types import Context, Event
from mathutils import Vector

from ..model.types import SlvsPoint2D
from ..model.types import SlvsLine2D, SlvsCircle, SlvsArc
from ..model.types import SlvsArc, SlvsCircle, SlvsLine2D, SlvsPoint2D
from ..model.utilities import slvs_entity_pointer
from ..utilities.view import get_pos_2d, get_scale_from_pos
from .base_stateful import GenericEntityOp
from .utilities import ignore_hover
from ..utilities.view import get_pos_2d, get_scale_from_pos


class Operator2d(GenericEntityOp):
Expand Down
5 changes: 5 additions & 0 deletions operators/project_include/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from .project_include import View3D_OT_slvs_project_include, register

__all__ = ["View3D_OT_slvs_project_include"]
if __name__ == "__main__":
register()
48 changes: 48 additions & 0 deletions operators/project_include/get_object_under_mouse.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import bpy
import bpy_extras
from bpy.types import Context, Event


def get_object_under_mouse(
context: Context, event: Event, return_index: bool = False
) -> tuple[bpy.types.MeshPolygon | bpy.types.Mesh | None, int | None]:
region = context.region
rv3d = context.space_data.region_3d
coord = (event.mouse_region_x, event.mouse_region_y)

view_vector = bpy_extras.view3d_utils.region_2d_to_vector_3d(region, rv3d, coord)
ray_origin = bpy_extras.view3d_utils.region_2d_to_origin_3d(region, rv3d, coord)

depsgraph = context.view_layer.depsgraph
hit, location, normal, face_index, obj, matrix = context.scene.ray_cast(
depsgraph, ray_origin, view_vector
)
if hit:
if getattr(event, "shift", False):
return _handle_shift(
context=context,
obj=obj,
face_index=face_index,
return_index=return_index,
)
else:
if hit:
return obj, None

return None, None


def _handle_shift(
context: Context, obj: bpy.types.Object, face_index: int, return_index: bool = False
) -> tuple[bpy.types.MeshPolygon | bpy.types.Mesh, int | None]:
depsgraph = context.view_layer.depsgraph
# Get the evaluated mesh for up-to-date data with modifiers
obj_eval = obj.evaluated_get(depsgraph)
mesh = obj_eval.to_mesh()

if return_index:
return obj, face_index

if face_index != -1 and 0 <= face_index < len(mesh.polygons):
face = mesh.polygons[face_index]
return face, None
64 changes: 64 additions & 0 deletions operators/project_include/handle_highlight.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import bpy
from bpy.types import Context, Event

from ..base_2d import Operator2d
from .get_object_under_mouse import get_object_under_mouse

highlight_name = "HighlightFace"


def clear_highlight(context: Context):
prev_highlight = context.scene.objects.get(highlight_name)
if prev_highlight:
bpy.data.objects.remove(prev_highlight, do_unlink=True)


def handle_highlight(self: Operator2d, context: Context, event: Event):
clear_highlight(context=context)

obj, face_index = get_object_under_mouse(context, event, return_index=True)

if not obj:
return # Nothing to highlight

mesh = obj.data
if face_index is not None:
faces = [mesh.polygons[face_index]]
else:
faces = list(mesh.polygons)

# Build vertices and face indices for all faces
verts = []
faces_indices = []
vert_idx = 0
for face in faces:
face_verts = [obj.matrix_world @ mesh.vertices[i].co for i in face.vertices]
verts.extend(face_verts)
faces_indices.append(list(range(vert_idx, vert_idx + len(face_verts))))
vert_idx += len(face_verts)

if not verts or not faces_indices:
return

mesh_data = bpy.data.meshes.new(highlight_name)
mesh_data.from_pydata(verts, [], faces_indices)
mesh_data.update()

highlight_obj = bpy.data.objects.new(highlight_name, mesh_data)
context.collection.objects.link(highlight_obj)

# Set highlight material (reuse or create)
mat_name = "HighlightMaterial"
mat = bpy.data.materials.get(mat_name)
if mat is None:
mat = bpy.data.materials.new(name=mat_name)
mat.use_nodes = True
bsdf = mat.node_tree.nodes.get("Principled BSDF")
if bsdf:
bsdf.inputs["Base Color"].default_value = (0.25, 1, 0, 1) # Yellow
bsdf.inputs["Alpha"].default_value = 1
mat.blend_method = "BLEND"
mesh_data.materials.append(mat)

highlight_obj.hide_select = True
highlight_obj.hide_render = True
59 changes: 59 additions & 0 deletions operators/project_include/object_interface.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
from typing import Protocol, Union

import bpy
from bpy.types import MeshPolygon


class ObjectInterfaceProtocol(Protocol):
def get_verticies(self) -> list[bpy.types.MeshVertex]:
pass

def get_edges(self) -> list[bpy.types.MeshEdges]:
pass


class ObjectInterface:

obj: bpy.types.Object

def __init__(self, obj: bpy.types.Object):
self.obj = obj

def get_verticies(self) -> list[bpy.types.MeshVertex]:
return self.obj.data.vertices

def get_edges(self) -> list[bpy.types.MeshEdges]:
return self.obj.data.edges


class FaceInterface:

obj: bpy.types.Object
face_index: int

def __init__(self, obj: bpy.types.Object, face_index: int):
self.obj = obj
self.face_index = face_index

def get_verticies(self) -> list[bpy.types.MeshVertex]:
return [
self.obj.data.vertices[vertex_index] for vertex_index in self._face.vertices
]

def get_edges(self) -> list[bpy.types.MeshEdges]:
edges_with_nones = [
self._get_edge(edge_key=edge_key) for edge_key in self._face.edge_keys
]

return [x for x in edges_with_nones if x is not None]

@property
def _face(self) -> MeshPolygon:
return self.obj.data.polygons[self.face_index]

def _get_edge(self, edge_key: tuple[int, int]) -> Union[None, bpy.types.MeshEdge]:
for edge in self.obj.data.edges:
if edge.key == edge_key:
return edge

return None
Loading