basically finish rail adder

This commit is contained in:
yyc12345 2024-01-07 17:33:21 +08:00
parent b5565d796a
commit f9502fe2d4
2 changed files with 405 additions and 237 deletions

View File

@ -10,163 +10,360 @@ from . import UTIL_functions, UTIL_naming_convension
# BallRadius is the radius of player ball. It always is 2. # BallRadius is the radius of player ball. It always is 2.
# Ref: https://tieba.baidu.com/p/6557180791 # Ref: https://tieba.baidu.com/p/6557180791
#region Operators #region Operator Helpers
class SharedRailSectionInputProperty():
"""
This class is served for user to pick the transition type of rail.
And order rail radius and span accoridng to user picked rail type.
"""
rail_type: bpy.props.EnumProperty(
name = "Type",
description = "Rail type",
items = [
('MONORAIL', "Monorail", ""),
('RAIL', "Rail", ""),
],
default = 'RAIL',
) # type: ignore
class SharedRailInputProperty():
rail_radius: bpy.props.FloatProperty( rail_radius: bpy.props.FloatProperty(
name = "Rail Radius", name = "Radius",
description = "Define rail section radius", description = "Define rail section radius",
default = 0.35, default = 0.35,
min = 0, min = 0,
unit = 'LENGTH'
) # type: ignore ) # type: ignore
rail_span: bpy.props.FloatProperty( rail_span: bpy.props.FloatProperty(
name = "Rail Span", name = "Span",
description = "The length between 2 single rails.", description = "The length between 2 single rails.",
default = 3.75, default = 3.75,
min = 0, min = 0,
unit = 'LENGTH'
) # type: ignore ) # type: ignore
rail_length: bpy.props.FloatProperty( def draw_rail_section_input(self, layout: bpy.types.UILayout, force_monorail: bool | None) -> None:
name = "Rail Length", """
description = "The length of this rail.", Draw rail section properties
default = 5.0,
min = 0,
step = 50, # same unit as BME Struct
) # type: ignore
rail_cap: bpy.props.BoolProperty( @param force_monorail[in] Force this draw method for monorail if True, or for rail if False. Accept None if you want user to choose it.
name = 'Rail Cap', """
description = 'Whether this rail should have terminal cap.', if force_monorail is None:
default = False # show picker to allow user pick
) # type: ignore layout.prop(self, 'rail_type', expand = True)
# show radius
def draw_rail_radius_input(self, layout: bpy.types.UILayout) -> None: layout.prop(self, "rail_radius")
layout.prop(self, "rail_radius") # show span for rail
def draw_rail_span_input(self, layout: bpy.types.UILayout) -> None: if self.rail_type == 'RAIL':
layout.prop(self, "rail_span") layout.prop(self, "rail_span")
def draw_rail_length_input(self, layout: bpy.types.UILayout) -> None: else:
layout.prop(self, "rail_length") # according to force type to show
def draw_rail_cap_input(self, layout: bpy.types.UILayout) -> None: # always show radius
layout.prop(self, "rail_cap") layout.prop(self, "rail_radius")
# show span in condition
if not force_monorail:
layout.prop(self, "rail_span")
def general_get_is_monorail(self) -> bool:
return self.rail_type == 'MONORAIL'
def general_get_rail_radius(self) -> float: def general_get_rail_radius(self) -> float:
return self.rail_radius return self.rail_radius
def general_get_rail_span(self) -> float: def general_get_rail_span(self) -> float:
return self.rail_span return self.rail_span
class SharedRailCapInputProperty():
"""
This class provide properties for cap switch.
Support head cap and tail cap. Both straight and screw rail can use this.
"""
rail_start_cap: bpy.props.BoolProperty(
name = 'Start Cap',
description = 'Whether this rail should have cap at start terminal.',
default = False
) # type: ignore
rail_end_cap: bpy.props.BoolProperty(
name = 'End Cap',
description = 'Whether this rail should have cap at end terminal.',
default = False
) # type: ignore
def draw_rail_cap_input(self, layout: bpy.types.UILayout) -> None:
row = layout.row()
row.prop(self, "rail_start_cap", toggle = 1)
row.prop(self, "rail_end_cap", toggle = 1)
def general_get_rail_start_cap(self) -> bool:
return self.rail_start_cap
def general_get_rail_end_cap(self) -> bool:
return self.rail_end_cap
class SharedStraightRailInputProperty():
"""
The properties for straight rail.
"""
rail_length: bpy.props.FloatProperty(
name = "Length",
description = "The length of this rail.",
default = 5.0,
min = 0,
step = 50, # same unit as BME Struct
unit = 'LENGTH'
) # type: ignore
def draw_straight_rail_input(self, layout: bpy.types.UILayout) -> None:
layout.prop(self, "rail_length")
def general_get_rail_length(self) -> float: def general_get_rail_length(self) -> float:
return self.rail_length return self.rail_length
def general_get_rail_cap(self) -> bool:
return self.rail_cap
class BBP_OT_add_monorail_section(SharedRailInputProperty, bpy.types.Operator): class SharedScrewRailInputProperty():
"""Add Monorail Section""" """
bl_idname = "bbp.add_monorail_section" The properties for straight rail.
bl_label = "Monorail Section" """
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context): rail_screw_angle: bpy.props.FloatProperty(
_create_monorail_section(self.general_get_rail_radius()) name = "Angle",
return {'FINISHED'} description = "The angle of this screw rail rotated in one interation.",
default = 90,
subtype = 'ANGLE',
) # type: ignore
def draw(self, context): rail_screw_screw: bpy.props.FloatProperty(
layout = self.layout name = "Screw",
self.draw_rail_radius_input(layout) description = "The increased height in each iteration. Minus height also is accepted.",
default = 6,
unit = 'LENGTH'
) # type: ignore
class BBP_OT_add_rail_section(SharedRailInputProperty, bpy.types.Operator): rail_screw_iterations: bpy.props.IntProperty(
name = "Iterations",
description = "The angle of this screw rail rotated in one interation.",
default = 1,
min = 1,
) # type: ignore
rail_screw_steps: bpy.props.IntProperty(
name = "Steps",
description = "The segment count per iteration.",
default = 20,
min = 1,
) # type: ignore
rail_screw_radius: bpy.props.FloatProperty(
name = "Radius",
description = "The screw radius. Minus radius will flip the built screw.",
default = 10,
unit = 'LENGTH'
) # type: ignore
def draw_screw_rail_input(self, layout: bpy.types.UILayout, show_for_screw: bool) -> None:
if show_for_screw:
# screw do not need angle property
layout.prop(self, "rail_screw_screw")
layout.prop(self, "rail_screw_iterations")
layout.prop(self, "rail_screw_radius")
layout.prop(self, "rail_screw_steps")
else:
# curve do not need iterations (always is 1)
# and do not need screw (always is 0)
layout.prop(self, "rail_screw_angle")
layout.prop(self, "rail_screw_radius")
layout.prop(self, "rail_screw_steps")
# Getter should return default value if corresponding field
# is not existing in that mode.
def general_get_rail_screw_angle(self, is_for_screw: bool) -> float:
"""This function return angle in degree unit."""
return 360 if is_for_screw else self.rail_screw_angle
def general_get_rail_screw_screw(self, is_for_screw: bool) -> float:
return self.rail_screw_screw if is_for_screw else 0
def general_get_rail_screw_iterations(self, is_for_screw: bool) -> int:
return self.rail_screw_iterations if is_for_screw else 1
def general_get_rail_screw_radius(self) -> float:
return self.rail_screw_radius
def general_get_rail_screw_steps(self) -> int:
return self.rail_screw_steps
#endregion
#region Operators
class BBP_OT_add_rail_section(SharedRailSectionInputProperty, bpy.types.Operator):
"""Add Rail Section""" """Add Rail Section"""
bl_idname = "bbp.add_rail_section" bl_idname = "bbp.add_rail_section"
bl_label = "Rail Section" bl_label = "Rail Section"
bl_options = {'REGISTER', 'UNDO'} bl_options = {'REGISTER', 'UNDO'}
def execute(self, context): def execute(self, context):
_create_rail_section(self.general_get_rail_radius(), self.general_get_rail_span()) _rail_creator_wrapper(
lambda bm: _create_rail_section(
bm,
self.general_get_is_monorail(), self.general_get_rail_radius(), self.general_get_rail_span()
)
)
return {'FINISHED'} return {'FINISHED'}
def draw(self, context): def draw(self, context):
layout = self.layout layout = self.layout
self.draw_rail_radius_input(layout) self.draw_rail_section_input(layout, None)
self.draw_rail_span_input(layout)
class BBP_OT_add_transition_section(SharedRailInputProperty, bpy.types.Operator): class BBP_OT_add_transition_section(SharedRailSectionInputProperty, bpy.types.Operator):
"""Add Transition Section""" """Add Transition Section"""
bl_idname = "bbp.add_transition_section" bl_idname = "bbp.add_transition_section"
bl_label = "Transition Section" bl_label = "Transition Section"
bl_options = {'REGISTER', 'UNDO'} bl_options = {'REGISTER', 'UNDO'}
def execute(self, context): def execute(self, context):
# calc sink _rail_creator_wrapper(
radius_: float = self.general_get_rail_radius() lambda bm: _create_transition_section(
span_: float = self.general_get_rail_span() bm,
sink_: float self.general_get_rail_radius(), self.general_get_rail_span()
try: )
sink_ = math.sqrt((radius_ + 2) ** 2 - (span_ / 2) ** 2) - 2 - radius_
except:
sink_ = -2 # if sqrt(minus number) happended, it mean no triangle relation. the depth should always be -2.
# create section
_create_transition_section(radius_, span_, sink_)
return {'FINISHED'}
def draw(self, context):
layout = self.layout
self.draw_rail_radius_input(layout)
self.draw_rail_span_input(layout)
class BBP_OT_add_straight_monorail(SharedRailInputProperty, bpy.types.Operator):
"""Add Straight Monorail"""
bl_idname = "bbp.add_straight_monorail"
bl_label = "Straight Monorail"
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
_create_straight_monorail(
self.general_get_rail_radius(),
self.general_get_rail_length(),
self.general_get_rail_cap()
) )
return {'FINISHED'} return {'FINISHED'}
def draw(self, context): def draw(self, context):
layout = self.layout layout = self.layout
self.draw_rail_radius_input(layout) # force show double rail params
self.draw_rail_length_input(layout) self.draw_rail_section_input(layout, False)
self.draw_rail_cap_input(layout)
class BBP_OT_add_straight_rail(SharedRailInputProperty, bpy.types.Operator): class BBP_OT_add_straight_rail(SharedRailSectionInputProperty, SharedRailCapInputProperty, SharedStraightRailInputProperty, bpy.types.Operator):
"""Add Straight Rail""" """Add Straight Rail"""
bl_idname = "bbp.add_straight_rail" bl_idname = "bbp.add_straight_rail"
bl_label = "Straight Rail" bl_label = "Straight Rail"
bl_options = {'REGISTER', 'UNDO'} bl_options = {'REGISTER', 'UNDO'}
def execute(self, context): def execute(self, context):
_create_straight_rail( _rail_creator_wrapper(
self.general_get_rail_radius(), lambda bm: _create_straight_rail(
self.general_get_rail_span(), bm,
self.general_get_rail_length(), self.general_get_is_monorail(), self.general_get_rail_radius(), self.general_get_rail_span(),
self.general_get_rail_cap() self.general_get_rail_length(),
self.general_get_rail_start_cap(), self.general_get_rail_end_cap()
)
) )
return {'FINISHED'} return {'FINISHED'}
def draw(self, context): def draw(self, context):
layout = self.layout layout = self.layout
self.draw_rail_radius_input(layout) self.draw_rail_section_input(layout, None)
self.draw_rail_span_input(layout) layout.separator()
self.draw_rail_length_input(layout)
self.draw_rail_cap_input(layout) self.draw_rail_cap_input(layout)
layout.separator()
self.draw_straight_rail_input(layout)
class BBP_OT_add_screw_rail(SharedRailSectionInputProperty, SharedRailCapInputProperty, SharedScrewRailInputProperty, bpy.types.Operator):
"""Add Screw Rail"""
bl_idname = "bbp.add_screw_rail"
bl_label = "Screw Rail"
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
_rail_creator_wrapper(
lambda bm: _create_screw_rail(
bm,
self.general_get_is_monorail(), self.general_get_rail_radius(), self.general_get_rail_span(),
self.general_get_rail_start_cap(), self.general_get_rail_end_cap(),
self.general_get_rail_screw_angle(True), self.general_get_rail_screw_screw(True), self.general_get_rail_screw_iterations(True),
self.general_get_rail_screw_steps(), self.general_get_rail_screw_radius()
)
)
return {'FINISHED'}
def draw(self, context):
layout = self.layout
self.draw_rail_section_input(layout, None)
layout.separator()
self.draw_rail_cap_input(layout)
layout.separator()
self.draw_screw_rail_input(layout, True)
#endregion #endregion
#region Modifier Adder #region BMesh Operations Helper
def _set_screw_modifier(obj: bpy.types.Object) -> None: def _bmesh_extrude(bm: bmesh.types.BMesh, start_edges: list[bmesh.types.BMEdge], direction: mathutils.Vector) -> list[bmesh.types.BMEdge]:
pass # extrude
ret: dict[str, typing.Any] = bmesh.ops.extrude_edge_only(
bm,
edges = start_edges,
use_normal_flip = False, use_select_history = False
)
# get end edges
ret_geom = ret['geom']
del ret
end_verts: list[bmesh.types.BMVert] = list(filter(lambda x: isinstance(x, bmesh.types.BMVert), ret_geom))
end_edges: list[bmesh.types.BMEdge] = list(filter(lambda x: isinstance(x, bmesh.types.BMEdge) and x.is_boundary, ret_geom))
# and move it
bmesh.ops.translate(
bm,
vec = direction, space = mathutils.Matrix.Identity(4),
verts = end_verts,
use_shapekey = False
)
# return value
return end_edges
def _bmesh_screw(
bm: bmesh.types.BMesh,
start_verts: list[bmesh.types.BMVert], start_edges: list[bmesh.types.BMEdge],
angle: float, steps: int, iterations: int,
center: mathutils.Vector, screw_per_iteration: float) -> list[bmesh.types.BMEdge]:
# screw
ret: dict[str, typing.Any] = bmesh.ops.spin(
bm,
geom = start_edges,
cent = center,
axis = mathutils.Vector((0, 0, 1)), # default to +Z
dvec = mathutils.Vector((0, 0, screw_per_iteration / steps)), # conv to step delta
angle = angle * iterations,
space = mathutils.Matrix.Identity(4),
steps = steps * iterations,
use_merge = False,
use_normal_flip = True, # NOTE: flip nml according to real test result
use_duplicate = False
)
# return last segment
geom_last = ret['geom_last']
del ret
return list(filter(lambda x: isinstance(x, bmesh.types.BMEdge), geom_last))
def _bmesh_cap(bm: bmesh.types.BMesh, edges: list[bmesh.types.BMEdge]) -> None:
# fill holes
bmesh.ops.triangle_fill(
bm,
use_beauty = False, use_dissolve = False,
edges = edges
# no pass to normal.
)
def _bmesh_mark_sharp(bm: bmesh.types.BMesh, edges: typing.Iterable[list[bmesh.types.BMEdge]]) -> None:
# Ref: https://blender.stackexchange.com/questions/41351/is-there-a-way-to-select-edges-marked-as-sharp-via-python/41352#41352
# reset all edges to smooth
edge: bmesh.types.BMEdge
for edge in bm.edges:
edge.smooth = True
# and only set sharp for specified edges
for subedges in edges:
for edge in subedges:
edge.smooth = False
#endregion #endregion
#region Polygon Adders #region Real Rail Creators
def _polygon_adder_wrapper(fct_poly_cret: typing.Callable[[bmesh.types.BMesh], None]) -> bpy.types.Object: def _rail_creator_wrapper(fct_poly_cret: typing.Callable[[bmesh.types.BMesh], None]) -> bpy.types.Object:
# create mesh first # create mesh first
bm: bmesh.types.BMesh = bmesh.new() bm: bmesh.types.BMesh = bmesh.new()
@ -197,178 +394,150 @@ def _polygon_adder_wrapper(fct_poly_cret: typing.Callable[[bmesh.types.BMesh], N
# return rail # return rail
return obj return obj
def _add_monorail_section( def _create_rail_section(
bm: bmesh.types.BMesh, bm: bmesh.types.BMesh,
matrix: mathutils.Matrix, is_monorail: bool, rail_radius: float, rail_span: float,
rail_radius: float) -> None: matrix: mathutils.Matrix = mathutils.Matrix.Identity(4)) -> None:
"""
Add a monorail section.
The original point locate at the center of section. The section will be placed in XZ panel.
"""
# create
bmesh.ops.create_circle(
bm,
cap_ends = False, cap_tris = False,
segments = 8,
radius = rail_radius,
matrix = typing.cast(mathutils.Matrix, matrix @ mathutils.Matrix.LocRotScale(
None,
mathutils.Euler((math.radians(90), math.radians(22.5), 0), 'XYZ'),
None
)),
calc_uvs = False
)
def _add_rail_section(
bm: bmesh.types.BMesh,
matrix: mathutils.Matrix,
rail_radius: float,
rail_span: float) -> None:
""" """
Add a rail section. Add a rail section.
The original point locate at the center point of the line connecting between left rail section and right rail section.
If created is monorail, the original point locate at the center of section.
Otherwise, the original point locate at the center point of the line connecting between left rail section and right rail section.
The section will be placed in XZ panel. The section will be placed in XZ panel.
"""
# create left one
bmesh.ops.create_circle(
bm,
cap_ends = False, cap_tris = False,
segments = 8,
radius = rail_radius,
matrix = typing.cast(mathutils.Matrix, matrix @ mathutils.Matrix.LocRotScale(
mathutils.Vector((-rail_span / 2, 0, 0)),
mathutils.Euler((math.radians(90), 0, 0), 'XYZ'),
None
)),
calc_uvs = False
)
# create right one
bmesh.ops.create_circle(
bm,
cap_ends = False, cap_tris = False,
segments = 8,
radius = rail_radius,
matrix = typing.cast(mathutils.Matrix, matrix @ mathutils.Matrix.LocRotScale(
mathutils.Vector((rail_span / 2, 0, 0)),
mathutils.Euler((math.radians(90), 0, 0), 'XYZ'),
None
)),
calc_uvs = False
)
def _add_straight_monorail( If ordered is monorail, `rail_span` param will be ignored.
bm: bmesh.types.BMesh,
length: float,
matrix: mathutils.Matrix,
has_cap: bool,
rail_radius: float) -> None:
""" """
Add a straight monorail. if is_monorail:
The original point is same as `_add_monorail_section()`. # create monorail
The start terminal of this straight will be placed in XZ panel. bmesh.ops.create_circle(
The expand direction is +Y. bm, cap_ends = False, cap_tris = False, segments = 8, radius = rail_radius,
""" matrix = typing.cast(mathutils.Matrix, matrix @ mathutils.Matrix.LocRotScale(
# create left one None,
bmesh.ops.create_cone( mathutils.Euler((math.radians(90), math.radians(22.5), 0), 'XYZ'),
bm, None
cap_ends = has_cap, cap_tris = True, )),
segments = 8, calc_uvs = False
radius1 = rail_radius, radius2 = rail_radius, )
depth = length, else:
matrix = typing.cast(mathutils.Matrix, matrix @ mathutils.Matrix.LocRotScale( # create rail
mathutils.Vector((0, length / 2, 0)), # create left rail
mathutils.Euler((math.radians(90), math.radians(22.5), 0), 'XYZ'), bmesh.ops.create_circle(
None bm, cap_ends = False, cap_tris = False, segments = 8, radius = rail_radius,
)), matrix = typing.cast(mathutils.Matrix, matrix @ mathutils.Matrix.LocRotScale(
calc_uvs = False mathutils.Vector((-rail_span / 2, 0, 0)),
) mathutils.Euler((math.radians(90), 0, 0), 'XYZ'),
None
)),
calc_uvs = False
)
# create right rail
bmesh.ops.create_circle(
bm, cap_ends = False, cap_tris = False, segments = 8, radius = rail_radius,
matrix = typing.cast(mathutils.Matrix, matrix @ mathutils.Matrix.LocRotScale(
mathutils.Vector((rail_span / 2, 0, 0)),
mathutils.Euler((math.radians(90), 0, 0), 'XYZ'),
None
)),
calc_uvs = False
)
def _add_straight_rail( def _create_transition_section(
bm: bmesh.types.BMesh, bm: bmesh.types.BMesh,
length: float,
matrix: mathutils.Matrix,
has_cap: bool,
rail_radius: float, rail_span: float) -> None: rail_radius: float, rail_span: float) -> None:
""" """
Create the transition section between rail and monorail.
"""
# create rail section
_create_rail_section(bm, False, rail_radius, rail_span)
# create monorail
# calc sink first
monorail_sink: float
try:
monorail_sink = math.sqrt((rail_radius + 2) ** 2 - (rail_span / 2) ** 2) - 2 - rail_radius
except:
monorail_sink = -2 # if sqrt(minus number) happended, it mean no triangle relation. the depth should always be -2.
# create monorail with calculated sink
_create_rail_section(
bm, True, rail_radius, rail_span,
mathutils.Matrix.Translation((0, 0, monorail_sink))
)
def _create_straight_rail(
bm: bmesh.types.BMesh,
is_monorail: bool, rail_radius: float, rail_span: float,
rail_length: float,
rail_start_cap: bool, rail_end_cap: bool) -> None:
"""
Add a straight rail. Add a straight rail.
The original point is same as `_add_rail_section()`. The original point is same as `_add_rail_section()`.
The expand direction is +Y.
If ordered is monorail, `rail_span` param will be ignored.
"""
# create section first
_create_rail_section(bm, is_monorail, rail_radius, rail_span)
# get start edges
start_edges: list[bmesh.types.BMEdge] = bm.edges[:]
# extrude and get end edges
end_edges: list[bmesh.types.BMEdge] = _bmesh_extrude(
bm, start_edges, mathutils.Vector((0, rail_length, 0))
)
# cap start and end edges if needed
if rail_start_cap:
_bmesh_cap(bm, start_edges)
if rail_end_cap:
_bmesh_cap(bm, end_edges)
# mark sharp
_bmesh_mark_sharp(bm, (start_edges, end_edges, ))
def _create_screw_rail(
bm: bmesh.types.BMesh,
is_monorail: bool, rail_radius: float, rail_span: float,
rail_start_cap: bool, rail_end_cap: bool,
rail_screw_angle: float, rail_screw_screw: float, rail_screw_iterations: int,
rail_screw_steps: int, rail_screw_radius: float) -> None:
"""
Add a screw rail.
The original point is same as `_add_rail_section()`.
The start terminal of this straight will be placed in XZ panel. The start terminal of this straight will be placed in XZ panel.
The expand direction is +Y. The expand direction is +Y.
If ordered is monorail, `rail_span` param will be ignored.
""" """
# create left one # create section first
bmesh.ops.create_cone( _create_rail_section(bm, is_monorail, rail_radius, rail_span)
start_edges: list[bmesh.types.BMEdge] = bm.edges[:]
end_edges: list[bmesh.types.BMEdge] = _bmesh_screw(
bm, bm,
cap_ends = has_cap, cap_tris = True, bm.verts[:], start_edges,
segments = 8, math.radians(rail_screw_angle),
radius1 = rail_radius, radius2 = rail_radius, rail_screw_steps, rail_screw_iterations,
depth = length, mathutils.Vector((rail_screw_radius, 0, 0)),
matrix = typing.cast(mathutils.Matrix, matrix @ mathutils.Matrix.LocRotScale( rail_screw_screw
mathutils.Vector((-rail_span / 2, length / 2, 0)),
mathutils.Euler((math.radians(90), 0, 0), 'XYZ'),
None
)),
calc_uvs = False
)
# create right one
bmesh.ops.create_cone(
bm,
cap_ends = has_cap, cap_tris = True,
segments = 8,
radius1 = rail_radius, radius2 = rail_radius,
depth = length,
matrix = typing.cast(mathutils.Matrix, matrix @ mathutils.Matrix.LocRotScale(
mathutils.Vector((rail_span / 2, length / 2, 0)),
mathutils.Euler((math.radians(90), 0, 0), 'XYZ'),
None
)),
calc_uvs = False
) )
#endregion # cap start and end edges if needed
if rail_start_cap:
_bmesh_cap(bm, start_edges)
if rail_end_cap:
_bmesh_cap(bm, end_edges)
#region Rail Adder _bmesh_mark_sharp(bm, (start_edges, end_edges, ))
def _create_monorail_section(rail_radius: float) -> bpy.types.Object:
return _polygon_adder_wrapper(
lambda bm: _add_monorail_section(bm, mathutils.Matrix.Identity(4), rail_radius)
)
def _create_rail_section(rail_radius: float, rail_span: float) -> bpy.types.Object:
return _polygon_adder_wrapper(
lambda bm: _add_rail_section(bm, mathutils.Matrix.Identity(4), rail_radius, rail_span)
)
def _create_transition_section(rail_radius: float, rail_span: float, monorail_sink: float) -> bpy.types.Object:
def invoker(bm: bmesh.types.BMesh) -> None:
_add_rail_section(bm, mathutils.Matrix.Identity(4), rail_radius, rail_span)
_add_monorail_section(bm, mathutils.Matrix.Translation((0, 0, monorail_sink)), rail_radius)
return _polygon_adder_wrapper(invoker)
def _create_straight_monorail(rail_radius: float, rail_length: float, rail_cap: bool) -> bpy.types.Object:
return _polygon_adder_wrapper(
lambda bm: _add_straight_monorail(bm, rail_length, mathutils.Matrix.Identity(4), rail_cap, rail_radius)
)
def _create_straight_rail(rail_radius: float, rail_span: float, rail_length: float, rail_cap: bool) -> bpy.types.Object:
return _polygon_adder_wrapper(
lambda bm: _add_straight_rail(bm, rail_length, mathutils.Matrix.Identity(4), rail_cap, rail_radius, rail_span)
)
#endregion #endregion
def register(): def register():
bpy.utils.register_class(BBP_OT_add_monorail_section)
bpy.utils.register_class(BBP_OT_add_rail_section) bpy.utils.register_class(BBP_OT_add_rail_section)
bpy.utils.register_class(BBP_OT_add_transition_section) bpy.utils.register_class(BBP_OT_add_transition_section)
bpy.utils.register_class(BBP_OT_add_straight_monorail)
bpy.utils.register_class(BBP_OT_add_straight_rail) bpy.utils.register_class(BBP_OT_add_straight_rail)
bpy.utils.register_class(BBP_OT_add_screw_rail)
def unregister(): def unregister():
bpy.utils.unregister_class(BBP_OT_add_screw_rail)
bpy.utils.unregister_class(BBP_OT_add_straight_rail) bpy.utils.unregister_class(BBP_OT_add_straight_rail)
bpy.utils.unregister_class(BBP_OT_add_straight_monorail)
bpy.utils.unregister_class(BBP_OT_add_transition_section) bpy.utils.unregister_class(BBP_OT_add_transition_section)
bpy.utils.unregister_class(BBP_OT_add_rail_section) bpy.utils.unregister_class(BBP_OT_add_rail_section)
bpy.utils.unregister_class(BBP_OT_add_monorail_section)

View File

@ -74,14 +74,13 @@ class BBP_MT_AddRailMenu(bpy.types.Menu):
layout = self.layout layout = self.layout
layout.label(text = "Sections") layout.label(text = "Sections")
layout.operator(OP_ADDS_rail.BBP_OT_add_monorail_section.bl_idname)
layout.operator(OP_ADDS_rail.BBP_OT_add_rail_section.bl_idname) layout.operator(OP_ADDS_rail.BBP_OT_add_rail_section.bl_idname)
layout.operator(OP_ADDS_rail.BBP_OT_add_transition_section.bl_idname) layout.operator(OP_ADDS_rail.BBP_OT_add_transition_section.bl_idname)
layout.separator() layout.separator()
layout.label(text = "Straight Rails") layout.label(text = "Rails")
layout.operator(OP_ADDS_rail.BBP_OT_add_straight_monorail.bl_idname)
layout.operator(OP_ADDS_rail.BBP_OT_add_straight_rail.bl_idname) layout.operator(OP_ADDS_rail.BBP_OT_add_straight_rail.bl_idname)
layout.operator(OP_ADDS_rail.BBP_OT_add_screw_rail.bl_idname)
class BBP_MT_AddComponentsMenu(bpy.types.Menu): class BBP_MT_AddComponentsMenu(bpy.types.Menu):
"""Add Ballance Components""" """Add Ballance Components"""