FreeCAD

Форк
0
/
TestPathGeneratorDogboneII.py 
347 строк · 14.0 Кб
1
# -*- coding: utf-8 -*-
2
# ***************************************************************************
3
# *   Copyright (c) 2022 sliptonic <shopinthewoods@gmail.com>               *
4
# *                                                                         *
5
# *   This program is free software; you can redistribute it and/or modify  *
6
# *   it under the terms of the GNU Lesser General Public License (LGPL)    *
7
# *   as published by the Free Software Foundation; either version 2 of     *
8
# *   the License, or (at your option) any later version.                   *
9
# *   for detail see the LICENCE text file.                                 *
10
# *                                                                         *
11
# *   This program is distributed in the hope that it will be useful,       *
12
# *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
13
# *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
14
# *   GNU Library General Public License for more details.                  *
15
# *                                                                         *
16
# *   You should have received a copy of the GNU Library General Public     *
17
# *   License along with this program; if not, write to the Free Software   *
18
# *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
19
# *   USA                                                                   *
20
# *                                                                         *
21
# ***************************************************************************
22

23
import FreeCAD
24
import Path
25
import Path.Base.Generator.dogboneII as dogboneII
26
import Path.Base.Language as PathLanguage
27
import Tests.PathTestUtils as PathTestUtils
28
import math
29

30

31
# Path.Log.setLevel(Path.Log.Level.DEBUG)
32
Path.Log.setLevel(Path.Log.Level.NOTICE)
33

34
PI = math.pi
35
DebugMode = Path.Log.getLevel(Path.Log.thisModule()) == Path.Log.Level.DEBUG
36

37

38
def createKinks(maneuver):
39
    k = []
40
    moves = maneuver.getMoves()
41
    if moves:
42
        move0 = moves[0]
43
        prev = move0
44
        for m in moves[1:]:
45
            k.append(dogboneII.Kink(prev, m))
46
            prev = m
47
        if Path.Geom.pointsCoincide(move0.positionBegin(), prev.positionEnd()):
48
            k.append(dogboneII.Kink(prev, move0))
49
    return k
50

51

52
def findDogboneKinks(maneuver, threshold):
53
    if threshold > 0:
54
        return [k for k in createKinks(maneuver) if k.deflection() > threshold]
55
    if threshold < 0:
56
        return [k for k in createKinks(maneuver) if k.deflection() < threshold]
57
    return createKinks(maneuver)
58

59

60
def MNVR(gcode, begin=None):
61
    # 'turns out the replace() isn't really necessary
62
    # leave it here anyway for clarity
63
    return PathLanguage.Maneuver.FromGCode(gcode.replace("/", "\n"), begin)
64

65

66
def INSTR(gcode, begin=None):
67
    return MNVR(gcode, begin).instr[0]
68

69

70
def KINK(gcode, begin=None):
71
    maneuver = MNVR(gcode, begin)
72
    if len(maneuver.instr) != 2:
73
        return None
74
    return dogboneII.Kink(maneuver.instr[0], maneuver.instr[1])
75

76

77
def GEN(generator, length):
78
    return generator(lambda k, a, n, c: n, length, 1)
79

80

81
class TestGeneratorDogboneII(PathTestUtils.PathTestBase):
82
    """Unit tests for the dogboneII generator."""
83

84
    def assertKinks(self, maneuver, s):
85
        kinks = [f"{k.deflection():4.2f}" for k in createKinks(maneuver)]
86
        self.assertEqual(f"[{', '.join(kinks)}]", s)
87

88
    def assertBones(self, maneuver, threshold, s):
89
        bones = [f"({int(b.x())},{int(b.y())})" for b in findDogboneKinks(maneuver, threshold)]
90
        self.assertEqual(f"[{', '.join(bones)}]", s)
91

92
    def assertBone(self, bone, s, digits=0):
93
        if DebugMode and FreeCAD.GuiUp:
94
            Path.show(dogboneII.kink_to_path(bone.kink))
95
            FreeCAD.ActiveDocument.Objects[-1].Visibility = False
96
            Path.show(dogboneII.bone_to_path(bone))
