CAM: Improvements to machine (#28011)
* CAM: Improvements to machine * CAM: SPDX * lint and translation string problems * fixing headers and missing toolhead tests --------- Co-authored-by: tarman3 <[email protected]>
This commit is contained in:
+196
-103
@@ -1,24 +1,32 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# ***************************************************************************
|
||||
# * Copyright (c) 2025 Brad Collette *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
# * as published by the Free Software Foundation; either version 2 of *
|
||||
# * the License, or (at your option) any later version. *
|
||||
# * for detail see the LICENCE text file. *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
# SPDX-FileCopyrightText: 2025 Brad Collette
|
||||
# SPDX-FileNotice: Part of the FreeCAD project.
|
||||
|
||||
################################################################################
|
||||
# #
|
||||
# FreeCAD is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU Lesser General Public License as #
|
||||
# published by the Free Software Foundation, either version 2.1 #
|
||||
# of the License, or (at your option) any later version. #
|
||||
# #
|
||||
# FreeCAD is distributed in the hope that it will be useful, #
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty #
|
||||
# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. #
|
||||
# See the GNU Lesser General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the GNU Lesser General Public #
|
||||
# License along with FreeCAD. If not, see https://www.gnu.org/licenses #
|
||||
# #
|
||||
################################################################################
|
||||
|
||||
import FreeCAD
|
||||
import tempfile
|
||||
import pathlib
|
||||
import CAMTests.PathTestUtils as PathTestUtils
|
||||
from Path.Machine.models.machine import (
|
||||
from Machine.models.machine import (
|
||||
Machine,
|
||||
Spindle,
|
||||
Toolhead,
|
||||
OutputOptions,
|
||||
GCodeBlocks,
|
||||
ProcessingOptions,
|
||||
MachineFactory,
|
||||
)
|
||||
@@ -58,12 +66,6 @@ class TestMachineDataclass(PathTestUtils.PathTestBase):
|
||||
machine.add_rotary_axis("C", FreeCAD.Vector(0, 0, 1), -360, 360)
|
||||
self.assertEqual(machine.machine_type, "xyzac")
|
||||
|
||||
# Coordinate system defaults
|
||||
self.assertEqual(machine.reference_system["X"], FreeCAD.Vector(1, 0, 0))
|
||||
self.assertEqual(machine.reference_system["Y"], FreeCAD.Vector(0, 1, 0))
|
||||
self.assertEqual(machine.reference_system["Z"], FreeCAD.Vector(0, 0, 1))
|
||||
self.assertEqual(machine.tool_axis, FreeCAD.Vector(0, 0, -1))
|
||||
|
||||
# Units and versioning
|
||||
self.assertEqual(machine.configuration_units, "metric")
|
||||
self.assertEqual(machine.version, 1)
|
||||
@@ -71,8 +73,9 @@ class TestMachineDataclass(PathTestUtils.PathTestBase):
|
||||
|
||||
# Post-processor defaults
|
||||
self.assertIsInstance(machine.output, OutputOptions)
|
||||
self.assertIsInstance(machine.blocks, GCodeBlocks)
|
||||
self.assertIsInstance(machine.processing, ProcessingOptions)
|
||||
self.assertEqual(machine.postprocessor_file_name, "")
|
||||
self.assertIsInstance(machine.postprocessor_properties, dict)
|
||||
|
||||
def test_custom_initialization(self):
|
||||
"""Test Machine initialization with custom values and verify machine_type is derived"""
|
||||
@@ -113,44 +116,99 @@ class TestOutputOptions(PathTestUtils.PathTestBase):
|
||||
"""Test OutputOptions initialization with defaults"""
|
||||
opts = OutputOptions()
|
||||
|
||||
# Default values
|
||||
self.assertTrue(opts.comments)
|
||||
self.assertTrue(opts.blank_lines)
|
||||
self.assertTrue(opts.header)
|
||||
# Default values - using current field names
|
||||
from Machine.models.machine import OutputUnits
|
||||
|
||||
self.assertEqual(opts.output_units, OutputUnits.METRIC)
|
||||
self.assertEqual(opts.command_space, " ")
|
||||
self.assertEqual(opts.comment_symbol, "(")
|
||||
self.assertEqual(opts.end_of_line_chars, "\n")
|
||||
self.assertEqual(opts.line_increment, 10)
|
||||
self.assertEqual(opts.line_number_start, 100)
|
||||
self.assertFalse(opts.line_numbers)
|
||||
self.assertFalse(opts.bcnc_blocks)
|
||||
self.assertFalse(opts.path_labels)
|
||||
self.assertFalse(opts.machine_name)
|
||||
self.assertTrue(opts.tool_change)
|
||||
self.assertTrue(opts.doubles)
|
||||
self.assertFalse(opts.adaptive)
|
||||
self.assertEqual(opts.line_number_prefix, "N")
|
||||
self.assertTrue(opts.output_comments)
|
||||
self.assertTrue(opts.output_blank_lines)
|
||||
self.assertTrue(opts.output_bcnc_comments)
|
||||
self.assertTrue(opts.output_header)
|
||||
self.assertFalse(opts.output_labels)
|
||||
self.assertTrue(opts.output_operation_labels)
|
||||
self.assertFalse(opts.list_tools_in_header)
|
||||
self.assertTrue(opts.list_fixtures_in_header)
|
||||
self.assertFalse(opts.machine_name_in_header)
|
||||
self.assertTrue(opts.description_in_header)
|
||||
self.assertTrue(opts.project_file_in_header)
|
||||
self.assertTrue(opts.output_units_in_header)
|
||||
self.assertTrue(opts.date_in_header)
|
||||
self.assertTrue(opts.document_name_in_header)
|
||||
self.assertTrue(opts.output_duplicate_parameters)
|
||||
self.assertTrue(opts.output_duplicate_commands)
|
||||
self.assertEqual(opts.axis_precision, 3)
|
||||
self.assertEqual(opts.feed_precision, 3)
|
||||
self.assertEqual(opts.spindle_precision, 0)
|
||||
|
||||
def test_custom_initialization(self):
|
||||
"""Test OutputOptions initialization with custom values"""
|
||||
from Machine.models.machine import OutputUnits
|
||||
|
||||
opts = OutputOptions(
|
||||
comments=False,
|
||||
blank_lines=False,
|
||||
header=False,
|
||||
output_units=OutputUnits.IMPERIAL,
|
||||
command_space="",
|
||||
comment_symbol=";",
|
||||
end_of_line_chars="\r\n",
|
||||
line_increment=5,
|
||||
line_number_start=10,
|
||||
line_numbers=True,
|
||||
bcnc_blocks=True,
|
||||
path_labels=True,
|
||||
machine_name=True,
|
||||
tool_change=False,
|
||||
doubles=False,
|
||||
adaptive=True,
|
||||
line_number_prefix="L",
|
||||
output_comments=False,
|
||||
output_blank_lines=False,
|
||||
output_bcnc_comments=False,
|
||||
output_header=False,
|
||||
output_labels=True,
|
||||
output_operation_labels=False,
|
||||
list_tools_in_header=True,
|
||||
list_fixtures_in_header=False,
|
||||
machine_name_in_header=True,
|
||||
description_in_header=False,
|
||||
project_file_in_header=False,
|
||||
output_units_in_header=False,
|
||||
date_in_header=False,
|
||||
document_name_in_header=False,
|
||||
output_duplicate_parameters=False,
|
||||
output_duplicate_commands=False,
|
||||
axis_precision=4,
|
||||
feed_precision=2,
|
||||
spindle_precision=1,
|
||||
)
|
||||
|
||||
# Verify custom values
|
||||
self.assertFalse(opts.comments)
|
||||
self.assertFalse(opts.blank_lines)
|
||||
self.assertFalse(opts.header)
|
||||
self.assertEqual(opts.output_units, OutputUnits.IMPERIAL)
|
||||
self.assertEqual(opts.command_space, "")
|
||||
self.assertEqual(opts.comment_symbol, ";")
|
||||
self.assertEqual(opts.end_of_line_chars, "\r\n")
|
||||
self.assertEqual(opts.line_increment, 5)
|
||||
self.assertEqual(opts.line_number_start, 10)
|
||||
self.assertTrue(opts.line_numbers)
|
||||
self.assertTrue(opts.bcnc_blocks)
|
||||
self.assertTrue(opts.path_labels)
|
||||
self.assertTrue(opts.machine_name)
|
||||
self.assertFalse(opts.tool_change)
|
||||
self.assertFalse(opts.doubles)
|
||||
self.assertTrue(opts.adaptive)
|
||||
self.assertEqual(opts.line_number_prefix, "L")
|
||||
self.assertFalse(opts.output_comments)
|
||||
self.assertFalse(opts.output_blank_lines)
|
||||
self.assertFalse(opts.output_bcnc_comments)
|
||||
self.assertFalse(opts.output_header)
|
||||
self.assertTrue(opts.output_labels)
|
||||
self.assertFalse(opts.output_operation_labels)
|
||||
self.assertTrue(opts.list_tools_in_header)
|
||||
self.assertFalse(opts.list_fixtures_in_header)
|
||||
self.assertTrue(opts.machine_name_in_header)
|
||||
self.assertFalse(opts.description_in_header)
|
||||
self.assertFalse(opts.project_file_in_header)
|
||||
self.assertFalse(opts.output_units_in_header)
|
||||
self.assertFalse(opts.date_in_header)
|
||||
self.assertFalse(opts.document_name_in_header)
|
||||
self.assertFalse(opts.output_duplicate_parameters)
|
||||
self.assertFalse(opts.output_duplicate_commands)
|
||||
self.assertEqual(opts.axis_precision, 4)
|
||||
self.assertEqual(opts.feed_precision, 2)
|
||||
self.assertEqual(opts.spindle_precision, 1)
|
||||
|
||||
def test_equality(self):
|
||||
"""Test OutputOptions equality comparison"""
|
||||
@@ -158,63 +216,98 @@ class TestOutputOptions(PathTestUtils.PathTestBase):
|
||||
opts2 = OutputOptions()
|
||||
self.assertEqual(opts1, opts2)
|
||||
|
||||
opts2.comments = False
|
||||
opts2.output_comments = False
|
||||
self.assertNotEqual(opts1, opts2)
|
||||
|
||||
|
||||
class TestSpindle(PathTestUtils.PathTestBase):
|
||||
"""Test Spindle dataclass"""
|
||||
class TestProcessingOptions(PathTestUtils.PathTestBase):
|
||||
"""Test ProcessingOptions dataclass"""
|
||||
|
||||
def test_spindle_initialization(self):
|
||||
"""Test Spindle initialization with defaults"""
|
||||
spindle = Spindle(
|
||||
name="Main Spindle",
|
||||
def test_default_initialization(self):
|
||||
"""Test ProcessingOptions initialization with defaults"""
|
||||
opts = ProcessingOptions()
|
||||
|
||||
# Default values
|
||||
self.assertFalse(opts.early_tool_prep)
|
||||
self.assertFalse(opts.filter_inefficient_moves)
|
||||
self.assertFalse(opts.split_arcs)
|
||||
self.assertTrue(opts.tool_change)
|
||||
self.assertFalse(opts.translate_rapid_moves)
|
||||
self.assertIsNone(opts.return_to)
|
||||
|
||||
def test_custom_initialization(self):
|
||||
"""Test ProcessingOptions initialization with custom values"""
|
||||
opts = ProcessingOptions(
|
||||
early_tool_prep=True,
|
||||
filter_inefficient_moves=True,
|
||||
split_arcs=True,
|
||||
tool_change=False,
|
||||
translate_rapid_moves=True,
|
||||
return_to=(10.0, 20.0, 30.0),
|
||||
)
|
||||
|
||||
# Verify custom values
|
||||
self.assertTrue(opts.early_tool_prep)
|
||||
self.assertTrue(opts.filter_inefficient_moves)
|
||||
self.assertTrue(opts.split_arcs)
|
||||
self.assertFalse(opts.tool_change)
|
||||
self.assertTrue(opts.translate_rapid_moves)
|
||||
self.assertEqual(opts.return_to, (10.0, 20.0, 30.0))
|
||||
|
||||
def test_equality(self):
|
||||
"""Test ProcessingOptions equality comparison"""
|
||||
opts1 = ProcessingOptions()
|
||||
opts2 = ProcessingOptions()
|
||||
self.assertEqual(opts1, opts2)
|
||||
|
||||
opts2.filter_inefficient_moves = True
|
||||
self.assertNotEqual(opts1, opts2)
|
||||
|
||||
|
||||
class TestToolhead(PathTestUtils.PathTestBase):
|
||||
"""Test Toolhead dataclass"""
|
||||
|
||||
def test_toolhead_initialization(self):
|
||||
"""Test Toolhead initialization with defaults"""
|
||||
toolhead = Toolhead(
|
||||
name="Main Toolhead",
|
||||
max_power_kw=5.5,
|
||||
max_rpm=24000,
|
||||
min_rpm=1000,
|
||||
tool_change="automatic",
|
||||
)
|
||||
|
||||
self.assertEqual(spindle.name, "Main Spindle")
|
||||
self.assertEqual(spindle.max_power_kw, 5.5)
|
||||
self.assertEqual(spindle.max_rpm, 24000)
|
||||
self.assertEqual(spindle.min_rpm, 1000)
|
||||
self.assertEqual(spindle.tool_change, "automatic")
|
||||
# Default tool axis should be set
|
||||
self.assertEqual(spindle.tool_axis, FreeCAD.Vector(0, 0, -1))
|
||||
self.assertEqual(toolhead.name, "Main Toolhead")
|
||||
self.assertEqual(toolhead.max_power_kw, 5.5)
|
||||
self.assertEqual(toolhead.max_rpm, 24000)
|
||||
self.assertEqual(toolhead.min_rpm, 1000)
|
||||
self.assertEqual(toolhead.tool_change, "automatic")
|
||||
# Default toolhead_wait should be 0.0
|
||||
self.assertEqual(toolhead.toolhead_wait, 0.0)
|
||||
|
||||
def test_spindle_custom_tool_axis(self):
|
||||
"""Test Spindle with custom tool axis"""
|
||||
spindle = Spindle(
|
||||
name="Side Spindle",
|
||||
tool_axis=FreeCAD.Vector(1, 0, 0),
|
||||
)
|
||||
|
||||
self.assertEqual(spindle.tool_axis, FreeCAD.Vector(1, 0, 0))
|
||||
|
||||
def test_spindle_serialization(self):
|
||||
def test_toolhead_serialization(self):
|
||||
"""Test to_dict and from_dict"""
|
||||
spindle = Spindle(
|
||||
name="Test Spindle",
|
||||
id="spindle-001",
|
||||
toolhead = Toolhead(
|
||||
name="Test Toolhead",
|
||||
id="toolhead-001",
|
||||
max_power_kw=3.0,
|
||||
max_rpm=18000,
|
||||
min_rpm=500,
|
||||
tool_change="manual",
|
||||
tool_axis=FreeCAD.Vector(0, 1, 0),
|
||||
toolhead_wait=1.5,
|
||||
)
|
||||
|
||||
data = spindle.to_dict()
|
||||
self.assertEqual(data["name"], "Test Spindle")
|
||||
self.assertEqual(data["id"], "spindle-001")
|
||||
data = toolhead.to_dict()
|
||||
self.assertEqual(data["name"], "Test Toolhead")
|
||||
self.assertEqual(data["id"], "toolhead-001")
|
||||
self.assertEqual(data["max_power_kw"], 3.0)
|
||||
self.assertEqual(data["tool_axis"], [0, 1, 0])
|
||||
self.assertEqual(data["toolhead_wait"], 1.5)
|
||||
|
||||
restored = Spindle.from_dict(data)
|
||||
self.assertEqual(restored.name, spindle.name)
|
||||
self.assertEqual(restored.id, spindle.id)
|
||||
self.assertEqual(restored.max_power_kw, spindle.max_power_kw)
|
||||
self.assertEqual(restored.tool_axis, spindle.tool_axis)
|
||||
restored = Toolhead.from_dict(data)
|
||||
self.assertEqual(restored.name, toolhead.name)
|
||||
self.assertEqual(restored.id, toolhead.id)
|
||||
self.assertEqual(restored.max_power_kw, toolhead.max_power_kw)
|
||||
self.assertEqual(restored.toolhead_wait, toolhead.toolhead_wait)
|
||||
|
||||
|
||||
class TestMachineFactory(PathTestUtils.PathTestBase):
|
||||
@@ -257,14 +350,14 @@ class TestMachineFactory(PathTestUtils.PathTestBase):
|
||||
machine.add_linear_axis("Y", FreeCAD.Vector(0, 1, 0))
|
||||
machine.add_linear_axis("Z", FreeCAD.Vector(0, 0, 1))
|
||||
|
||||
# Add a spindle
|
||||
spindle = Spindle(
|
||||
name="Main Spindle",
|
||||
# Add a toolhead
|
||||
toolhead = Toolhead(
|
||||
name="Main Toolhead",
|
||||
max_power_kw=5.5,
|
||||
max_rpm=24000,
|
||||
min_rpm=1000,
|
||||
)
|
||||
machine.spindles.append(spindle)
|
||||
machine.toolheads.append(toolhead)
|
||||
|
||||
# Save configuration
|
||||
filepath = MachineFactory.save_configuration(machine, "test_machine.fcm")
|
||||
@@ -279,8 +372,8 @@ class TestMachineFactory(PathTestUtils.PathTestBase):
|
||||
self.assertEqual(loaded_machine.description, "Test description")
|
||||
self.assertEqual(loaded_machine.machine_type, "xyz")
|
||||
self.assertEqual(loaded_machine.configuration_units, "metric")
|
||||
self.assertEqual(len(loaded_machine.spindles), 1)
|
||||
self.assertEqual(loaded_machine.spindles[0].name, "Main Spindle")
|
||||
self.assertEqual(len(loaded_machine.toolheads), 1)
|
||||
self.assertEqual(loaded_machine.toolheads[0].name, "Main Toolhead")
|
||||
|
||||
def test_save_configuration_auto_filename(self):
|
||||
"""Test saving with automatic filename generation"""
|
||||
@@ -305,7 +398,7 @@ class TestMachineFactory(PathTestUtils.PathTestBase):
|
||||
# The data structure has nested "machine" key
|
||||
self.assertIn("machine", data)
|
||||
self.assertEqual(data["machine"]["name"], "New Machine")
|
||||
self.assertIn("spindles", data["machine"])
|
||||
self.assertIn("toolheads", data["machine"])
|
||||
|
||||
def test_list_configuration_files(self):
|
||||
"""Test listing available configuration files"""
|
||||
@@ -381,9 +474,9 @@ class TestMachineFactory(PathTestUtils.PathTestBase):
|
||||
configuration_units="metric",
|
||||
)
|
||||
|
||||
# Add spindle
|
||||
machine.spindles.append(
|
||||
Spindle(
|
||||
# Add toolhead
|
||||
machine.toolheads.append(
|
||||
Toolhead(
|
||||
name="Main",
|
||||
max_power_kw=7.5,
|
||||
max_rpm=30000,
|
||||
@@ -391,9 +484,9 @@ class TestMachineFactory(PathTestUtils.PathTestBase):
|
||||
)
|
||||
|
||||
# Configure post-processor settings
|
||||
machine.output.output_comments = False
|
||||
machine.output.axis_precision = 4
|
||||
machine.output.line_increment = 5
|
||||
machine.output.comments.enabled = False
|
||||
machine.output.precision.axis = 4
|
||||
machine.output.formatting.line_increment = 5
|
||||
|
||||
# line_increment is set to default 10 in OutputOptions
|
||||
|
||||
@@ -404,7 +497,7 @@ class TestMachineFactory(PathTestUtils.PathTestBase):
|
||||
# Verify all components
|
||||
self.assertEqual(loaded.name, machine.name)
|
||||
self.assertEqual(loaded.manufacturer, machine.manufacturer)
|
||||
self.assertEqual(len(loaded.spindles), 1)
|
||||
self.assertFalse(loaded.output.output_comments)
|
||||
self.assertEqual(loaded.output.axis_precision, 4)
|
||||
self.assertEqual(loaded.output.line_increment, 5)
|
||||
self.assertEqual(len(loaded.toolheads), 1)
|
||||
self.assertFalse(loaded.output.comments.enabled)
|
||||
self.assertEqual(loaded.output.precision.axis, 4)
|
||||
self.assertEqual(loaded.output.formatting.line_increment, 5)
|
||||
|
||||
@@ -171,17 +171,17 @@ SET(PathPythonToolsGui_SRCS
|
||||
)
|
||||
|
||||
SET(PathPythonMachineUi_SRCS
|
||||
Path/Machine/ui/__init__.py
|
||||
Machine/ui/__init__.py
|
||||
)
|
||||
|
||||
SET(PathPythonMachineUiEditor_SRCS
|
||||
Path/Machine/ui/editor/machine_editor.py
|
||||
Path/Machine/ui/editor/__init__.py
|
||||
Machine/ui/editor/machine_editor.py
|
||||
Machine/ui/editor/__init__.py
|
||||
)
|
||||
|
||||
SET(PathPythonMachineModels_SRCS
|
||||
Path/Machine/models/__init__.py
|
||||
Path/Machine/models/machine.py
|
||||
Machine/models/__init__.py
|
||||
Machine/models/machine.py
|
||||
)
|
||||
|
||||
SET(PathPythonToolsToolBit_SRCS
|
||||
@@ -927,21 +927,21 @@ INSTALL(
|
||||
FILES
|
||||
${PathPythonMachineModels_SRCS}
|
||||
DESTINATION
|
||||
Mod/CAM/Path/Machine/models
|
||||
Mod/CAM/Machine/models
|
||||
)
|
||||
|
||||
INSTALL(
|
||||
FILES
|
||||
${PathPythonMachineUi_SRCS}
|
||||
DESTINATION
|
||||
Mod/CAM/Path/Machine/ui
|
||||
Mod/CAM/Machine/ui
|
||||
)
|
||||
|
||||
INSTALL(
|
||||
FILES
|
||||
${PathPythonMachineUiEditor_SRCS}
|
||||
DESTINATION
|
||||
Mod/CAM/Path/Machine/ui/editor
|
||||
Mod/CAM/Machine/ui/editor
|
||||
)
|
||||
|
||||
INSTALL(
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
{
|
||||
"freecad_version": "1.2.0",
|
||||
"machine": {
|
||||
"axes": {
|
||||
"X": {
|
||||
"joint": [
|
||||
[
|
||||
1.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
[
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
],
|
||||
"max": 1000,
|
||||
"max_velocity": 10000,
|
||||
"min": 0.0,
|
||||
"sequence": 0,
|
||||
"type": "linear"
|
||||
},
|
||||
"Y": {
|
||||
"joint": [
|
||||
[
|
||||
0.0,
|
||||
1.0,
|
||||
0.0
|
||||
],
|
||||
[
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
],
|
||||
"max": 1000,
|
||||
"max_velocity": 10000,
|
||||
"min": 0,
|
||||
"sequence": 0,
|
||||
"type": "linear"
|
||||
},
|
||||
"Z": {
|
||||
"joint": [
|
||||
[
|
||||
0.0,
|
||||
0.0,
|
||||
1.0
|
||||
],
|
||||
[
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
],
|
||||
"max": 1000,
|
||||
"max_velocity": 10000,
|
||||
"min": 0,
|
||||
"sequence": 0,
|
||||
"type": "linear"
|
||||
}
|
||||
},
|
||||
"description": "3 axis mill using Grbl controller",
|
||||
"manufacturer": "",
|
||||
"name": "Generic Grbl",
|
||||
"spindles": [
|
||||
{
|
||||
"id": "spindle1",
|
||||
"max_power_kw": 1.5,
|
||||
"max_rpm": 24000,
|
||||
"min_rpm": 0,
|
||||
"name": "Spindle 1",
|
||||
"tool_axis": [
|
||||
0.0,
|
||||
0.0,
|
||||
-1.0
|
||||
],
|
||||
"tool_change": "manual",
|
||||
"coolant_flood": false,
|
||||
"coolant_mist": false,
|
||||
"coolant_delay": 0.0,
|
||||
"spindle_wait": 0.0
|
||||
}
|
||||
],
|
||||
"units": "metric"
|
||||
},
|
||||
"output": {
|
||||
"units": "metric",
|
||||
"output_tool_length_offset": true,
|
||||
"output_header": true,
|
||||
"header": {
|
||||
"include_date": true,
|
||||
"include_description": true,
|
||||
"include_document_name": true,
|
||||
"include_machine_name": false,
|
||||
"include_project_file": true,
|
||||
"include_units": true,
|
||||
"include_tool_list": false,
|
||||
"include_fixture_list": true
|
||||
},
|
||||
"comments": {
|
||||
"enabled": true,
|
||||
"symbol": "(",
|
||||
"include_operation_labels": true,
|
||||
"include_blank_lines": true,
|
||||
"output_bcnc_comments": false
|
||||
},
|
||||
"formatting": {
|
||||
"line_numbers": false,
|
||||
"line_number_start": 100,
|
||||
"line_number_prefix": "N",
|
||||
"line_increment": 10,
|
||||
"command_space": " ",
|
||||
"end_of_line_chars": "\n"
|
||||
},
|
||||
"precision": {
|
||||
"axis": 3,
|
||||
"feed": 3,
|
||||
"spindle": 0
|
||||
},
|
||||
"duplicates": {
|
||||
"commands": true,
|
||||
"parameters": true
|
||||
}
|
||||
},
|
||||
"postprocessor": {
|
||||
"file_name": "generic",
|
||||
"properties": {
|
||||
"supports_tool_radius_compensation": false,
|
||||
"supported_commands": "G0\nG00\nG1\nG01\nG2\nG02\nG3\nG03\nG73\nG74\nG81\nG82\nG83\nG84\nG38.2\nG54\nG55\nG56\nG57\nG58\nG59\nG59.1\nG59.2\nG59.3\nG59.4\nG59.5\nG59.6\nG59.7\nG59.8\nG59.9\nM0\nM00\nM1\nM01\nM3\nM03\nM4\nM04\nM6\nM06",
|
||||
"drill_cycles_to_translate": "G73\nG81\nG82\nG83",
|
||||
"preamble": "G17 G90",
|
||||
"postamble": "M5\nG17 G90\nM2",
|
||||
"safetyblock": "",
|
||||
"pre_operation": "",
|
||||
"post_operation": "",
|
||||
"pre_tool_change": "",
|
||||
"post_tool_change": "",
|
||||
"pre_job": "",
|
||||
"post_job": "",
|
||||
"pre_fixture_change": "",
|
||||
"post_fixture_change": "",
|
||||
"pre_rotary_move": "",
|
||||
"post_rotary_move": "",
|
||||
"tool_return": ""
|
||||
}
|
||||
},
|
||||
"processing": {
|
||||
"early_tool_prep": false,
|
||||
"filter_inefficient_moves": false,
|
||||
"split_arcs": false,
|
||||
"tool_change": false,
|
||||
"translate_rapid_moves": true
|
||||
},
|
||||
"version": 1
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
{
|
||||
"freecad_version": "1.2.0",
|
||||
"machine": {
|
||||
"axes": {
|
||||
"X": {
|
||||
"type": "linear",
|
||||
"role": "table_linear",
|
||||
"parent": null,
|
||||
"sequence": 0,
|
||||
"joint": {
|
||||
"origin": [0, 0, 0],
|
||||
"axis": [1, 0, 0]
|
||||
},
|
||||
"limits": {
|
||||
"min": 0,
|
||||
"max": 1000
|
||||
},
|
||||
"max_velocity": 10000
|
||||
},
|
||||
"Y": {
|
||||
"type": "linear",
|
||||
"role": "table_linear",
|
||||
"parent": null,
|
||||
"sequence": 0,
|
||||
"joint": {
|
||||
"origin": [0, 0, 0],
|
||||
"axis": [0, 1, 0]
|
||||
},
|
||||
"limits": {
|
||||
"min": 0,
|
||||
"max": 1000
|
||||
},
|
||||
"max_velocity": 10000
|
||||
},
|
||||
"Z": {
|
||||
"type": "linear",
|
||||
"role": "head_linear",
|
||||
"parent": null,
|
||||
"sequence": 0,
|
||||
"joint": {
|
||||
"origin": [0, 0, 0],
|
||||
"axis": [0, 0, 1]
|
||||
},
|
||||
"limits": {
|
||||
"min": 0,
|
||||
"max": 1000
|
||||
},
|
||||
"max_velocity": 10000
|
||||
}
|
||||
},
|
||||
"description": "Basic LinuxCNC configuration",
|
||||
"manufacturer": "",
|
||||
"name": "Generic LinuxCNC",
|
||||
"toolheads": [
|
||||
{
|
||||
"id": "toolhead1",
|
||||
"name": "Toolhead 1",
|
||||
"toolhead_type": "rotary",
|
||||
"tool_change": "manual",
|
||||
"max_power_kw": 3.0,
|
||||
"min_rpm": 6000,
|
||||
"max_rpm": 24000,
|
||||
"coolant_flood": false,
|
||||
"coolant_mist": false,
|
||||
"coolant_delay": 0.0,
|
||||
"toolhead_wait": 0.0
|
||||
}
|
||||
],
|
||||
"units": "metric"
|
||||
},
|
||||
"output": {
|
||||
"units": "metric",
|
||||
"output_tool_length_offset": true,
|
||||
"output_header": true,
|
||||
"header": {
|
||||
"include_date": true,
|
||||
"include_description": true,
|
||||
"include_document_name": true,
|
||||
"include_machine_name": false,
|
||||
"include_project_file": true,
|
||||
"include_units": true,
|
||||
"include_tool_list": false,
|
||||
"include_fixture_list": true
|
||||
},
|
||||
"comments": {
|
||||
"enabled": true,
|
||||
"symbol": "(",
|
||||
"include_operation_labels": true,
|
||||
"include_blank_lines": true,
|
||||
"output_bcnc_comments": true
|
||||
},
|
||||
"formatting": {
|
||||
"line_numbers": false,
|
||||
"line_number_start": 100,
|
||||
"line_number_prefix": "N",
|
||||
"line_increment": 10,
|
||||
"command_space": " ",
|
||||
"end_of_line_chars": "\n"
|
||||
},
|
||||
"precision": {
|
||||
"axis": 3,
|
||||
"feed": 3,
|
||||
"spindle": 0
|
||||
},
|
||||
"duplicates": {
|
||||
"commands": true,
|
||||
"parameters": true
|
||||
}
|
||||
},
|
||||
"postprocessor": {
|
||||
"file_name": "linuxcnc",
|
||||
"properties": {
|
||||
"supports_tool_radius_compensation": true,
|
||||
"supported_commands": "G0\nG00\nG1\nG01\nG2\nG02\nG3\nG03\nG73\nG74\nG81\nG82\nG83\nG84\nG38.2\nG54\nG55\nG56\nG57\nG58\nG59\nG59.1\nG59.2\nG59.3\nG59.4\nG59.5\nG59.6\nG59.7\nG59.8\nG59.9\nM0\nM00\nM1\nM01\nM3\nM03\nM4\nM04\nM6\nM06",
|
||||
"drill_cycles_to_translate": "",
|
||||
"preamble": "G17 G54 G40 G49 G80 G90",
|
||||
"postamble": "M05\nG17 G54 G90 G80 G40\nM2",
|
||||
"safetyblock": "G40 G49 G80",
|
||||
"pre_operation": "",
|
||||
"post_operation": "",
|
||||
"pre_tool_change": "",
|
||||
"post_tool_change": "",
|
||||
"blend_mode": "BLEND",
|
||||
"blend_tolerance": 0.0
|
||||
}
|
||||
},
|
||||
"processing": {
|
||||
"early_tool_prep": false,
|
||||
"filter_inefficient_moves": false,
|
||||
"split_arcs": false,
|
||||
"tool_change": true,
|
||||
"translate_rapid_moves": false
|
||||
},
|
||||
"version": 1
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
{
|
||||
"blocks": {
|
||||
"postamble": "M05\nG17 G90\nM2",
|
||||
"preamble": "G17 G90"
|
||||
},
|
||||
"freecad_version": "1.2.0",
|
||||
"machine": {
|
||||
"axes": {
|
||||
"X": {
|
||||
"joint": [
|
||||
[
|
||||
1.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
[
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
],
|
||||
"max": 500,
|
||||
"max_velocity": 10000,
|
||||
"min": 0,
|
||||
"sequence": 0,
|
||||
"type": "linear"
|
||||
},
|
||||
"Y": {
|
||||
"joint": [
|
||||
[
|
||||
0.0,
|
||||
1.0,
|
||||
0.0
|
||||
],
|
||||
[
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
],
|
||||
"max": 300,
|
||||
"max_velocity": 10000,
|
||||
"min": 0,
|
||||
"sequence": 0,
|
||||
"type": "linear"
|
||||
},
|
||||
"Z": {
|
||||
"joint": [
|
||||
[
|
||||
0.0,
|
||||
0.0,
|
||||
1.0
|
||||
],
|
||||
[
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
],
|
||||
"max": 300,
|
||||
"max_velocity": 10000,
|
||||
"min": 0,
|
||||
"sequence": 0,
|
||||
"type": "linear"
|
||||
}
|
||||
},
|
||||
"description": "3 axis CNC using SmoothieBoard controller",
|
||||
"manufacturer": "Smoothieware",
|
||||
"name": "Generic SmoothieBoard",
|
||||
"spindles": [
|
||||
{
|
||||
"id": "spindle1",
|
||||
"max_power_kw": 2.2,
|
||||
"max_rpm": 24000,
|
||||
"min_rpm": 0,
|
||||
"name": "Spindle 1",
|
||||
"tool_axis": [
|
||||
0.0,
|
||||
0.0,
|
||||
-1.0
|
||||
],
|
||||
"tool_change": "manual",
|
||||
"coolant_flood": false,
|
||||
"coolant_mist": false,
|
||||
"coolant_delay": 0.0
|
||||
}
|
||||
],
|
||||
"units": "metric"
|
||||
},
|
||||
"output": {
|
||||
"units": "metric",
|
||||
"output_tool_length_offset": true,
|
||||
"output_header": true,
|
||||
"header": {
|
||||
"include_date": true,
|
||||
"include_description": true,
|
||||
"include_document_name": true,
|
||||
"include_machine_name": false,
|
||||
"include_project_file": true,
|
||||
"include_units": true,
|
||||
"include_tool_list": false,
|
||||
"include_fixture_list": true
|
||||
},
|
||||
"comments": {
|
||||
"enabled": true,
|
||||
"symbol": "(",
|
||||
"include_operation_labels": true,
|
||||
"include_blank_lines": true,
|
||||
"output_bcnc_comments": true
|
||||
},
|
||||
"formatting": {
|
||||
"line_numbers": false,
|
||||
"line_number_start": 100,
|
||||
"line_number_prefix": "N",
|
||||
"line_increment": 10,
|
||||
"command_space": " ",
|
||||
"end_of_line_chars": "\n"
|
||||
},
|
||||
"precision": {
|
||||
"axis": 3,
|
||||
"feed": 3,
|
||||
"spindle": 0
|
||||
},
|
||||
"duplicates": {
|
||||
"commands": true,
|
||||
"parameters": true
|
||||
}
|
||||
},
|
||||
"postprocessor": {
|
||||
"args": "",
|
||||
"file_name": "smoothie"
|
||||
},
|
||||
"processing": {
|
||||
"drill_cycles_to_translate": [
|
||||
"G73",
|
||||
"G81",
|
||||
"G82",
|
||||
"G83"
|
||||
],
|
||||
"early_tool_prep": false,
|
||||
"filter_inefficient_moves": false,
|
||||
"spindle_wait": 0.0,
|
||||
"split_arcs": false,
|
||||
"suppress_commands": [],
|
||||
"tool_change": true,
|
||||
"translate_drill_cycles": false,
|
||||
"translate_rapid_moves": false
|
||||
},
|
||||
"version": 1
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
# SPDX-FileCopyrightText: 2025 Billy Huddleston <[email protected]>
|
||||
# SPDX-FileNotice: Part of the FreeCAD project.
|
||||
|
||||
################################################################################
|
||||
# #
|
||||
# FreeCAD is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU Lesser General Public License as #
|
||||
# published by the Free Software Foundation, either version 2.1 #
|
||||
# of the License, or (at your option) any later version. #
|
||||
# #
|
||||
# FreeCAD is distributed in the hope that it will be useful, #
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty #
|
||||
# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. #
|
||||
# See the GNU Lesser General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the GNU Lesser General Public #
|
||||
# License along with FreeCAD. If not, see https://www.gnu.org/licenses #
|
||||
# #
|
||||
################################################################################
|
||||
|
||||
from .machine import (
|
||||
Machine,
|
||||
MachineFactory,
|
||||
LinearAxis,
|
||||
RotaryAxis,
|
||||
Toolhead,
|
||||
ToolheadType,
|
||||
MachineUnits,
|
||||
OutputUnits,
|
||||
OutputOptions,
|
||||
ProcessingOptions,
|
||||
)
|
||||
|
||||
# Legacy compatibility aliases
|
||||
Spindle = Toolhead
|
||||
SpindleType = ToolheadType
|
||||
|
||||
__all__ = [
|
||||
"Machine",
|
||||
"MachineFactory",
|
||||
"LinearAxis",
|
||||
"RotaryAxis",
|
||||
"Toolhead",
|
||||
"ToolheadType",
|
||||
"Spindle", # Legacy alias
|
||||
"SpindleType", # Legacy alias
|
||||
"MachineUnits",
|
||||
"OutputUnits",
|
||||
"OutputOptions",
|
||||
"ProcessingOptions",
|
||||
]
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,10 +1,10 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
# SPDX-FileCopyrightText: 2025 Billy Huddleston <[email protected]>
|
||||
# SPDX-FileNotice: Part of the FreeCAD project.
|
||||
|
||||
|
||||
################################################################################
|
||||
# #
|
||||
# © 2026 Billy Huddleston <[email protected]> #
|
||||
# #
|
||||
# FreeCAD is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU Lesser General Public License as #
|
||||
# published by the Free Software Foundation, either version 2.1 #
|
||||
@@ -0,0 +1,25 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
# SPDX-FileCopyrightText: 2025 Billy Huddleston <[email protected]>
|
||||
# SPDX-FileNotice: Part of the FreeCAD project.
|
||||
|
||||
################################################################################
|
||||
# #
|
||||
# FreeCAD is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU Lesser General Public License as #
|
||||
# published by the Free Software Foundation, either version 2.1 #
|
||||
# of the License, or (at your option) any later version. #
|
||||
# #
|
||||
# FreeCAD is distributed in the hope that it will be useful, #
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty #
|
||||
# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. #
|
||||
# See the GNU Lesser General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the GNU Lesser General Public #
|
||||
# License along with FreeCAD. If not, see https://www.gnu.org/licenses #
|
||||
# #
|
||||
################################################################################
|
||||
|
||||
"""Machine editor package."""
|
||||
from .machine_editor import MachineEditorDialog
|
||||
|
||||
__all__ = ["MachineEditorDialog"]
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,155 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
# SPDX-FileCopyrightText: 2025 Billy Huddleston <[email protected]>
|
||||
# SPDX-FileNotice: Part of the FreeCAD project.
|
||||
|
||||
################################################################################
|
||||
# #
|
||||
# FreeCAD is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU Lesser General Public License as #
|
||||
# published by the Free Software Foundation, either version 2.1 #
|
||||
# of the License, or (at your option) any later version. #
|
||||
# #
|
||||
# FreeCAD is distributed in the hope that it will be useful, #
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty #
|
||||
# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. #
|
||||
# See the GNU Lesser General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the GNU Lesser General Public #
|
||||
# License along with FreeCAD. If not, see https://www.gnu.org/licenses #
|
||||
# #
|
||||
################################################################################
|
||||
|
||||
"""
|
||||
Helper module for managing postprocessor properties in the machine editor.
|
||||
"""
|
||||
from PySide import QtGui
|
||||
from typing import Dict, Any
|
||||
|
||||
|
||||
class PostProcessorPropertyManager:
|
||||
"""Manages dynamic creation and handling of postprocessor property widgets."""
|
||||
|
||||
@staticmethod
|
||||
def create_property_widget(prop: Dict[str, Any], current_value: Any) -> QtGui.QWidget:
|
||||
"""Create a widget for a postprocessor property based on its type.
|
||||
|
||||
Args:
|
||||
prop: Property schema dictionary with keys: name, type, label, default, help, etc.
|
||||
current_value: Current value of the property
|
||||
|
||||
Returns:
|
||||
QWidget configured for the property type, with a value_getter() method
|
||||
"""
|
||||
prop_type = prop.get("type")
|
||||
|
||||
if prop_type == "bool":
|
||||
widget = QtGui.QCheckBox()
|
||||
widget.setChecked(current_value if current_value is not None else False)
|
||||
widget.value_getter = lambda: widget.isChecked()
|
||||
return widget
|
||||
|
||||
elif prop_type == "int":
|
||||
widget = QtGui.QSpinBox()
|
||||
widget.setRange(prop.get("min", -999999), prop.get("max", 999999))
|
||||
widget.setValue(current_value if current_value is not None else 0)
|
||||
widget.value_getter = lambda: widget.value()
|
||||
return widget
|
||||
|
||||
elif prop_type == "float":
|
||||
widget = QtGui.QDoubleSpinBox()
|
||||
widget.setRange(prop.get("min", -999999.0), prop.get("max", 999999.0))
|
||||
widget.setDecimals(prop.get("decimals", 4))
|
||||
widget.setValue(current_value if current_value is not None else 0.0)
|
||||
widget.value_getter = lambda: widget.value()
|
||||
return widget
|
||||
|
||||
elif prop_type == "choice":
|
||||
widget = QtGui.QComboBox()
|
||||
choices = prop.get("choices", [])
|
||||
for choice in choices:
|
||||
widget.addItem(str(choice), choice)
|
||||
if current_value:
|
||||
index = widget.findData(current_value)
|
||||
if index >= 0:
|
||||
widget.setCurrentIndex(index)
|
||||
widget.value_getter = lambda: widget.itemData(widget.currentIndex())
|
||||
return widget
|
||||
|
||||
elif prop_type == "text":
|
||||
widget = QtGui.QPlainTextEdit()
|
||||
widget.setMaximumHeight(100)
|
||||
widget.setPlainText(current_value if current_value else "")
|
||||
widget.value_getter = lambda: widget.toPlainText()
|
||||
return widget
|
||||
|
||||
elif prop_type == "file":
|
||||
# File picker widget
|
||||
container = QtGui.QWidget()
|
||||
layout = QtGui.QHBoxLayout(container)
|
||||
layout.setContentsMargins(0, 0, 0, 0)
|
||||
|
||||
line_edit = QtGui.QLineEdit()
|
||||
line_edit.setText(current_value if current_value else "")
|
||||
|
||||
browse_button = QtGui.QPushButton("...")
|
||||
browse_button.setMaximumWidth(30)
|
||||
|
||||
def browse_file():
|
||||
filters = prop.get("filters", "All Files (*)")
|
||||
filename, _ = QtGui.QFileDialog.getOpenFileName(
|
||||
container, "Select File", "", filters
|
||||
)
|
||||
if filename:
|
||||
line_edit.setText(filename)
|
||||
|
||||
browse_button.clicked.connect(browse_file)
|
||||
|
||||
layout.addWidget(line_edit)
|
||||
layout.addWidget(browse_button)
|
||||
|
||||
container.value_getter = lambda: line_edit.text()
|
||||
return container
|
||||
|
||||
else: # Default to string
|
||||
widget = QtGui.QLineEdit()
|
||||
widget.setText(str(current_value) if current_value else "")
|
||||
widget.value_getter = lambda: widget.text()
|
||||
return widget
|
||||
|
||||
@staticmethod
|
||||
def connect_property_widget(
|
||||
widget: QtGui.QWidget, prop_name: str, prop_type: str, machine, callback=None
|
||||
):
|
||||
"""Connect a property widget to update the machine configuration.
|
||||
|
||||
Args:
|
||||
widget: The widget to connect
|
||||
prop_name: Name of the property
|
||||
prop_type: Type of the property
|
||||
machine: Machine object to update
|
||||
callback: Optional callback function to call after update
|
||||
"""
|
||||
|
||||
def update_property():
|
||||
if hasattr(widget, "value_getter"):
|
||||
value = widget.value_getter()
|
||||
machine.postprocessor_properties[prop_name] = value
|
||||
if callback:
|
||||
callback(prop_name, value)
|
||||
|
||||
# Connect appropriate signal based on widget type
|
||||
if isinstance(widget, QtGui.QCheckBox):
|
||||
widget.stateChanged.connect(update_property)
|
||||
elif isinstance(widget, QtGui.QSpinBox) or isinstance(widget, QtGui.QDoubleSpinBox):
|
||||
widget.valueChanged.connect(update_property)
|
||||
elif isinstance(widget, QtGui.QComboBox):
|
||||
widget.currentIndexChanged.connect(update_property)
|
||||
elif isinstance(widget, QtGui.QPlainTextEdit):
|
||||
widget.textChanged.connect(update_property)
|
||||
elif isinstance(widget, QtGui.QLineEdit):
|
||||
widget.textChanged.connect(update_property)
|
||||
elif isinstance(widget, QtGui.QWidget):
|
||||
# For composite widgets (like file picker), find the line edit
|
||||
line_edit = widget.findChild(QtGui.QLineEdit)
|
||||
if line_edit:
|
||||
line_edit.textChanged.connect(update_property)
|
||||
@@ -1,48 +0,0 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
# ***************************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2025 Billy Huddleston <[email protected]> *
|
||||
# * *
|
||||
# * This file is part of FreeCAD. *
|
||||
# * *
|
||||
# * FreeCAD is free software: you can redistribute it and/or modify it *
|
||||
# * under the terms of the GNU Lesser General Public License as *
|
||||
# * published by the Free Software Foundation, either version 2.1 of the *
|
||||
# * License, or (at your option) any later version. *
|
||||
# * *
|
||||
# * FreeCAD is distributed in the hope that it will be useful, but *
|
||||
# * WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
# * Lesser General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Lesser General Public *
|
||||
# * License along with FreeCAD. If not, see *
|
||||
# * <https://www.gnu.org/licenses/>. *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
|
||||
from .machine import (
|
||||
Machine,
|
||||
MachineFactory,
|
||||
LinearAxis,
|
||||
RotaryAxis,
|
||||
Spindle,
|
||||
MachineUnits,
|
||||
OutputUnits,
|
||||
OutputOptions,
|
||||
GCodeBlocks,
|
||||
ProcessingOptions,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"Machine",
|
||||
"MachineFactory",
|
||||
"LinearAxis",
|
||||
"RotaryAxis",
|
||||
"Spindle",
|
||||
"MachineUnits",
|
||||
"OutputUnits",
|
||||
"OutputOptions",
|
||||
"GCodeBlocks",
|
||||
"ProcessingOptions",
|
||||
]
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,26 +0,0 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
# ***************************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2025 Billy Huddleston <[email protected]> *
|
||||
# * *
|
||||
# * This file is part of FreeCAD. *
|
||||
# * *
|
||||
# * FreeCAD is free software: you can redistribute it and/or modify it *
|
||||
# * under the terms of the GNU Lesser General Public License as *
|
||||
# * published by the Free Software Foundation, either version 2.1 of the *
|
||||
# * License, or (at your option) any later version. *
|
||||
# * *
|
||||
# * FreeCAD is distributed in the hope that it will be useful, but *
|
||||
# * WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
# * Lesser General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Lesser General Public *
|
||||
# * License along with FreeCAD. If not, see *
|
||||
# * <https://www.gnu.org/licenses/>. *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
"""Machine editor package."""
|
||||
from .machine_editor import MachineEditorDialog
|
||||
|
||||
__all__ = ["MachineEditorDialog"]
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,33 +1,31 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
# SPDX-FileCopyrightText: 2025 Samuel Abels <[email protected]>
|
||||
# SPDX-FileNotice: Part of the FreeCAD project.
|
||||
|
||||
# ***************************************************************************
|
||||
# * Copyright (c) 2025 Samuel Abels <[email protected]> *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
# * as published by the Free Software Foundation; either version 2 of *
|
||||
# * the License, or (at your option) any later version. *
|
||||
# * for detail see the LICENCE text file. *
|
||||
# * *
|
||||
# * This program is distributed in the hope that it will be useful, *
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
# * GNU Library General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Library General Public *
|
||||
# * License along with this program; if not, write to the Free Software *
|
||||
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
################################################################################
|
||||
# #
|
||||
# FreeCAD is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU Lesser General Public License as #
|
||||
# published by the Free Software Foundation, either version 2.1 #
|
||||
# of the License, or (at your option) any later version. #
|
||||
# #
|
||||
# FreeCAD is distributed in the hope that it will be useful, #
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty #
|
||||
# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. #
|
||||
# See the GNU Lesser General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the GNU Lesser General Public #
|
||||
# License along with FreeCAD. If not, see https://www.gnu.org/licenses #
|
||||
# #
|
||||
################################################################################
|
||||
|
||||
import pathlib
|
||||
import tempfile
|
||||
import FreeCAD
|
||||
import Path
|
||||
from PySide import QtGui, QtCore
|
||||
from ....Machine.ui.editor import MachineEditorDialog
|
||||
from ....Machine.models import MachineFactory
|
||||
from Machine.ui.editor import MachineEditorDialog
|
||||
from Machine.models.machine import MachineFactory
|
||||
|
||||
translate = FreeCAD.Qt.translate
|
||||
|
||||
|
||||
+20
-25
@@ -1,36 +1,31 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
# SPDX-FileCopyrightText: 2025 sliptonic <[email protected]>
|
||||
# SPDX-FileNotice: Part of the FreeCAD project.
|
||||
|
||||
################################################################################
|
||||
# #
|
||||
# FreeCAD is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU Lesser General Public License as #
|
||||
# published by the Free Software Foundation, either version 2.1 #
|
||||
# of the License, or (at your option) any later version. #
|
||||
# #
|
||||
# FreeCAD is distributed in the hope that it will be useful, #
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty #
|
||||
# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. #
|
||||
# See the GNU Lesser General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the GNU Lesser General Public #
|
||||
# License along with FreeCAD. If not, see https://www.gnu.org/licenses #
|
||||
# #
|
||||
################################################################################
|
||||
|
||||
# flake8: noqa import
|
||||
# ***************************************************************************
|
||||
# * Copyright (c) 2016 sliptonic <[email protected]> *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
# * as published by the Free Software Foundation; either version 2 of *
|
||||
# * the License, or (at your option) any later version. *
|
||||
# * for detail see the LICENCE text file. *
|
||||
# * *
|
||||
# * This program is distributed in the hope that it will be useful, *
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
# * GNU Library General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Library General Public *
|
||||
# * License along with this program; if not, write to the Free Software *
|
||||
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
|
||||
import TestApp
|
||||
|
||||
from CAMTests.TestCAMSanity import TestCAMSanity
|
||||
from CAMTests.TestLinkingGenerator import TestGetLinkingMoves
|
||||
from CAMTests.TestMachine import (
|
||||
TestMachineDataclass,
|
||||
TestMachineFactory,
|
||||
TestSpindle,
|
||||
)
|
||||
from CAMTests.TestMachine import TestMachineDataclass, TestMachineFactory, TestToolhead
|
||||
from CAMTests.TestPathProfile import TestPathProfile
|
||||
|
||||
from CAMTests.TestPathAdaptive import TestPathAdaptive
|
||||
|
||||
Reference in New Issue
Block a user