microstation 0.4.1 → 0.8.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (110) hide show
  1. checksums.yaml +7 -0
  2. data/.autotest +23 -23
  3. data/.rspec +2 -2
  4. data/Gemfile +29 -10
  5. data/History.txt +6 -6
  6. data/LICENSE.adoc +22 -0
  7. data/Manifest.txt +91 -60
  8. data/README.adoc +131 -0
  9. data/Rakefile +72 -30
  10. data/bin/dgn2pdf +36 -37
  11. data/bin/dgn_template +107 -0
  12. data/bin/pw_print +35 -0
  13. data/cad_files/drawing_faatitle_in_non_default_model.dgn +0 -0
  14. data/cad_files/drawing_no_block.dgn +0 -0
  15. data/cad_files/drawing_with_3_block.dgn +0 -0
  16. data/cad_files/drawing_with_block.dgn +0 -0
  17. data/cad_files/drawing_with_text.dgn +0 -0
  18. data/cad_files/seed2d.dgn +0 -0
  19. data/cad_files/seed3d.dgn +0 -0
  20. data/lib/microstation/app.rb +781 -286
  21. data/lib/microstation/cad_input_queue.rb +100 -25
  22. data/lib/microstation/cell.rb +191 -0
  23. data/lib/microstation/changer.rb +70 -0
  24. data/lib/microstation/configuration.rb +193 -57
  25. data/lib/microstation/criteria_creation_t.rb +23 -0
  26. data/lib/microstation/dir.rb +252 -252
  27. data/lib/microstation/directory.rb +46 -0
  28. data/lib/microstation/drawing.rb +686 -189
  29. data/lib/microstation/element.rb +311 -0
  30. data/lib/microstation/enumerator.rb +32 -29
  31. data/lib/microstation/errors.rb +17 -0
  32. data/lib/microstation/event_handler.rb +28 -0
  33. data/lib/microstation/ext/pathname.rb +23 -25
  34. data/lib/microstation/ext/win32ole.rb +7 -0
  35. data/lib/microstation/extensions/faa.rb +124 -0
  36. data/lib/microstation/file_tests.rb +68 -0
  37. data/lib/microstation/functions.rb +60 -0
  38. data/lib/microstation/graphics.rb +35 -0
  39. data/lib/microstation/line.rb +19 -0
  40. data/lib/microstation/model.rb +45 -0
  41. data/lib/microstation/model_trait.rb +189 -0
  42. data/lib/microstation/ole_cad_input_message.rb +101 -0
  43. data/lib/microstation/ole_helper.rb +152 -0
  44. data/lib/microstation/pdf_support.rb +40 -40
  45. data/lib/microstation/point3d.rb +71 -0
  46. data/lib/microstation/primitive_command_interface.rb +66 -0
  47. data/lib/microstation/properties.rb +61 -57
  48. data/lib/microstation/property_handler.rb +48 -0
  49. data/lib/microstation/scan/color.rb +38 -38
  50. data/lib/microstation/scan/criteria.rb +89 -85
  51. data/lib/microstation/scan/klass.rb +43 -43
  52. data/lib/microstation/scan/level.rb +38 -38
  53. data/lib/microstation/scan/line_style.rb +45 -45
  54. data/lib/microstation/scan/line_weight.rb +33 -33
  55. data/lib/microstation/scan/range.rb +19 -0
  56. data/lib/microstation/scan/scan_trait.rb +51 -0
  57. data/lib/microstation/scan/subtype.rb +40 -40
  58. data/lib/microstation/scan/type.rb +134 -109
  59. data/lib/microstation/scan_trait.rb +62 -0
  60. data/lib/microstation/scanner.rb +24 -24
  61. data/lib/microstation/tag.rb +87 -58
  62. data/lib/microstation/tag_set.rb +385 -280
  63. data/lib/microstation/tag_set_trait.rb +51 -0
  64. data/lib/microstation/tagged_element.rb +105 -0
  65. data/lib/microstation/template.rb +90 -84
  66. data/lib/microstation/template_info.rb +172 -0
  67. data/lib/microstation/template_runner.rb +65 -0
  68. data/lib/microstation/text.rb +79 -54
  69. data/lib/microstation/text_node.rb +124 -74
  70. data/lib/microstation/ts/attribute.rb +140 -139
  71. data/lib/microstation/ts/instance.rb +146 -112
  72. data/lib/microstation/ts/tagset_trait.rb +49 -0
  73. data/lib/microstation/types.rb +91 -91
  74. data/lib/microstation/version.rb +5 -0
  75. data/lib/microstation/wrap.rb +28 -214
  76. data/lib/microstation.rb +252 -88
  77. data/plot/pdf-bw.plt +164 -164
  78. data/plot/pdf.plt +163 -163
  79. data/plot/png.plt +383 -383
  80. data/plot/tiff.plt +384 -384
  81. data/plot/wmbw.tbl +324 -66
  82. data/plot/wmcolor.tbl +62 -62
  83. data/spec/microstation/app_spec.rb +184 -0
  84. data/spec/microstation/configuration_spec.rb +131 -0
  85. data/spec/microstation/drawing_spec.rb +245 -0
  86. data/spec/microstation/functions_spec.rb +36 -0
  87. data/spec/microstation/tag_set_spec.rb +159 -0
  88. data/spec/microstation/template_spec.rb +159 -0
  89. data/spec/microstation/text_node_spec.rb +67 -0
  90. data/spec/microstation/text_spec.rb +42 -0
  91. data/spec/microstation_spec.rb +47 -36
  92. data/spec/spec_helper.rb +97 -31
  93. metadata +308 -84
  94. data/.gemtest +0 -0
  95. data/README.txt +0 -75
  96. data/lib/microstation/attributes.rb +0 -35
  97. data/lib/microstation/extensions/hash.rb +0 -27
  98. data/spec/app_spec.rb +0 -267
  99. data/spec/configuration_spec.rb +0 -122
  100. data/spec/drawing_spec.rb +0 -247
  101. data/spec/drawings/new_drawing.dgn +0 -0
  102. data/spec/drawings/test.dgn +0 -0
  103. data/spec/drawings/test1.dgn +0 -0
  104. data/spec/drawings/testfile.pdf +0 -0
  105. data/spec/enumerator_spec.rb +0 -60
  106. data/spec/scanner_spec.rb +0 -155
  107. data/spec/spec_app.rb +0 -11
  108. data/spec/tag_set_spec.rb +0 -123
  109. data/spec/text_node_spec.rb +0 -92
  110. data/spec/text_spec.rb +0 -62