97
            FreeCAD.ActiveDocument.Objects[-1].Visibility = False
98
        Path.Log.debug(f"{bone.kink} : {bone.angle / PI:.2f}")
99

100
        b = [i.str(digits) for i in bone.instr]
101
        self.assertEqual(f"[{', '.join(b)}]", s)
102

103
    def test20(self):
104
        """Verify kinks of maneuvers"""
105
        self.assertKinks(MNVR("G1X1/G1Y1"), "[1.57]")
106
        self.assertKinks(MNVR("G1X1/G1Y-1"), "[-1.57]")
107
        self.assertKinks(MNVR("G1X1/G1Y1/G1X0"), "[1.57, 1.57]")
108
        self.assertKinks(MNVR("G1X1/G1Y1/G1X0/G1Y0"), "[1.57, 1.57, 1.57, 1.57]")
109

110
        self.assertKinks(MNVR("G1Y1/G1X1"), "[-1.57]")
111
        self.assertKinks(MNVR("G1Y1/G1X1/G1Y0"), "[-1.57, -1.57]")
112
        self.assertKinks(MNVR("G1Y1/G1X1/G1Y0/G1X0"), "[-1.57, -1.57, -1.57, -1.57]")
113

114
        # tangential arc moves
115
        self.assertKinks(MNVR("G1X1/G3Y2J1"), "[0.00]")
116
        self.assertKinks(MNVR("G1X1/G3Y2J1G1X0"), "[0.00, 0.00]")
117

118
        # folding back arc moves
119
        self.assertKinks(MNVR("G1X1/G2Y2J1"), "[-3.14]")
120
        self.assertKinks(MNVR("G1X1/G2Y2J1G1X0"), "[-3.14, 3.14]")
121

122
    def test30(self):
123
        """Verify dogbone detection"""
124
        self.assertBones(MNVR("G1X1/G1Y1/G1X0/G1Y0"), PI / 4, "[(1,0), (1,1), (0,1), (0,0)]")
125
        self.assertBones(MNVR("G1X1/G1Y1/G1X0/G1Y0"), -PI / 4, "[]")
126

127
        # no bones on flat angle
128
        self.assertBones(MNVR("G1X1/G1X3Y1/G1X0/G1Y0"), PI / 4, "[(3,1), (0,1), (0,0)]")
129
        self.assertBones(MNVR("G1X1/G1X3Y1/G1X0/G1Y0"), -PI / 4, "[]")
130

131
        # no bones on tangential arc
132
        self.assertBones(MNVR("G1X1/G3Y2J1/G1X0/G1Y0"), PI / 4, "[(0,2), (0,0)]")
133
        self.assertBones(MNVR("G1X1/G3Y2J1/G1X0/G1Y0"), -PI / 4, "[]")
134

135
        # a bone on perpendicular arc
136
        self.assertBones(MNVR("G1X1/G3X3I1/G1Y1/G1X0/G1Y0"), PI / 4, "[(3,1), (0,1), (0,0)]")
137
        self.assertBones(MNVR("G1X1/G3X3I1/G1Y1/G1X0/G1Y0"), -PI / 4, "[(1,0)]")
138

139
    def test40(self):
140
        """Verify horizontal t-bone creation"""
141
        # Uses test data from test30, if that broke, this can't succeed
142

143
        horizontal = GEN(dogboneII.GeneratorTBoneHorizontal, 1)
144

145
        # single move right
146
        maneuver = MNVR("G1X1/G1Y1")
147
        kinks = findDogboneKinks(maneuver, PI / 4)
148
        self.assertEqual(len(kinks), 1)
149
        k = kinks[0]
150
        p = k.position()
151
        self.assertEqual(f"({int(p.x)}, {int(p.y)})", "(1, 0)")
152
        bone = horizontal.generate(k)
153
        self.assertBone(bone, "[G1{X: 2}, G1{X: 1}]")
154

155
        # full loop CCW
156
        kinks = findDogboneKinks(MNVR("G1X1/G1Y1/G1X0/G1Y0"), PI / 4)
