There are several instances of class (items) that are crated and managed by a Tool class instance (manager). Every item must react to the view being changed.
Which is better?
A) Add an instance of the observer to each item?
B) Add an instance of the observer to the Tool instance and “inform” items about the change?
In the examples, for simplicity, I create 100 items during initialization, and the reaction of the items is a simple count.
Case A:
module Dezmo
class MyItemA
def initialize
@my_variable = 0
start_observing
end
def onViewChanged(view)
@my_variable += 1
end
def start_observing
model = Sketchup.active_model
model.active_view.remove_observer(self)
model.active_view.add_observer(self)
end
def stop_observing
model = Sketchup.active_model
model.active_view.remove_observer(self)
end
end
class MyItemManagerToolA
def initialize
@my_items = {}
100.times{|i|
@my_items[i] = Dezmo::MyItemA.new
}
end
def deactivate(view)
@my_items.each{ |item| item.stop_observing }
end
def manage_items_method_1
# ...and so on
end
end
end
Case B
module Dezmo
class MyItemB
def initialize
@my_variable = 0
end
def view_changed(view)
@my_variable += 1
end
end
class MyItemManagerToolB
def initialize
@my_items = {}
100.times{|i|
@my_items[i] = Dezmo::MyItemB.new
}
start_observing
end
def deactivate(view)
stop_observing
end
def onViewChanged(view)
@my_items.each{ |item| item.view_changed(view) }
end
def start_observing
model = Sketchup.active_model
model.active_view.remove_observer(self)
model.active_view.add_observer(self)
end
def stop_observing
model = Sketchup.active_model
model.active_view.remove_observer(self)
end
def manage_items_method_1
# ...and so on
end
end
end
Other quiestions:
If I replace e.g. @my_items[50] = Dezmo::MyItemA.new
What happens to the item that was previously assigned to @my_items[50]?
What happens to its observer if it was assigned to it and I did not remove it?
Does the garbage collection mechanism remove them?
I think that the SketchUp observer queue disposes of observers attached to invalid objects. The observer queue will be holding a reference to MyItemA which might prevent immediate garbage collection when your code stops referencing it, so the stop_observing() method has benefit.
Of the two scenarios, I’d prefer B. But I also would likely key the hash with object IDs or PIDs if they are Drawingelement subclass objects. You can also key the hash with object references as well which are also unique.
If the things to be watched are model objects, you could just insert @vars into the entity instances using the instance_variable_set() method.
No. There are a lot more to do inside in one item. I just put an example that need a calculation if view changes.
These are not a Drawingelement, but It is a holding a calculated points of let say, shapes, however I also can call it as my own virtual Drawingelement, because it will drawn by a Tool (or Overlay).
Some have the property that they always seem to be the same size (like the protractor), so I have to watch when the view changes and calculate a new transformation.
The thing is, there’s quite a lot of calculation (can be) involved, so I’d rather calculate it in advance and have # draw(…) just draw the *points (cached in instance variable).
I have the feeling (but I have no idea) that view.draw(...) is called more often than the view observer changes (?)
I woul use B, that is, an observer attached to the tool, created at `activate` and removed at `deactivate`.
Another option is to store the view parameters (eye, target, etc…) in `draw` and compare them each time. If they are different, then you perform the view-dependent calculation. Otherwise, you used the cached value. draw is called anyway when the view changes.
I wrote a test code to compare the number of calls in draw vs. observer, Tool vs. Overlay.
animation: I change the view with the mouse wheel or the middle mouse button (Orbit Tool).
In Overlay, the draw method is called more times than the observer. If in Tool - obviously when using the Orbit Tool, MyTool is suspended - it does not call draw.
animation: I change the view with 3Dconnection mouse.
There is no really significant difference in the number of draw or observer calls.
It seems that in Tool it is better to calculate in the draw method than in the Observer.
With Overlay it is almost the same.
Is there something I did not take into account?
module Dezmo
class MyOv < Sketchup::Overlay
def initialize
super('example_inc.my_ov', 'TestOv')
end
def onViewChanged(view)
@viewobs_count += 1
end
def start
@draw_count = 0
@viewobs_count = 0
model = Sketchup.active_model
model.active_view.remove_observer(self)
model.active_view.add_observer(self)
end
def stop
model = Sketchup.active_model
model.active_view.remove_observer(self)
end
def draw(view)
@draw_count += 1
view.draw_text([10,60],
"Odraw_count:#{@draw_count}\nOviewobs_count:#{@viewobs_count}",
size:16,
bold:true,
color:"red")
end
end
ov = MyOv.new
Sketchup.active_model.overlays.add(ov)
class MyTool
def initialize
@draw_count = 0
@viewobs_count = 0
start_observing
end
def deactivate(view)
stop_observing
end
def resume(view)
view.invalidate
end
def onViewChanged(view)
@viewobs_count += 1
end
def start_observing
model = Sketchup.active_model
model.active_view.remove_observer(self)
model.active_view.add_observer(self)
end
def stop_observing
model = Sketchup.active_model
model.active_view.remove_observer(self)
end
def draw(view)
@draw_count += 1
view.draw_text([10,10],
"draw_count:#{@draw_count}\nviewobs_count:#{@viewobs_count}",
size:16,
bold:true)
end
end
Sketchup.active_model.select_tool(MyTool.new)
end