Skip to content

Commit

Permalink
Add ability to generate axis rod cut list (Closes #25)
Browse files Browse the repository at this point in the history
  • Loading branch information
gbroques committed Apr 16, 2020
1 parent aa436f8 commit 9f04b2c
Show file tree
Hide file tree
Showing 16 changed files with 457 additions and 17 deletions.
4 changes: 3 additions & 1 deletion InitGui.py
Expand Up @@ -20,11 +20,13 @@ def Initialize(self):
"""
Executed when FreeCAD starts
"""
from ose3dprinter.workbench import main_toolbar, register_commands
from ose3dprinter.workbench import (
main_menu, main_toolbar, register_commands)

register_commands()

self.appendToolbar(main_toolbar.name, main_toolbar.command_keys)
self.appendMenu(main_menu.name, main_menu.command_keys)

def Activated(self):
"""
Expand Down
6 changes: 3 additions & 3 deletions ose3dprinter/core/model/frame/angle_frame_connector.py
Expand Up @@ -191,7 +191,7 @@ def fillet_bracket(bracket, height):

def find_top_wires_parallel_to_xy_plane(bracket, height):
wires_parallel_to_xy_plane = filter(
is_shape_parallel_to_xy_plane, bracket.Wires)
is_wire_parallel_to_xy_plane, bracket.Wires)
is_top_shape = get_is_top_shape(height)
return filter(
is_top_shape, wires_parallel_to_xy_plane)
Expand All @@ -201,8 +201,8 @@ def get_is_top_shape(height):
return lambda shape: shape.BoundBox.ZMax == height


def is_shape_parallel_to_xy_plane(shape):
return shape.BoundBox.ZMin == shape.BoundBox.ZMax
def is_wire_parallel_to_xy_plane(wire):
return wire.BoundBox.ZMin == wire.BoundBox.ZMax


def get_outer_points(width,
Expand Down
46 changes: 35 additions & 11 deletions ose3dprinter/core/model/universal_axis/universal_axis_model.py
Expand Up @@ -20,6 +20,9 @@ class UniversalAxisModel(BaseModel):

idler_box_width = 26

# Motor side, idler side, and carriage boxes share same height
box_height = 24

hole_radius = 3.39

# y_distance_between_holes
Expand Down Expand Up @@ -74,18 +77,15 @@ def execute(self, obj):
rod_length = obj.Length.Value
rod_radius = obj.RodDiameter.Value / 2

# Motor side, idler side, and carriage boxes share same height
box_height = 24

# Define dimensions of motor side box
motor_box_length = 66
motor_side_box_dimensions = (
self.motor_box_width, motor_box_length, box_height)
self.motor_box_width, motor_box_length, self.box_height)

# Make motor side box
motor_side_box = Part.makeBox(*motor_side_box_dimensions)
motor_side_box_with_holes = self.cut_holes_in_motor_side_box(
motor_side_box, box_height, motor_box_length)
motor_side_box, self.box_height, motor_box_length)

# Motor
motor_side = 37.8
Expand All @@ -100,7 +100,7 @@ def execute(self, obj):
motor.translate(Vector(
half_motor_box_width - half_motor_side,
half_motor_box_length - half_motor_side,
box_height
self.box_height
))
motor.rotate(Vector(half_motor_box_width,
half_motor_box_length, 0), Vector(0, 0, 1), 45)
Expand All @@ -111,7 +111,7 @@ def execute(self, obj):
# Define dimensions of carriage box
carriage_box_length = 74
carriage_box_dimensions = (
self.carriage_box_width, carriage_box_length, box_height)
self.carriage_box_width, carriage_box_length, self.box_height)

# Make carriage
carriage_box = Part.makeBox(*carriage_box_dimensions)
Expand All @@ -123,11 +123,11 @@ def execute(self, obj):
# Define dimensions of idler side box
idler_box_length = 66
idler_side_box_dimensions = (
self.idler_box_width, idler_box_length, box_height)
self.idler_box_width, idler_box_length, self.box_height)

distance_between_hole_and_idler_side = (
idler_box_length - (self.distance_between_holes + (self.hole_radius * 2))) / 2
front_cylinder = Part.makeCylinder(self.hole_radius, box_height)
front_cylinder = Part.makeCylinder(self.hole_radius, self.box_height)
rear_cylinder = front_cylinder.copy()
front_cylinder.translate(Vector(
self.idler_box_width / 2,
Expand All @@ -151,7 +151,7 @@ def execute(self, obj):
Vector(rod_length - self.idler_box_width, 0, 0))

space_between_rod_and_box_edge = 10
half_box_height = box_height / 2
half_box_height = self.box_height / 2

rod1_y_position = idler_box_length - space_between_rod_and_box_edge

Expand All @@ -173,7 +173,7 @@ def execute(self, obj):
rod2
]

reference_dimensions = (rod_length, motor_box_length, box_height)
reference_dimensions = (rod_length, motor_box_length, self.box_height)
self.move_parts(parts, reference_dimensions)

compound = Part.makeCompound(parts)
Expand Down Expand Up @@ -258,6 +258,30 @@ def calculate_carriage_box_x(self):
)
)

def is_x(self):
"""Return whether or not this axis is a X axis.
This assumes the axis is parallel to the XY, YZ, or XZ planes,
and not rotated in a weird diagonal or skewed way.
:return: Whether this axis is a X axis.
:rtype: bool
"""
axis = self.Object
return _is_oriented_in(axis, AxisOrientation.X)

def is_y(self):
"""Return whether or not this axis is a Y axis.
This assumes the axis is parallel to the XY, YZ, or XZ planes,
and not rotated in a weird diagonal or skewed way.
:return: Whether this axis is a Y axis.
:rtype: bool
"""
axis = self.Object
return _is_oriented_in(axis, AxisOrientation.Y)

def is_z(self):
"""Return whether or not this axis is a Z axis.
Expand Down
5 changes: 3 additions & 2 deletions ose3dprinter/workbench/__init__.py
@@ -1,4 +1,5 @@
__all__ = ['main_toolbar', 'register_commands', 'get_resource_path']
__all__ = [
'main_toolbar', 'main_toolbar', 'register_commands', 'get_resource_path']

from .commands import main_toolbar, register_commands
from .commands import main_menu, main_toolbar, register_commands
from .resources import get_resource_path
8 changes: 8 additions & 0 deletions ose3dprinter/workbench/commands.py
Expand Up @@ -10,6 +10,7 @@
from .add_universal_y_axis import AddUniversalYAxis
from .add_universal_z_axis import AddUniversalZAxis
from .command_registry import CommandCollection, command_registry
from .generate_cut_list import CopyCutListToClipboard, SaveCutListAsCsv


def register_commands():
Expand All @@ -19,6 +20,9 @@ def register_commands():
command_registry.register(AddUniversalZAxis.NAME, AddUniversalZAxis())
command_registry.register(AddHeatedBed.NAME, AddHeatedBed())
command_registry.register(AddExtruder.NAME, AddExtruder())
command_registry.register(
CopyCutListToClipboard.NAME, CopyCutListToClipboard())
command_registry.register(SaveCutListAsCsv.NAME, SaveCutListAsCsv())


main_toolbar = CommandCollection('OSE 3D Printer')
Expand All @@ -28,3 +32,7 @@ def register_commands():
main_toolbar.add(AddUniversalZAxis.NAME)
main_toolbar.add(AddHeatedBed.NAME)
main_toolbar.add(AddExtruder.NAME)

main_menu = CommandCollection('OSE 3D Printer')
main_menu.add(CopyCutListToClipboard.NAME)
main_menu.add(SaveCutListAsCsv.NAME)
2 changes: 2 additions & 0 deletions ose3dprinter/workbench/generate_cut_list/__init__.py
@@ -0,0 +1,2 @@
from .copy_cut_list_to_clipboard import CopyCutListToClipboard
from .save_cut_list_as_csv import SaveCutListAsCsv
@@ -0,0 +1,8 @@
def convert_dict_list_to_wiki_list_markup(dict_list):
return reduce(row_to_list_item, dict_list, '')


def row_to_list_item(table_markup, row):
list_item_template = u"* ['''{}'''] {} \u2014 {}\n"
return table_markup + list_item_template.format(
row['Quantity'], row['Description'], row['Length'])
@@ -0,0 +1,22 @@
def convert_dict_list_to_wiki_table_markup(dict_list, columns):
"""
See:
https://www.mediawiki.org/wiki/Help:Tables#Wiki_table_markup_summary
:param dict_list: list of dictionaries
:type dict_list: List(Dict)
:param columns: Columns of table
:type columns: list of strings
:return: wiki table markup
:rtype: string
"""
table = '{| class="wikitable"\n'
row_separator = '|----\n'
for column in columns:
table += '!|{}\n'.format(column)
table += row_separator
for row in dict_list:
for value in row.values():
table += '|{}\n'.format(value)
table += row_separator
return table + '|}\n'
@@ -0,0 +1,22 @@
from .generate_cut_list import generate_cut_list
from .task_type import TaskType


class CopyCutListToClipboard:
"""
Command to copy cut-list to clipboard
"""

NAME = 'CopyCutListToClipboard'

def Activated(self):
generate_cut_list(TaskType.CopyToClipboard)

def IsActive(self):
return True

def GetResources(self):
return {
'MenuText': 'Copy Axis Rod Cut List to Clipboard',
'ToolTip': 'Copy Axis Rod Cut List to Clipboard'
}
@@ -0,0 +1,72 @@
import FreeCADGui
from FreeCAD import Console
from PySide import QtGui

from .convert_dict_list_to_wiki_list_markup import \
convert_dict_list_to_wiki_list_markup
from .convert_dict_list_to_wiki_table_markup import \
convert_dict_list_to_wiki_table_markup
from .generate_cut_list_task_panel import GenerateCutListTaskPanel


class CopyCutListToClipboardTaskPanel(GenerateCutListTaskPanel):

def __init__(self, cut_list_table_rows, columns):
title = 'Copy Axis Rod Cut List to Clipboard'
super(CopyCutListToClipboardTaskPanel, self).__init__(
title, cut_list_table_rows, columns)

# Row 1 - Markup Format options
row1 = QtGui.QVBoxLayout()

# Table option
self.table_option = QtGui.QRadioButton('Table', self.form)
self.table_option.setChecked(True)
row1.addWidget(self.table_option)

# List option
self.list_option = QtGui.QRadioButton('List', self.form)
row1.addWidget(self.list_option)

self.layout.addLayout(row1)

# ----------------------------------

# Row 2
row2 = QtGui.QHBoxLayout()

# Copy Status Label
self.copyStatusLabel = QtGui.QLabel(self.form)
self.copyStatusLabel.setObjectName('copyStatusLabel')
self.copyStatusLabel.setText('<b>Status:</b> Not Copied')
row2.addWidget(self.copyStatusLabel)

# Copy to Clipboard button
copy_to_clipboard_button = QtGui.QPushButton(
'Copy to Clipboard')
copy_to_clipboard_button.clicked.connect(self.handle_copy_to_clipboard)
row2.addWidget(copy_to_clipboard_button)

self.layout.addLayout(row2)

def handle_copy_to_clipboard(self):
clipboard = QtGui.QApplication.clipboard()
table_markup = ''
if self.table_option.isChecked():
table_markup = convert_dict_list_to_wiki_table_markup(
self.cut_list_table_rows, self.columns)
elif self.list_option.isChecked():
table_markup = convert_dict_list_to_wiki_list_markup(
self.cut_list_table_rows)
else:
raise ValueError('Table or list option must be checked.')
clipboard.setText(table_markup)
self.copyStatusLabel.setText('<b>Status:</b> Copied!')
Console.PrintMessage('Copied table markup to clipboard.\n')

def accept(self):
"""
Executed upon clicking "OK" button in FreeCAD Tasks panel.
"""
self.handle_copy_to_clipboard()
FreeCADGui.Control.closeDialog()

0 comments on commit 9f04b2c

Please sign in to comment.