157
        bones = [horizontal.generate(k) for k in kinks]
158
        self.assertEqual(len(bones), 4)
159
        self.assertBone(bones[0], "[G1{X: 2}, G1{X: 1}]")
160
        self.assertBone(bones[1], "[G1{X: 2}, G1{X: 1}]")
161
        self.assertBone(bones[2], "[G1{X: -1}, G1{X: 0}]")
162
        self.assertBone(bones[3], "[G1{X: -1}, G1{X: 0}]")
163

164
        # single move left
165
        maneuver = MNVR("G1X1/G1Y-1")
166
        kinks = findDogboneKinks(maneuver, -PI / 4)
167
        self.assertEqual(len(kinks), 1)
168
        k = kinks[0]
169
        p = k.position()
170
        self.assertEqual(f"({int(p.x)}, {int(p.y)})", "(1, 0)")
171
        bone = horizontal.generate(k)
172
        self.assertBone(bone, "[G1{X: 2}, G1{X: 1}]")
173

174
        # full loop CW
175
        kinks = findDogboneKinks(MNVR("G1X1/G1Y-1/G1X0/G1Y0"), -PI / 4)
176
        bones = [horizontal.generate(k) for k in kinks]
177
        self.assertEqual(len(bones), 4)
178
        self.assertBone(bones[0], "[G1{X: 2}, G1{X: 1}]")
179
        self.assertBone(bones[1], "[G1{X: 2}, G1{X: 1}]")
180
        self.assertBone(bones[2], "[G1{X: -1}, G1{X: 0}]")
181
        self.assertBone(bones[3], "[G1{X: -1}, G1{X: 0}]")
182

183
        # bones on arcs
184
        kinks = findDogboneKinks(MNVR("G1X1/G3X3I1/G1Y1/G1X0/G1Y0"), PI / 4)
185
        bones = [horizontal.generate(k) for k in kinks]
186
        self.assertEqual(len(bones), 3)
187
        self.assertBone(bones[0], "[G1{X: 4}, G1{X: 3}]")
188
        self.assertBone(bones[1], "[G1{X: -1}, G1{X: 0}]")
189
        self.assertBone(bones[2], "[G1{X: -1}, G1{X: 0}]")
190

191
        # bones on arcs
192
        kinks = findDogboneKinks(MNVR("G1X1/G3X3I1/G1Y1/G1X0/G1Y0"), -PI / 4)
193
        bones = [horizontal.generate(k) for k in kinks]
194
        self.assertEqual(len(bones), 1)
195
        self.assertBone(bones[0], "[G1{X: 2}, G1{X: 1}]")
196

197
    def test50(self):
198
        """Verify vertical t-bone creation"""
199
        # Uses test data from test30, if that broke, this can't succeed
200

201
        vertical = GEN(dogboneII.GeneratorTBoneVertical, 1)
202

203
        # single move right
204
        maneuver = MNVR("G1X1/G1Y1")
205
        kinks = findDogboneKinks(maneuver, PI / 4)
206
        self.assertEqual(len(kinks), 1)
207
        k = kinks[0]
208
        p = k.position()
209
        self.assertEqual(f"({int(p.x)}, {int(p.y)})", "(1, 0)")
210
        bone = vertical.generate(k)
211
        self.assertBone(bone, "[G1{Y: -1}, G1{Y: 0}]")
212

213
        # full loop CCW
214
        kinks = findDogboneKinks(MNVR("G1X1/G1Y1/G1X0/G1Y0"), PI / 4)
215
        bones = [vertical.generate(k) for k in kinks]
216
        self.assertEqual(len(bones), 4)
217
        self.assertBone(bones[0], "[G1{Y: -1}, G1{Y: 0}]")
218
        self.assertBone(bones[1], "[G1{Y: 2}, G1{Y: 1}]")
219
        self.assertBone(bones[2], "[G1{Y: 2}, G1{Y: 1}]")
220
        self.assertBone(bones[3], "[G1{Y: -1}, G1{Y: 0}]")
221

222
        # single move left
223
        maneuver = MNVR("G1X1/G1Y-1")
