Solvespace
1251 строка · 48.6 Кб
1'-----------------------------------------------------------------------------
2' Some sample code for slvs.dll. We draw some geometric entities, provide
3' initial guesses for their positions, and then constrain them. The solver
4' calculates their new positions, in order to satisfy the constraints.
5'
6' The library is distributed as a DLL, but the functions are designed to
7' be usable from .net languages through a P/Invoke. This file contains an
8' example of that process, and a wrapper class around those P/Invoke'd
9' functions that you may wish to use a starting point in your own
10' application.
11'
12' Copyright 2008-2013 Jonathan Westhues.
13'-----------------------------------------------------------------------------
14
15Imports System.Runtime.InteropServices
16
17Module VbDemo
18
19' Call our example functions, which set up some kind of sketch, solve
20' it, and then print the result.
21Sub Main()
22Console.WriteLine("EXAMPLE IN 3d (by objects):")
23Example3dWithObjects()
24Console.WriteLine("")
25
26Console.WriteLine("EXAMPLE IN 2d (by objects):")
27Example2dWithObjects()
28Console.WriteLine("")
29
30Console.WriteLine("EXAMPLE IN 3d (by handles):")
31Example3dWithHandles()
32Console.WriteLine("")
33
34Console.WriteLine("EXAMPLE IN 2d (by handles):")
35Example2dWithHandles()
36Console.WriteLine("")
37End Sub
38
39
40'''''''''''''''''''''''''''''''
41' This is the simplest way to use the library. A set of wrapper
42' classes allow us to represent entities (e.g., lines and points)
43' as .net objects. So we create an Slvs object, which will contain
44' the entire sketch, with all the entities and constraints.
45'
46' We then create entity objects (for example, points and lines)
47' associated with that sketch, indicating the initial positions of
48' those entities and any hierarchical relationships among them (e.g.,
49' defining a line entity in terms of endpoint entities). We also add
50' constraints associated with those entities.
51'
52' Finally, we solve, and print the new positions of the entities. If the
53' solution succeeded, then the entities will satisfy the constraints. If
54' not, then the solver will suggest problematic constraints that, if
55' removed, would render the sketch solvable.
56
57Sub Example3dWithObjects()
58Dim g As UInteger
59Dim slv As New Slvs
60
61' This will contain a single group, which will arbitrarily number 1.
62g = 1
63
64Dim p1, p2 As Slvs.Point3d
65' A point, initially at (x y z) = (10 10 10)
66p1 = slv.NewPoint3d(g, 10.0, 10.0, 10.0)
67' and a second point at (20 20 20)
68p2 = slv.NewPoint3d(g, 20.0, 20.0, 20.0)
69
70Dim ln As Slvs.LineSegment
71' and a line segment connecting them.
72ln = slv.NewLineSegment(g, slv.FreeIn3d(), p1, p2)
73
74' The distance between the points should be 30.0 units.
75slv.AddConstraint(1, g, Slvs.SLVS_C_PT_PT_DISTANCE, _
76slv.FreeIn3d(), 30.0, p1, p2, Nothing, Nothing)
77
78' Let's tell the solver to keep the second point as close to constant
79' as possible, instead moving the first point.
80slv.Solve(g, p2, True)
81
82If (slv.GetResult() = Slvs.SLVS_RESULT_OKAY) Then
83' We call the GetX(), GetY(), and GetZ() functions to see
84' where the solver moved our points to.
85Console.WriteLine(String.Format( _
86"okay; now at ({0:F3}, {1:F3}, {2:F3})", _
87p1.GetX(), p1.GetY(), p1.GetZ()))
88Console.WriteLine(String.Format( _
89" ({0:F3}, {1:F3}, {2:F3})", _
90p2.GetX(), p2.GetY(), p2.GetZ()))
91Console.WriteLine(slv.GetDof().ToString() + " DOF")
92Else
93Console.WriteLine("solve failed")
94End If
95End Sub
96
97Sub Example2dWithObjects()
98Dim g As UInteger
99Dim slv As New Slvs
100
101g = 1
102
103' First, we create our workplane. Its origin corresponds to the origin
104' of our base frame (x y z) = (0 0 0)
105Dim origin As Slvs.Point3d
106origin = slv.NewPoint3d(g, 0.0, 0.0, 0.0)
107' and it is parallel to the xy plane, so it has basis vectors (1 0 0)
108' and (0 1 0).
109Dim normal As Slvs.Normal3d
110normal = slv.NewNormal3d(g, 1.0, 0.0, 0.0, _
1110.0, 1.0, 0.0)
112
113Dim wrkpl As Slvs.Workplane
114wrkpl = slv.NewWorkplane(g, origin, normal)
115
116' Now create a second group. We'll solve group 2, while leaving group 1
117' constant; so the workplane that we've created will be locked down,
118' and the solver can't move it.
119g = 2
120' These points are represented by their coordinates (u v) within the
121' workplane, so they need only two parameters each.
122Dim pl1, pl2 As Slvs.Point2d
123pl1 = slv.NewPoint2d(g, wrkpl, 10.0, 20.0)
124pl2 = slv.NewPoint2d(g, wrkpl, 20.0, 10.0)
125
126' And we create a line segment with those endpoints.
127Dim ln As Slvs.LineSegment
128ln = slv.NewLineSegment(g, wrkpl, pl1, pl2)
129
130' Now three more points.
131Dim pc, ps, pf As Slvs.Point2d
132pc = slv.NewPoint2d(g, wrkpl, 100.0, 120.0)
133ps = slv.NewPoint2d(g, wrkpl, 120.0, 110.0)
134pf = slv.NewPoint2d(g, wrkpl, 115.0, 115.0)
135
136' And arc, centered at point pc, starting at point ps, ending at
137' point pf.
138Dim arc As Slvs.ArcOfCircle
139arc = slv.NewArcOfCircle(g, wrkpl, normal, pc, ps, pf)
140
141' Now one more point, and a distance
142Dim pcc As Slvs.Point2d
143pcc = slv.NewPoint2d(g, wrkpl, 200.0, 200.0)
144Dim r As Slvs.Distance
145r = slv.NewDistance(g, wrkpl, 30.0)
146
147' And a complete circle, centered at point pcc with radius equal to
148' distance r. The normal is the same as for our workplane.
149Dim circle As Slvs.Circle
150circle = slv.NewCircle(g, wrkpl, pcc, normal, r)
151
152' The length of our line segment is 30.0 units.
153slv.AddConstraint(1, g, Slvs.SLVS_C_PT_PT_DISTANCE, _
154wrkpl, 30.0, pl1, pl2, Nothing, Nothing)
155
156' And the distance from our line segment to the origin is 10.0 units.
157slv.AddConstraint(2, g, Slvs.SLVS_C_PT_LINE_DISTANCE, _
158wrkpl, 10.0, origin, Nothing, ln, Nothing)
159
160' And the line segment is vertical.
161slv.AddConstraint(3, g, Slvs.SLVS_C_VERTICAL, _
162wrkpl, 0.0, Nothing, Nothing, ln, Nothing)
163
164' And the distance from one endpoint to the origin is 15.0 units.
165slv.AddConstraint(4, g, Slvs.SLVS_C_PT_PT_DISTANCE, _
166wrkpl, 15.0, pl1, origin, Nothing, Nothing)
167
168' And same for the other endpoint; so if you add this constraint then
169' the sketch is overconstrained and will signal an error.
170'slv.AddConstraint(5, g, Slvs.SLVS_C_PT_PT_DISTANCE, _
171' wrkpl, 18.0, pl2, origin, Nothing, Nothing)
172
173' The arc and the circle have equal radius.
174slv.AddConstraint(6, g, Slvs.SLVS_C_EQUAL_RADIUS, _
175wrkpl, 0.0, Nothing, Nothing, arc, circle)
176
177' The arc has radius 17.0 units.
178slv.AddConstraint(7, g, Slvs.SLVS_C_DIAMETER, _
179wrkpl, 2 * 17.0, Nothing, Nothing, arc, Nothing)
180
181' If the solver fails, then ask it to report which constraints caused
182' the problem.
183slv.Solve(g, True)
184
185If (slv.GetResult() = Slvs.SLVS_RESULT_OKAY) Then
186Console.WriteLine("solved okay")
187' We call the GetU(), GetV(), and GetDistance() functions to
188' see where the solver moved our points and distances to.
189Console.WriteLine(String.Format( _
190"line from ({0:F3} {1:F3}) to ({2:F3} {3:F3})", _
191pl1.GetU(), pl1.GetV(), _
192pl2.GetU(), pl2.GetV()))
193Console.WriteLine(String.Format( _
194"arc center ({0:F3} {1:F3}) start ({2:F3} {3:F3}) " + _
195"finish ({4:F3} {5:F3})", _
196pc.GetU(), pc.GetV(), _
197ps.GetU(), ps.GetV(), _
198pf.GetU(), pf.GetV()))
199Console.WriteLine(String.Format( _
200"circle center ({0:F3} {1:F3}) radius {2:F3}", _
201pcc.GetU(), pcc.GetV(), _
202r.GetDistance()))
203
204Console.WriteLine(slv.GetDof().ToString() + " DOF")
205Else
206Console.Write("solve failed; problematic constraints are:")
207Dim t As UInteger
208For Each t In slv.GetFaileds()
209Console.Write(" " + t.ToString())
210Next
211Console.WriteLine("")
212If (slv.GetResult() = Slvs.SLVS_RESULT_INCONSISTENT) Then
213Console.WriteLine("system inconsistent")
214Else
215Console.WriteLine("system nonconvergent")
216End If
217End If
218
219End Sub
220
221
222'''''''''''''''''''''''''''''''
223' This is a lower-level way to use the library. Internally, the library
224' represents parameters, entities, and constraints by integer handles.
225' Here, those handles are assigned manually, and not by the wrapper
226' classes.
227
228Sub Example3dWithHandles()
229Dim g As UInteger
230Dim slv As New Slvs
231
232' This will contain a single group, which will arbitrarily number 1.
233g = 1
234
235' A point, initially at (x y z) = (10 10 10)
236slv.AddParam(1, g, 10.0)
237slv.AddParam(2, g, 10.0)
238slv.AddParam(3, g, 10.0)
239slv.AddPoint3d(101, g, 1, 2, 3)
240
241' and a second point at (20 20 20)
242slv.AddParam(4, g, 20.0)
243slv.AddParam(5, g, 20.0)
244slv.AddParam(6, g, 20.0)
245slv.AddPoint3d(102, g, 4, 5, 6)
246
247' and a line segment connecting them.
248slv.AddLineSegment(200, g, Slvs.SLVS_FREE_IN_3D, 101, 102)
249
250' The distance between the points should be 30.0 units.
251slv.AddConstraint(1, g, Slvs.SLVS_C_PT_PT_DISTANCE, _
252Slvs.SLVS_FREE_IN_3D, 30.0, 101, 102, 0, 0)
253
254' Let's tell the solver to keep the second point as close to constant
255' as possible, instead moving the first point. That's parameters
256' 4, 5, and 6.
257slv.Solve(g, 4, 5, 6, 0, True)
258
259If (slv.GetResult() = Slvs.SLVS_RESULT_OKAY) Then
260' Note that we are referring to the parameters by their handles,
261' and not by their index in the list. This is a difference from
262' the C example.
263Console.WriteLine(String.Format( _
264"okay; now at ({0:F3}, {1:F3}, {2:F3})", _
265slv.GetParamByHandle(1), slv.GetParamByHandle(2), _
266slv.GetParamByHandle(3)))
267Console.WriteLine(String.Format( _
268" ({0:F3}, {1:F3}, {2:F3})", _
269slv.GetParamByHandle(4), slv.GetParamByHandle(5), _
270slv.GetParamByHandle(6)))
271Console.WriteLine(slv.GetDof().ToString() + " DOF")
272Else
273Console.WriteLine("solve failed")
274End If
275End Sub
276
277
278Sub Example2dWithHandles()
279Dim g As UInteger
280Dim qw, qx, qy, qz As Double
281
282Dim slv As New Slvs
283
284g = 1
285
286' First, we create our workplane. Its origin corresponds to the origin
287' of our base frame (x y z) = (0 0 0)
288slv.AddParam(1, g, 0.0)
289slv.AddParam(2, g, 0.0)
290slv.AddParam(3, g, 0.0)
291slv.AddPoint3d(101, g, 1, 2, 3)
292' and it is parallel to the xy plane, so it has basis vectors (1 0 0)
293' and (0 1 0).
294slv.MakeQuaternion(1, 0, 0, _
2950, 1, 0, qw, qx, qy, qz)
296slv.AddParam(4, g, qw)
297slv.AddParam(5, g, qx)
298slv.AddParam(6, g, qy)
299slv.AddParam(7, g, qz)
300slv.AddNormal3d(102, g, 4, 5, 6, 7)
301
302slv.AddWorkplane(200, g, 101, 102)
303
304' Now create a second group. We'll solve group 2, while leaving group 1
305' constant; so the workplane that we've created will be locked down,
306' and the solver can't move it.
307g = 2
308' These points are represented by their coordinates (u v) within the
309' workplane, so they need only two parameters each.
310slv.AddParam(11, g, 10.0)
311slv.AddParam(12, g, 20.0)
312slv.AddPoint2d(301, g, 200, 11, 12)
313
314slv.AddParam(13, g, 20.0)
315slv.AddParam(14, g, 10.0)
316slv.AddPoint2d(302, g, 200, 13, 14)
317
318' And we create a line segment with those endpoints.
319slv.AddLineSegment(400, g, 200, 301, 302)
320
321' Now three more points.
322slv.AddParam(15, g, 100.0)
323slv.AddParam(16, g, 120.0)
324slv.AddPoint2d(303, g, 200, 15, 16)
325
326slv.AddParam(17, g, 120.0)
327slv.AddParam(18, g, 110.0)
328slv.AddPoint2d(304, g, 200, 17, 18)
329
330slv.AddParam(19, g, 115.0)
331slv.AddParam(20, g, 115.0)
332slv.AddPoint2d(305, g, 200, 19, 20)
333
334' And arc, centered at point 303, starting at point 304, ending at
335' point 305.
336slv.AddArcOfCircle(401, g, 200, 102, 303, 304, 305)
337
338' Now one more point, and a distance
339slv.AddParam(21, g, 200.0)
340slv.AddParam(22, g, 200.0)
341slv.AddPoint2d(306, g, 200, 21, 22)
342
343slv.AddParam(23, g, 30.0)
344slv.AddDistance(307, g, 200, 23)
345
346' And a complete circle, centered at point 306 with radius equal to
347' distance 307. The normal is 102, the same as our workplane.
348slv.AddCircle(402, g, 200, 306, 102, 307)
349
350' The length of our line segment is 30.0 units.
351slv.AddConstraint(1, g, Slvs.SLVS_C_PT_PT_DISTANCE, _
352200, 30.0, 301, 302, 0, 0)
353
354' And the distance from our line segment to the origin is 10.0 units.
355slv.AddConstraint(2, g, Slvs.SLVS_C_PT_LINE_DISTANCE, _
356200, 10.0, 101, 0, 400, 0)
357
358' And the line segment is vertical.
359slv.AddConstraint(3, g, Slvs.SLVS_C_VERTICAL, _
360200, 0.0, 0, 0, 400, 0)
361
362' And the distance from one endpoint to the origin is 15.0 units.
363slv.AddConstraint(4, g, Slvs.SLVS_C_PT_PT_DISTANCE, _
364200, 15.0, 301, 101, 0, 0)
365
366' And same for the other endpoint; so if you add this constraint then
367' the sketch is overconstrained and will signal an error.
368'slv.AddConstraint(5, g, Slvs.SLVS_C_PT_PT_DISTANCE, _
369' 200, 18.0, 302, 101, 0, 0)
370
371' The arc and the circle have equal radius.
372slv.AddConstraint(6, g, Slvs.SLVS_C_EQUAL_RADIUS, _
373200, 0.0, 0, 0, 401, 402)
374
375' The arc has radius 17.0 units.
376slv.AddConstraint(7, g, Slvs.SLVS_C_DIAMETER, _
377200, 2 * 17.0, 0, 0, 401, 0)
378
379' If the solver fails, then ask it to report which constraints caused
380' the problem.
381slv.Solve(g, 0, 0, 0, 0, True)
382
383If (slv.GetResult() = Slvs.SLVS_RESULT_OKAY) Then
384Console.WriteLine("solved okay")
385' Note that we are referring to the parameters by their handles,
386' and not by their index in the list. This is a difference from
387' the C example.
388Console.WriteLine(String.Format( _
389"line from ({0:F3} {1:F3}) to ({2:F3} {3:F3})", _
390slv.GetParamByHandle(11), slv.GetParamByHandle(12), _
391slv.GetParamByHandle(13), slv.GetParamByHandle(14)))
392Console.WriteLine(String.Format( _
393"arc center ({0:F3} {1:F3}) start ({2:F3} {3:F3}) " + _
394"finish ({4:F3} {5:F3})", _
395slv.GetParamByHandle(15), slv.GetParamByHandle(16), _
396slv.GetParamByHandle(17), slv.GetParamByHandle(18), _
397slv.GetParamByHandle(19), slv.GetParamByHandle(20)))
398Console.WriteLine(String.Format( _
399"circle center ({0:F3} {1:F3}) radius {2:F3}", _
400slv.GetParamByHandle(21), slv.GetParamByHandle(22), _
401slv.GetParamByHandle(23)))
402
403Console.WriteLine(slv.GetDof().ToString() + " DOF")
404Else
405Console.Write("solve failed; problematic constraints are:")
406Dim t As UInteger
407For Each t In slv.GetFaileds()
408Console.Write(" " + t.ToString())
409Next
410Console.WriteLine("")
411If (slv.GetResult() = Slvs.SLVS_RESULT_INCONSISTENT) Then
412Console.WriteLine("system inconsistent")
413Else
414Console.WriteLine("system nonconvergent")
415End If
416End If
417
418End Sub
419
420
421'''''''''''''''''''''''''''''''
422' The interface to the library, and the wrapper functions around
423' that interface, follow.
424
425' These are the core functions imported from the DLL
426<DllImport("slvs.dll", CallingConvention:=CallingConvention.Cdecl)> _
427Public Sub Slvs_Solve(ByVal sys As IntPtr, ByVal hg As UInteger)
428End Sub
429
430<DllImport("slvs.dll", CallingConvention:=CallingConvention.Cdecl)> _
431Public Sub Slvs_MakeQuaternion(
432ByVal ux As Double, ByVal uy As Double, ByVal uz As Double,
433ByVal vx As Double, ByVal vy As Double, ByVal vz As Double,
434ByRef qw As Double, ByRef qx As Double, ByRef qy As Double,
435ByRef qz As Double)
436End Sub
437
438' And this is a thin wrapper around those functions, which provides
439' convenience functions similar to those provided in slvs.h for the C API.
440Public Class Slvs
441
442<StructLayout(LayoutKind.Sequential)> Public Structure Slvs_Param
443Public h As UInteger
444Public group As UInteger
445Public val As Double
446End Structure
447
448Public Const SLVS_FREE_IN_3D As Integer = 0
449
450Public Const SLVS_E_POINT_IN_3D As Integer = 50000
451Public Const SLVS_E_POINT_IN_2D As Integer = 50001
452Public Const SLVS_E_NORMAL_IN_3D As Integer = 60000
453Public Const SLVS_E_NORMAL_IN_2D As Integer = 60001
454Public Const SLVS_E_DISTANCE As Integer = 70000
455Public Const SLVS_E_WORKPLANE As Integer = 80000
456Public Const SLVS_E_LINE_SEGMENT As Integer = 80001
457Public Const SLVS_E_CUBIC As Integer = 80002
458Public Const SLVS_E_CIRCLE As Integer = 80003
459Public Const SLVS_E_ARC_OF_CIRCLE As Integer = 80004
460
461<StructLayout(LayoutKind.Sequential)> Public Structure Slvs_Entity
462Public h As UInteger
463Public group As UInteger
464
465Public type As Integer
466
467Public wrkpl As UInteger
468Public point0 As UInteger
469Public point1 As UInteger
470Public point2 As UInteger
471Public point3 As UInteger
472Public normal As UInteger
473Public distance As UInteger
474
475Public param0 As UInteger
476Public param1 As UInteger
477Public param2 As UInteger
478Public param3 As UInteger
479End Structure
480
481Public Const SLVS_C_POINTS_COINCIDENT As Integer = 100000
482Public Const SLVS_C_PT_PT_DISTANCE As Integer = 100001
483Public Const SLVS_C_PT_PLANE_DISTANCE As Integer = 100002
484Public Const SLVS_C_PT_LINE_DISTANCE As Integer = 100003
485Public Const SLVS_C_PT_FACE_DISTANCE As Integer = 100004
486Public Const SLVS_C_PT_IN_PLANE As Integer = 100005
487Public Const SLVS_C_PT_ON_LINE As Integer = 100006
488Public Const SLVS_C_PT_ON_FACE As Integer = 100007
489Public Const SLVS_C_EQUAL_LENGTH_LINES As Integer = 100008
490Public Const SLVS_C_LENGTH_RATIO As Integer = 100009
491Public Const SLVS_C_EQ_LEN_PT_LINE_D As Integer = 100010
492Public Const SLVS_C_EQ_PT_LN_DISTANCES As Integer = 100011
493Public Const SLVS_C_EQUAL_ANGLE As Integer = 100012
494Public Const SLVS_C_EQUAL_LINE_ARC_LEN As Integer = 100013
495Public Const SLVS_C_SYMMETRIC As Integer = 100014
496Public Const SLVS_C_SYMMETRIC_HORIZ As Integer = 100015
497Public Const SLVS_C_SYMMETRIC_VERT As Integer = 100016
498Public Const SLVS_C_SYMMETRIC_LINE As Integer = 100017
499Public Const SLVS_C_AT_MIDPOINT As Integer = 100018
500Public Const SLVS_C_HORIZONTAL As Integer = 100019
501Public Const SLVS_C_VERTICAL As Integer = 100020
502Public Const SLVS_C_DIAMETER As Integer = 100021
503Public Const SLVS_C_PT_ON_CIRCLE As Integer = 100022
504Public Const SLVS_C_SAME_ORIENTATION As Integer = 100023
505Public Const SLVS_C_ANGLE As Integer = 100024
506Public Const SLVS_C_PARALLEL As Integer = 100025
507Public Const SLVS_C_PERPENDICULAR As Integer = 100026
508Public Const SLVS_C_ARC_LINE_TANGENT As Integer = 100027
509Public Const SLVS_C_CUBIC_LINE_TANGENT As Integer = 100028
510Public Const SLVS_C_EQUAL_RADIUS As Integer = 100029
511Public Const SLVS_C_PROJ_PT_DISTANCE As Integer = 100030
512Public Const SLVS_C_WHERE_DRAGGED As Integer = 100031
513Public Const SLVS_C_CURVE_CURVE_TANGENT As Integer = 100032
514Public Const SLVS_C_LENGTH_DIFFERENCE As Integer = 100033
515
516<StructLayout(LayoutKind.Sequential)> Public Structure Slvs_Constraint
517Public h As UInteger
518Public group As UInteger
519
520Public type As Integer
521
522Public wrkpl As UInteger
523
524Public valA As Double
525Public ptA As UInteger
526Public ptB As UInteger
527Public entityA As UInteger
528Public entityB As UInteger
529Public entityC As UInteger
530Public entityD As UInteger
531
532Public other As Integer
533Public other2 As Integer
534End Structure
535
536Public Const SLVS_RESULT_OKAY As Integer = 0
537Public Const SLVS_RESULT_INCONSISTENT As Integer = 1
538Public Const SLVS_RESULT_DIDNT_CONVERGE As Integer = 2
539Public Const SLVS_RESULT_TOO_MANY_UNKNOWNS As Integer = 3
540
541<StructLayout(LayoutKind.Sequential)> Public Structure Slvs_System
542Public param As IntPtr
543Public params As Integer
544Public entity As IntPtr
545Public entities As Integer
546Public constraint As IntPtr
547Public constraints As Integer
548
549Public dragged0 As UInteger
550Public dragged1 As UInteger
551Public dragged2 As UInteger
552Public dragged3 As UInteger
553
554Public calculatedFaileds As Integer
555
556Public failed As IntPtr
557Public faileds As Integer
558
559Public dof As Integer
560
561Public result As Integer
562End Structure
563
564Dim Params As New List(Of Slvs_Param)
565Dim Entities As New List(Of Slvs_Entity)
566Dim Constraints As New List(Of Slvs_Constraint)
567
568Dim Faileds As New List(Of UInteger)
569
570Dim Result As Integer
571Dim Dof As Integer
572
573' Return the value of a parameter, by its handle. This function
574' may be used, for example, to obtain the new values of the
575' parameters after a call to Solve().
576Public Function GetParamByHandle(ByVal h As UInteger) As Double
577Dim t As Slvs_Param
578For Each t In Params
579If (t.h = h) Then
580Return t.val
581End If
582Next
583Throw New Exception("Invalid parameter handle.")
584End Function
585
586' Return the value of a parameter, by its index in the list (where
587' that index is determined by the order in which the parameters
588' were inserted with AddParam(), not by its handle).
589Public Function GetParamByIndex(ByVal i As Integer) As Double
590Return Params(i).val
591End Function
592
593' Get the result after a call to Solve(). This may be
594' SLVS_RESULT_OKAY - it worked
595' SLVS_RESULT_INCONSISTENT - failed, inconsistent
596' SLVS_RESULT_DIDNT_CONVERGE - consistent, but still failed
597' SLVS_RESULT_TOO_MANY_UNKNOWNS - too many parameters in one group
598Public Function GetResult() As Integer
599Return Result
600End Function
601
602' After a call to Solve(), this returns the number of unconstrained
603' degrees of freedom for the sketch.
604Public Function GetDof() As Integer
605Return Dof
606End Function
607
608' After a failing call to Solve(), this returns the list of
609' constraints, identified by their handle, that would fix the
610' system if they were deleted. This list will be populated only
611' if calculateFaileds is True in the Solve() call.
612Public Function GetFaileds() As List(Of UInteger)
613Return Faileds
614End Function
615
616' Clear our lists of entities, constraints, and parameters.
617Public Sub ResetAll()
618Params.Clear()
619Entities.Clear()
620Constraints.Clear()
621End Sub
622
623
624'''''''''''''''''''''''''''''''
625' These functions are broadly similar to the Slvs_Make...
626' functions in slvs.h. See the file DOC.txt accompanying the
627' library for details.
628
629Public Sub AddParam(ByVal h As UInteger, ByVal group As UInteger,
630ByVal val As Double)
631Dim p As Slvs_Param
632p.h = h
633p.group = group
634p.val = val
635Params.Add(p)
636End Sub
637
638Public Sub AddPoint2d(ByVal h As UInteger, ByVal group As UInteger,
639ByVal wrkpl As UInteger,
640ByVal u As UInteger, ByVal v As UInteger)
641Dim e As Slvs_Entity
642e.h = h
643e.group = group
644e.type = SLVS_E_POINT_IN_2D
645e.wrkpl = wrkpl
646e.param0 = u
647e.param1 = v
648Entities.Add(e)
649End Sub
650
651Public Sub AddPoint3d(ByVal h As UInteger, ByVal group As UInteger,
652ByVal x As UInteger, ByVal y As UInteger, ByVal z As UInteger)
653Dim e As Slvs_Entity
654e.h = h
655e.group = group
656e.type = SLVS_E_POINT_IN_3D
657e.wrkpl = SLVS_FREE_IN_3D
658e.param0 = x
659e.param1 = y
660e.param2 = z
661Entities.Add(e)
662End Sub
663
664Public Sub AddNormal3d(ByVal h As UInteger, ByVal group As UInteger,
665ByVal qw As UInteger, ByVal qx As UInteger,
666ByVal qy As UInteger, ByVal qz As UInteger)
667Dim e As Slvs_Entity
668e.h = h
669e.group = group
670e.type = SLVS_E_NORMAL_IN_3D
671e.wrkpl = SLVS_FREE_IN_3D
672e.param0 = qw
673e.param1 = qx
674e.param2 = qy
675e.param3 = qz
676Entities.Add(e)
677End Sub
678
679Public Sub AddNormal2d(ByVal h As UInteger, ByVal group As UInteger,
680ByVal wrkpl As UInteger)
681Dim e As Slvs_Entity
682e.h = h
683e.group = group
684e.type = SLVS_E_NORMAL_IN_2D
685e.wrkpl = wrkpl
686Entities.Add(e)
687End Sub
688
689Public Sub AddDistance(ByVal h As UInteger, ByVal group As UInteger,
690ByVal wrkpl As UInteger, ByVal d As UInteger)
691Dim e As Slvs_Entity
692e.h = h
693e.group = group
694e.type = SLVS_E_DISTANCE
695e.wrkpl = wrkpl
696e.param0 = d
697Entities.Add(e)
698End Sub
699
700Public Sub AddLineSegment(ByVal h As UInteger, ByVal group As UInteger,
701ByVal wrkpl As UInteger,
702ByVal ptA As UInteger, ByVal ptB As UInteger)
703Dim e As Slvs_Entity
704e.h = h
705e.group = group
706e.type = SLVS_E_LINE_SEGMENT
707e.wrkpl = wrkpl
708e.point0 = ptA
709e.point1 = ptB
710Entities.Add(e)
711End Sub
712
713Public Sub AddCubic(ByVal h As UInteger, ByVal group As UInteger,
714ByVal wrkpl As UInteger,
715ByVal pt0 As UInteger, ByVal pt1 As UInteger,
716ByVal pt2 As UInteger, ByVal pt3 As UInteger)
717Dim e As Slvs_Entity
718e.h = h
719e.group = group
720e.type = SLVS_E_CUBIC
721e.wrkpl = wrkpl
722e.point0 = pt0
723e.point1 = pt1
724e.point2 = pt2
725e.point3 = pt3
726Entities.Add(e)
727End Sub
728
729Public Sub AddArcOfCircle(ByVal h As UInteger, ByVal group As UInteger,
730ByVal wrkpl As UInteger,
731ByVal normal As UInteger,
732ByVal center As UInteger,
733ByVal pstart As UInteger,
734ByVal pend As UInteger)
735Dim e As Slvs_Entity
736e.h = h
737e.group = group
738e.type = SLVS_E_ARC_OF_CIRCLE
739e.wrkpl = wrkpl
740e.normal = normal
741e.point0 = center
742e.point1 = pstart
743e.point2 = pend
744Entities.Add(e)
745End Sub
746
747Public Sub AddCircle(ByVal h As UInteger, ByVal group As UInteger,
748ByVal wrkpl As UInteger,
749ByVal center As UInteger, ByVal normal As UInteger,
750ByVal radius As UInteger)
751Dim e As Slvs_Entity
752e.h = h
753e.group = group
754e.type = SLVS_E_CIRCLE
755e.wrkpl = wrkpl
756e.point0 = center
757e.normal = normal
758e.distance = radius
759Entities.Add(e)
760End Sub
761
762Public Sub AddWorkplane(ByVal h As UInteger, ByVal group As UInteger,
763ByVal origin As UInteger,
764ByVal normal As UInteger)
765Dim e As Slvs_Entity
766e.h = h
767e.group = group
768e.type = SLVS_E_WORKPLANE
769e.wrkpl = SLVS_FREE_IN_3D
770e.point0 = origin
771e.normal = normal
772Entities.Add(e)
773End Sub
774
775Public Sub AddConstraint(ByVal h As UInteger,
776ByVal group As UInteger,
777ByVal type As Integer,
778ByVal wrkpl As UInteger,
779ByVal valA As Double,
780ByVal ptA As UInteger,
781ByVal ptB As UInteger,
782ByVal entityA As UInteger,
783ByVal entityB As UInteger)
784Dim c As Slvs_Constraint
785c.h = h
786c.group = group
787c.type = type
788c.wrkpl = wrkpl
789c.valA = valA
790c.ptA = ptA
791c.ptB = ptB
792c.entityA = entityA
793c.entityB = entityB
794Constraints.Add(c)
795End Sub
796
797' Solve the system. The geometry of the system must already have
798' been specified through the Add...() calls. The result of the
799' solution process may be obtained by calling GetResult(),
800' GetFaileds(), GetDof(), and GetParamByXXX().
801'
802' The parameters draggedx (indicated by their handles) will be held
803' as close as possible to their original positions, even if this
804' results in large moves for other parameters. This feature may be
805' useful if, for example, the user is dragging the point whose
806' location is defined by those parameters. Unused draggedx
807' parameters may be specified as zero.
808Public Sub Solve(ByVal group As UInteger,
809ByVal dragged0 As UInteger, ByVal dragged1 As UInteger,
810ByVal dragged2 As UInteger, ByVal dragged3 As UInteger,
811ByVal calculateFaileds As Boolean)
812Dim i As Integer
813
814Dim pp, p(Params.Count()) As Slvs_Param
815i = 0
816For Each pp In Params
817p(i) = pp
818i += 1
819Next
820
821Dim ee, e(Entities.Count()) As Slvs_Entity
822i = 0
823For Each ee In Entities
824e(i) = ee
825i += 1
826Next
827
828Dim cc, c(Constraints.Count()) As Slvs_Constraint
829i = 0
830For Each cc In Constraints
831c(i) = cc
832i += 1
833Next
834Dim f(Constraints.Count()) As UInteger
835
836Dim sys As Slvs_System
837
838Dim pgc, egc, cgc As GCHandle
839pgc = GCHandle.Alloc(p, GCHandleType.Pinned)
840sys.param = pgc.AddrOfPinnedObject()
841sys.params = Params.Count()
842egc = GCHandle.Alloc(e, GCHandleType.Pinned)
843sys.entity = egc.AddrOfPinnedObject()
844sys.entities = Entities.Count()
845cgc = GCHandle.Alloc(c, GCHandleType.Pinned)
846sys.constraint = cgc.AddrOfPinnedObject()
847sys.constraints = Constraints.Count()
848
849sys.dragged0 = dragged0
850sys.dragged1 = dragged1
851sys.dragged2 = dragged2
852sys.dragged3 = dragged3
853
854Dim fgc As GCHandle
855fgc = GCHandle.Alloc(f, GCHandleType.Pinned)
856If calculateFaileds Then
857sys.calculatedFaileds = 1
858Else
859sys.calculatedFaileds = 0
860End If
861sys.faileds = Constraints.Count()
862sys.failed = fgc.AddrOfPinnedObject()
863
864Dim sysgc As GCHandle
865sysgc = GCHandle.Alloc(sys, GCHandleType.Pinned)
866
867Slvs_Solve(sysgc.AddrOfPinnedObject(), group)
868
869sys = sysgc.Target
870
871For i = 0 To Params.Count() - 1
872Params(i) = p(i)
873Next
874
875Faileds.Clear()
876For i = 0 To sys.faileds - 1
877Faileds.Add(f(i))
878Next
879
880sysgc.Free()
881fgc.Free()
882pgc.Free()
883egc.Free()
884cgc.Free()
885
886Result = sys.result
887Dof = sys.dof
888End Sub
889' A simpler version of the function, if the parameters being dragged
890' correspond to a single point.
891Public Sub Solve(ByVal group As UInteger, ByVal dragged As Point,
892ByVal calculatedFaileds As Boolean)
893If TypeOf dragged Is Point2d Then
894Dim p As Point2d
895p = dragged
896Solve(group, p.up.H, p.vp.H, 0, 0, calculatedFaileds)
897ElseIf TypeOf dragged Is Point3d Then
898Dim p As Point3d
899p = dragged
900Solve(group, p.xp.H, p.yp.H, p.zp.H, 0, calculatedFaileds)
901Else
902Throw New Exception("Can't get dragged params for point.")
903End If
904End Sub
905' or if it's a single distance (e.g., the radius of a circle)
906Public Sub Solve(ByVal group As UInteger, ByVal dragged As Distance,
907ByVal calculatedFaileds As Boolean)
908Solve(group, dragged.dp.H, 0, 0, 0, calculatedFaileds)
909End Sub
910' or if it's nothing.
911Public Sub Solve(ByVal group As UInteger,
912ByVal calculateFaileds As Boolean)
913Solve(group, 0, 0, 0, 0, calculateFaileds)
914End Sub
915
916' Return the quaternion in (qw, qx, qy, qz) that represents a
917' rotation from the base frame to a coordinate system with the
918' specified basis vectors u and v. For example, u = (0, 1, 0)
919' and v = (0, 0, 1) specifies the yz plane, such that a point with
920' (u, v) = (7, 12) has (x, y, z) = (0, 7, 12).
921Public Sub MakeQuaternion(
922ByVal ux As Double, ByVal uy As Double, ByVal uz As Double,
923ByVal vx As Double, ByVal vy As Double, ByVal vz As Double,
924ByRef qw As Double, ByRef qx As Double, ByRef qy As Double,
925ByRef qz As Double)
926Slvs_MakeQuaternion(ux, uy, uz, _
927vx, vy, vz, _
928qw, qx, qy, qz)
929End Sub
930
931Public Function FreeIn3d()
932Return New Workplane(Me)
933End Function
934
935
936'''''''''''''''''''''''''''''''
937' Functions to create the object-oriented wrappers defined below.
938
939Public Function NewParam(ByVal group As UInteger, ByVal val As Double)
940Return New Param(Me, group, val)
941End Function
942Public Function NewPoint2d(ByVal group As UInteger,
943ByVal wrkpl As Workplane,
944ByVal u As Double, ByVal v As Double)
945Return New Point2d(Me, group, wrkpl, u, v)
946End Function
947Public Function NewPoint2d(ByVal group As UInteger,
948ByVal wrkpl As Workplane,
949ByVal u As Param, ByVal v As Param)
950Return New Point2d(Me, group, wrkpl, u, v)
951End Function
952Public Function NewPoint3d(ByVal group As UInteger,
953ByVal x As Double,
954ByVal y As Double,
955ByVal z As Double)
956Return New Point3d(Me, group, x, y, z)
957End Function
958Public Function NewPoint3d(ByVal group As UInteger,
959ByVal x As Param,
960ByVal y As Param,
961ByVal z As Param)
962Return New Point3d(Me, group, x, y, z)
963End Function
964Public Function NewNormal3d(ByVal group As UInteger,
965ByVal ux As Double, ByVal uy As Double, ByVal uz As Double,
966ByVal vx As Double, ByVal vy As Double, ByVal vz As Double)
967Return New Normal3d(Me, group, ux, uy, uz, vx, vy, vz)
968End Function
969Public Function NewNormal3d(ByVal group As UInteger,
970ByVal qw As Param, ByVal qx As Param,
971ByVal qy As Param, ByVal qz As Param)
972Return New Normal3d(Me, group, qw, qx, qy, qz)
973End Function
974Public Function NewNormal2d(ByVal group As UInteger,
975ByVal wrkpl As Workplane)
976Return New Normal2d(Me, group, wrkpl)
977End Function
978Public Function NewDistance(ByVal group As UInteger,
979ByVal wrkpl As Workplane, ByVal d As Double)
980Return New Distance(Me, group, wrkpl, d)
981End Function
982Public Function NewDistance(ByVal group As UInteger,
983ByVal wrkpl As Workplane, ByVal d As Param)
984Return New Distance(Me, group, wrkpl, d)
985End Function
986Public Function NewLineSegment(ByVal group As UInteger,
987ByVal wrkpl As Workplane,
988ByVal ptA As Point, ByVal ptB As Point)
989Return New LineSegment(Me, group, wrkpl, ptA, ptB)
990End Function
991Public Function NewArcOfCircle(ByVal group As UInteger,
992ByVal wrkpl As Workplane,
993ByVal normal As Normal,
994ByVal center As Point,
995ByVal pstart As Point,
996ByVal pend As Point)
997Return New ArcOfCircle(Me, group, wrkpl, normal, _
998center, pstart, pend)
999End Function
1000Public Function NewCircle(ByVal group As UInteger,
1001ByVal wrkpl As Workplane,
1002ByVal center As Point,
1003ByVal normal As Normal,
1004ByVal radius As Distance)
1005Return New Circle(Me, group, wrkpl, center, normal, radius)
1006End Function
1007Public Function NewWorkplane(ByVal group As UInteger,
1008ByVal origin As Point,
1009ByVal normal As Normal)
1010Return New Workplane(Me, group, origin, normal)
1011End Function
1012
1013Public Sub AddConstraint(ByVal H As UInteger, ByVal group As UInteger,
1014ByVal type As Integer,
1015ByVal wrkpl As Workplane,
1016ByVal valA As Double,
1017ByVal ptA As Point, ByVal ptB As Point,
1018ByVal entityA As Entity,
1019ByVal entityB As Entity)
1020AddConstraint(H, group, type, _
1021If(IsNothing(wrkpl), 0, wrkpl.H), _
1022valA, _
1023If(IsNothing(ptA), 0, ptA.H), _
1024If(IsNothing(ptB), 0, ptB.H), _
1025If(IsNothing(entityA), 0, entityA.H), _
1026If(IsNothing(entityB), 0, entityB.H))
1027End Sub
1028
1029
1030'''''''''''''''''''''''''''''''
1031' The object-oriented wrapper classes themselves, to allow the
1032' representation of entities and constraints as .net objects, not
1033' integer handles. These don't do any work themselves, beyond
1034' allocating and storing a unique integer handle.
1035'
1036' These functions will assign parameters and entities with
1037' consecutive handles starting from 1. If they are intermixed
1038' with parameters and entities with user-specified handles, then
1039' those handles must be chosen not to conflict, e.g. starting
1040' from 100 000 or another large number.
1041
1042Public Class Param
1043Public Slv As Slvs
1044Public H As UInteger
1045
1046Public Sub New(ByVal s As Slvs, ByVal group As UInteger,
1047ByVal val As Double)
1048Slv = s
1049H = Slv.Params.Count() + 1
1050Slv.AddParam(H, group, val)
1051End Sub
1052End Class
1053
1054Public MustInherit Class Entity
1055Public Slv As Slvs
1056Public H As UInteger
1057
1058Public Sub New(ByVal s As Slvs)
1059Slv = s
1060H = Slv.Entities.Count() + 1
1061End Sub
1062End Class
1063
1064Public MustInherit Class Point
1065Inherits Entity
1066Public Sub New(ByVal s As Slvs)
1067MyBase.New(s)
1068End Sub
1069End Class
1070
1071Public MustInherit Class Normal
1072Inherits Entity
1073Public Sub New(ByVal s As Slvs)
1074MyBase.New(s)
1075End Sub
1076End Class
1077
1078Public Class Point2d
1079Inherits Point
1080Public up, vp As Param
1081Public Sub New(ByVal s As Slvs, ByVal group As UInteger,
1082ByVal wrkpl As Workplane,
1083ByVal u As Double, ByVal v As Double)
1084MyBase.New(s)
1085up = New Param(Slv, group, u)
1086vp = New Param(Slv, group, v)
1087Slv.AddPoint2d(H, group, wrkpl.H, up.H, vp.H)
1088End Sub
1089Public Sub New(ByVal s As Slvs, ByVal group As UInteger,
1090ByVal wrkpl As Workplane,
1091ByVal u As Param, ByVal v As Param)
1092MyBase.New(s)
1093Slv.AddPoint2d(H, group, wrkpl.H, u.H, v.H)
1094up = u
1095vp = v
1096End Sub
1097Function GetU()
1098Return Slv.GetParamByHandle(up.H)
1099End Function
1100Function GetV()
1101Return Slv.GetParamByHandle(vp.H)
1102End Function
1103End Class
1104
1105Public Class Point3d
1106Inherits Point
1107Public xp, yp, zp As Param
1108Public Sub New(ByVal s As Slvs, ByVal group As UInteger,
1109ByVal x As Double, ByVal y As Double,
1110ByVal z As Double)
1111MyBase.New(s)
1112xp = New Param(Slv, group, x)
1113yp = New Param(Slv, group, y)
1114zp = New Param(Slv, group, z)
1115Slv.AddPoint3d(H, group, xp.H, yp.H, zp.H)
1116End Sub
1117Public Sub New(ByVal s As Slvs, ByVal group As UInteger,
1118ByVal x As Param, ByVal y As Param, ByVal z As Param)
1119MyBase.New(s)
1120Slv.AddPoint3d(H, group, x.H, y.H, z.H)
1121xp = x
1122yp = y
1123zp = z
1124End Sub
1125Function GetX()
1126Return Slv.GetParamByHandle(xp.H)
1127End Function
1128Function GetY()
1129Return Slv.GetParamByHandle(yp.H)
1130End Function
1131Function GetZ()
1132Return Slv.GetParamByHandle(zp.H)
1133End Function
1134End Class
1135
1136Public Class Normal3d
1137Inherits Normal
1138Dim qwp, qxp, qyp, qzp As Param
1139Public Sub New(ByVal s As Slvs, ByVal group As UInteger,
1140ByVal ux As Double, ByVal uy As Double, ByVal uz As Double,
1141ByVal vx As Double, ByVal vy As Double, ByVal vz As Double)
1142MyBase.New(s)
1143Dim qw, qx, qy, qz As Double
1144Slv.MakeQuaternion(ux, uy, uz, vx, vy, vz, qw, qx, qy, qz)
1145qwp = New Param(Slv, group, qw)
1146qxp = New Param(Slv, group, qx)
1147qyp = New Param(Slv, group, qy)
1148qzp = New Param(Slv, group, qz)
1149Slv.AddNormal3d(H, group, qwp.H, qxp.H, qyp.H, qzp.H)
1150End Sub
1151Public Sub New(ByVal s As Slvs, ByVal group As UInteger,
1152ByVal qw As Param, ByVal qx As Param,
1153ByVal qy As Param, ByVal qz As Param)
1154MyBase.New(s)
1155Slv.AddNormal3d(H, group, qw.H, qx.H, qy.H, qz.H)
1156qwp = qw
1157qxp = qx
1158qyp = qy
1159qzp = qz
1160End Sub
1161End Class
1162
1163Public Class Normal2d
1164Inherits Normal
1165Public Sub New(ByVal s As Slvs, ByVal group As UInteger,
1166ByVal wrkpl As Workplane)
1167MyBase.New(s)
1168Slv.AddNormal2d(H, group, wrkpl.H)
1169End Sub
1170End Class
1171
1172Public Class Distance
1173Inherits Entity
1174Public dp As Param
1175
1176Public Sub New(ByVal s As Slvs, ByVal group As UInteger,
1177ByVal wrkpl As Workplane, ByVal d As Double)
1178MyBase.New(s)
1179dp = New Param(Slv, group, d)
1180Slv.AddDistance(H, group, wrkpl.H, dp.H)
1181End Sub
1182Public Sub New(ByVal s As Slvs, ByVal group As UInteger,
1183ByVal wrkpl As Workplane, ByVal d As Param)
1184MyBase.New(s)
1185Slv.AddDistance(H, group, wrkpl.H, d.H)
1186dp = d
1187End Sub
1188Function GetDistance() As Double
1189Return Slv.GetParamByHandle(dp.H)
1190End Function
1191End Class
1192
1193Public Class LineSegment
1194Inherits Entity
1195Public Sub New(ByVal s As Slvs, ByVal group As UInteger,
1196ByVal wrkpl As Workplane,
1197ByVal ptA As Point, ByVal ptB As Point)
1198MyBase.New(s)
1199Slv.AddLineSegment(H, group, wrkpl.H, ptA.H, ptB.H)
1200End Sub
1201End Class
1202
1203Public Class Cubic
1204Inherits Entity
1205Public Sub New(ByVal s As Slvs, ByVal group As UInteger,
1206ByVal wrkpl As Workplane,
1207ByVal pt0 As Point, ByVal pt1 As Point,
1208ByVal pt2 As Point, ByVal pt3 As Point)
1209MyBase.New(s)
1210Slv.AddCubic(H, group, wrkpl.H, pt0.H, pt1.H, pt2.H, pt3.H)
1211End Sub
1212End Class
1213
1214Public Class ArcOfCircle
1215Inherits Entity
1216Public Sub New(ByVal s As Slvs, ByVal group As UInteger,
1217ByVal wrkpl As Workplane, ByVal normal As Normal,
1218ByVal center As Point, ByVal pstart As Point,
1219ByVal pend As Point)
1220MyBase.New(s)
1221Slv.AddArcOfCircle(H, group, wrkpl.H, normal.H, _
1222center.H, pstart.H, pend.H)
1223End Sub
1224End Class
1225
1226Public Class Circle
1227Inherits Entity
1228Public Sub New(ByVal s As Slvs, ByVal group As UInteger,
1229ByVal wrkpl As Workplane, ByVal center As Point,
1230ByVal normal As Normal, ByVal radius As Distance)
1231MyBase.New(s)
1232Slv.AddCircle(H, group, wrkpl.H, center.H, normal.H, radius.H)
1233End Sub
1234End Class
1235
1236Public Class Workplane
1237Inherits Entity
1238Public Sub New(ByVal s As Slvs)
1239MyBase.New(s)
1240H = SLVS_FREE_IN_3D
1241End Sub
1242Public Sub New(ByVal s As Slvs, ByVal group As UInteger,
1243ByVal origin As Point, ByVal normal As Normal)
1244MyBase.New(s)
1245Slv.AddWorkplane(H, group, origin.H, normal.H)
1246End Sub
1247End Class
1248
1249End Class
1250
1251End Module
1252
1253