Search Blogs AGI.com Blogs

UI Plugins: Mouse Events

By: Ismir Tufek

In my second blog, I promised I would explain the last UI plugin interface; IAgUiPlugin3DNotify. The interface allows, for the first time, for UI Plugins to detect mouse events on the globe window. We had similar functionality in standalone STK Engine applications for years and I lobbied hard to add the same functionality to the UI Plugins.

The IAgUiPlugin3DNotify contains two methods: OnMouseClick and OnPickInfo. As the names imply, OnMouseClick is triggered when the user clicks on the 3D Graphics window and OnPickInfo is triggered after the pick event is completed.

OnMouseClick is triggered by every mouse button action inside the 3D globe window. You most likely will not need to respond on every single click. You have two options. The first option is that you can respond to a specific keyboard/mouse combination. For examples, you can check if the user is holding the “CTRL” key at the same time as left clicking on the globe. The other way is to allow the user to turn on the functionality, respond to any action, and turn off the feature.  I believe the second option provides grater affordance. OnMouseClick signature is as follows:

OnMouseClick(IAgUiPlugin3DMouseEventArgs EventArgs, IAgUiPlugin3DNotifyContext Context)

The EventArgs parameter contains the information about the mouse click. KeyState is an enumeration that contains information about which mouse and keyboard keys are pressed. EventArgs also provides the current mouse coordinates and 3D window ID.

The second parameter for both OnMouseClick and OnPickInfo is “Context” of the type IAgUiPlugin3DNotifyContext. Even though the Context looks like a local variable for the methods, it is actually the pointer to the interface that controls the pick interface in the STK Desktop application. In STK engine, most objects are passed by reference. The Context parameter is used to initiate the pick event with the OnMouseClick method and to respond to the pick event in the OnPickInfo method.

Below is some sample code.

First I created enumeration to help me turn on certain behaviors.

public enum GlobeEventType {
Location,
Object,
Globe,
Screen,
None
}

The user can choose to get position coordinates (Location), select individual objects (Object), and start pick selection in screen space (Screen) or on the globe (Globe). Your application probably will not need all these options.

In the first three lines of code, I get the scene object corresponding to the Globe window where the mouse click originated:

public void OnMouseClick(IAgUiPlugin3DMouseEventArgs EventArgs, IAgUiPlugin3DNotifyContext Context)
{ IAgScenario scenario = (IAgScenario)CommonData.StkRoot.CurrentScenario; IAgStkGraphicsSceneManager sceneManager = scenario.SceneManager; IAgStkGraphicsScene scene = scenario.SceneManager.Scenes[EventArgs.SceneID - 1]; List<string> objectPaths = new List<string>(); switch (m_globeEventType) { case GlobeEventType.Location:

Below is an example of getting cartographic location from mouse coordinates:

Array position = new object[] { EventArgs.X, EventArgs.Y }; object[] cartographic = (object[])scene.Camera.WindowToCartographic("Earth", ref position); string latitudeString = cartographic.GetValue(0).ToString(); string longitudeString = cartographic.GetValue(1).ToString(); double altitude = double.Parse(cartographic.GetValue(2).ToString());< break;

Please note that I am getting the latitude and longitude as string values but am getting altitude as a numeric value. You cannot assume that latitude and longitude are numeric because STK accepts units like DMS (degrees minutes seconds) as valid angle units. In that case, the default latitude (angle) value would be 40:02:18.9960.

The next example is for selecting an individual object. The IAgUiPlugin3DNotifyContext interface includes the “Pick” method that returns objects at specified coordinates. I prefer to make the selected area a little bigger so the user does not have to click on the exact pixel.

case GlobeEventType.Object:

var objects = Context.PickRectangular(EventArgs.X - 5,EventArgs.Y + 5, EventArgs.X + 5, EventArgs.Y - 5);

foreach (string s in objects) { objectPaths.Add(s); }

break;

The following two examples start object selections on the globe and in screen space respectively. It is also possible to control the appearance of the selection rectangle.

case GlobeEventType.Globe:

Context.RubberBandLineWidth = 2;

Context.RubberBandColor = System.Drawing.Color.White;

Context.ActivateRubberBandOnCentralBody();

break;

case GlobeEventType.Screen:

Context.RubberBandLineWidth = 2;

Context.RubberBandColor = System.Drawing.Color.Yellow;

Context.ActivateRubberBand();

break;

case GlobeEventType.None:

break;

default:

break;

}

}

Once the rubber band selection is finished, the OnPickInfo method is called.

public void OnPickInfo(IAgUiPlugin3DPickEventArgs EventArgs, IAgUiPlugin3DNotifyContext Context)

{

Array region = EventArgs.SelectedRegion;

List<string> objectPaths = new List<string>();

switch (EventArgs.PickType)

{

case AgEUiPlugin3DPickType.eUiPlugin3DPickTypeProjectedOnCentralBody:

double west = (double)region.GetValue(0);

double south = (double)region.GetValue(1);

double east = (double)region.GetValue(2);

double north = (double)region.GetValue(3);

var objects = Context.PickExtent(west, south, east, north);

foreach (string s in objects) { objectPaths.Add(s); }

break;

case AgEUiPlugin3DPickType.eUiPlugin3DPickTypeRubberBand:

int left = (int)(double)region.GetValue(0);

int bottom = (int)(double)region.GetValue(1);

int right = (int)(double)region.GetValue(2);

int top = (int)(double)region.GetValue(3);

var objects1 = Context.PickRectangular(left, bottom, right, top);

foreach (string s in objects1) { objectPaths.Add(s); }

break;

default:

break;

}

}

Posted: 12/6/2016 10:32:26 AM


Tags

Dev