224
        kinks = findDogboneKinks(maneuver, -PI / 4)
225
        self.assertEqual(len(kinks), 1)
226
        k = kinks[0]
227
        p = k.position()
228
        self.assertEqual(f"({int(p.x)}, {int(p.y)})", "(1, 0)")
229
        bone = vertical.generate(k)
230
        self.assertBone(bone, "[G1{Y: 1}, G1{Y: 0}]")
231

232
        # full loop CW
233
        kinks = findDogboneKinks(MNVR("G1X1/G1Y-1/G1X0/G1Y0"), -PI / 4)
234
        bones = [vertical.generate(k) for k in kinks]
235
        self.assertEqual(len(bones), 4)
236
        self.assertBone(bones[0], "[G1{Y: 1}, G1{Y: 0}]")
237
        self.assertBone(bones[1], "[G1{Y: -2}, G1{Y: -1}]")
238
        self.assertBone(bones[2], "[G1{Y: -2}, G1{Y: -1}]")
239
        self.assertBone(bones[3], "[G1{Y: 1}, G1{Y: 0}]")
240

241
        # bones on arcs
242
        kinks = findDogboneKinks(MNVR("G1X1/G3X3I1/G1Y1/G1X0/G1Y0"), PI / 4)
243
        bones = [vertical.generate(k) for k in kinks]
244
        self.assertEqual(len(bones), 3)
245
        self.assertBone(bones[0], "[G1{Y: 2}, G1{Y: 1}]")
246
        self.assertBone(bones[1], "[G1{Y: 2}, G1{Y: 1}]")
247
        self.assertBone(bones[2], "[G1{Y: -1}, G1{Y: 0}]")
248

249
        # bones on arcs
250
        kinks = findDogboneKinks(MNVR("G1X1/G3X3I1/G1Y1/G1X0/G1Y0"), -PI / 4)
251
        bones = [vertical.generate(k) for k in kinks]
252
        self.assertEqual(len(bones), 1)
253
        self.assertBone(bones[0], "[G1{Y: 1}, G1{Y: 0}]")
254

255
    def test60(self):
256
        """Verify t-bones on edges"""
257

258
        on_short_1 = GEN(dogboneII.GeneratorTBoneOnShort, 1)
259
        on_short_5 = GEN(dogboneII.GeneratorTBoneOnShort, 5)
260

261
        # horizontal short edge
262
        bone = on_short_1.generate(KINK("G1X1/G1Y2"))
263
        self.assertBone(bone, "[G1{Y: -1}, G1{Y: 0}]")
264

265
        bone = on_short_1.generate(KINK("G1X-1/G1Y2"))
266
        self.assertBone(bone, "[G1{Y: -1}, G1{Y: 0}]")
267

268
        # vertical short edge
269
        bone = on_short_1.generate(KINK("G1Y1/G1X2"))
270
        self.assertBone(bone, "[G1{X: -1}, G1{X: 0}]")
271

272
        bone = on_short_1.generate(KINK("G1Y1/G1X-2"))
273
        self.assertBone(bone, "[G1{X: 1}, G1{X: 0}]")
274

275
        # some other angle
276
        bone = on_short_5.generate(KINK("G1X1Y1/G1Y-1"))
277
        self.assertBone(bone, "[G1{X: -2.5, Y: 4.5}, G1{X: 1.0, Y: 1.0}]", 2)
278

279
        bone = on_short_5.generate(KINK("G1X-1Y-1/G1Y1"))
280
        self.assertBone(bone, "[G1{X: 2.5, Y: -4.5}, G1{X: -1.0, Y: -1.0}]", 2)
281

282
        # some other angle
283
        bone = on_short_5.generate(KINK("G1X2Y1/G1Y-3"))
284
        self.assertBone(bone, "[G1{X: -0.24, Y: 5.5}, G1{X: 2.0, Y: 1.0}]", 2)
285

286
        bone = on_short_5.generate(KINK("G1X-2Y-1/G1Y3"))
287
        self.assertBone(bone, "[G1{X: 0.24, Y: -5.5}, G1{X: -2.0, Y: -1.0}]", 2)
