Class: Autocad::App

Inherits:
Object
  • Object
show all
Includes:
Common
Defined in:
lib/autocad/app.rb,
lib/autocad/element.rb

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Common

#method_missing

Constructor Details

#initialize(visible: true, error_proc: self.class.default_error_proc, event_handler: default_event_handler, wait_interval: nil, wait_time: nil) ⇒ App

Constructor for app



262
263
264
265
266
267
268
269
270
271
272
273
274
275
# File 'lib/autocad/app.rb', line 262

def initialize(visible: true, error_proc: self.class.default_error_proc, event_handler: default_event_handler, wait_interval: nil, wait_time: nil)
  @visible = visible
  @logger = Logger.new("autocad.log")
  @event_handler = event_handler
  @error_proc = error_proc
  @ole_obj, @app_event = init_ole_and_app_event(visible: @visible, event_handler: @event_handler, tries: 5,
    sleep_duration: 0.5)
  @run_loop = true
  @windows = Windows::FileSystem.new
  #  make_visible(visible)
  @scanners = {}
rescue => e
  @error_proc.call(e, nil)
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class Autocad::Common

Class Attribute Details

.default_error_procObject

Returns the value of attribute default_error_proc.



79
80
81
# File 'lib/autocad/app.rb', line 79

def default_error_proc
  @default_error_proc
end

Instance Attribute Details

#error_procObject

Returns the value of attribute error_proc.



257
258
259
# File 'lib/autocad/app.rb', line 257

def error_proc
  @error_proc
end

#loggerObject (readonly)

Returns the value of attribute logger.



256
257
258
# File 'lib/autocad/app.rb', line 256

def logger
  @logger
end

#visibleObject

Returns the value of attribute visible.



256
257
258
# File 'lib/autocad/app.rb', line 256

def visible
  @visible
end

Class Method Details

.debug_errorObject



85
86
87
88
# File 'lib/autocad/app.rb', line 85

def debug_error
  require "debug"
  binding.break
end

.default_app_optionsObject



81
82
83
# File 'lib/autocad/app.rb', line 81

def default_app_options
  {visible: false, error_proc: @default_error_proc, wait_time: 500, wait_interval: 0.5}
end

.dwg2pdf(dir_or_file, outdir: dir_or_file, mode: :dir) ⇒ Object

gets all dwg and dgn files in the directory given by dir_or_file or gets the file given by dir_or_file and saves them as pdf files in the outdir



176
177
178
179
180
181
182
183
184
185
186
187
188
# File 'lib/autocad/app.rb', line 176

def dwg2pdf(dir_or_file, outdir: dir_or_file, mode: :dir)
  raise "Mode on of :dir or :file" unless [:dir, :file].include? mode
  if mode == :dir
    drawings = drawings_in_dir(dir_or_file)
    with_drawings(drawings, read_only: true) do |drawing|
      drawing.save_as_pdf(name: drawing.name, dir: outdir)
    end
  else
    open_drawing(dir_or_file) do |drawing|
      drawing.save_as_pdf(name: drawing.name, dir: outdir)
    end
  end
end

.open_drawing(drawing, **options, &block) ⇒ Object

Calls #run to get an app instance then call open drawing with that app (see #open_drawing)



227
228
229
230
231
# File 'lib/autocad/app.rb', line 227

def open_drawing(drawing, **options, &block) #: void
  run(**options) do |app|
    app.open_drawing(drawing, **options, &block)
  end
end

.run(options = {}) ⇒ Object

Initialize an instance of app with the options

source

App.run do |app|

drawing = app.open_drawing('test.dgn')
drawing.scan_all_text do |model,text|
puts "#{model} #{text}"
end

end

Parameters:

  • options (Hash) (defaults to: {})

    a customizable set of options

Options Hash (options):

  • bool (Object)

    :visible Is the app visible



204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
# File 'lib/autocad/app.rb', line 204

def run(options = {}) #: void
  opts = default_app_options.merge(options)
  err_fn = opts.fetch(:error_proc, default_error_proc)
  begin
    the_app = new(**opts)
    # binding.break if the_app.nil?
    yield the_app
  rescue => e
    if e.respond_to? :drawing
      err_fn.call(e, e.drawing)
    else
      err_fn.call(e, nil)
    end
  ensure
    the_app&.quit
    GC.start
  end
