finish rail adder
This commit is contained in:
parent
31aa5c3127
commit
013096459a
@ -9,6 +9,27 @@ from . import UTIL_functions, UTIL_naming_convension
|
|||||||
# Equation: Sink = sqrt( ((RailRadius + BallRadius) ^ 2) - ((RailSpan / 2) ^ 2) ) - BallRadius - RailRadius
|
# Equation: Sink = sqrt( ((RailRadius + BallRadius) ^ 2) - ((RailSpan / 2) ^ 2) ) - BallRadius - RailRadius
|
||||||
# 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
|
||||||
|
#
|
||||||
|
# For Normal Side Rail (paper ball + wood ball can pass it):
|
||||||
|
# Rail Span: 3.864
|
||||||
|
# Angle (between rail panel and XY panel): 79.563 degree
|
||||||
|
# For Special Side Rail (stone ball can pass it):
|
||||||
|
# Rail Span: 3.864
|
||||||
|
# Angle (between rail panel and XY panel): 57 degree
|
||||||
|
# These infos are gotten from BallanceBug.
|
||||||
|
#
|
||||||
|
# For Side Spiral Rail, the distance between each layer is 3.6
|
||||||
|
# Measured in Level 9 and Level 13.
|
||||||
|
# For Spiral Rail, the distance between each layer is 5
|
||||||
|
# Measured in Level 10.
|
||||||
|
|
||||||
|
c_DefaultRailRadius: float = 0.35
|
||||||
|
c_DefaultRailSpan: float = 3.75
|
||||||
|
c_SideRailSpan: float = 3.864
|
||||||
|
c_NormalSideRailAngle: float = 79.563
|
||||||
|
c_StoneSideRailAngle: float = 57
|
||||||
|
c_SpiralRailScrew: float = 5
|
||||||
|
c_SideSpiralRailScrew: float = 3.6
|
||||||
|
|
||||||
#region Operator Helpers
|
#region Operator Helpers
|
||||||
|
|
||||||
@ -28,56 +49,12 @@ class SharedRailSectionInputProperty():
|
|||||||
default = 'RAIL',
|
default = 'RAIL',
|
||||||
) # type: ignore
|
) # type: ignore
|
||||||
|
|
||||||
rail_radius: bpy.props.FloatProperty(
|
def draw_rail_section_input(self, layout: bpy.types.UILayout) -> None:
|
||||||
name = "Radius",
|
|
||||||
description = "Define rail section radius",
|
|
||||||
default = 0.35,
|
|
||||||
min = 0,
|
|
||||||
unit = 'LENGTH'
|
|
||||||
) # type: ignore
|
|
||||||
|
|
||||||
rail_span: bpy.props.FloatProperty(
|
|
||||||
name = "Span",
|
|
||||||
description = "The length between 2 single rails.",
|
|
||||||
default = 3.75,
|
|
||||||
min = 0,
|
|
||||||
unit = 'LENGTH'
|
|
||||||
) # type: ignore
|
|
||||||
|
|
||||||
def draw_rail_section_input(self, layout: bpy.types.UILayout, force_monorail: bool | None) -> None:
|
|
||||||
"""
|
|
||||||
Draw rail section properties
|
|
||||||
|
|
||||||
@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.
|
|
||||||
"""
|
|
||||||
# draw title
|
|
||||||
layout = layout.box()
|
|
||||||
layout.label(text = 'Section')
|
|
||||||
|
|
||||||
if force_monorail is None:
|
|
||||||
# show picker to allow user pick
|
|
||||||
# force it show horizontal
|
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
row.prop(self, 'rail_type', expand = True)
|
row.prop(self, 'rail_type', expand = True)
|
||||||
# show radius
|
|
||||||
layout.prop(self, "rail_radius")
|
|
||||||
# show span for rail
|
|
||||||
if self.rail_type == 'RAIL':
|
|
||||||
layout.prop(self, "rail_span")
|
|
||||||
else:
|
|
||||||
# according to force type to show
|
|
||||||
# always show radius
|
|
||||||
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:
|
def general_get_is_monorail(self) -> bool:
|
||||||
return self.rail_type == 'MONORAIL'
|
return self.rail_type == 'MONORAIL'
|
||||||
def general_get_rail_radius(self) -> float:
|
|
||||||
return self.rail_radius
|
|
||||||
def general_get_rail_span(self) -> float:
|
|
||||||
return self.rail_span
|
|
||||||
|
|
||||||
class SharedRailCapInputProperty():
|
class SharedRailCapInputProperty():
|
||||||
"""
|
"""
|
||||||
@ -98,9 +75,6 @@ class SharedRailCapInputProperty():
|
|||||||
) # type: ignore
|
) # type: ignore
|
||||||
|
|
||||||
def draw_rail_cap_input(self, layout: bpy.types.UILayout) -> None:
|
def draw_rail_cap_input(self, layout: bpy.types.UILayout) -> None:
|
||||||
# draw title
|
|
||||||
layout = layout.box()
|
|
||||||
layout.label(text = 'Cap')
|
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
row.prop(self, "rail_start_cap", toggle = 1)
|
row.prop(self, "rail_start_cap", toggle = 1)
|
||||||
row.prop(self, "rail_end_cap", toggle = 1)
|
row.prop(self, "rail_end_cap", toggle = 1)
|
||||||
@ -125,9 +99,6 @@ class SharedStraightRailInputProperty():
|
|||||||
) # type: ignore
|
) # type: ignore
|
||||||
|
|
||||||
def draw_straight_rail_input(self, layout: bpy.types.UILayout) -> None:
|
def draw_straight_rail_input(self, layout: bpy.types.UILayout) -> None:
|
||||||
# draw title
|
|
||||||
layout = layout.box()
|
|
||||||
layout.label(text = 'Straight Rail')
|
|
||||||
layout.prop(self, "rail_length")
|
layout.prop(self, "rail_length")
|
||||||
|
|
||||||
def general_get_rail_length(self) -> float:
|
def general_get_rail_length(self) -> float:
|
||||||
@ -138,69 +109,24 @@ class SharedScrewRailInputProperty():
|
|||||||
The properties for straight rail.
|
The properties for straight rail.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
rail_screw_angle: bpy.props.FloatProperty(
|
|
||||||
name = "Angle",
|
|
||||||
description = "The angle of this screw rail rotated in one interation.",
|
|
||||||
default = 90,
|
|
||||||
subtype = 'ANGLE',
|
|
||||||
) # type: ignore
|
|
||||||
|
|
||||||
rail_screw_screw: bpy.props.FloatProperty(
|
|
||||||
name = "Screw",
|
|
||||||
description = "The increased height in each iteration. Minus height also is accepted.",
|
|
||||||
default = 6,
|
|
||||||
unit = 'LENGTH'
|
|
||||||
) # type: ignore
|
|
||||||
|
|
||||||
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(
|
rail_screw_steps: bpy.props.IntProperty(
|
||||||
name = "Steps",
|
name = "Steps",
|
||||||
description = "The segment count per iteration.",
|
description = "The segment count per iteration. More segment, more smooth but lower performance.",
|
||||||
default = 20,
|
default = 16,
|
||||||
min = 1,
|
min = 1,
|
||||||
) # type: ignore
|
) # type: ignore
|
||||||
|
|
||||||
rail_screw_radius: bpy.props.FloatProperty(
|
rail_screw_radius: bpy.props.FloatProperty(
|
||||||
name = "Radius",
|
name = "Radius",
|
||||||
description = "The screw radius. Minus radius will flip the built screw.",
|
description = "The screw radius. Minus radius will flip the built screw.",
|
||||||
default = 10,
|
default = 5,
|
||||||
unit = 'LENGTH'
|
unit = 'LENGTH'
|
||||||
) # type: ignore
|
) # type: ignore
|
||||||
|
|
||||||
def draw_screw_rail_input(self, layout: bpy.types.UILayout, show_for_screw: bool) -> None:
|
def draw_screw_rail_input(self, layout: bpy.types.UILayout) -> None:
|
||||||
# draw title
|
|
||||||
layout = layout.box()
|
|
||||||
layout.label(text = 'Screw Rail')
|
|
||||||
|
|
||||||
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_radius")
|
||||||
layout.prop(self, "rail_screw_steps")
|
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:
|
def general_get_rail_screw_radius(self) -> float:
|
||||||
return self.rail_screw_radius
|
return self.rail_screw_radius
|
||||||
def general_get_rail_screw_steps(self) -> int:
|
def general_get_rail_screw_steps(self) -> int:
|
||||||
@ -219,17 +145,17 @@ class BBP_OT_add_rail_section(SharedRailSectionInputProperty, bpy.types.Operator
|
|||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
_rail_creator_wrapper(
|
_rail_creator_wrapper(
|
||||||
lambda bm: _create_rail_section(
|
lambda bm: _create_rail_section(
|
||||||
bm,
|
bm, self.general_get_is_monorail(),
|
||||||
self.general_get_is_monorail(), self.general_get_rail_radius(), self.general_get_rail_span()
|
c_DefaultRailRadius, c_DefaultRailSpan
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
return {'FINISHED'}
|
return {'FINISHED'}
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
layout = self.layout
|
layout = self.layout
|
||||||
self.draw_rail_section_input(layout, None)
|
self.draw_rail_section_input(layout)
|
||||||
|
|
||||||
class BBP_OT_add_transition_section(SharedRailSectionInputProperty, bpy.types.Operator):
|
class BBP_OT_add_transition_section(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"
|
||||||
@ -237,17 +163,13 @@ class BBP_OT_add_transition_section(SharedRailSectionInputProperty, bpy.types.Op
|
|||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
_rail_creator_wrapper(
|
_rail_creator_wrapper(
|
||||||
lambda bm: _create_transition_section(
|
lambda bm: _create_transition_section(bm, c_DefaultRailRadius, c_DefaultRailSpan)
|
||||||
bm,
|
|
||||||
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
|
||||||
# force show double rail params
|
layout.label(text = 'No Options Available')
|
||||||
self.draw_rail_section_input(layout, False)
|
|
||||||
|
|
||||||
class BBP_OT_add_straight_rail(SharedRailSectionInputProperty, SharedRailCapInputProperty, SharedStraightRailInputProperty, bpy.types.Operator):
|
class BBP_OT_add_straight_rail(SharedRailSectionInputProperty, SharedRailCapInputProperty, SharedStraightRailInputProperty, bpy.types.Operator):
|
||||||
"""Add Straight Rail"""
|
"""Add Straight Rail"""
|
||||||
@ -259,8 +181,8 @@ class BBP_OT_add_straight_rail(SharedRailSectionInputProperty, SharedRailCapInpu
|
|||||||
_rail_creator_wrapper(
|
_rail_creator_wrapper(
|
||||||
lambda bm: _create_straight_rail(
|
lambda bm: _create_straight_rail(
|
||||||
bm,
|
bm,
|
||||||
self.general_get_is_monorail(), self.general_get_rail_radius(), self.general_get_rail_span(),
|
self.general_get_is_monorail(), c_DefaultRailRadius, c_DefaultRailSpan,
|
||||||
self.general_get_rail_length(),
|
self.general_get_rail_length(), 0,
|
||||||
self.general_get_rail_start_cap(), self.general_get_rail_end_cap()
|
self.general_get_rail_start_cap(), self.general_get_rail_end_cap()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -268,25 +190,71 @@ class BBP_OT_add_straight_rail(SharedRailSectionInputProperty, SharedRailCapInpu
|
|||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
layout = self.layout
|
layout = self.layout
|
||||||
self.draw_rail_section_input(layout, None)
|
layout.label(text = 'Straight Rail')
|
||||||
layout.separator()
|
self.draw_rail_section_input(layout)
|
||||||
self.draw_rail_cap_input(layout)
|
|
||||||
layout.separator()
|
|
||||||
self.draw_straight_rail_input(layout)
|
self.draw_straight_rail_input(layout)
|
||||||
|
layout.separator()
|
||||||
|
layout.label(text = 'Rail Cap')
|
||||||
|
self.draw_rail_cap_input(layout)
|
||||||
|
|
||||||
class BBP_OT_add_screw_rail(SharedRailSectionInputProperty, SharedRailCapInputProperty, SharedScrewRailInputProperty, bpy.types.Operator):
|
class BBP_OT_add_side_rail(SharedRailCapInputProperty, SharedStraightRailInputProperty, bpy.types.Operator):
|
||||||
"""Add Screw Rail"""
|
"""Add Side Rail"""
|
||||||
bl_idname = "bbp.add_screw_rail"
|
bl_idname = "bbp.add_side_rail"
|
||||||
bl_label = "Screw Rail"
|
bl_label = "Side Rail"
|
||||||
bl_options = {'REGISTER', 'UNDO'}
|
bl_options = {'REGISTER', 'UNDO'}
|
||||||
|
|
||||||
|
side_rail_type: bpy.props.EnumProperty(
|
||||||
|
name = "Side Type",
|
||||||
|
description = "Side rail type",
|
||||||
|
items = [
|
||||||
|
('NORMAL', "Normal", "The normal side rail."),
|
||||||
|
('STONE', "Stone Specific", "The side rail which also allow stone ball passed."),
|
||||||
|
],
|
||||||
|
default = 'NORMAL',
|
||||||
|
) # type: ignore
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
_rail_creator_wrapper(
|
||||||
|
lambda bm: _create_straight_rail(
|
||||||
|
bm,
|
||||||
|
False, c_DefaultRailRadius, c_DefaultRailSpan,
|
||||||
|
self.general_get_rail_length(),
|
||||||
|
c_NormalSideRailAngle if self.side_rail_type == 'NORMAL' else c_StoneSideRailAngle,
|
||||||
|
self.general_get_rail_start_cap(), self.general_get_rail_end_cap()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
layout = self.layout
|
||||||
|
layout.label(text = 'Side Rail')
|
||||||
|
layout.prop(self, 'side_rail_type')
|
||||||
|
self.draw_straight_rail_input(layout)
|
||||||
|
layout.separator()
|
||||||
|
layout.label(text = 'Rail Cap')
|
||||||
|
self.draw_rail_cap_input(layout)
|
||||||
|
|
||||||
|
class BBP_OT_add_arc_rail(SharedRailSectionInputProperty, SharedRailCapInputProperty, SharedScrewRailInputProperty, bpy.types.Operator):
|
||||||
|
"""Add Arc Rail"""
|
||||||
|
bl_idname = "bbp.add_arc_rail"
|
||||||
|
bl_label = "Arc Rail"
|
||||||
|
bl_options = {'REGISTER', 'UNDO'}
|
||||||
|
|
||||||
|
rail_screw_angle: bpy.props.FloatProperty(
|
||||||
|
name = "Angle",
|
||||||
|
description = "The angle of this arc rail rotated.",
|
||||||
|
default = math.radians(90),
|
||||||
|
min = 0, max = math.radians(360),
|
||||||
|
subtype = 'ANGLE',
|
||||||
|
) # type: ignore
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
_rail_creator_wrapper(
|
_rail_creator_wrapper(
|
||||||
lambda bm: _create_screw_rail(
|
lambda bm: _create_screw_rail(
|
||||||
bm,
|
bm,
|
||||||
self.general_get_is_monorail(), self.general_get_rail_radius(), self.general_get_rail_span(),
|
self.general_get_is_monorail(), c_DefaultRailRadius, c_DefaultRailSpan,
|
||||||
self.general_get_rail_start_cap(), self.general_get_rail_end_cap(),
|
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),
|
math.degrees(self.rail_screw_angle), 0, 1, # blender passed value is in radians
|
||||||
self.general_get_rail_screw_steps(), self.general_get_rail_screw_radius()
|
self.general_get_rail_screw_steps(), self.general_get_rail_screw_radius()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -294,11 +262,91 @@ class BBP_OT_add_screw_rail(SharedRailSectionInputProperty, SharedRailCapInputPr
|
|||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
layout = self.layout
|
layout = self.layout
|
||||||
self.draw_rail_section_input(layout, None)
|
layout.label(text = 'Arc Rail')
|
||||||
|
self.draw_rail_section_input(layout)
|
||||||
|
self.draw_screw_rail_input(layout)
|
||||||
|
layout.prop(self, "rail_screw_angle")
|
||||||
layout.separator()
|
layout.separator()
|
||||||
|
layout.label(text = 'Rail Cap')
|
||||||
self.draw_rail_cap_input(layout)
|
self.draw_rail_cap_input(layout)
|
||||||
|
|
||||||
|
class BBP_OT_add_spiral_rail(SharedRailCapInputProperty, SharedScrewRailInputProperty, bpy.types.Operator):
|
||||||
|
"""Add Spiral Rail"""
|
||||||
|
bl_idname = "bbp.add_spiral_rail"
|
||||||
|
bl_label = "Spiral Rail"
|
||||||
|
bl_options = {'REGISTER', 'UNDO'}
|
||||||
|
|
||||||
|
rail_screw_screw: bpy.props.FloatProperty(
|
||||||
|
name = "Screw",
|
||||||
|
description = "The increased height in each iteration. Minus height also is accepted.",
|
||||||
|
default = c_SpiralRailScrew,
|
||||||
|
unit = 'LENGTH'
|
||||||
|
) # type: ignore
|
||||||
|
|
||||||
|
rail_screw_iterations: bpy.props.IntProperty(
|
||||||
|
name = "Iterations",
|
||||||
|
description = "Indicate how many layers of this spiral rail should be generated.",
|
||||||
|
default = 1,
|
||||||
|
min = 1,
|
||||||
|
) # type: ignore
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
_rail_creator_wrapper(
|
||||||
|
lambda bm: _create_screw_rail(
|
||||||
|
bm,
|
||||||
|
False, c_DefaultRailRadius, c_DefaultRailSpan,
|
||||||
|
self.general_get_rail_start_cap(), self.general_get_rail_end_cap(),
|
||||||
|
360, self.rail_screw_screw, self.rail_screw_iterations,
|
||||||
|
self.general_get_rail_screw_steps(), self.general_get_rail_screw_radius()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
layout = self.layout
|
||||||
|
layout.label(text = 'Spiral Rail')
|
||||||
|
self.draw_screw_rail_input(layout)
|
||||||
|
layout.prop(self, "rail_screw_screw")
|
||||||
|
layout.prop(self, "rail_screw_iterations")
|
||||||
layout.separator()
|
layout.separator()
|
||||||
self.draw_screw_rail_input(layout, True)
|
layout.label(text = 'Rail Cap')
|
||||||
|
self.draw_rail_cap_input(layout)
|
||||||
|
|
||||||
|
class BBP_OT_add_side_spiral_rail(SharedRailSectionInputProperty, SharedRailCapInputProperty, SharedScrewRailInputProperty, bpy.types.Operator):
|
||||||
|
"""Add Side Spiral Rail"""
|
||||||
|
bl_idname = "bbp.add_side_spiral_rail"
|
||||||
|
bl_label = "Side Spiral Rail"
|
||||||
|
bl_options = {'REGISTER', 'UNDO'}
|
||||||
|
|
||||||
|
rail_screw_iterations: bpy.props.IntProperty(
|
||||||
|
name = "Iterations",
|
||||||
|
description = "Indicate how many layers of this spiral rail should be generated.",
|
||||||
|
default = 2,
|
||||||
|
# at least 2 ietrations can create 1 useful side spiral rail.
|
||||||
|
# becuase side spiral rail is edge shared.
|
||||||
|
min = 2,
|
||||||
|
) # type: ignore
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
_rail_creator_wrapper(
|
||||||
|
lambda bm: _create_screw_rail(
|
||||||
|
bm,
|
||||||
|
True, c_DefaultRailRadius, c_DefaultRailSpan,
|
||||||
|
self.general_get_rail_start_cap(), self.general_get_rail_end_cap(),
|
||||||
|
360, c_SideSpiralRailScrew, self.rail_screw_iterations,
|
||||||
|
self.general_get_rail_screw_steps(), self.general_get_rail_screw_radius()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
layout = self.layout
|
||||||
|
layout.label(text = 'Spiral Rail')
|
||||||
|
self.draw_screw_rail_input(layout)
|
||||||
|
layout.prop(self, "rail_screw_iterations")
|
||||||
|
layout.separator()
|
||||||
|
layout.label(text = 'Rail Cap')
|
||||||
|
self.draw_rail_cap_input(layout)
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -333,6 +381,9 @@ def _bmesh_screw(
|
|||||||
start_verts: list[bmesh.types.BMVert], start_edges: list[bmesh.types.BMEdge],
|
start_verts: list[bmesh.types.BMVert], start_edges: list[bmesh.types.BMEdge],
|
||||||
angle: float, steps: int, iterations: int,
|
angle: float, steps: int, iterations: int,
|
||||||
center: mathutils.Vector, screw_per_iteration: float) -> list[bmesh.types.BMEdge]:
|
center: mathutils.Vector, screw_per_iteration: float) -> list[bmesh.types.BMEdge]:
|
||||||
|
"""
|
||||||
|
Hints: Angle is input as degree unit.
|
||||||
|
"""
|
||||||
# screw
|
# screw
|
||||||
ret: dict[str, typing.Any] = bmesh.ops.spin(
|
ret: dict[str, typing.Any] = bmesh.ops.spin(
|
||||||
bm,
|
bm,
|
||||||
@ -340,7 +391,7 @@ def _bmesh_screw(
|
|||||||
cent = center,
|
cent = center,
|
||||||
axis = mathutils.Vector((0, 0, 1)), # default to +Z
|
axis = mathutils.Vector((0, 0, 1)), # default to +Z
|
||||||
dvec = mathutils.Vector((0, 0, screw_per_iteration / steps)), # conv to step delta
|
dvec = mathutils.Vector((0, 0, screw_per_iteration / steps)), # conv to step delta
|
||||||
angle = angle * iterations,
|
angle = math.radians(angle) * iterations,
|
||||||
space = mathutils.Matrix.Identity(4),
|
space = mathutils.Matrix.Identity(4),
|
||||||
steps = steps * iterations,
|
steps = steps * iterations,
|
||||||
use_merge = False,
|
use_merge = False,
|
||||||
@ -487,16 +538,29 @@ def _create_transition_section(
|
|||||||
def _create_straight_rail(
|
def _create_straight_rail(
|
||||||
bm: bmesh.types.BMesh,
|
bm: bmesh.types.BMesh,
|
||||||
is_monorail: bool, rail_radius: float, rail_span: float,
|
is_monorail: bool, rail_radius: float, rail_span: float,
|
||||||
rail_length: float,
|
rail_length: float, rail_angle: float,
|
||||||
rail_start_cap: bool, rail_end_cap: bool) -> None:
|
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 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.
|
If ordered is monorail, `rail_span` param will be ignored.
|
||||||
|
|
||||||
|
The rail angle is in degree unit and indicate how any angle this rail should rotated by its axis.
|
||||||
|
It usually used to create side rail.
|
||||||
"""
|
"""
|
||||||
# create section first
|
# create section first
|
||||||
_create_rail_section(bm, is_monorail, rail_radius, rail_span)
|
_create_rail_section(
|
||||||
|
bm, is_monorail, rail_radius, rail_span,
|
||||||
|
mathutils.Matrix.LocRotScale(
|
||||||
|
None,
|
||||||
|
mathutils.Euler((0, math.radians(rail_angle), 0), 'XYZ'),
|
||||||
|
None
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
# get start edges
|
# get start edges
|
||||||
start_edges: list[bmesh.types.BMEdge] = bm.edges[:]
|
start_edges: list[bmesh.types.BMEdge] = bm.edges[:]
|
||||||
@ -522,10 +586,14 @@ def _create_screw_rail(
|
|||||||
rail_screw_steps: int, rail_screw_radius: float) -> None:
|
rail_screw_steps: int, rail_screw_radius: float) -> None:
|
||||||
"""
|
"""
|
||||||
Add a screw rail.
|
Add a screw rail.
|
||||||
|
|
||||||
The original point is same as `_add_rail_section()`.
|
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.
|
If ordered is monorail, `rail_span` param will be ignored.
|
||||||
|
|
||||||
|
Angle is input as degree unit.
|
||||||
"""
|
"""
|
||||||
# create section first
|
# create section first
|
||||||
_create_rail_section(bm, is_monorail, rail_radius, rail_span)
|
_create_rail_section(bm, is_monorail, rail_radius, rail_span)
|
||||||
@ -534,7 +602,7 @@ def _create_screw_rail(
|
|||||||
end_edges: list[bmesh.types.BMEdge] = _bmesh_screw(
|
end_edges: list[bmesh.types.BMEdge] = _bmesh_screw(
|
||||||
bm,
|
bm,
|
||||||
bm.verts[:], start_edges,
|
bm.verts[:], start_edges,
|
||||||
math.radians(rail_screw_angle),
|
rail_screw_angle,
|
||||||
rail_screw_steps, rail_screw_iterations,
|
rail_screw_steps, rail_screw_iterations,
|
||||||
mathutils.Vector((rail_screw_radius, 0, 0)),
|
mathutils.Vector((rail_screw_radius, 0, 0)),
|
||||||
rail_screw_screw
|
rail_screw_screw
|
||||||
@ -553,12 +621,22 @@ def _create_screw_rail(
|
|||||||
def register():
|
def register():
|
||||||
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_rail)
|
bpy.utils.register_class(BBP_OT_add_straight_rail)
|
||||||
bpy.utils.register_class(BBP_OT_add_screw_rail)
|
bpy.utils.register_class(BBP_OT_add_side_rail)
|
||||||
|
|
||||||
|
bpy.utils.register_class(BBP_OT_add_arc_rail)
|
||||||
|
bpy.utils.register_class(BBP_OT_add_spiral_rail)
|
||||||
|
bpy.utils.register_class(BBP_OT_add_side_spiral_rail)
|
||||||
|
|
||||||
|
|
||||||
def unregister():
|
def unregister():
|
||||||
bpy.utils.unregister_class(BBP_OT_add_screw_rail)
|
bpy.utils.unregister_class(BBP_OT_add_side_spiral_rail)
|
||||||
|
bpy.utils.unregister_class(BBP_OT_add_spiral_rail)
|
||||||
|
bpy.utils.unregister_class(BBP_OT_add_arc_rail)
|
||||||
|
|
||||||
|
bpy.utils.unregister_class(BBP_OT_add_side_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_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)
|
||||||
|
@ -73,14 +73,20 @@ class BBP_MT_AddRailMenu(bpy.types.Menu):
|
|||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
layout = self.layout
|
layout = self.layout
|
||||||
|
|
||||||
layout.label(text = "Sections")
|
layout.label(text = "Sections", icon = 'MESH_CIRCLE')
|
||||||
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 = "Rails")
|
layout.label(text = "Straight Rails", icon = 'IPO_CONSTANT')
|
||||||
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)
|
layout.operator(OP_ADDS_rail.BBP_OT_add_side_rail.bl_idname)
|
||||||
|
|
||||||
|
layout.separator()
|
||||||
|
layout.label(text = "Curve Rails", icon = 'MOD_SCREW')
|
||||||
|
layout.operator(OP_ADDS_rail.BBP_OT_add_arc_rail.bl_idname)
|
||||||
|
layout.operator(OP_ADDS_rail.BBP_OT_add_spiral_rail.bl_idname)
|
||||||
|
layout.operator(OP_ADDS_rail.BBP_OT_add_side_spiral_rail.bl_idname)
|
||||||
|
|
||||||
class BBP_MT_AddComponentsMenu(bpy.types.Menu):
|
class BBP_MT_AddComponentsMenu(bpy.types.Menu):
|
||||||
"""Add Ballance Components"""
|
"""Add Ballance Components"""
|
||||||
|
Loading…
Reference in New Issue
Block a user