288

289
        # short edge - the 2nd
290
        bone = on_short_1.generate(KINK("G1Y2/G1X1"))
291
        self.assertBone(bone, "[G1{Y: 3}, G1{Y: 2}]")
292
        bone = on_short_1.generate(KINK("G1Y2/G1X-1"))
293
        self.assertBone(bone, "[G1{Y: 3}, G1{Y: 2}]")
294

295
        bone = on_short_5.generate(KINK("G1Y-3/G1X2Y-2"))
296
        self.assertBone(bone, "[G1{X: 2.2, Y: -7.5}, G1{X: 0.0, Y: -3.0}]", 2)
297

298
        bone = on_short_5.generate(KINK("G1Y3/G1X-2Y2"))
299
        self.assertBone(bone, "[G1{X: -2.2, Y: 7.5}, G1{X: 0.0, Y: 3.0}]", 2)
300

301
        # long edge
302
        on_long_1 = GEN(dogboneII.GeneratorTBoneOnLong, 1)
303
        on_long_5 = GEN(dogboneII.GeneratorTBoneOnLong, 5)
304

305
        bone = on_long_1.generate(
306
            KINK("G1X2/G1Y1"),
307
        )
308
        self.assertBone(bone, "[G1{Y: -1}, G1{Y: 0}]")
309
        bone = on_long_1.generate(KINK("G1X-2/G1Y1"))
310
        self.assertBone(bone, "[G1{Y: -1}, G1{Y: 0}]")
311

312
        bone = on_long_5.generate(KINK("G1Y-1/G1X2Y0"))
313
        self.assertBone(bone, "[G1{X: 2.2, Y: -5.5}, G1{X: 0.0, Y: -1.0}]", 2)
314

315
        bone = on_long_5.generate(KINK("G1Y1/G1X-2Y0"))
316
        self.assertBone(bone, "[G1{X: -2.2, Y: 5.5}, G1{X: 0.0, Y: 1.0}]", 2)
317

318
    def test70(self):
319
        """Verify dogbone angles"""
320
        self.assertRoughly(180 * KINK("G1X1/G1Y+1").normAngle() / PI, -45)
321
        self.assertRoughly(180 * KINK("G1X1/G1Y-1").normAngle() / PI, 45)
322

323
        self.assertRoughly(180 * KINK("G1X1/G1X2Y1").normAngle() / PI, -67.5)
324
        self.assertRoughly(180 * KINK("G1X1/G1X2Y-1").normAngle() / PI, 67.5)
325

326
        self.assertRoughly(180 * KINK("G1Y1/G1X+1").normAngle() / PI, 135)
327
        self.assertRoughly(180 * KINK("G1Y1/G1X-1").normAngle() / PI, 45)
328

329
        self.assertRoughly(180 * KINK("G1X-1/G1Y+1").normAngle() / PI, -135)
330
        self.assertRoughly(180 * KINK("G1X-1/G1Y-1").normAngle() / PI, 135)
331

332
        self.assertRoughly(180 * KINK("G1Y-1/G1X-1").normAngle() / PI, -45)
333
        self.assertRoughly(180 * KINK("G1Y-1/G1X+1").normAngle() / PI, -135)
334

335
    def test71(self):
336
        """Verify dogbones"""
337

338
        dogbone = GEN(dogboneII.GeneratorDogbone, 1)
339

340
        bone = dogbone.generate(KINK("G1X1/G1Y1"))
341
        self.assertBone(bone, "[G1{X: 1.7, Y: -0.71}, G1{X: 1.0, Y: 0.0}]", 2)
342

343
        bone = dogbone.generate(KINK("G1X1/G1X3Y-1"))
344
        self.assertBone(bone, "[G1{X: 1.2, Y: 0.97}, G1{X: 1.0, Y: 0.0}]", 2)
345

346
        bone = dogbone.generate(KINK("G1X1Y1/G1X2"))
347
        self.assertBone(bone, "[G1{X: 0.62, Y: 1.9}, G1{X: 1.0, Y: 1.0}]", 2)
348

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.