autocad 0.4.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rubocop/minitest.yml +2 -0
- data/.rubocop/strict.yml +4 -0
- data/.rubocop.yml +33 -0
- data/.solargraph.yml +22 -0
- data/.vscode/launch.json +30 -0
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +132 -0
- data/Guardfile +66 -0
- data/LICENSE.txt +21 -0
- data/README.md +39 -0
- data/Rakefile +10 -0
- data/Steepfile +35 -0
- data/WASD-D-TDS-C001.dwg +0 -0
- data/WASD-D-TDS-C001.pdf +0 -0
- data/autocad.log +1 -0
- data/autocad_example.rb +26 -0
- data/event_handler.log +24 -0
- data/examples/example_save_pdf.rb +5 -0
- data/exe/autocad +3 -0
- data/exe/dgn2pdf +50 -0
- data/exe/pw_print +43 -0
- data/gemfiles/rubocop.gemfile +6 -0
- data/lib/autocad/app.rb +655 -0
- data/lib/autocad/arc.rb +29 -0
- data/lib/autocad/block.rb +141 -0
- data/lib/autocad/block_reference.rb +198 -0
- data/lib/autocad/drawing.rb +426 -0
- data/lib/autocad/element.rb +454 -0
- data/lib/autocad/enumerator.rb +24 -0
- data/lib/autocad/errors.rb +37 -0
- data/lib/autocad/event_handler.rb +30 -0
- data/lib/autocad/filter.rb +168 -0
- data/lib/autocad/layer.rb +41 -0
- data/lib/autocad/line.rb +55 -0
- data/lib/autocad/message_box.rb +95 -0
- data/lib/autocad/model.rb +89 -0
- data/lib/autocad/mtext.rb +110 -0
- data/lib/autocad/paths.rb +29 -0
- data/lib/autocad/point3d.rb +143 -0
- data/lib/autocad/pviewport.rb +21 -0
- data/lib/autocad/selection_filter.rb +180 -0
- data/lib/autocad/selection_set.rb +61 -0
- data/lib/autocad/selection_set_adapter.rb +146 -0
- data/lib/autocad/text.rb +74 -0
- data/lib/autocad/version.rb +5 -0
- data/lib/autocad.rb +161 -0
- data/olegen.rb +341 -0
- data/rbs_collection.lock.yaml +188 -0
- data/rbs_collection.yaml +19 -0
- data/scanner.obj +0 -0
- data/sig/generated/autocad/app.rbs +251 -0
- data/sig/generated/autocad/arc.rbs +17 -0
- data/sig/generated/autocad/block.rbs +63 -0
- data/sig/generated/autocad/block_reference.rbs +59 -0
- data/sig/generated/autocad/drawing.rbs +158 -0
- data/sig/generated/autocad/element.rbs +166 -0
- data/sig/generated/autocad/enumerator.rbs +15 -0
- data/sig/generated/autocad/errors.rbs +23 -0
- data/sig/generated/autocad/event_handler.rbs +14 -0
- data/sig/generated/autocad/filter.rbs +60 -0
- data/sig/generated/autocad/layer.rbs +19 -0
- data/sig/generated/autocad/line.rbs +25 -0
- data/sig/generated/autocad/message_box.rbs +81 -0
- data/sig/generated/autocad/model.rbs +41 -0
- data/sig/generated/autocad/paths.rbs +19 -0
- data/sig/generated/autocad/point3d.rbs +66 -0
- data/sig/generated/autocad/selection_filter.rbs +50 -0
- data/sig/generated/autocad/selection_set.rbs +37 -0
- data/sig/generated/autocad/selection_set_adapter.rbs +28 -0
- data/sig/generated/autocad/text.rbs +19 -0
- data/sig/generated/autocad/text_node.rbs +37 -0
- data/sig/generated/autocad/version.rbs +5 -0
- data/sig/generated/autocad/viewport.rbs +11 -0
- data/sig/generated/autocad.rbs +68 -0
- data/sig/prototype/lib/autocad/app.rbs +34 -0
- data/sig/prototype/lib/autocad/block.rbs +5 -0
- data/sig/prototype/lib/autocad/block_reference.rbs +5 -0
- data/sig/prototype/lib/autocad/drawing.rbs +13 -0
- data/sig/prototype/lib/autocad/element.rbs +9 -0
- data/sig/prototype/lib/autocad/enumerator.rbs +5 -0
- data/sig/prototype/lib/autocad/event_handler.rbs +7 -0
- data/sig/prototype/lib/autocad/model.rbs +5 -0
- data/sig/prototype/lib/autocad/paths.rbs +5 -0
- data/sig/prototype/lib/autocad.rbs +3 -0
- data/temp/autocad.dwg +0 -0
- data/temp/autocad.log +1 -0
- data/temp/event_handler.log +0 -0
- metadata +147 -0
data/lib/autocad/app.rb
ADDED
@@ -0,0 +1,655 @@
|
|
1
|
+
# rbs_inline: enabled
|
2
|
+
|
3
|
+
require_relative "event_handler"
|
4
|
+
require_relative "drawing"
|
5
|
+
require_relative "paths"
|
6
|
+
require_relative "element"
|
7
|
+
require_relative "line"
|
8
|
+
require_relative "text"
|
9
|
+
require_relative "mtext"
|
10
|
+
require_relative "pviewport"
|
11
|
+
require_relative "block"
|
12
|
+
require_relative "block_reference"
|
13
|
+
require_relative "selection_set"
|
14
|
+
|
15
|
+
require "win32ole"
|
16
|
+
module Windows
|
17
|
+
class FileSystem
|
18
|
+
def self.windows_path(path)
|
19
|
+
obj = new
|
20
|
+
obj.windows_path(path)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Convert path to windows path
|
24
|
+
# @rbs path: String, Pathname the path you want to convert
|
25
|
+
def windows_path(path)
|
26
|
+
path = path.to_path if path.respond_to? :to_path
|
27
|
+
fs_object.GetAbsolutePathName(path.to_str)
|
28
|
+
end
|
29
|
+
|
30
|
+
def fs_object
|
31
|
+
@fs_object ||= WIN32OLE.new("Scripting.FileSystemObject")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
module Autocad
|
37
|
+
class App
|
38
|
+
include Common
|
39
|
+
@default_error_proc = ->(e, f) {
|
40
|
+
puts "Couldn't open drawing #{f}" if f
|
41
|
+
debug_error if $DEBUG
|
42
|
+
raise e
|
43
|
+
}
|
44
|
+
|
45
|
+
class << self
|
46
|
+
attr_accessor :default_error_proc
|
47
|
+
|
48
|
+
def default_app_options
|
49
|
+
{visible: false, error_proc: @default_error_proc, wait_time: 500, wait_interval: 0.5}
|
50
|
+
end
|
51
|
+
|
52
|
+
def debug_error
|
53
|
+
require "debug"
|
54
|
+
binding.break
|
55
|
+
end
|
56
|
+
|
57
|
+
# save the current drawing
|
58
|
+
# @rbs dir: String|Pathname -- the dir to save drawing to
|
59
|
+
# @rbs exit: bool -- whether to exit afterwards or start irb
|
60
|
+
# @rbs model: bool -- prints model space instead of paperspace in pdf document
|
61
|
+
# @rbs return void
|
62
|
+
def save_open_drawings(dir: Pathname.getwd, exit: true, model: false)
|
63
|
+
if exit
|
64
|
+
run do |app|
|
65
|
+
return unless app.has_drawings?
|
66
|
+
drawings = app.drawings
|
67
|
+
drawings.each do |d|
|
68
|
+
d.copy(dir:)
|
69
|
+
d.save_as_pdf(dir:, model:)
|
70
|
+
d.close(false)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
else
|
74
|
+
app = App.new
|
75
|
+
return unless app.has_drawings?
|
76
|
+
drawings = app.drawings
|
77
|
+
drawings.each do |d|
|
78
|
+
d.copy(dir:)
|
79
|
+
d.save_as_pdf(dir:, model:)
|
80
|
+
# d.close(false)
|
81
|
+
end
|
82
|
+
app
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# Runs the app, opening the filenames
|
87
|
+
# and yielding each open drawing to the
|
88
|
+
# supplied block
|
89
|
+
# it automatically closes the drawing and
|
90
|
+
# the app when done
|
91
|
+
#
|
92
|
+
# [source]
|
93
|
+
# dir = Pathname.new('C:/templates')
|
94
|
+
# drawings = Pathname.glob(dir + '/**/*.dgn')
|
95
|
+
# App.with_drawings(drawings) do |drawing|
|
96
|
+
# drawing.save_as_pdf(dir: 'c:/output/')
|
97
|
+
# end
|
98
|
+
#
|
99
|
+
# @rbs *files: Array[String|Pathname]
|
100
|
+
# @rbs visible: bool -- show the app window
|
101
|
+
# @rbs error_proc: (Exception, Drawing) -> void
|
102
|
+
# @rbs wait_time: Integer -- the total amount of time to wait to open file (500)
|
103
|
+
# @rbs wait_interval: Float -- the amount of time to wait between attempts (0.5)
|
104
|
+
# @rbs read_only: bool
|
105
|
+
# @rbs &: (Drawing) -> void
|
106
|
+
def with_drawings(*files, visible: false, error_proc: @default_error_proc,
|
107
|
+
wait_time: 500, wait_interval: 0.5, read_only: false, &block)
|
108
|
+
# drawing_options = default_drawing_options.merge(options)
|
109
|
+
# app_options = default_app_options
|
110
|
+
files = files[0] if files[0].is_a? Array
|
111
|
+
begin
|
112
|
+
the_app = new(visible:, error_proc:, wait_time:, wait_interval:)
|
113
|
+
files_enum = files.each
|
114
|
+
loop do
|
115
|
+
file = files_enum.next
|
116
|
+
puts "opening #{file}.."
|
117
|
+
begin
|
118
|
+
the_app.open_drawing(file, read_only:, wait_time:, wait_interval:, error_proc:, &block)
|
119
|
+
the_app.ole_obj.ole_methods # check if server still open
|
120
|
+
rescue => e
|
121
|
+
raise e unless error_proc
|
122
|
+
|
123
|
+
error_proc.call(e, file)
|
124
|
+
the_app = new(visible: opt_visible)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
ensure
|
128
|
+
the_app&.quit
|
129
|
+
the_app = nil
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
# gets all dwg and dgn files in the directory given by
|
134
|
+
# dir_or_file or gets the file given by dir_or_file
|
135
|
+
# and saves them as pdf files in the outdir
|
136
|
+
# @rbs dir_or_file: String the directory of drawing [dgn,dwg] to convert
|
137
|
+
# @rbs outdir: String the output dir for converted pdf files
|
138
|
+
# @rbs return void
|
139
|
+
def dwg2pdf(dir_or_file, outdir: dir_or_file, mode: :dir)
|
140
|
+
raise "Mode on of :dir or :file" unless [:dir, :file].include? mode
|
141
|
+
if mode == :dir
|
142
|
+
drawings = drawings_in_dir(dir_or_file)
|
143
|
+
with_drawings(drawings, read_only: true) do |drawing|
|
144
|
+
drawing.save_as_pdf(name: drawing.name, dir: outdir)
|
145
|
+
end
|
146
|
+
else
|
147
|
+
open_drawing(dir_or_file) do |drawing|
|
148
|
+
drawing.save_as_pdf(name: drawing.name, dir: outdir)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
# Initialize an instance of app with the options
|
154
|
+
# @rbs : Hash] options the options to create the app with
|
155
|
+
# @option options bool :visible Is the app visible
|
156
|
+
#
|
157
|
+
# [source]
|
158
|
+
# ----
|
159
|
+
# App.run do |app|
|
160
|
+
# drawing = app.open_drawing('test.dgn')
|
161
|
+
# drawing.scan_all_text do |model,text|
|
162
|
+
# puts "#{model} #{text}"
|
163
|
+
# end
|
164
|
+
# end
|
165
|
+
# @rbs options: Hash[Symbol,Object]
|
166
|
+
# @rbs &: (App) -> void -- the_app yields the instanciated app
|
167
|
+
def run(options = {}) #: void
|
168
|
+
opts = default_app_options.merge(options)
|
169
|
+
err_fn = opts.fetch(:error_proc, default_error_proc)
|
170
|
+
begin
|
171
|
+
the_app = new(**opts)
|
172
|
+
# binding.break if the_app.nil?
|
173
|
+
yield the_app
|
174
|
+
rescue => e
|
175
|
+
if e.respond_to? :drawing
|
176
|
+
err_fn.call(e, e.drawing)
|
177
|
+
else
|
178
|
+
err_fn.call(e, nil)
|
179
|
+
end
|
180
|
+
ensure
|
181
|
+
the_app&.quit
|
182
|
+
GC.start
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
# Calls #run to get an app instance then call open drawing with
|
187
|
+
# that app
|
188
|
+
# (see #open_drawing)
|
189
|
+
# @rbs &block: { (Drawing) -> void }
|
190
|
+
def open_drawing(drawing, **options, &block) #: void
|
191
|
+
run(**options) do |app|
|
192
|
+
app.open_drawing(drawing, **options, &block)
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
# @rbs return bool -- true if there is an active drawing
|
198
|
+
def active_drawing?
|
199
|
+
ole_obj.Documents.count > 0
|
200
|
+
end
|
201
|
+
|
202
|
+
# @rbs return Drawing | nil -- returns drawing if active_drawing
|
203
|
+
def active_drawing
|
204
|
+
return unless active_drawing?
|
205
|
+
ole = ole_obj.ActiveDocument
|
206
|
+
drawing_from_ole(ole)
|
207
|
+
end
|
208
|
+
|
209
|
+
def drawing_from_ole(ole) #: Drawing
|
210
|
+
Drawing.new(self, ole)
|
211
|
+
end
|
212
|
+
|
213
|
+
attr_reader :error_proc, :visible, :logger
|
214
|
+
|
215
|
+
# Constructor for app
|
216
|
+
# @rbs visible: bool -- do you want the app to be visible
|
217
|
+
# @rbs event_handler: EventHandler
|
218
|
+
def initialize(visible: true, error_proc: self.class.default_error_proc, event_handler: default_event_handler, wait_interval: nil, wait_time: nil)
|
219
|
+
@visible = visible
|
220
|
+
@logger = Logger.new("autocad.log")
|
221
|
+
@event_handler = event_handler
|
222
|
+
@error_proc = error_proc
|
223
|
+
@ole_obj, @app_event = init_ole_and_app_event(visible: @visible, event_handler: @event_handler, tries: 5,
|
224
|
+
sleep_duration: 0.5)
|
225
|
+
@run_loop = true
|
226
|
+
@windows = Windows::FileSystem.new
|
227
|
+
# make_visible(visible)
|
228
|
+
@scanners = {}
|
229
|
+
rescue => e
|
230
|
+
@error_proc.call(e, nil)
|
231
|
+
end
|
232
|
+
|
233
|
+
def windows_path(path)
|
234
|
+
@windows.windows_path(path)
|
235
|
+
end
|
236
|
+
|
237
|
+
def wrap(item, cell = nil)
|
238
|
+
Element.convert_item(item, self, cell)
|
239
|
+
end
|
240
|
+
|
241
|
+
# the default EventHandler
|
242
|
+
#
|
243
|
+
# @rbs return EventHandler -- returns the default EventHandler
|
244
|
+
def default_event_handler
|
245
|
+
event_handler = EventHandler.new
|
246
|
+
# event_handler.add_handler("BeginOpen") do |*args|
|
247
|
+
# puts "begining opening drawing #{args}"
|
248
|
+
# end
|
249
|
+
event_handler.add_handler("EndOpen") do |*args|
|
250
|
+
puts "drawing #{args} opened"
|
251
|
+
@drawing_opened = true
|
252
|
+
end
|
253
|
+
event_handler.add_handler("BeginDocClose") do |*args|
|
254
|
+
@drawing_opened = false
|
255
|
+
puts "drawing #{args} closed"
|
256
|
+
end
|
257
|
+
|
258
|
+
event_handler.add_handler("NewDrawing") do |*args|
|
259
|
+
@drawing_opened = true
|
260
|
+
puts "drawing #{args} created"
|
261
|
+
end
|
262
|
+
event_handler
|
263
|
+
end
|
264
|
+
|
265
|
+
def default_app_options
|
266
|
+
self.class.default_app_options
|
267
|
+
end
|
268
|
+
|
269
|
+
# register an handler
|
270
|
+
#
|
271
|
+
# @rbs event: String -- event to registor for
|
272
|
+
def register_handler(event, &)
|
273
|
+
@event_handler.add_handler(event, &) unless event == "OnQuit"
|
274
|
+
end
|
275
|
+
|
276
|
+
#
|
277
|
+
# return a Handler
|
278
|
+
#
|
279
|
+
# @rbs : String,Symbol] event the event key
|
280
|
+
#
|
281
|
+
# @rbs return Proc returns the Proc given by event name
|
282
|
+
#
|
283
|
+
def get_handler(event)
|
284
|
+
@event_handler.get_handler(event)
|
285
|
+
end
|
286
|
+
|
287
|
+
def load_constants(ole)
|
288
|
+
WIN32OLE.const_load(ole, ACAD) unless ACAD.constants.size > 0
|
289
|
+
end
|
290
|
+
|
291
|
+
def run_loop
|
292
|
+
WIN32OLE_EVENT.message_loop if @run_loop
|
293
|
+
end
|
294
|
+
|
295
|
+
def stop_loop
|
296
|
+
@run_loop = false
|
297
|
+
end
|
298
|
+
|
299
|
+
def exit_message_loop
|
300
|
+
puts "Autocad exiting..."
|
301
|
+
@run_loop = false
|
302
|
+
end
|
303
|
+
|
304
|
+
def visible?
|
305
|
+
@visible
|
306
|
+
end
|
307
|
+
|
308
|
+
def visible=(value)
|
309
|
+
make_visible !!value
|
310
|
+
end
|
311
|
+
|
312
|
+
def make_visible(visible)
|
313
|
+
@visible = visible
|
314
|
+
begin
|
315
|
+
@ole_obj.Visible = visible
|
316
|
+
true
|
317
|
+
rescue
|
318
|
+
false
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
# Zooms the current viewport to display the entire drawing
|
323
|
+
def zoom_all
|
324
|
+
ole_obj.ZoomAll
|
325
|
+
end
|
326
|
+
|
327
|
+
def zoom_center(center, magnify: 1.0)
|
328
|
+
pt = Point3d(center)
|
329
|
+
ole_obj.ZoomCenter(pt.to_ole, magnify.to_f)
|
330
|
+
end
|
331
|
+
|
332
|
+
def zoom_window(pt1, pt2)
|
333
|
+
pt1 = Point3d(pt1)
|
334
|
+
pt2 = Point3d(pt2)
|
335
|
+
ole_obj.ZoomWindow(pt1.to_ole, pt2.to_ole)
|
336
|
+
end
|
337
|
+
|
338
|
+
def zoom_pick_window
|
339
|
+
ole_obj.ZoomPickWindowo
|
340
|
+
end
|
341
|
+
|
342
|
+
def zoom_extents
|
343
|
+
ole_obj.ZoomExtents
|
344
|
+
end
|
345
|
+
|
346
|
+
def zoom_previous
|
347
|
+
ole_obj.ZoomPrevious
|
348
|
+
end
|
349
|
+
|
350
|
+
def zoom_scaled(magnify: 1.0, scale_type: :paper_space)
|
351
|
+
scale_type = case scale_type
|
352
|
+
when :paper_space
|
353
|
+
ACAD::AcZoomScaledRelativePSpace
|
354
|
+
when :absolute
|
355
|
+
ACAD::AcZoomScaledAbsolute
|
356
|
+
when :relative
|
357
|
+
ACAD::AcZoomScaledRelative
|
358
|
+
else
|
359
|
+
ACAD::AcZoomScaledRelative
|
360
|
+
end
|
361
|
+
ole_obj.ZoomScaled(magnify.to_f, scale_type)
|
362
|
+
end
|
363
|
+
|
364
|
+
# Zooms the current viewport to a specific center point and magnify factor
|
365
|
+
# @rbs center: Point3d | [Float, Float, Float| nil] -- center of zoom
|
366
|
+
# @rbs magnify: Float
|
367
|
+
def zoom_center(center, magnify: 1.0)
|
368
|
+
pt = Point3d(center)
|
369
|
+
ole_obj.ZoomCenter(pt.to_ole, magnify.to_f)
|
370
|
+
end
|
371
|
+
|
372
|
+
def ole_obj
|
373
|
+
is_ok = true
|
374
|
+
begin
|
375
|
+
@ole_obj.Visible
|
376
|
+
rescue
|
377
|
+
is_ok = false
|
378
|
+
end
|
379
|
+
|
380
|
+
@ole_obj, @app_event = init_ole_and_app_event(visible: @visible, event_handler: @event_handler, tries: 3) unless is_ok
|
381
|
+
|
382
|
+
@ole_obj
|
383
|
+
end
|
384
|
+
|
385
|
+
def quit
|
386
|
+
close_all_drawings
|
387
|
+
@ole_obj&.Quit
|
388
|
+
rescue
|
389
|
+
nil
|
390
|
+
end
|
391
|
+
|
392
|
+
def close_all_drawings(save: false)
|
393
|
+
return unless @ole_obj
|
394
|
+
until @ole_obj.Documents.Count == 0
|
395
|
+
begin
|
396
|
+
@ole_obj.ActiveDocument.Close(save)
|
397
|
+
rescue
|
398
|
+
break
|
399
|
+
end
|
400
|
+
end
|
401
|
+
end
|
402
|
+
|
403
|
+
def close_active_drawing
|
404
|
+
drawing = active_drawing
|
405
|
+
drawing&.close
|
406
|
+
end
|
407
|
+
|
408
|
+
# create a new drawing
|
409
|
+
#
|
410
|
+
# @rbs filename: String | Pathname -- The name of the drawing.
|
411
|
+
# @rbs seedfile: String -- The name of the seed file.
|
412
|
+
# should not include a path. The default ggextension is ".dgn".
|
413
|
+
# Typical values are "seed2d" or "seed3d".
|
414
|
+
# @rbs open: bool -- If the open argument is True,
|
415
|
+
# CreateDesignFile returns the newly-opened DesignFile object;
|
416
|
+
# this is the same value as ActiveDesignFile. If the Open argument is False,
|
417
|
+
# CreateDesignFile returns Nothing.
|
418
|
+
# @rbs return Drawing, void -- returns the new drawing
|
419
|
+
def new_drawing(filename, open: true, options: {}, &block)
|
420
|
+
opts = default_app_options.merge(options)
|
421
|
+
err_fn = opts.fetch(:error_proc, error_proc)
|
422
|
+
file_path = Pathname.new(filename).expand_path
|
423
|
+
raise ExistingFile, file_path if file_path.exist?
|
424
|
+
|
425
|
+
# drawing_name = normalize_name(filename)
|
426
|
+
# seedfile = determine_seed(seedfile)
|
427
|
+
# binding.break unless seedfile
|
428
|
+
windows_name = windows_path(filename)
|
429
|
+
ole = new_ole_drawing(windows_name, open: open, wait_time: opts[:wait_time], wait_interval: opts[:wait_interval])
|
430
|
+
drawing = drawing_from_ole(ole)
|
431
|
+
return drawing unless block
|
432
|
+
|
433
|
+
begin
|
434
|
+
yield drawing
|
435
|
+
rescue DrawingError => e
|
436
|
+
err_fn.call(e, e.drawing)
|
437
|
+
rescue => e
|
438
|
+
err_fn.call(e, file_path)
|
439
|
+
ensure
|
440
|
+
drawing.close
|
441
|
+
end
|
442
|
+
end
|
443
|
+
|
444
|
+
# open the drawing
|
445
|
+
# @rbs filename: String the name of the file to open
|
446
|
+
# @rbs : bool :read_only (false)
|
447
|
+
# @rbs wait_time: Integer -- the total amount of time to wait to open file (500)
|
448
|
+
# @rbs wait_interval: Float -- the amount of time in seconds to wait before retry (0.5)
|
449
|
+
# @rbs error_proc: Proc -- a proc to run
|
450
|
+
# @rbs &: (Drawing) -> (void)
|
451
|
+
# @rbs return Drawing | void
|
452
|
+
def open_drawing(filename, read_only: false, wait_time: nil,
|
453
|
+
wait_interval: nil, error_proc: nil, &block)
|
454
|
+
file_path = Pathname.new(filename).expand_path
|
455
|
+
raise FileNotFound.new(file_path) unless file_path.file?
|
456
|
+
|
457
|
+
begin
|
458
|
+
ole = ole_open_drawing(windows_path(filename), read_only:, wait_time:, wait_interval:)
|
459
|
+
rescue DrawingError => e
|
460
|
+
raise e unless err_fn
|
461
|
+
|
462
|
+
err_fn.call(e, e.drawing)
|
463
|
+
end
|
464
|
+
drawing = drawing_from_ole(ole)
|
465
|
+
return drawing unless block_given?
|
466
|
+
|
467
|
+
begin
|
468
|
+
yield drawing
|
469
|
+
rescue => e
|
470
|
+
raise e unless err_fn
|
471
|
+
err_fn.call(e, filename)
|
472
|
+
ensure
|
473
|
+
drawing.close
|
474
|
+
end
|
475
|
+
end
|
476
|
+
|
477
|
+
alias_method :doc, :active_drawing
|
478
|
+
|
479
|
+
alias_method :current_drawing, :active_drawing
|
480
|
+
|
481
|
+
def model_space
|
482
|
+
ModelSpace.new(doc_ole.ModelSpace)
|
483
|
+
end
|
484
|
+
|
485
|
+
def paper_space
|
486
|
+
PaperSpace.new(doc_ole.PaperSpace)
|
487
|
+
end
|
488
|
+
|
489
|
+
alias_method :model, :model_space
|
490
|
+
|
491
|
+
# @rbs message: String -- the String to put in Autocad prompt
|
492
|
+
def prompt(message)
|
493
|
+
doc.prompt(message)
|
494
|
+
end
|
495
|
+
|
496
|
+
# @rbs prompt: string -- the string to prompt the user for string
|
497
|
+
# @rbs has_spaces: bool -- whether the string returned can contain spaces
|
498
|
+
def get_input_string(...)
|
499
|
+
doc.get_input_string(...)
|
500
|
+
end
|
501
|
+
|
502
|
+
# @rbs prompt: string -- the string to prompt the user for integer
|
503
|
+
def get_input_integer(...)
|
504
|
+
doc.get_input_integer(...)
|
505
|
+
end
|
506
|
+
|
507
|
+
# In a running Autocad instance, prompts the user for a point.
|
508
|
+
# Uses the prompt argument as the prompt string.
|
509
|
+
# If base_point is provided, it is used as the base point and a
|
510
|
+
# stretched line is drawn from the base point to the returned point.
|
511
|
+
# @rbs prompt: String
|
512
|
+
# @rbs base_point: Array, Point3d, nil
|
513
|
+
# @rbs return [Point3d]
|
514
|
+
def get_point(...)
|
515
|
+
doc.get_point(...)
|
516
|
+
end
|
517
|
+
|
518
|
+
# In autocad prompts the user for a selection.
|
519
|
+
# @rbs prompt: String the prompt that displays in Autocad
|
520
|
+
# @rbs name: String the name of the selection
|
521
|
+
# @rbs return [SelectionSet]
|
522
|
+
def get_selection(prompt: "Select objects", name: "_SS1")
|
523
|
+
prompt(prompt)
|
524
|
+
begin
|
525
|
+
doc_ole.SelectionSets.Item(name).Delete
|
526
|
+
rescue
|
527
|
+
logger.debug("Delete selection failed")
|
528
|
+
end
|
529
|
+
|
530
|
+
selection = doc_ole.SelectionSets.Add(name)
|
531
|
+
selection.SelectOnScreen
|
532
|
+
selection
|
533
|
+
end
|
534
|
+
|
535
|
+
def has_documents?
|
536
|
+
ole_obj.Documents.Count > 0
|
537
|
+
end
|
538
|
+
|
539
|
+
alias_method :has_drawings?, :has_documents?
|
540
|
+
|
541
|
+
# @rbs return Enumerator[Drawing] | void
|
542
|
+
# @rbs &: (Drawing) -> void
|
543
|
+
def documents
|
544
|
+
return to_enum(__callee__) unless block_given?
|
545
|
+
ole_obj.Documents.each { |o| yield Drawing.new(self, o) }
|
546
|
+
end
|
547
|
+
|
548
|
+
alias_method :drawings, :documents
|
549
|
+
|
550
|
+
# @rbs return [bool] true
|
551
|
+
def drawing_opened?
|
552
|
+
@drawing_opened
|
553
|
+
end
|
554
|
+
|
555
|
+
# @rbs return [Pathname] Autocad Files.TemplateDwgPath
|
556
|
+
def templates_path
|
557
|
+
Pathname.new(ole_preferences_files.TemplateDwgPath)
|
558
|
+
end
|
559
|
+
|
560
|
+
def templates
|
561
|
+
return enum_for(:templates) unless block_given?
|
562
|
+
|
563
|
+
templates_path.children.each do |template|
|
564
|
+
yield template if template.file?
|
565
|
+
end
|
566
|
+
end
|
567
|
+
|
568
|
+
# Set Autocad Files.TemplateDwgPath
|
569
|
+
# @rbs path: Pathname, String the location on disk for Autocad templates
|
570
|
+
def template_path=(path)
|
571
|
+
ole_preferences_files.TemplateDwgPath = path.to_s
|
572
|
+
end
|
573
|
+
|
574
|
+
# @rbs return [Array<Pathname>] all paths in Files.SupportPath
|
575
|
+
def support_paths
|
576
|
+
ole_preferences_files.SupportPath.split(";").map { |f| Pathname.new(f) }
|
577
|
+
end
|
578
|
+
|
579
|
+
# @rbs return [Array<Pathname>] all paths in Files.PrinterConfigPath
|
580
|
+
def printer_config_paths
|
581
|
+
ole_preferences_files.PrinterConfigPath.split(";").map { |f| Pathname.new(f) }
|
582
|
+
end
|
583
|
+
|
584
|
+
# from the printer_config_paths, return all plotcfg files
|
585
|
+
# @rbs return [Enumerator[String]]
|
586
|
+
def plot_configs
|
587
|
+
return enum_for(:plot_configs) unless block_given?
|
588
|
+
printer_config_paths.each do |path|
|
589
|
+
path.children.each do |plot|
|
590
|
+
yield plot.to_s if plot.file?
|
591
|
+
end
|
592
|
+
end
|
593
|
+
end
|
594
|
+
|
595
|
+
private
|
596
|
+
|
597
|
+
def ole_preferences_files
|
598
|
+
@ole_preferences_files ||= ole_obj.Preferences.Files
|
599
|
+
end
|
600
|
+
|
601
|
+
def send_command(command)
|
602
|
+
ole_obj.SendCommand command
|
603
|
+
end
|
604
|
+
|
605
|
+
def init_ole_and_app_event(visible: @visible, event_handler: @event_handler, tries: 5, sleep_duration: 1)
|
606
|
+
ole = nil
|
607
|
+
begin
|
608
|
+
ole = WIN32OLE.connect("Autocad.Application")
|
609
|
+
rescue WIN32OLERuntimeError
|
610
|
+
ole = WIN32OLE.new("Autocad.Application")
|
611
|
+
end
|
612
|
+
|
613
|
+
sleep(sleep_duration)
|
614
|
+
# ole.Visible = visible
|
615
|
+
# ole.IsProcessLocked = true
|
616
|
+
load_constants(ole)
|
617
|
+
app_event = WIN32OLE_EVENT.new(ole)
|
618
|
+
app_event.handler = event_handler
|
619
|
+
[ole, app_event]
|
620
|
+
rescue => e
|
621
|
+
tries -= 1
|
622
|
+
sleep_duration += 1.5
|
623
|
+
puts "Error: #{e}. #{tries} tries left."
|
624
|
+
retry if tries.positive?
|
625
|
+
raise e, "unable to init ole app"
|
626
|
+
end
|
627
|
+
|
628
|
+
def doc_ole
|
629
|
+
ole_obj.ActiveDocument
|
630
|
+
end
|
631
|
+
|
632
|
+
def new_ole_drawing(filename, open: true, wait_time: 500, wait_interval: 0.5)
|
633
|
+
ole = ole_obj.Documents.add(filename)
|
634
|
+
wait_drawing_opened(wait_time, wait_interval)
|
635
|
+
return ole if drawing_opened?
|
636
|
+
raise DrawingError.new("New drawing not opened in #{wait_time} seconds", filename)
|
637
|
+
end
|
638
|
+
|
639
|
+
def ole_open_drawing(filename, read_only: false, wait_time: 500, wait_interval: 0.5)
|
640
|
+
ole = ole_obj.Documents.Open(filename, read_only)
|
641
|
+
wait_drawing_opened(wait_time: wait_time, wait_interval: wait_interval)
|
642
|
+
return ole if drawing_opened?
|
643
|
+
raise DrawingError.new("drewing not opened in #{wait_time}", path) unless drawing_opened?
|
644
|
+
end
|
645
|
+
|
646
|
+
def wait_drawing_opened(secs, interval = 1)
|
647
|
+
elapsed = 0
|
648
|
+
while !drawing_opened? && elapsed <= secs
|
649
|
+
elapsed += interval
|
650
|
+
sleep(interval)
|
651
|
+
run_loop
|
652
|
+
end
|
653
|
+
end
|
654
|
+
end
|
655
|
+
end
|
data/lib/autocad/arc.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require_relative "element"
|
2
|
+
|
3
|
+
module Autocad
|
4
|
+
class Arc < Element
|
5
|
+
def length
|
6
|
+
@ole_obj.ArcLength
|
7
|
+
end
|
8
|
+
|
9
|
+
def start_point
|
10
|
+
Point3d(ole_obj.StartPoint)
|
11
|
+
end
|
12
|
+
|
13
|
+
def end_point
|
14
|
+
Point3d(ole_obj.EndPoint)
|
15
|
+
end
|
16
|
+
|
17
|
+
def start_angle
|
18
|
+
@ole_obj.StartAngle
|
19
|
+
end
|
20
|
+
|
21
|
+
def end_angle
|
22
|
+
@ole_obj.EndAngle
|
23
|
+
end
|
24
|
+
|
25
|
+
def total_angle
|
26
|
+
@ole_obj.TotalAngle
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|