@@ -1,286 +1,781 @@
1
- require_relative 'wrap'
2
-
3
- module Windows
4
-
5
- class FileSystem
6
-
7
- def self.windows_path(path)
8
- obj = new
9
- obj.windows_path(path)
10
- end
11
-
12
- def fs_object
13
- @fs_object ||= WIN32OLE.new('Scripting.FileSystemObject')
14
- end
15
-
16
- def windows_path(path)
17
- path = path.to_path if path.respond_to? :to_path
18
- fs_object.GetAbsolutePathName(path.to_str)
19
- end
20
-
21
- end
22
- end
23
-
24
- module Microstation
25
-
26
- module MSD
27
- end
28
-
29
- def self.win_fs
30
- @windows_fs ||= Windows::FileSystem.new
31
- end
32
-
33
- class App
34
-
35
- include Wrap
36
-
37
- def self.run(options={})
38
- begin
39
- the_app = new(options)
40
-
41
- yield the_app
42
- ensure
43
- the_app.quit
44
- end
45
- end
46
-
47
- def self.open_drawing(drawing,options={},&block)
48
- self.run(options) do |app|
49
- app.open_drawing(drawing,options,&block)
50
- end
51
- end
52
-
53
- def self.with_drawings(*files,&block)
54
- files = files[0] if files[0].kind_of? Array
55
- opts = {:read_only => true}
56
- self.run do |app|
57
- files.each do |file|
58
- puts "opening #{file}.."
59
- app.open_drawing(file,opts) do |draw|
60
- block.call draw
61
- end
62
-
63
- end
64
- end
65
- end
66
-
67
- def load_constants
68
- WIN32OLE.const_load(@ole_obj, MSD) unless MSD.constants.size > 0
69
- end
70
-
71
- attr_reader :scanners
72
-
73
- def initialize(options = {})
74
- visible = options.fetch(:visible){ true }
75
-
76
- @ole_obj = WIN32OLE.new('MicrostationDGN.Application')
77
- @windows = Windows::FileSystem.new
78
- make_visible(visible)
79
- @scanners = []
80
- end
81
-
82
- def visible?
83
- @visible
84
- end
85
-
86
- def project_dir
87
- @project_dir
88
- end
89
-
90
- def project_dir=(dir)
91
- @project_dir = dir ? Pathname.new(dir) : dir
92
- end
93
-
94
- def base_dir
95
- project_dir ? project_dir : Pathname.getwd
96
- end
97
-
98
- def normalize_name(name)
99
- name = Pathname.new(name) unless name.kind_of? Pathname
100
- name = name.ext('.dgn') unless name.extname.to_s == /\.(dgn|dwg)$/
101
- return (base_dir + name).expand_path
102
- end
103
-
104
- def make_visible(visible)
105
- @visible = visible
106
- @ole_obj.Visible = @visible
107
- end
108
-
109
- attr_reader :ole_obj
110
-
111
- # def method_missing(name,*args,&block)
112
- # @ole_obj.send(name,*args,&block)
113
- # end
114
-
115
- def with_drawing(drawing)
116
- begin
117
- yield drawing
118
- ensure
119
- drawing.close
120
- end
121
- end
122
-
123
- def with_template(template)
124
- template = Template.new(template,self)
125
- yield template
126
- template = nil
127
- end
128
-
129
- def open_drawing(filename,options = {})
130
- filename = Pathname(filename)
131
- raise FileNotFound unless filename.file?
132
- readonly = options.fetch(:read_only){ false}
133
- ole = @ole_obj.OpenDesignFile(windows_path(filename), "ReadOnly" => readonly)
134
- drawing = drawing_from_ole(ole)
135
- return drawing unless block_given?
136
- begin
137
- yield drawing
138
- rescue
139
- puts "got error"
140
- ensure
141
- drawing.close
142
- end
143
-
144
- end
145
-
146
- def windows_path(path)
147
- @windows.windows_path(path)
148
- end
149
-
150
- def active_workspace
151
- @ole_obj.ActiveWorkspace
152
- end
153
-
154
- def configuration
155
- @config ||= Microstation::Configuration.new(self)
156
- end
157
-
158
- def username
159
- configuration["USERNAME"]
160
- end
161
-
162
- # seedfile A String expression. The name of the seed file. Should not include a path. The default extension is ".dgn".
163
- # Typical values are "seed2d" or "seed3d".
164
- # open
165
- # If the open argument is True, CreateDesignFile returns the newly-opened DesignFile object; this is the same value as
166
- # ActiveDesignFile. If the Open argument is False, CreateDesignFile returns Nothing.
167
- def new_drawing(filename, seedfile=nil ,open = true,&block)
168
- #drawing_name = normalize_name(filename)
169
- seedfile = determine_seed(seedfile)
170
- windows_name = windows_path(filename)
171
- ole = @ole_obj.CreateDesignFile(seedfile, windows_name, open)
172
- drawing = drawing_from_ole(ole)
173
- return drawing unless block_given?
174
- begin
175
- yield drawing
176
- rescue
177
- ensure
178
- drawing.close
179
- end
180
-
181
- end
182
-
183
- def drawing_from_ole(ole)
184
- Drawing.new(self,ole)
185
- end
186
-
187
- def determine_seed(seedfile)
188
- return "seed2d" unless seedfile
189
- return windows_path( File.expand_path(seedfile))
190
- end
191
-
192
- def eval_cexpression(string)
193
- @ole_obj.GetCExpressionValue(string)
194
- end
195
-
196
- def quit
197
- active_design_file.close if active_file?
198
- @scanners.each{|sc| sc.close}
199
- @ole_obj.quit
200
- end
201
-
202
- def active_design_file
203
- ole = @ole_obj.ActiveDesignFile rescue nil
204
- drawing_from_ole(ole) if ole
205
- end
206
-
207
- def current_drawing
208
- active_design_file
209
- end
210
-
211
- # alias :current_drawing :active_design_file
212
-
213
- def close_active_drawing
214
- active_design_file.close if active_design_file
215
- end
216
-
217
- def active_file?
218
- !!active_design_file
219
- end
220
-
221
- def file_exists?(file)
222
- File.file?( File.expand_path(file) )
223
- end
224
-
225
- def create_scanner(&block)
226
- Microstation::Scan::Criteria.create_scanner(self,&block)
227
- end
228
-
229
- def find_by_id(id)
230
- model = active_model_reference.GetElementById64(id)
231
- wrap(model)
232
- end
233
-
234
- def scan(criteria = nil)
235
- result = []
236
- raise 'NoActiveModel' unless active_model_reference
237
- if criteria
238
- criteria.resolve
239
- ee = active_model_reference.Scan(criteria.ole_obj)
240
- else
241
- ee = active_model_reference.Scan(nil)
242
- end
243
- scan_result = Microstation::Enumerator.new ee
244
- return scan_result.to_enum unless block_given?
245
- scan_result.each do |item|
246
- yield item
247
- end
248
- nil
249
- end
250
-
251
- def cad_input_queue
252
- queue = init_cad_input_queue
253
- return queue unless block_given?
254
- begin
255
- yield queue
256
- rescue
257
-
258
- ensure
259
- queue.close
260
- queue = nil
261
- end
262
- end
263
-
264
- def can_open?(filename)
265
- ext = File.extname(filename)
266
- (ext == ".dwg") || (ext == ".dgn")
267
- end
268
-
269
- def active_model_reference
270
- @ole_obj.ActiveModelReference rescue nil
271
- end
272
-
273
- private
274
-
275
-
276
-
277
-
278
- def init_cad_input_queue
279
- Microstation::CadInputQueue.new(@ole_obj.CadInputQueue)
280
- end
281
-
282
-
283
- end
284
-
285
- end
286
-
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'wrap'
4
+ require_relative 'point3d'
5
+ require_relative 'event_handler'
6
+ require_relative 'functions'
7
+ require 'pry'
8
+
9
+ class WIN32OLE
10
+ def ole_obj
11
+ self
12
+ end
13
+ end
14
+
15
+ module Windows
16
+ class FileSystem
17
+ def self.windows_path(path)
18
+ obj = new
19
+ obj.windows_path(path)
20
+ end
21
+
22
+ def fs_object
23
+ @fs_object ||= WIN32OLE.new('Scripting.FileSystemObject')
24
+ end
25
+
26
+ def windows_path(path)
27
+ path = path.to_path if path.respond_to? :to_path
28
+ fs_object.GetAbsolutePathName(path.to_str)
29
+ end
30
+ end
31
+ end
32
+
33
+ module Microstation
34
+ module MSD
35
+ end
36
+
37
+ def self.win_fs
38
+ @windows_fs ||= Windows::FileSystem.new
39
+ end
40
+
41
+ class App
42
+ include Functions
43
+
44
+
45
+ @default_app_options = { visible: false }
46
+
47
+ class << self
48
+
49
+ attr_accessor :default_app_options
50
+
51
+ # include Wrap
52
+
53
+ # Initialize an instance of app with the options
54
+ # @param [Hash] options the options to create the app with
55
+ # @option options [Boolean] :visible Is the app visible
56
+ #
57
+ # [source]
58
+ # ----
59
+ # App.run do |app|
60
+ # drawing = app.open_drawing('test.dgn')
61
+ # drawing.scan_all_text do |model,text|
62
+ # puts "#{model} #{text}"
63
+ # end
64
+ # end
65
+ #
66
+ # @yield [App] the_app yields the instanciated app
67
+ # @return [void]
68
+ def run(options = {})
69
+ opts = self.default_app_options.merge(options)
70
+ begin
71
+ the_app = new(**opts)
72
+ binding.pry if the_app.nil?
73
+ yield the_app
74
+ rescue StandardError
75
+ binding.pry
76
+ ensure
77
+ the_app.quit if the_app.respond_to? :quit
78
+ the_app = nil
79
+ GC.start
80
+ nil
81
+ end
82
+ end
83
+
84
+ # Calls #run to get an app instance then call open drawing with
85
+ # that app
86
+ # (see #open_drawing)
87
+ # @yield Drawing
88
+ # @return [void]
89
+ def open_drawing(drawing, app_options: {}, options: {}, &block)
90
+ run(**app_options) do |app|
91
+ app.open_drawing(drawing, **options, &block)
92
+ end
93
+ end
94
+
95
+ # Runs the app, opening the filenames
96
+ # and yielding each open drawing to the
97
+ # supplied block
98
+ # it automatically closes the drawing and
99
+ # the app when done
100
+ #
101
+ # [source]
102
+ # dir = Pathname('C:/templates')
103
+ # drawings = Pathname.glob(dir + '/**/*.dgn')
104
+ # App.with_drawings(drawings) do |drawing|
105
+ # drawing.save_as_pdf(dir: 'c:/output/')
106
+ # end
107
+ #
108
+ # @param files [Array<String,Pathname>]
109
+ # @param visible [Boolean]
110
+ # @param readonly [Boolean]
111
+ # @param error_proc [Proc]
112
+ # @yield [Drawing]
113
+ # @return [void]
114
+ def with_drawings(*files, visible: true, readonly: false, error_proc: ::Microstation.default_error_proc, &block)
115
+ # drawing_options = default_drawing_options.merge(options)
116
+ # app_options = default_app_options
117
+ errors = []
118
+ files = files[0] if files[0].is_a? Array
119
+ begin
120
+ the_app = new(visible: visible)
121
+ files_enum = files.each
122
+ loop do
123
+ file = files_enum.next
124
+ puts "opening #{file}.."
125
+ begin
126
+ the_app.open_drawing(file, readonly: readonly, error_proc: error_proc, &block)
127
+ the_app.ole_obj.ole_methods # check if server still open
128
+ rescue StandardError => e
129
+ error_proc.call(e, file)
130
+ the_app = new(app_options)
131
+ end
132
+ end
133
+ ensure
134
+ the_app&.quit
135
+ the_app = nil
136
+ end
137
+ end
138
+ end
139
+
140
+ attr_reader :scanners, :visible, :app_event, :project_dir
141
+
142
+ # Constructor for app
143
+ # @param [Boolean] visible
144
+ # @param event_handler [EventHandler]
145
+ def initialize(visible: false, event_handler: default_event_handler)
146
+ @visible = visible
147
+ @event_handler = event_handler
148
+ @ole_obj, @app_event = init_ole_and_app_event(visible: @visible, event_handler: @event_handler, tries: 5,
149
+ sleep_duration: 0.5)
150
+ @run_loop = true
151
+ @windows = Windows::FileSystem.new
152
+ # make_visible(visible)
153
+ @scanners = {}
154
+ rescue StandardError => e
155
+ binding.pry
156
+ end
157
+
158
+ def run_templates_in_dir(dir, options = {})
159
+ yaml_files = Pathname.glob("#{Pathname(dir).expand_path}*.yaml")
160
+ yaml_files.each do |f|
161
+ TemplateRunner.new(f).run_with_app(self, options)
162
+ end
163
+ end
164
+
165
+ def change_drawing(dgn, output_dir: nil, name: nil, options: {}, &block)
166
+ changer = Changer.new(dgn, name: name, output_dir: output_dir, app: self)
167
+ changer.run(&block)
168
+ end
169
+
170
+ def render_template(drawing, output_dir: nil, locals: {}, name: nil)
171
+ temp = Template.new(drawing, output_dir: output_dir, app: self, name: name)
172
+ temp.render(output_dir: output_dir, locals: locals)
173
+ end
174
+
175
+ #
176
+ # the default EventHandler
177
+ #
178
+ # @return [EventHandler] returns the default EventHandler
179
+ #
180
+ def default_event_handler
181
+ event_handler = EventHandler.new
182
+ event_handler.add_handler('OnDesignFileOpened') do |*_args|
183
+ puts 'drawing opened'
184
+ @drawing_opened = true
185
+ end
186
+ event_handler.add_handler('OnDesignFileClosed') do |*_args|
187
+ @drawing_opened = false
188
+ puts 'drawing closed'
189
+ end
190
+ event_handler
191
+ end
192
+
193
+ #
194
+ # register an handler
195
+ #
196
+ # @param [String] event key for handler
197
+ # @param [<Type>] &block <description>
198
+ #
199
+ # @return [<Type>] <description>
200
+ #
201
+ def register_handler(event, &block)
202
+ @event_handler.add_handler(event, &block) unless event == 'OnQuit'
203
+ end
204
+
205
+ #
206
+ # return a Handler
207
+ #
208
+ # @param [String,Symbol] event the event key
209
+ #
210
+ # @return [Proc] returns the Proc given by event name
211
+ #
212
+ def get_handler(event)
213
+ @event_handler.get_handler(event)
214
+ end
215
+
216
+ def exit_message_looop
217
+ puts 'Microstation exiting...'
218
+ @run_loop = false
219
+ end
220
+
221
+ def wait_drawing_opened(secs, interval = 1)
222
+ elapsed = 0
223
+ while !drawing_opened? && elapsed <= secs
224
+ elapsed += interval
225
+ sleep(interval)
226
+ WIN32OLE_EVENT.message_loop
227
+ end
228
+ end
229
+
230
+ def init_ole_and_app_event(visible: @visible, event_handler: @event_handler, tries: 5, sleep_duration: 1)
231
+ ole = WIN32OLE.new('MicrostationDGN.Application')
232
+ sleep(sleep_duration)
233
+ ole.Visible = visible
234
+ ole.IsProcessLocked = true
235
+ load_constants(ole)
236
+ app_event = WIN32OLE_EVENT.new(ole)
237
+ app_event.handler = event_handler
238
+ [ole, app_event]
239
+ rescue StandardError => e
240
+ tries -= 1
241
+ sleep_duration += 1.5
242
+ puts "Error: #{e}. #{tries} tries left."
243
+ retry if tries.positive?
244
+ raise e, 'unable to init ole app'
245
+ end
246
+
247
+ # @return [Boolean] whether the app is visible
248
+ def visible?
249
+ @visible
250
+ end
251
+
252
+ #
253
+ # Change the visible attribute
254
+ #
255
+ # @param [Boolean] bool true or false to make it visible
256
+ #
257
+ # @return [void]
258
+ #
259
+ def visible=(bool)
260
+ ole_obj.Visible = bool
261
+ end
262
+
263
+ def project_dir=(dir)
264
+ @project_dir = dir ? Pathname.new(dir) : dir
265
+ end
266
+
267
+ def base_dir
268
+ project_dir || Pathname.getwd
269
+ end
270
+
271
+ def wrap(item, cell = nil)
272
+ Element.convert_item(item, self, cell)
273
+ end
274
+
275
+ def normalize_name(name)
276
+ name = Pathname.new(name) unless name.is_a? Pathname
277
+ name = name.ext('.dgn') unless name.extname.to_s == /\.(dgn|dwg)$/
278
+ (base_dir + name).expand_path
279
+ end
280
+
281
+ def make_visible(visible)
282
+ @visible = visible
283
+ begin
284
+ ole_obj.Visible = @visible
285
+ true
286
+ rescue Exception => e
287
+ false
288
+ end
289
+ end
290
+
291
+ def ole_obj
292
+ is_ok = true
293
+ begin
294
+ @ole_obj.Visible
295
+ rescue StandardError => e
296
+ is_ok = false
297
+ end
298
+
299
+ @ole_obj, @app_event = init_ole_and_app_event(tries: 3) unless is_ok
300
+
301
+ @ole_obj
302
+ end
303
+
304
+ def with_drawing(drawing)
305
+ yield drawing
306
+ ensure
307
+ drawing.close
308
+ end
309
+
310
+ def with_template(template)
311
+ template = Template.new(template, self)
312
+ yield template
313
+ template = nil
314
+ end
315
+
316
+ # open the drawing
317
+ # @param filename [String] the name of the file to open
318
+ # @param [Boolean] :readonly (false)
319
+ # @param [Proc] :error_proc (raise) a proc to run
320
+ # @param wait_time [Integer] the total amount of time to wait to open file (500)
321
+ # @param wait_interval [Float] the amount of time in seconds to wait before retry (0.5)
322
+ # @yield [Drawing] drawing
323
+ # @return [void]
324
+ def open_drawing(filename, readonly: false, error_proc: nil, wait_time: 500, wait_interval: 0.5)
325
+ filename = Pathname(filename)
326
+ raise FileNotFound unless filename.file?
327
+
328
+ begin
329
+ ole = ole_open_drawing(windows_path(filename), readonly: readonly, wait_time: wait_time,
330
+ wait_interval: wait_interval)
331
+ rescue StandardError => e
332
+ if error_proc
333
+ error_proc.call(filename)
334
+ return
335
+ else
336
+ raise e
337
+ end
338
+ end
339
+ drawing = drawing_from_ole(ole)
340
+ return drawing unless block_given?
341
+
342
+ begin
343
+ yield drawing
344
+ ensure
345
+ drawing.close
346
+ end
347
+ end
348
+
349
+ def drawing_opened?
350
+ @drawing_opened
351
+ end
352
+
353
+ def windows_path(path)
354
+ @windows.windows_path(path)
355
+ end
356
+
357
+ def active_workspace
358
+ ole_obj.ActiveWorkspace
359
+ end
360
+
361
+ # @return the [Configuration]
362
+ def configuration
363
+ @config ||= ::Microstation::Configuration.new(self)
364
+ end
365
+
366
+ # @return [String] the configuration variable USERNAME
367
+ def username
368
+ configuration['USERNAME']
369
+ end
370
+
371
+ # create a new drawing
372
+ # @param filename [String,Pathname] the name of the file
373
+ # @param seedfile [String] The name of the seed file.
374
+ # should not include a path. The default extension is ".dgn".
375
+ # Typical values are "seed2d" or "seed3d".
376
+ # @param open [Boolean] .If the open argument is True,
377
+ # CreateDesignFile returns the newly-opened DesignFile object;
378
+ # this is the same value as ActiveDesignFile. If the Open argument is False,
379
+ # CreateDesignFile returns Nothing.
380
+ # @return [Drawing]
381
+ def new_drawing(filename, seedfile: nil, open: true, wait_time: 500, wait_interval: 1, &block)
382
+ file_path = Pathname(filename).expand_path
383
+ raise ExistingFile, file_path if file_path.exist?
384
+
385
+ # drawing_name = normalize_name(filename)
386
+ seedfile = determine_seed(seedfile)
387
+ binding.pry unless seedfile
388
+ windows_name = windows_path(filename)
389
+ ole = new_ole_drawing(seedfile, windows_name, open: open, wait_time: wait_time, wait_interval: wait_interval)
390
+ drawing = drawing_from_ole(ole)
391
+ return drawing unless block_given?
392
+
393
+ begin
394
+ yield drawing
395
+ rescue StandardError => e
396
+ 'puts error in new drawing'
397
+ raise e
398
+ ensure
399
+ drawing.close
400
+ end
401
+ end
402
+
403
+ def new_ole_drawing(seedfile, new_design_file_name, open: true, wait_time: 500, wait_interval: 0.5)
404
+ ole = ole_obj.CreateDesignFile(seedfile, new_design_file_name, open)
405
+ wait_drawing_opened(wait_time, wait_interval)
406
+ raise "drawing not opened in #{wait_time}" unless drawing_opened?
407
+
408
+ ole
409
+ rescue StandardError => e
410
+ raise e
411
+ end
412
+
413
+ def has_current_drawing?
414
+ ole_obj.HasActiveDesignFile
415
+ end
416
+
417
+ # prepend a dir to the MS_SEEDFILES configuration
418
+ # @param dir [String,Pathname]
419
+ def prepend_seed_path(dir)
420
+ configuration.prepend('MS_SEEDFILES', windows_path(dir))
421
+ end
422
+
423
+ def drawing_from_ole(ole)
424
+ Drawing.new(self, ole)
425
+ end
426
+
427
+ def determine_seed(seedfile)
428
+ return configuration['MS_DESIGNSEED'] unless seedfile
429
+
430
+ seed = find_seed(seedfile)
431
+ return seed.to_s if seed
432
+
433
+ raise "Seedfile #{seedfile} not found in #{configured_seed_paths}"
434
+ end
435
+
436
+ # @return [String] the configuration variable MS_SEEDFILES
437
+ def configured_seed_paths
438
+ configuration['MS_SEEDFILES']
439
+ end
440
+
441
+ # find the seedfile
442
+ # @param [String,Pathname] seedfile
443
+ #
444
+ # * If the seed file is absolute and found the return the
445
+ # seedfile.
446
+ # * If the seed file is not found search MS_SEEDFILES
447
+ # @return [Pathname] seedfile the found seedfile
448
+ def find_seed(seedfile)
449
+ seed = Pathname(seedfile).expand_path.sub_ext('.dgn')
450
+ return seed if seed.file?
451
+
452
+ find_seed_in_seed_dirs(seed.basename)
453
+ end
454
+
455
+ def find_seed_in_seed_dirs(seedfile)
456
+ seed_dir = seed_paths.find { |p| (p + seedfile).file? }
457
+ return (seed_dir + seedfile) if seed_dir
458
+ end
459
+
460
+ # @return [Array] returns the MS_SEEDFILES as Pathnames Array
461
+ def seed_paths
462
+ configured_seed_paths.split(';').map { |d| Pathname(d) }
463
+ end
464
+
465
+ def eval_cexpression(string)
466
+ ole_obj.GetCExpressionValue(string)
467
+ end
468
+
469
+ #
470
+ # quit the app
471
+ #
472
+ # @return [void]
473
+ #
474
+ def quit
475
+ close_active_drawing
476
+ @scanners.each { |_name, sc| sc.close }
477
+ begin
478
+ ole_obj.Quit
479
+ rescue StandardError
480
+ nil
481
+ end
482
+ end
483
+
484
+ # the active design file
485
+ # @return [Drawing]
486
+ def active_design_file
487
+ if active_design_file?
488
+ ole = ole_obj.ActiveDesignFile
489
+ drawing_from_ole(ole)
490
+ end
491
+ end
492
+
493
+ alias active_drawing active_design_file
494
+ alias current_drawing active_design_file
495
+
496
+ #
497
+ # close the active_design_file
498
+ #
499
+ # @return [void]
500
+ #
501
+ def close_active_drawing
502
+ active_design_file.close if active_design_file?
503
+ end
504
+
505
+ alias close_current_drawing close_active_drawing
506
+
507
+ #
508
+ #
509
+ #
510
+ # @return [Boolean] true if app has an active design file open
511
+ #
512
+ def active_design_file?
513
+ ole_obj.HasActiveDesignFile
514
+ end
515
+
516
+ alias current_design_file? active_design_file?
517
+
518
+ #
519
+ # <Description>
520
+ #
521
+ # @param [String,Pathname] file name of file to search for
522
+ #
523
+ # @return [Boolean] true if file exists
524
+ #
525
+ def file_exists?(file)
526
+ Pathname(file).expand_path.file?
527
+ end
528
+
529
+ def create_scanner(name = nil, &block)
530
+ ::Microstation::Scan::Criteria.create_scanner(name, self, &block)
531
+ end
532
+
533
+ def text_criteria
534
+ scanners[:textual] || create_scanner(:textual) { include_textual }
535
+ end
536
+
537
+ def tags_criteria
538
+ sc = scanners[:tags] || create_scanner(:tags) { include_tags }
539
+ end
540
+
541
+ def create_scan_criteria(name = nil, &block)
542
+ ::Microstation::Scan::Criteria.create_scanner(name, self, &block)
543
+ end
544
+
545
+ # def find_by_id(id)
546
+ # active_design_file.find_by_id(id)
547
+ # wrap(model) if el
548
+ # end
549
+
550
+ def scan_model(criteria = nil, model = nil)
551
+ model ||= active_model_reference
552
+ model.scan(criteria)
553
+ end
554
+
555
+ def get_ole_element_enumerator(model:, criteria: nil)
556
+ criteria ||= create_scan_criteria
557
+ criteria.resolve
558
+ model.scan(criteria.ole_obj)
559
+ rescue Exception
560
+ # binding.pry
561
+ end
562
+
563
+ # lets you interact with the cad_input_queue
564
+ # @yield [CadInputQueue]
565
+ # @return [void]
566
+ def cad_input_queue
567
+ queue = init_cad_input_queue
568
+ return queue unless block_given?
569
+
570
+ begin
571
+ yield queue
572
+ rescue StandardError
573
+ ensure
574
+ queue.close
575
+ queue = nil
576
+ @cad_input_queue = nil
577
+ end
578
+ end
579
+
580
+ def show_command(text)
581
+ ole_obj.ShowCommand(text)
582
+ end
583
+
584
+ def show_prompt(text)
585
+ ole_obj.ShowPrompt(text)
586
+ end
587
+
588
+ def show_message(text)
589
+ ole_obj.ShowMessage(text)
590
+ end
591
+
592
+ #
593
+ #
594
+ # @param [String] text text to show
595
+ # @param [Symbol] location (one of :left, :middle)
596
+ #
597
+ # @return [void]
598
+ #
599
+ def show_temp_message(text, location: nil)
600
+ loc = case location
601
+ when :left
602
+ MSD::MsdStatusBarAreaLeft
603
+ when :middle
604
+ MSD::MsdStatusBarAreaMiddle
605
+ else
606
+ MSD::MsdStatusBarAreaLeft
607
+ end
608
+ ole_obj.ShowTempMessage(loc, text)
609
+ end
610
+
611
+ def can_open?(filename)
612
+ ext = File.extname(filename)
613
+ (ext == '.dwg') || (ext == '.dgn')
614
+ end
615
+
616
+ def active_model_reference
617
+ DefaultModel.new(self, ole_obj.ActiveModelReference)
618
+ rescue StandardError
619
+ nil
620
+ end
621
+
622
+ def default_model
623
+ DefaultModel.new(self, ole_obj.DefaultModelReference)
624
+ rescue StandardError
625
+ nil
626
+ end
627
+
628
+ def ole_point
629
+ ::WIN32OLE_RECORD.new('Point3d', ole_obj)
630
+ end
631
+
632
+ def ole_rotation
633
+ ::WIN32OLE_RECORD.new('Rotation', ole_obj)
634
+ end
635
+
636
+ def ole_matrix
637
+ ::WIN32OLE_RECORD.new('Matrix', ole_obj)
638
+ end
639
+
640
+ #
641
+ # Create an WIN32OLE_RECORD of type Point3d
642
+ #
643
+ # @param [Numeric] x coordinate in x axis
644
+ # @param [Numeric] y coordinate in y axis
645
+ # @param [Numeric] z coordinate in z direction (0.0)
646
+ #
647
+ # @return [WIN32OLE_RECORD] record of type Point3d
648
+ #
649
+ def create_ole_point(x, y, z = 0)
650
+ ole = ole_point
651
+ ole.X = x
652
+ ole.Y = y
653
+ ole.Z = z
654
+ ole
655
+ end
656
+
657
+ def to_ole_matrix3d(vec)
658
+ if vec.instance_of?(WIN32OLE_RECORD) && vec.typename == 'Matrix3d'
659
+ vec
660
+ else
661
+ binding.pry
662
+ end
663
+ end
664
+
665
+ #
666
+ # Conversion to WIN32OLE_RECORD of type Point3d
667
+ #
668
+ # @param [WIN32OLE_RECORD, Point3d, Array<Numeric>] pt Point to normalize to ole point
669
+ # @return [WIN32OLE_RECORD] 'Point3d' WIN32OLE_RECORD
670
+ #
671
+ def to_ole_point3d(pt)
672
+ case pt
673
+ when ole_point3d?(pt)
674
+ pt
675
+ when Point3d
676
+ create_ole_point(pt.x, pt.y, pt.z)
677
+ when Array
678
+ pt1 = pt.map(&:to_f)
679
+ x, y, z = pt1
680
+ z ||= 0.0
681
+ create_ole_point(x, y, z)
682
+ end
683
+ end
684
+
685
+ #
686
+ # <Description>
687
+ #
688
+ # @param [Object] pt pt object to test if it is a WIN32OLE_RECORD of 'Point3d'
689
+ #
690
+ # @return [Boolean] true if pt is WIN32OLE_RECORD of 'Point3d'
691
+ #
692
+ def ole_point3d?(pt)
693
+ pt.instance_of?(WIN32OLE_RECORD) && pt.typename == 'Point3d'
694
+ end
695
+
696
+ def create_text_node(origin, rotation, temp = nil)
697
+ ole_origin = to_ole_point3d(origin)
698
+ ole_rotation = to_ole_matrix3d(rotation)
699
+ temp ||= WIN32OLE_VARIANT::Nothing
700
+ ole = ole_obj.CreateTextNodeElement1(temp, ole_origin, ole_rotation)
701
+ rescue Exception => e
702
+ puts e.message
703
+ nil
704
+ end
705
+
706
+ #
707
+ # convert pt to Point3d
708
+ #
709
+ # @param [Array<Numeric,Numeric,Numeric>, Point3d, WIN32OLE_RECORD] pt Point to convert
710
+ #
711
+ # @return [Point3d]
712
+ #
713
+ def to_point3d(pt)
714
+ case pt
715
+ when Array
716
+ pt_a = pt.map(&:to_f)
717
+ x, y, z = pt_a
718
+ z ||= 0.0
719
+ Point3d.new(x, y, z)
720
+ when Point3d
721
+ pt
722
+ when WIN32OLE_RECORD
723
+ Point3d.from_ole(pt) if pt.typename == 'Point3d'
724
+ end
725
+ end
726
+
727
+ def to_point(pt)
728
+ to_point3d(pt)
729
+ end
730
+
731
+ def start_primitive(klass)
732
+ ole_obj.CommandState.StartPrimitive klass.new(self)
733
+ end
734
+
735
+ def my_place_line
736
+ require_relative 'primitive_command_interface'
737
+ start_primitive LineCreation
738
+ end
739
+
740
+ def method_missing(meth, *args, &block)
741
+ if meth.to_s =~ /^[A-Z]/
742
+ require 'pry'; binding.pry
743
+ result = ole_obj.send(meth, *args, &block)
744
+ else
745
+ super(meth, *args, &block)
746
+ end
747
+ rescue StandardError => e
748
+ binding.pry
749
+ end
750
+
751
+ protected
752
+
753
+ def ole_open_drawing(path, readonly: false, wait_time: 500, wait_interval: 0.5)
754
+ ole = ole_obj.OpenDesignFile(windows_path(path), 'ReadOnly' => readonly)
755
+ wait_drawing_opened(wait_time, wait_interval)
756
+ raise "drawing not opened in #{wait_time}" unless drawing_opened?
757
+
758
+ ole
759
+ rescue StandardError => e
760
+ raise e
761
+ end
762
+
763
+ def load_constants(ole_obj)
764
+ WIN32OLE.const_load(ole_obj, MSD) unless MSD.constants.size.positive?
765
+ end
766
+
767
+ def run_loop
768
+ WIN32OLE_EVENT.message_loop while @run_loop
769
+ end
770
+
771
+ def stop_loop
772
+ @run_loop = false
773
+ end
774
+
775
+ private
776
+
777
+ def init_cad_input_queue
778
+ ::Microstation::CadInputQueue.new(ole_obj.CadInputQueue, self)
779
+ end
780
+ end
781
+ end