175 lines
5.9 KiB
Python
175 lines
5.9 KiB
Python
import numpy as np
|
|
import unittest
|
|
from unittest.mock import MagicMock
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
# Add workspace directory to sys.path to resolve root package name (NodeSlicer)
|
|
PROJECT_ROOT = Path(__file__).resolve().parent.parent
|
|
sys.path.append(str(PROJECT_ROOT.parent))
|
|
|
|
# Define dummy classes to avoid metaclass conflicts
|
|
class DummyNodeSocket: pass
|
|
class DummyNode: pass
|
|
class DummyObject: pass
|
|
class DummyMesh: pass
|
|
class DummyNodeSocketShader: pass
|
|
class DummyNodeCustomGroup: pass
|
|
class DummyNodeTree: pass
|
|
class DummyOperator: pass
|
|
class DummyMenu: pass
|
|
class DummyPanel: pass
|
|
class DummyPropertyGroup: pass
|
|
|
|
mock_types = MagicMock()
|
|
mock_types.NodeSocket = DummyNodeSocket
|
|
mock_types.Node = DummyNode
|
|
mock_types.Object = DummyObject
|
|
mock_types.Mesh = DummyMesh
|
|
mock_types.NodeSocketShader = DummyNodeSocketShader
|
|
mock_types.NodeCustomGroup = DummyNodeCustomGroup
|
|
mock_types.NodeTree = DummyNodeTree
|
|
mock_types.Operator = DummyOperator
|
|
mock_types.Menu = DummyMenu
|
|
mock_types.Panel = DummyPanel
|
|
mock_types.PropertyGroup = DummyPropertyGroup
|
|
|
|
# Mock bpy and its subpackages before importing core modules
|
|
mock_bpy = MagicMock()
|
|
mock_bpy.context.scene = MagicMock()
|
|
mock_bpy.context.scene.unit_settings.scale_length = 0.001
|
|
mock_bpy.types = mock_types
|
|
|
|
sys.modules['bpy'] = mock_bpy
|
|
sys.modules['bpy.types'] = mock_types
|
|
sys.modules['bpy.props'] = MagicMock()
|
|
sys.modules['bpy.utils'] = MagicMock()
|
|
sys.modules['bpy.utils.previews'] = MagicMock()
|
|
sys.modules['bpy.app'] = MagicMock()
|
|
sys.modules['bpy.app.handlers'] = MagicMock()
|
|
|
|
# Import the actual classes to test
|
|
from NodeSlicer.core.nodeslicer.nodes.mesh import SLICENODE_ArrangeMesh
|
|
from NodeSlicer.infra.blender.blender_mesh_capture import SlicingGroup, SlicingCollection, SlicingObject
|
|
|
|
class TestArrangeMesh(unittest.TestCase):
|
|
def test_arrange_mesh_simple(self):
|
|
# Create a SlicingObject with a single triangle
|
|
so = SlicingObject()
|
|
so.name = "part1"
|
|
so.mesh = np.array([[[10.0, 10.0, 0.0],
|
|
[20.0, 10.0, 0.0],
|
|
[15.0, 20.0, 0.0],
|
|
[0.0, 0.0, 1.0]]], dtype=np.float64)
|
|
|
|
# Create SlicingCollection
|
|
sc = SlicingCollection([], "coll1")
|
|
sc.objects = [so]
|
|
|
|
# Create SlicingGroup
|
|
sg = SlicingGroup([])
|
|
sg.collections = {"coll1": sc}
|
|
|
|
# Mock node inputs resolution
|
|
node = SLICENODE_ArrangeMesh()
|
|
node.method = 'NFP'
|
|
|
|
# We override resolve to simulate inputs
|
|
def mock_resolve(fieldname):
|
|
if fieldname == "Slicing Group":
|
|
return sg
|
|
elif fieldname == "Bed X":
|
|
return 250.0
|
|
elif fieldname == "Bed Y":
|
|
return 250.0
|
|
elif fieldname == "Spacing":
|
|
return 2.0
|
|
return None
|
|
|
|
node.resolve = mock_resolve
|
|
|
|
# Evaluate output
|
|
result_group = node.evaluate_output("Slicing Group")
|
|
self.assertIsNotNone(result_group)
|
|
self.assertIn("coll1", result_group.collections)
|
|
|
|
arranged_sc = result_group.collections["coll1"]
|
|
# The bounding box should now be centered on the 250x250 bed
|
|
self.assertEqual(arranged_sc.min_x, 120.0)
|
|
self.assertEqual(arranged_sc.min_y, 120.0)
|
|
self.assertEqual(arranged_sc.max_x, 130.0)
|
|
self.assertEqual(arranged_sc.max_y, 130.0)
|
|
|
|
# Check normal remains unchanged
|
|
self.assertTrue(np.allclose(arranged_sc.objects[0].mesh[0, 3, :], [0.0, 0.0, 1.0]))
|
|
|
|
def test_arrange_mesh_bl(self):
|
|
so = SlicingObject()
|
|
so.name = "part1"
|
|
so.mesh = np.array([[[10.0, 10.0, 0.0],
|
|
[20.0, 10.0, 0.0],
|
|
[15.0, 20.0, 0.0],
|
|
[0.0, 0.0, 1.0]]], dtype=np.float64)
|
|
|
|
sc = SlicingCollection([], "coll1")
|
|
sc.objects = [so]
|
|
sg = SlicingGroup([])
|
|
sg.collections = {"coll1": sc}
|
|
|
|
node = SLICENODE_ArrangeMesh()
|
|
node.method = 'BL'
|
|
|
|
def mock_resolve(fieldname):
|
|
if fieldname == "Slicing Group":
|
|
return sg
|
|
elif fieldname == "Bed X":
|
|
return 250.0
|
|
elif fieldname == "Bed Y":
|
|
return 250.0
|
|
elif fieldname == "Spacing":
|
|
return 2.0
|
|
return None
|
|
node.resolve = mock_resolve
|
|
|
|
result_group = node.evaluate_output("Slicing Group")
|
|
self.assertIsNotNone(result_group)
|
|
arranged_sc = result_group.collections["coll1"]
|
|
self.assertGreaterEqual(arranged_sc.min_x, 0.0)
|
|
self.assertGreaterEqual(arranged_sc.min_y, 0.0)
|
|
|
|
def test_arrange_mesh_djd(self):
|
|
so = SlicingObject()
|
|
so.name = "part1"
|
|
so.mesh = np.array([[[10.0, 10.0, 0.0],
|
|
[20.0, 10.0, 0.0],
|
|
[15.0, 20.0, 0.0],
|
|
[0.0, 0.0, 1.0]]], dtype=np.float64)
|
|
|
|
sc = SlicingCollection([], "coll1")
|
|
sc.objects = [so]
|
|
sg = SlicingGroup([])
|
|
sg.collections = {"coll1": sc}
|
|
|
|
node = SLICENODE_ArrangeMesh()
|
|
node.method = 'DJD'
|
|
|
|
def mock_resolve(fieldname):
|
|
if fieldname == "Slicing Group":
|
|
return sg
|
|
elif fieldname == "Bed X":
|
|
return 250.0
|
|
elif fieldname == "Bed Y":
|
|
return 250.0
|
|
elif fieldname == "Spacing":
|
|
return 2.0
|
|
return None
|
|
node.resolve = mock_resolve
|
|
|
|
result_group = node.evaluate_output("Slicing Group")
|
|
self.assertIsNotNone(result_group)
|
|
arranged_sc = result_group.collections["coll1"]
|
|
self.assertEqual(arranged_sc.min_x, 120.0)
|
|
self.assertEqual(arranged_sc.min_y, 120.0)
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|