ADG Lua 

ADG Lua Git Source Tree

Root/piston.lua

1--[[
2
3This file is part of adg-lua.
4Copyright (C) 2012-2013 Nicola Fontana <ntd at entidi.it>
5
6adg-lua is free software; you can redistribute it and/or modify
7it under the terms of the GNU Lesser General Public License as
8published by the Free Software Foundation; either version 2 of
9the License, or (at your option) any later version.
10
11adg-lua is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU Lesser General Public License for more details.
15
16You should have received a copy of the GNU Lesser General
17Public License along with adg-lua; if not, write to the Free
18Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19Boston, MA 02110-1301, USA.
20
21]]
22
23local lgi = require 'lgi'
24local cairo = lgi.require 'cairo'
25local Cpml = lgi.require 'Cpml'
26local Adg = lgi.require 'Adg'
27
28local SQRT3 = math.sqrt(3)
29
30
31-- Backward compatibility
32
33if not cairo.Status.to_string then
34 -- Pull request: http://github.com/pavouk/lgi/pull/44
35 local core = require 'lgi.core'
36 local ffi = require 'lgi.ffi'
37 local ti = ffi.types
38
39 cairo._enum.Status.to_string = core.callable.new {
40addr = cairo._module.cairo_status_to_string,
41ret = ti.utf8,
42ti.int
43 }
44end
45
46
47-- MODEL
48-----------------------------------------------------------------
49
50local model = {}
51
52function model.body(piston)
53 local pair = Cpml.Pair {}
54 local path = Adg.Path {}
55
56 pair.x = 0
57 pair.y = piston.D1 / 2
58 path:move_to(pair)
59 path:set_named_pair('D1I', pair)
60
61 pair.x = piston.A - piston.B - piston.LD2
62 path:line_to(pair)
63
64 pair.y = piston.D3 / 2
65 path:set_named_pair('D2_POS', pair)
66
67 pair.x = pair.x + (piston.D1 - piston.D2) / 2
68 pair.y = piston.D2 / 2
69 path:line_to(pair)
70 path:set_named_pair('D2I', pair)
71
72 pair.x = piston.A - piston.B
73 path:line_to(pair)
74 path:fillet(0.4)
75
76 pair.x = piston.A - piston.B
77 pair.y = piston.D3 / 2
78 path:line_to(pair)
79 path:set_named_pair('D3I', pair)
80
81 pair.x = piston.A
82 path:set_named_pair('East', pair)
83
84 pair.x = 0
85 path:set_named_pair('West', pair)
86
87 path:chamfer(0.3, 0.3)
88
89 pair.x = piston.A - piston.B + piston.LD3
90 pair.y = piston.D3 / 2
91 path:line_to(pair)
92
93 local primitive = path:over_primitive()
94 local tmp = primitive:put_point(0)
95 path:set_named_pair('D3I_X', tmp)
96
97 tmp = primitive:put_point(-1)
98 path:set_named_pair('D3I_Y', tmp)
99
100 path:chamfer(0.3, 0.3)
101
102 pair.y = piston.D4 / 2
103 path:line_to(pair)
104
105 primitive = path:over_primitive()
106 tmp = primitive:put_point(0)
107 path:set_named_pair('D3F_Y', tmp)
108 tmp = primitive:put_point(-1)
109 path:set_named_pair('D3F_X', tmp)
110
111 path:fillet(piston.RD34)
112
113 pair.x = pair.x + piston.RD34
114 path:set_named_pair('D4I', pair)
115
116 pair.x = piston.A - piston.C - piston.LD5
117 path:line_to(pair)
118 path:set_named_pair('D4F', pair)
119
120 pair.y = piston.D3 / 2
121 path:set_named_pair('D4_POS', pair)
122
123 primitive = path:over_primitive()
124 tmp = primitive:put_point(0)
125 tmp.x = tmp.x + piston.RD34
126 path:set_named_pair('RD34', tmp)
127
128 tmp.x = tmp.x - math.cos(math.pi / 4) * piston.RD34
129 tmp.y = tmp.y - math.sin(math.pi / 4) * piston.RD34
130 path:set_named_pair('RD34_R', tmp)
131
132 tmp.x = tmp.x + piston.RD34
133 tmp.y = tmp.y + piston.RD34
134 path:set_named_pair('RD34_XY', tmp)
135
136 pair.x = pair.x + (piston.D4 - piston.D5) / 2
137 pair.y = piston.D5 / 2
138 path:line_to(pair)
139 path:set_named_pair('D5I', pair)
140
141 pair.x = piston.A - piston.C
142 path:line_to(pair)
143
144 path:fillet(0.2)
145
146 pair.y = piston.D6 / 2
147 path:line_to(pair)
148
149 primitive = path:over_primitive()
150 tmp = primitive:put_point(0)
151 path:set_named_pair('D5F', tmp)
152
153 path:fillet(0.1)
154
155 pair.x = pair.x + piston.LD6
156 path:line_to(pair)
157 path:set_named_pair('D6F', pair)
158
159 primitive = path:over_primitive()
160 tmp = primitive:put_point(0)
161 path:set_named_pair('D6I_X', tmp)
162
163 primitive = path:over_primitive()
164 tmp = primitive:put_point(-1)
165 path:set_named_pair('D6I_Y', tmp)
166
167 pair.x = piston.A - piston.LD7
168 pair.y = pair.y - (piston.C - piston.LD7 - piston.LD6) / SQRT3
169 path:line_to(pair)
170 path:set_named_pair('D67', pair)
171
172 pair.y = piston.D7 / 2
173 path:line_to(pair)
174
175 pair.x = piston.A
176 path:line_to(pair)
177 path:set_named_pair('D7F', pair)
178
179 path:reflect_explicit(1, 0)
180 path:close()
181
182 return path
183end
184
185function model.edges(piston)
186 return Adg.Edges { source = piston.model.body }
187end
188
189function model.hole(piston)
190 local pair = Cpml.Pair {}
191 local tmp = Cpml.Pair {}
192 local path = Adg.Path {}
193
194 pair.x = piston.LHOLE
195 pair.y = 0
196 path:move_to(pair)
197 path:set_named_pair('LHOLE', pair)
198
199 tmp.y = piston.DHOLE / 2
200 tmp.x = pair.x - tmp.y / SQRT3
201 path:line_to(tmp)
202
203 pair.x = 0
204 pair.y = tmp.y
205 path:line_to(pair)
206 path:set_named_pair('DHOLE', pair)
207
208 path:line_to_explicit(0, (piston.D1 + piston.DHOLE) / 4)
209 path:curve_to_explicit(piston.LHOLE / 2, piston.DHOLE / 2,
210 piston.LHOLE + 2, piston.D1 / 2,
211 piston.LHOLE + 2, 0)
212 path:reflect_explicit(1, 0)
213 path:close()
214
215 path:move_to(tmp)
216 tmp.y = -tmp.y
217 path:line_to(tmp)
218
219 return path
220end
221
222
223-- VIEW
224-----------------------------------------------------------------
225
226local view = {}
227
228-- Inject the export method into Adg.Canvas
229rawset(Adg.Canvas, 'export', function (canvas, file)
230 -- The export format is guessed from the file suffix
231 local suffix = file:match('%..*$')
232 local size = canvas:get_size()
233 size.x = size.x + canvas:get_left_margin() + canvas:get_right_margin()
234 size.y = size.y + canvas:get_top_margin() + canvas:get_bottom_margin()
235
236 -- Create the cairo surface
237 local surface
238 if suffix == '.png' and cairo.ImageSurface then
239surface = cairo.ImageSurface.create(cairo.Format.RGB24, size.x, size.y)
240 elseif suffix == '.svg' and cairo.SvgSurface then
241surface = cairo.SvgSurface.create(file, size.x, size.y)
242 elseif suffix == '.pdf' and cairo.PdfSurface then
243surface = cairo.PdfSurface.create(file, size.x, size.y)
244 elseif suffix == '.ps' and cairo.PsSurface then
245-- Pull request: http://github.com/pavouk/lgi/pull/46
246surface = cairo.PsSurface.create(file, size.x, size.y)
247surface:dsc_comment('%%Title: adg-lua demonstration program')
248surface:dsc_comment('%%Copyright: Copyleft (C) 2013 Fontana Nicola')
249surface:dsc_comment('%%Orientation: Portrait')
250surface:dsc_begin_setup()
251surface:dsc_begin_page_setup()
252surface:dsc_comment('%%IncludeFeature: *PageSize A4')
253 end
254 if not surface then return nil, 'Requested format not supported' end
255
256 -- Render the canvas content
257 local cr = cairo.Context.create(surface);
258 canvas:render(cr)
259 local status
260
261 if cairo.Surface.get_type(surface) == 'IMAGE' then
262status = cairo.Surface.write_to_png(surface, file)
263 else
264cr:show_page()
265status = cr.status
266 end
267
268 if status ~= 'SUCCESS' then
269return nil, cairo.Status.to_string(cairo.Status[status])
270 end
271end)
272
273local function add_title_block(canvas, title)
274 canvas:set_title_block(Adg.TitleBlock {
275title = title or 'Generic title',
276author = 'adg-demo',
277date = os.date('%d/%m/%Y'),
278drawing = 'PISTON',
279logo = Adg.Logo {},
280projection = Adg.Projection { scheme = Adg.ProjectionScheme.FIRST_ANGLE },
281scale = '---',
282size = 'A4',
283 })
284end
285
286local function add_dimensions(canvas, model)
287 local body = model.body
288 local hole = model.hole
289 local dim
290
291
292 -- North
293
294 dim = Adg.LDim.new_full_from_model(body, '-D3I_X', '-D3F_X', '-D3F_Y', -math.pi/2)
295 dim:set_outside(Adg.ThreeState.OFF)
296 canvas:add(dim)
297
298 dim = Adg.LDim.new_full_from_model(body, '-D6I_X', '-D67', '-East', -math.pi/2)
299 dim:set_level(0)
300 dim:switch_extension1(false)
301 canvas:add(dim)
302
303 dim = Adg.LDim.new_full_from_model(body, '-D6I_X', '-D7F', '-East', -math.pi/2)
304 dim:set_limits('-0.06', nil)
305 canvas:add(dim)
306
307 dim = Adg.ADim.new_full_from_model(body, '-D6I_Y', '-D6F', '-D6F', '-D67', '-D6F')
308 dim:set_level(2)
309 canvas:add(dim)
310
311 dim = Adg.RDim.new_full_from_model(body, '-RD34', '-RD34_R', '-RD34_XY')
312 canvas:add(dim)
313
314 dim = Adg.LDim.new_full_from_model(body, '-DGROOVEI_X', '-DGROOVEF_X', '-DGROOVEX_POS', -math.pi/2)
315 canvas:add(dim)
316
317 dim = Adg.LDim.new_full_from_model(body, 'D2I', '-D2I', '-D2_POS', math.pi)
318 dim:set_limits('-0.1', nil)
319 dim:set_outside(Adg.ThreeState.OFF)
320 dim:set_value('\226\140\128 <>')
321 canvas:add(dim)
322
323 dim = Adg.LDim.new_full_from_model(body, 'DGROOVEI_Y', '-DGROOVEI_Y', '-DGROOVEY_POS', math.pi)
324 dim:set_limits('-0.1', nil)
325 dim:set_outside(Adg.ThreeState.OFF)
326 dim:set_value('\226\140\128 <>')
327 canvas:add(dim)
328
329
330 -- South
331
332 dim = Adg.ADim.new_full_from_model(body, 'D1F', 'D1I', 'D2I', 'D1F', 'D1F')
333 dim:set_level(2)
334 dim:switch_extension2(false)
335 canvas:add(dim)
336
337 dim = Adg.LDim.new_full_from_model(body, 'D1I', nil, 'West', math.pi / 2)
338 dim:set_ref2_from_model(hole, '-LHOLE')
339 dim:switch_extension1(false)
340 canvas:add(dim)
341
342 dim = Adg.LDim.new_full_from_model(body, 'D1I', 'DGROOVEI_X', 'West', math.pi / 2)
343 dim:switch_extension1(false)
344 dim:set_level(2)
345 canvas:add(dim)
346
347 dim = Adg.LDim.new_full_from_model(body, 'D4F', 'D6I_X', 'D4_POS', math.pi / 2)
348 dim:set_limits(nil, '+0.2')
349 dim:set_outside(Adg.ThreeState.OFF)
350 canvas:add(dim)
351
352 dim = Adg.LDim.new_full_from_model(body, 'D1F', 'D3I_X', 'D2_POS', math.pi / 2)
353 dim:set_level(2)
354 dim:switch_extension2(false)
355 dim:set_outside(Adg.ThreeState.OFF)
356 canvas:add(dim)
357
358 dim = Adg.LDim.new_full_from_model(body, 'D3I_X', 'D7F', 'East', math.pi / 2)
359 dim:set_limits(nil, '+0.1')
360 dim:set_level(2)
361 dim:set_outside(Adg.ThreeState.OFF)
362 dim:switch_extension2(false)
363 canvas:add(dim)
364
365 dim = Adg.LDim.new_full_from_model(body, 'D1I', 'D7F', 'D3F_Y', math.pi / 2)
366 dim:set_limits('-0.05', '+0.05')
367 dim:set_level(3)
368 canvas:add(dim)
369
370 dim = Adg.ADim.new_full_from_model(body, 'D4F', 'D4I', 'D5I', 'D4F', 'D4F')
371 dim:set_level(1.5)
372 dim:switch_extension2(false)
373 canvas:add(dim)
374
375
376 -- East
377
378 dim = Adg.LDim.new_full_from_model(body, 'D6F', '-D6F', 'East', 0)
379 dim:set_limits('-0.1', nil)
380 dim:set_level(4)
381 dim:set_value('\226\140\128 <>')
382 canvas:add(dim)
383
384 dim = Adg.LDim.new_full_from_model(body, 'D4F', '-D4F', 'East', 0)
385 dim:set_level(3)
386 dim:set_value('\226\140\128 <>')
387 canvas:add(dim)
388
389 dim = Adg.LDim.new_full_from_model(body, 'D5F', '-D5F', 'East', 0)
390 dim:set_limits('-0.1', nil)
391 dim:set_level(2)
392 dim:set_value('\226\140\128 <>')
393 canvas:add(dim)
394
395 dim = Adg.LDim.new_full_from_model(body, 'D7F', '-D7F', 'East', 0)
396 dim:set_value('\226\140\128 <>')
397 canvas:add(dim)
398
399
400 -- West
401
402 dim = Adg.LDim.new_full_from_model(hole, 'DHOLE', '-DHOLE', nil, math.pi)
403 dim:set_pos_from_model(body, '-West')
404 dim:set_value('\226\140\128 <>')
405 canvas:add(dim)
406
407 dim = Adg.LDim.new_full_from_model(body, 'D1I', '-D1I', '-West', math.pi)
408 dim:set_limits('-0.05', '+0.05')
409 dim:set_level(2)
410 dim:set_value('\226\140\128 <>')
411 canvas:add(dim)
412
413 dim = Adg.LDim.new_full_from_model(body, 'D3I_Y', '-D3I_Y', '-West', math.pi)
414 dim:set_limits('-0.25', nil)
415 dim:set_level(3)
416 dim:set_value('\226\140\128 <>')
417 canvas:add(dim)
418end
419
420function view.detailed(model)
421 local canvas = Adg.Canvas {}
422
423 add_title_block(canvas, 'Detailed view')
424 canvas:add(Adg.Stroke { trail = model.body })
425 canvas:add(Adg.Stroke { trail = model.edges })
426 canvas:add(Adg.Hatch { trail = model.hole })
427 canvas:add(Adg.Stroke { trail = model.hole })
428 add_dimensions(canvas, model)
429
430 return canvas
431end
432
433
434-- CONTROLLER
435-----------------------------------------------------------------
436
437local controller = {}
438
439function controller.new(data)
440 local part = data or {}
441
442 part.model = {}
443 setmetatable(part.model, {
444__index = function (self, key)
445 -- Check if the model name is valid
446 if not model[key] then return end
447
448 -- Create the model and store it into the cache
449 self[key] = model[key](part)
450
451 -- Return the cached result
452 return self[key]
453end
454 })
455
456 part.view = {}
457 setmetatable(part.view, {
458__index = function (self, key)
459 -- Check if the view name is valid
460 if not view[key] then return end
461
462 -- Create the view and store it into the cache
463 self[key] = view[key](part.model)
464
465 -- Return the cached result
466 return self[key]
467end
468 })
469
470 return part
471end
472
473
474return controller

Archive Download this file

Branches

Tags