FreeCAD
223 строки · 9.3 Кб
1# SPDX-License-Identifier: LGPL-2.1-or-later
2# /****************************************************************************
3# *
4# Copyright (c) 2023 Ondsel <development@ondsel.com> *
5# *
6# This file is part of FreeCAD. *
7# *
8# FreeCAD is free software: you can redistribute it and/or modify it *
9# under the terms of the GNU Lesser General Public License as *
10# published by the Free Software Foundation, either version 2.1 of the *
11# License, or (at your option) any later version. *
12# *
13# FreeCAD is distributed in the hope that it will be useful, but *
14# WITHOUT ANY WARRANTY; without even the implied warranty of *
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
16# Lesser General Public License for more details. *
17# *
18# You should have received a copy of the GNU Lesser General Public *
19# License along with FreeCAD. If not, see *
20# <https://www.gnu.org/licenses/>. *
21# *
22# ***************************************************************************/
23
24import FreeCAD as App25import Part26import unittest27
28import UtilsAssembly29import JointObject30
31
32def _msg(text, end="\n"):33"""Write messages to the console including the line ending."""34App.Console.PrintMessage(text + end)35
36
37class TestCore(unittest.TestCase):38@classmethod39def setUpClass(cls):40"""setUpClass()...41This method is called upon instantiation of this test class. Add code and objects here
42that are needed for the duration of the test() methods in this class. In other words,
43set up the 'global' test environment here; use the `setUp()` method to set up a 'local'
44test environment.
45This method does not have access to the class `self` reference, but it
46is able to call static methods within this same class.
47"""
48pass49
50@classmethod51def tearDownClass(cls):52"""tearDownClass()...53This method is called prior to destruction of this test class. Add code and objects here
54that cleanup the test environment after the test() methods in this class have been executed.
55This method does not have access to the class `self` reference. This method
56is able to call static methods within this same class.
57"""
58pass59
60# Setup and tear down methods called before and after each unit test61def setUp(self):62"""setUp()...63This method is called prior to each `test()` method. Add code and objects here
64that are needed for multiple `test()` methods.
65"""
66doc_name = self.__class__.__name__67if App.ActiveDocument:68if App.ActiveDocument.Name != doc_name:69App.newDocument(doc_name)70else:71App.newDocument(doc_name)72App.setActiveDocument(doc_name)73self.doc = App.ActiveDocument74
75self.assembly = App.ActiveDocument.addObject("Assembly::AssemblyObject", "Assembly")76if self.assembly:77self.jointgroup = self.assembly.newObject("Assembly::JointGroup", "Joints")78
79_msg(" Temporary document '{}'".format(self.doc.Name))80
81def tearDown(self):82"""tearDown()...83This method is called after each test() method. Add cleanup instructions here.
84Such cleanup instructions will likely undo those in the setUp() method.
85"""
86App.closeDocument(self.doc.Name)87
88def test_create_assembly(self):89"""Create an assembly."""90operation = "Create Assembly Object"91_msg(" Test '{}'".format(operation))92self.assertTrue(self.assembly, "'{}' failed".format(operation))93
94def test_create_jointGroup(self):95"""Create a joint group in an assembly."""96operation = "Create JointGroup Object"97_msg(" Test '{}'".format(operation))98self.assertTrue(self.jointgroup, "'{}' failed".format(operation))99
100def test_create_joint(self):101"""Create a joint in an assembly."""102operation = "Create Joint Object"103_msg(" Test '{}'".format(operation))104
105joint = self.jointgroup.newObject("App::FeaturePython", "testJoint")106self.assertTrue(joint, "'{}' failed (FeaturePython creation failed)".format(operation))107JointObject.Joint(joint, 0)108
109self.assertTrue(hasattr(joint, "JointType"), "'{}' failed".format(operation))110
111def test_create_grounded_joint(self):112"""Create a grounded joint in an assembly."""113operation = "Create Grounded Joint Object"114_msg(" Test '{}'".format(operation))115
116groundedjoint = self.jointgroup.newObject("App::FeaturePython", "testJoint")117self.assertTrue(118groundedjoint, "'{}' failed (FeaturePython creation failed)".format(operation)119)120
121box = self.assembly.newObject("Part::Box", "Box")122
123JointObject.GroundedJoint(groundedjoint, box)124
125self.assertTrue(126hasattr(groundedjoint, "ObjectToGround"),127"'{}' failed: No attribute 'ObjectToGround'".format(operation),128)129self.assertTrue(130groundedjoint.ObjectToGround == box,131"'{}' failed: ObjectToGround not set correctly.".format(operation),132)133
134def test_find_placement(self):135"""Test find placement of joint."""136operation = "Find placement"137_msg(" Test '{}'".format(operation))138
139joint = self.jointgroup.newObject("App::FeaturePython", "testJoint")140JointObject.Joint(joint, 0)141
142L = 2143W = 3144H = 7145box = self.assembly.newObject("Part::Box", "Box")146box.Length = L147box.Width = W148box.Height = H149box.Placement = App.Placement(App.Vector(10, 20, 30), App.Rotation(15, 25, 35))150
151# Step 0 : box with placement. No element selected152plc = joint.Proxy.findPlacement(joint, box.Name, box, "", "")153targetPlc = App.Placement(App.Vector(), App.Rotation())154self.assertTrue(plc.isSame(targetPlc, 1e-6), "'{}' failed - Step 0".format(operation))155
156# Step 1 : box with placement. Face + Vertex157plc = joint.Proxy.findPlacement(joint, box.Name, box, "Face6", "Vertex7")158targetPlc = App.Placement(App.Vector(L, W, H), App.Rotation())159self.assertTrue(plc.isSame(targetPlc, 1e-6), "'{}' failed - Step 1".format(operation))160
161# Step 2 : box with placement. Edge + Vertex162plc = joint.Proxy.findPlacement(joint, box.Name, box, "Edge8", "Vertex8")163targetPlc = App.Placement(App.Vector(L, W, 0), App.Rotation(0, 0, -90))164self.assertTrue(plc.isSame(targetPlc, 1e-6), "'{}' failed - Step 2".format(operation))165
166# Step 3 : box with placement. Vertex167plc = joint.Proxy.findPlacement(joint, box.Name, box, "Vertex3", "Vertex3")168targetPlc = App.Placement(App.Vector(0, W, H), App.Rotation())169_msg(" plc '{}'".format(plc))170_msg(" targetPlc '{}'".format(targetPlc))171self.assertTrue(plc.isSame(targetPlc, 1e-6), "'{}' failed - Step 3".format(operation))172
173# Step 4 : box with placement. Face174plc = joint.Proxy.findPlacement(joint, box.Name, box, "Face2", "Face2")175targetPlc = App.Placement(App.Vector(L, W / 2, H / 2), App.Rotation(0, -90, 180))176_msg(" plc '{}'".format(plc))177_msg(" targetPlc '{}'".format(targetPlc))178self.assertTrue(plc.isSame(targetPlc, 1e-6), "'{}' failed - Step 4".format(operation))179
180def test_solve_assembly(self):181"""Test solving an assembly."""182operation = "Solve assembly"183_msg(" Test '{}'".format(operation))184
185box = self.assembly.newObject("Part::Box", "Box")186box.Length = 10187box.Width = 10188box.Height = 10189box.Placement = App.Placement(App.Vector(10, 20, 30), App.Rotation(15, 25, 35))190
191box2 = self.assembly.newObject("Part::Box", "Box")192box2.Length = 10193box2.Width = 10194box2.Height = 10195box2.Placement = App.Placement(App.Vector(40, 50, 60), App.Rotation(45, 55, 65))196
197ground = self.jointgroup.newObject("App::FeaturePython", "GroundedJoint")198JointObject.GroundedJoint(ground, box2)199
200joint = self.jointgroup.newObject("App::FeaturePython", "testJoint")201JointObject.Joint(joint, 0)202
203current_selection = []204current_selection.append(205{206"object": box2,207"part": box2,208"element_name": "Face6",209"vertex_name": "Vertex7",210}211)212current_selection.append(213{214"object": box,215"part": box,216"element_name": "Face6",217"vertex_name": "Vertex7",218}219)220
221joint.Proxy.setJointConnectors(joint, current_selection)222
223self.assertTrue(box.Placement.isSame(box2.Placement, 1e-6), "'{}'".format(operation))224