This article shows you how to create your own map model so that you can add objects to your visualization.

You should know the information in the following article:
Before you start, remember to:
Add the Ubisense references to your application
Add a Ubisense.UVis.Visualization named visualization to your form
Add using statements for Ubisense.UBase and Ubisense.UVis to all your files:
using System; |
In order to define the types of objects that you can add to your model,
create an enumeration of the types. In this example, we have 2 possible
additions to the map: Sensor and Zone. We will
make sensors clickable by the user, but zones not clickable.
The default Nil type is also required, to be used when the
the mouse pointer moves over somewhere other than one of our objects on the map.
|
In order to tell which object the mouse is over on the visualization,
we need to give each object a unique ID.
Each object's unique ID can be made up of its type and an ID number.
This means you don't need to create a unique number for all objects,
only those of the same type.
In our example, the class TypeId provides the unique ID
for each object in the model. It contains the MapModelObjectType
along with a long integer, which will be unique to each object
of the specified type.
The public members allow the user to get the type or id number as required.
The available constructors create instances of either the Nil type
or the specified MapModelObjectType and id number.
Finally, in this example, the class needs to inherit from IComparable.
This is because it is going to be used as the key in a mapping from TypeId
to UObject. The CompareTo method is implemented with
precedence type followed by id number.
|
Our representations should all have a unique id, so we can determine which one
the mouse is over at any point.
Therefore, you should define a base class for the representations that
contains our TypeId class as follows:
|
Now we can define MyMapModel. Firstly, it inherits from MapModel since
it will be our visualization map model. Secondly, it inherits from the interface IModel
so our objects can be rendered in the visualization.
|
Define an object for multi-thread synchronisation:
|
Define mappings from UObject to Key, TypeId and Rep:
|
We need a way of determining which object, if any, the mouse is over at any point.
Define a public method to return a TypeId given the UObject
that we will obtain from the renderer's hit test:
|
We need a way of adding objects to our map model. Define the following private method
to populate all the mappings and tell any renderers that an object has been inserted
into the model.
Note: This means that the visualization will always be updated with the new
object as soon as it is added - there is no need to call invalidate()
on your visualization instance.
|
Create a templated public method that calls the private add_obj just defined.
Any representation that derives from MyMapModelRep can now be added to the model
using this method:
|
We need a way of removing objects from the map model. Define the following private method
to clear the mappings and tell any renderers than an object has been removed from the model.
Note: This means that the visualization will always be updated to remove the
object as soon as it is deleted - there is no need to call invalidate()
on your visualization instance.
|
Making use of the clear_mapping method just defined, create a public
method to remove a single object from the map model, given the type and id:
|
Create a public method to remove all objects of the given types from the map model:
|
Create a public method to remove all objects from the map model. After clearing the mappings,
use the OnRepEstablish method on all renderers to re-establish renderer state:
|
Now define the IModel interface. The following members only call the base method:
|
The following members need you to do something with the mappings of your additional objects.
Remember to use the local synchonisation object for multi-thread accesses.
GetKey returns the representation key for the given object:
|
GetRep returns the representation for the given key:
|
RenderEachObject calls the IRenderer.OnRender method on each located object.
The context is 0 for the opaque pass, 1 for the transparent pass and 2 for a hit calculation pass.
This is where we need to call OnRender on each of our objects to draw them on the map.
Clicking on the map causes hit calculations (context==2). Here, we will not render zones for hit tests
so the map can be dragged with the mouse even if the user clicks in a zone. Also, we will not render
objects from outside our map model for hit tests, since this example doesn't do anything with these hits.
|
Create an instance of MyMapModel. This will need to be visible throughout the Windows Form
class so you can call the public methods we defined above when, for example, sensors are added or removed
to/from your dataset.
|
Assign the instance of MyMapModel in the Windows Form load handler:
|
In your Windows Form code, define the following method to detect whether the mouse is
over an object. This uses the hit test from RenderEachObject, so in this
example, we will detect sensors but not zones.
|
You are now ready to use your map model. The
example program
populates the map with all sensors and cell extents found when it loads.
To show you how you might use the mouse_is_over_object method defined above,
it displays the MAC address of any sensor that the mouse is over on the map.
It also has a "View" menu to demonstrate the methods to remove objects from the map.