end

.save_open_drawings(dir: Pathname.getwd, exit: true, model: false) ⇒ Object

save the current drawing



95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/autocad/app.rb', line 95

def save_open_drawings(dir: Pathname.getwd, exit: true, model: false)
  if exit
    run do |app|
      return unless app.has_drawings?
      drawings = app.drawings
      drawings.each do |d|
        d.copy(dir:)
        d.save_as_pdf(dir:, model:)
        d.close(false)
      end
    end
  else
    app = App.new
    return unless app.has_drawings?
    drawings = app.drawings
    drawings.each do |d|
      d.copy(dir:)
      d.save_as_pdf(dir:, model:)
      # d.close(false)
    end
    app
  end
end

.with_drawings(*files, visible: false, error_proc: @default_error_proc, wait_time: 500, wait_interval: 0.5, read_only: false, &block) ⇒ Object

Runs the app, opening the filenames and yielding each open drawing to the supplied block it automatically closes the drawing and the app when done

source

dir = Pathname.new(‘C:/templates’) drawings = Pathname.glob(dir + ‘/*/.dgn’) App.with_drawings(drawings) do |drawing|

drawing.save_as_pdf(dir: 'c:/output/')

end



139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/autocad/app.rb', line 139

def with_drawings(*files, visible: false, error_proc: @default_error_proc,
  wait_time: 500, wait_interval: 0.5, read_only: false, &block)
  # drawing_options = default_drawing_options.merge(options)
  # app_options = default_app_options
  files = files[0] if files[0].is_a? Array
  begin
    the_app = new(visible:, error_proc:, wait_time:, wait_interval:)
    files_enum = files.each
    loop do
      file = files_enum.next
      puts "opening #{file}.."
      begin
        the_app.open_drawing(file, read_only:, wait_time:, wait_interval:, error_proc:, &block)
        the_app.ole_obj.ole_methods # check if server still open
      rescue DrawingClose => e
        # Handle DrawingClose errors specifically
        error_proc.call(e, e.drawing_name)
        next # Continue to the next drawing
      rescue => e
        raise e unless error_proc

        error_proc.call(e, file)
        the_app = new(visible: visible)
      end
    end
  ensure
    the_app&.quit
    the_app = nil
  end
end

Instance Method Details

#active_drawingObject Also known as: doc, current_drawing



240
241
242
243
244
# File 'lib/autocad/app.rb', line 240

def active_drawing
  return unless active_drawing?
  ole = ole_obj.ActiveDocument
  drawing_from_ole(ole)
end

#active_drawing=(drawing) ⇒ Object



248
249
250
# File 'lib/autocad/app.rb', line 248

def active_drawing=(drawing)
  ole_obj.ActiveDocument = drawing.ole_obj
end

#active_drawing?Boolean

Returns:

  • (Boolean)


235
236
237
# File 'lib/autocad/app.rb', line 235

def active_drawing?
  ole_obj.Documents.count > 0
end

#close_active_drawingObject



491
492
493
494
# File 'lib/autocad/app.rb', line 491

def close_active_drawing
  drawing = active_drawing
  drawing&.close
end

#close_all_drawings(save: false) ⇒ Object



449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
# File 'lib/autocad/app.rb', line 449

def close_all_drawings(save: false)
  return unless @ole_obj
  begin
    # Get a count first since the collection will change as we close drawings
    count = @ole_obj.Documents.Count
    count.times do |i|
      # Always close the first one since the collection shifts
      begin
        doc = @ole_obj.Documents.Item(0)
        doc.Close(save) if doc
      rescue StandardError => e
        puts "Error closing document: #{document.name} #{e.message}"
        break
      end
    end
  rescue StandardError => e
    puts "Error in close_all_drawings: #{e.message}"
  end
end

#close_drawing(drawing, save = true) ⇒ Object

Close a specific drawing



472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
# File 'lib/autocad/app.rb', line 472

def close_drawing(drawing, save = true)
  begin
    # Get the drawing name
    drawing_name = drawing.is_a?(String) ? drawing : (drawing.respond_to?(:name) ? drawing.name : nil)
    return unless drawing_name

    # Try to find the drawing in the Documents collection and close it
    ole_obj.Documents.each do |doc|
      if doc.Name == drawing_name
        doc.Close(save)
        puts "Successfully closed drawing #{drawing_name}"
        break
      end
    end
  rescue StandardError => e
    puts "Error in close_drawing #{drawing_name}: #{e.message}"
  end
end

#default_app_optionsObject



322
323
324
# File 'lib/autocad/app.rb', line 322

def default_app_options
  self.class.default_app_options
end

#default_event_handlerObject

the default EventHandler



301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
# File 'lib/autocad/app.rb', line 301

def default_event_handler
  event_handler = EventHandler.new
  # event_handler.add_handler("BeginOpen") do |*args|
  #   puts "begining opening drawing #{args}"
  # end
  event_handler.add_handler("EndOpen") do |*args|
    puts "drawing #{args} opened"
    @drawing_opened = true
  end
  event_handler.add_handler("BeginDocClose") do |*args|
    @drawing_opened = false
    puts "drawing #{args} closed"
  end

  event_handler.add_handler("NewDrawing") do |*args|
    @drawing_opened = true
    puts "drawing #{args} created"
  end
  event_handler
end

#documentsObject Also known as: drawings



632
633
634
635
# File 'lib/autocad/app.rb', line 632

def documents
  return to_enum(__callee__) unless block_given?
  ole_obj.Documents.each { |o| yield Drawing.new(self, o) }
end

#drawing_from_ole(ole, requested_name = nil) ⇒ Object

: Drawing



252
253
254
# File 'lib/autocad/app.rb', line 252

def drawing_from_ole(ole, requested_name = nil) #: Drawing
  Drawing.new(self, ole, requested_name)
end

#drawing_opened?Boolean

Returns:

  • (Boolean)


640
641
642
# File 'lib/autocad/app.rb', line 640

def drawing_opened?
  @drawing_opened
end

#exit_message_loopObject



356
357
358
359
# File 'lib/autocad/app.rb', line 356

def exit_message_loop
  puts "Autocad exiting..."
  @run_loop = false
end

#get_handler(event) ⇒ Object

return a Handler



340
341
342
# File 'lib/autocad/app.rb', line 340

def get_handler(event)
  @event_handler.get_handler(event)
end

#get_input_integerObject



592
593
594
# File 'lib/autocad/app.rb', line 592

def get_input_integer(...)
  doc.get_input_integer(...)
end

#get_input_stringObject



587
588
589
# File 'lib/autocad/app.rb', line 587

def get_input_string(...)
  doc.get_input_string(...)
end

#get_pointObject

In a running Autocad instance, prompts the user for a point. Uses the prompt argument as the prompt string. If base_point is provided, it is used as the base point and a stretched line is drawn from the base point to the returned point.



603
604
605
# File 'lib/autocad/app.rb', line 603

def get_point(...)
  doc.get_point(...)
end

#get_selection(prompt: "Select objects", name: "_SS1") ⇒ Object

In autocad prompts the user for a selection.



611
612
613
614
615
616
617
618
619
620
621
622
# File 'lib/autocad/app.rb', line 611

def get_selection(prompt: "Select objects", name: "_SS1")
  prompt(prompt)
  begin
    doc_ole.SelectionSets.Item(name).Delete
  rescue
    logger.debug("Delete selection failed")
  end

  selection = doc_ole.SelectionSets.Add(name)
  selection.SelectOnScreen
  selection
end

#has_documents?Boolean Also known as: has_drawings?

Returns:

  • (Boolean)


624
625
626
# File 'lib/autocad/app.rb', line 624

def has_documents?
  ole_obj.Documents.Count > 0
end

#load_constants(ole) ⇒ Object



344
345
346
# File 'lib/autocad/app.rb', line 344

def load_constants(ole)
  WIN32OLE.const_load(ole, ACAD) unless ACAD.constants.size > 0
end

#make_visible(visible) ⇒ Object



369
370
371
372
373
374
375
376
377
# File 'lib/autocad/app.rb', line 369

def make_visible(visible)
  @visible = visible
  begin
    @ole_obj.Visible = visible
    true
  rescue
    false
  end
end

#new_drawing(filename, open: true, options: {}, &block) ⇒ Object

create a new drawing

Raises:



507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
# File 'lib/autocad/app.rb', line 507

def new_drawing(filename, open: true, options: {}, &block)
  opts = default_app_options.merge(options)
  err_fn = opts.fetch(:error_proc, error_proc)
  file_path = Pathname.new(filename).expand_path
  raise ExistingFile, file_path if file_path.exist?

  # drawing_name = normalize_name(filename)
  # seedfile = determine_seed(seedfile)
  # binding.break unless seedfile
  windows_name = windows_path(filename)
  ole = new_ole_drawing(windows_name, open: open, wait_time: opts[:wait_time], wait_interval: opts[:wait_interval])
  drawing = Drawing.new(self, ole, filename)
  return drawing unless block

  begin
    yield drawing
  rescue DrawingError => e
    err_fn.call(e, e.drawing)
  rescue => e
    err_fn.call(e, file_path)
  ensure
    drawing.close
  end
end

#ole_objObject



429
430
431
432
433
434
435
436
437
438
439
440
# File 'lib/autocad/app.rb', line 429

def ole_obj
  is_ok = true
  begin
    @ole_obj.Visible
  rescue
    is_ok = false
  end

  @ole_obj, @app_event = init_ole_and_app_event(visible: @visible, event_handler: @event_handler, tries: 3) unless is_ok

  @ole_obj
end

#ole_to_ruby(ole) ⇒ Object



601
602
603
# File 'lib/autocad/element.rb', line 601

def ole_to_ruby(ole)
  Element.convert_item(ole, self)
end

#open_drawing(filename, read_only: false, wait_time: nil, wait_interval: nil, error_proc: nil, &block) ⇒ Object

open the drawing

Raises:



540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
# File 'lib/autocad/app.rb', line 540

def open_drawing(filename, read_only: false, wait_time: nil,
  wait_interval: nil, error_proc: nil, &block)
  file_path = Pathname.new(filename).expand_path
  raise FileNotFound.new(file_path) unless file_path.file?

  err_fn = error_proc || @error_proc

  begin
    ole = ole_open_drawing(windows_path(filename), read_only:, wait_time:, wait_interval:)
  rescue DrawingError => e
    raise e unless err_fn
    err_fn.call(e, e.drawing)
    return nil
  end

  drawing = drawing_from_ole(ole)
  return drawing unless block_given?

  begin
    yield drawing
  rescue DrawingClose => e
    # Handle DrawingClose errors specifically
    err_fn.call(e, e.drawing_name)
    return nil
  rescue => e
    raise e unless err_fn
    err_fn.call(e, filename)
  ensure
    begin
      drawing.close unless drawing.nil? || drawing.instance_variable_get(:@drawing_closed)
    rescue DrawingClose => e
      err_fn.call(e, e.drawing_name)
    end
  end
end

#plot_configsObject

from the printer_config_paths, return all plotcfg files



685
686
687
688
689
690
691
692
# File 'lib/autocad/app.rb', line 685

def plot_configs
  return enum_for(:plot_configs) unless block_given?
  printer_config_paths.each do |path|
    path.children.each do |plot|
      yield plot.to_s if plot.file?
    end
  end
end

#printer_config_pathsObject



679
680
681
# File 'lib/autocad/app.rb', line 679

def printer_config_paths
  ole_preferences_files.PrinterConfigPath.split(";").map { |f| Pathname.new(f) }
end

#prompt(message) ⇒ Object



581
582
583
# File 'lib/autocad/app.rb', line 581

def prompt(message)
  doc.prompt(message)
end

#quitObject



442
443
444
445
446
447
# File 'lib/autocad/app.rb', line 442

def quit
  close_all_drawings
  @ole_obj&.Quit
rescue
  nil
end

#register_handler(event) ⇒ Object

register an handler



329
330
331
# File 'lib/autocad/app.rb', line 329

def register_handler(event, &)
  @event_handler.add_handler(event, &) unless event == "OnQuit"
end

#run_loopObject



348
349
350
# File 'lib/autocad/app.rb', line 348

def run_loop
  WIN32OLE_EVENT.message_loop if @run_loop
end

#save_open_drawings(dir: Pathname.getwd, model: false) ⇒ Object

save the current drawing



281
282
283
284
285
286
287
288
# File 'lib/autocad/app.rb', line 281

def save_open_drawings(dir: Pathname.getwd, model: false)
  return unless has_drawings?
  drawings.each do |d|
    d.copy(dir:)
    d.save_as_pdf(dir:, model:)
    # d.close(false)
  end
end

#stop_loopObject



352
353
354
# File 'lib/autocad/app.rb', line 352

def stop_loop
  @run_loop = false
end

#support_path_filesObject



668
669
670
671
672
673
674
675
676
# File 'lib/autocad/app.rb', line 668

def support_path_files
  return enum_for(:support_path_files) unless block_given?

  support_paths.each do |path|
    path.children.each do |file|
      yield file if file.file?
    end
  end
end

#support_pathsObject



664
665
666
# File 'lib/autocad/app.rb', line 664

def support_paths
  ole_preferences_files.SupportPath.split(";").map { |f| Pathname.new(f) }
end

#template_path=(path) ⇒ Object

Set Autocad Files.TemplateDwgPath



659
660
661
# File 'lib/autocad/app.rb', line 659

def template_path=(path)
  ole_preferences_files.TemplateDwgPath = path.to_s
end

#templatesObject



649
650
651
652
653
654
655
# File 'lib/autocad/app.rb', line 649

def templates
  return enum_for(:templates) unless block_given?

  templates_path.children.each do |template|
    yield template if template.file?
  end
end

#templates_pathObject



645
646
647
# File 'lib/autocad/app.rb', line 645

def templates_path
  Pathname.new(ole_preferences_files.TemplateDwgPath)
end

#visible?Boolean

Returns:

  • (Boolean)


361
362
363
# File 'lib/autocad/app.rb', line 361

def visible?
  @visible
end

#windows_path(path) ⇒ Object



290
291
292
# File 'lib/autocad/app.rb', line 290

def windows_path(path)
  @windows.windows_path(path)
end

#wrap(item, cell = nil) ⇒ Object



294
295
296
# File 'lib/autocad/app.rb', line 294

def wrap(item, cell = nil)
  Element.convert_item(item, self, cell)
end

#zoom_allObject

Zooms the current viewport to display the entire drawing



380
381
382
# File 'lib/autocad/app.rb', line 380

def zoom_all
  ole_obj.ZoomAll
end

#zoom_center(center, magnify: 1.0) ⇒ Object

Zooms the current viewport to a specific center point and magnify factor



424
425
426
427
# File 'lib/autocad/app.rb', line 424

def zoom_center(center, magnify: 1.0)
  pt = Point3d(center)
  ole_obj.ZoomCenter(pt.to_ole, magnify.to_f)
end

#zoom_extentsObject



399
400
401
# File 'lib/autocad/app.rb', line 399

def zoom_extents
  ole_obj.ZoomExtents
end

#zoom_pick_windowObject



395
396
397
# File 'lib/autocad/app.rb', line 395

def zoom_pick_window
  ole_obj.ZoomPickWindow
end

#zoom_previousObject



403
404
405
# File 'lib/autocad/app.rb', line 403

def zoom_previous
  ole_obj.ZoomPrevious
end

#zoom_scaled(magnify = 1.0, scale_type: :relative) ⇒ Object



407
408
409
410
411
412
413
414
415
416
417
418
419
# File 'lib/autocad/app.rb', line 407

def zoom_scaled(magnify = 1.0, scale_type: :relative)
  scale_type = case scale_type
  when :paper_space
    ACAD::AcZoomScaledRelativePSpace
  when :absolute
    ACAD::AcZoomScaledAbsolute
  when :relative
    ACAD::AcZoomScaledRelative
  else
    ACAD::AcZoomScaledRelative
  end
  ole_obj.ZoomScaled(magnify.to_f, scale_type)
end

#zoom_window(pt1, pt2) ⇒ Object



389
390
391
392
393
# File 'lib/autocad/app.rb', line 389

def zoom_window(pt1, pt2)
  pt1 = Point3d(pt1)
  pt2 = Point3d(pt2)
  ole_obj.ZoomWindow(pt1.to_ole, pt2.to_ole)
end