PolygonGeometry with offset?Or is there something off with the Mouse events? - c#

I came across the weirdest situation while code-generating polygons and attaching them to a Virtual Earth 3D Globe Control. I have enabled mouse controls, as discussed on this thread in codeplex: http://bingmapswpf.codeplex.com/discussions/279548
Context: Map with several polygonGeometries, some of them are intentionally overlayed (using z-index).
*strong text*Actions: Click over a given polygonGeometry or trigger MouseEnter/Leave event over a given polygonGeometry.
Result: The object isn't detected by the click or by the MouseEnter/Leave event, however if I apply some "offset" to my clicks/hovers over the PolygonGeometry, the events pickup the object on a "empty space" in the map, a couple of pixels away for the actual object.
Aditional info: This behaviour goes away completely if I zoom in the object (almost to a full screen size), and starts getting worse as I zoom out. In High-level views of the map/objects it's impossible to click or hover any objects, or at least they don't get picked up by the events.
So, right now my theory is that by some reason, in lower zoom scenarios, the map "missplaces" the polygonGeometrys (although it seems that they are drawn properly). Being the object missplaced, no shapeId/layerId are detected and thus no action over the event is triggered.
So, I would like to know if someone has already came across this situation and how it was fixed, and/or if I'm doing something wrong on my development (check the mouse events adventure on the post mentioned in the beginning of this discussion), because this is on annoying problem that just doesn't go away... Any suggestion, tip or theory is most welcome!
Thanks in advance for reading and helping. Sorry for any bad english,
-RG

Related

DevExpress WaitForm and PreFilterMessage - unexpected MouseMove messages

I need the application idle time in my software. For that reason, I made a helper class ApplicationIdleHelper which implements the IMessageFilter interface.
This works fine and if my application is in idle for some time, I'm showing a DevExpress WaitForm using this line of code:
SplashScreenManager.ShowForm(typeof(WaitForm));
In this WaitForm I show the user some information about what's being done in the background. If the user moves the mouse or presses some keys I close the WaitForm like this:
SplashScreenManager.CloseForm();
Here's the problem explained in steps:
Mouse cursor is on the form.
User doesn't do anything for some time -> idle time -> so I show the WaitForm.
Now I get a MouseMove message in my PreFilterMessage method? BUT WHY? Mouse didn't move. No keys pressed? Because I get a MouseMove message my application thinks, the user did some input and automatically closes the WaitForm.
Same behavior if I close the WaitForm.
Here's a sample application, so you should be able to reproduce the behavior:
https://drive.google.com/file/d/0BxabrokJG-OWV3FLV2hNNVk5NjQ/view?usp=sharing
The DevExpress documentation says:
Wait Forms and Splash Screens are displayed by a Splash Screen Manager
in a separate thread.
Maybe this has something to do with that behavior?
Hope somebody can explain me, why I geht a MouseMove message in my PreFilterMessage function, after showing or closing the WaitForm.
Thank you in advance.
The most likely cause of this is that the mouse is sensitive to environmental noise. It's entirely possible for a mouse to experience a little bit of jitter that causes it to report very small movements, which ultimately work out to zero change in position. Alternatively, and this isn't verified, Windows or some other software on the system could be generating extra mouse move messages to make sure that everyone stays in sync with the current mouse position.
Either way, the most stable solution is to decide on an amount of motion you consider "real" (see threshold below), and then:
Capture the mouse position when you're going to sleep.
Every time you get a WM_MOUSEMOVE message (or a MouseMove event) calculate the amount of that motion, as in:
Point cached; // from when you went to sleep
Point current; // determined from the window message/event
double move = Math.Sqrt(Math.Pow(cached.X - current.X, 2) +
Math.Pow(cached.Y - current.Y, 2))
if (move > threshold)
{
// Wake up
}
else
{
// Ignore and optionally update the cached position
// in case the mouse is slowly drifting
}
(Note that you don't necessarily need to calculate the real distance that way, you could just use ΔX+ΔY)
Whenever you're dealing with hardware, you need to be ready for it to send you updates that you aren't expecting. Pressing a button for example, can cause the physical contact to bounce, which causes multiple press/break signals at the electrical level. Most of the time, the hardware is designed to filter the noise, but sometimes this seeps through.

MonoGame - Working With Specific Gestures for Different Purposes

Part of my particular dilemma is that I would like to be able to get the initial position of a drag gesture. Depending on the initial position of that drag gesture, the application would either 1) pan the view or 2) display a menu, but not perform these gestures at the same time (which is where part of struggle lies).
For example, if the user initiated a drag from the very left side of their screen and dragged inwards, a menu would pop in instead of the view panning.
I would also like to be able to execute a double tap gesture without also activating a tap gesture, if that's at all possible. I've tried working with boolean flags - for example,
// ...
if (gesture.GestureType == GestureType.DoubleTap)
{
isDoubleTap == true;
}
// ...
public static Vector2 Tap
{
get
{
if (!isDoubleTap)
return gesture.Position;
// ...
But that doesn't work.
I've tried using TouchCollection - if anyone would like me to elaborate on my issues with that I can, but for now I'll say what I tried hasn't worked. It's entirely possible I may have just goofed as I am a novice when it comes to working with touch input.
I've been working on this for a few days and have done as much searching as I can, and nothing I've found has alleviated my issue - if I happened to have missed something, I apologize.
Thank you for your time!
Concerning start position of a drag:
There is a gesture for a drag ending, so if you receive a drag and its the first one since the last drag ended, thats the initial position.
Concerning tap/doubletap:
MonoGame works the same way as XNA as documented here:
The user tapped the screen twice in quick succession. This
always is preceded by a Tap gesture.
This sounds like a input-bindings design problem more than a technical question imo. Consider also what you can move to instead occur on press or release rather than only making use of gestures.

WP7 Pivot control and a WebBrowser control

I have a Pivot which contains a WebBrowser control that practically takes up the whole page (appart from the Pivot header of course).
I would like to figure out how to make the WebBrowser control allow for the user to swipe left/right to activate the Pivot control. Currently it just pans the WebBrowser control left/right
Can this be done??
Thank
While I cannot tell you exactly how to pass the swipes to the pivot, I can tell you how to do a part of the job: how to catch/analyze/disable custom gestures over the WebBrowser.
If I remember correctly, in the 7.0:
the WebBrowser component consisted almost only of an internal TileHost wrapped in some grids/borders
the TileHost did all the work related to processing touch events
the TileHost did it completely internally (in the native layer), without the .Net seeing any manipulation-events (I think), or at least it ignored all the attempts to handle/override the manipulation-event on the upper layer. The WebBrowserInterop class was mostly empty in these matters.
Now, in the 7.5 that I have (maybe on 7.1 too, I dont know), it seems that the MS is working really hard on some WebBrowser manipulation problems --- I think they are working towards having the scrolling/swiping fully processed by the .Net layer. They have written a special class PanZoomContainer and injected them into the VisualTree of WebBrowser's internal template. The WebBrowserInterop was greatly enriched with many tunnels for event notifications. The WebBrowserInterop hooks into PanZoomContainer's ManipulationEvents, then passes them to the native layer. Also, it listens to events/commands from the native layer, called for example "ZoomAndScroll" or "ShowSIP" - and mostly passes them back to the PanZoomContainer. The idea is crystal clear right? They have rewired the event handling from completely-internal to a bit of spaghetti, but have achieved passing them through the PanZoomC.
Now, whats in that for me/us?
It is the PanZoomContainer, whose Mani-Events are inspected. The TileHost does not capture them now. In this version of the WebBrowser control, it's VisualTree consists of some borders, grids, a PanZoomContainer and a TileHost (the renderer). It is similar to that:
WebBrowser
PanZoom
ContentPresenter
Border/Name="border" <- you want this one
TileHost
I've skipped a few Borders and Grids, they are mostly irrelevant to the problem. Now, if the PanZoomContainer's Mani-Events are listened to, let's block them!
Using VisualTreeHelper, just dig deeper and deeper until you find a FrameworkElement.Name=="border". This is the border that wraps the TileHost that is the "renderer" that takes 99% space of the control. Be warned that there's a ContentPresenter, so you may have to wait until the controltemplate gets instantiated (ie. Loaded/LayoutUpdated).
Once you have your hands on that Border, attach all Mani-Event handlers to it: started, delta and completed. PanZoom is a normal xaml/silverlight/.net/etc control, so it actually obeys e.Handled = true :) Now, if you want to disable ie. vertical scrolling, filter the Delta and Completed events for Translation.Y<>0. If you want to disable tapping but leave srolling/panning - filter X==0&Y==0.
And that was the easy part.
The hard part is to experiment with filtering on different Start/Delta/Stop and adjusting the behaviour to your likes.
Although it might look very nice and tempting, this will NOT get you any real/nice results easily. For example, I wrote "if you want to disable vertical scrolling, then set a filter 'if y==0 then e.handled=true' ". Great? easy? Not!
Assume we want to "disable bouncy horizontal panning" while leaving "vertical scrolling". or vice versa, whatever, it is only an example:
Here's a small rectangular device with a sensitive touchscreen. Please make such a vertical swipe/pan/drag on the screen, that the resulting X-compound will be ZERO. If you set such filter, it will be almost impossible to it properly. Your users will want to kill you for forcing them to retry-that-vertical-scrolling for five or more times, until they make a perfect vertical swipe.
Of course you can make it not ==0, but leave some small margin. ok. But if you make the margin too big, the control will catch the intermediate offaxis movement and make a tiny horizontal pan also.. After a few unlucky vertical swipes, the total horizontal pan may accumulate from those small leftovers will accumulate and the diplacement maybe will be noticeable.
But there's some another vile side effects:
Saying shortly, you have commited e.Handled=true. The event is GONE. Dead. Deased. if you just wanted the WebBrowser to SKIP for example horizontal swipes, so that the outer (Pivot) control notices them and processes..... whoops. The event is GONE. Earlier, the TileHost/PanZoomC have extinguished the events, now you have it done yourself. Sounds like a bad joke, eh?
Fortunatelly:
since you have attached your handlers to the bottommost "border", they may not only block the events, but may also actually listen&publish them elsewhere. That is, if those handlers detect an interesting movement, they may e.Handled=true on it, but at the same time they can notify your custom objects about that discovery, and ie. start your storyboards.
mani-events are at hand, but there is also a second layer that listens to the manipulations: the GestureListener/GestureService from the Silverlight Toolkit. It reports events after they are handled by mani-events, but it reports them with no regard to any e.Handled=true that were set on them. It is completely separate gesture-listening mechanism, and you can also use it to detect manipulations that were 'cancelled'
.. and so the fun goes like that and maybe even a little further.
This is similar to putting a Map inside a Pivot - which is discussed here - http://mine.tuxfamily.org/?p=111 - already mentioned in quite a few questions - https://stackoverflow.com/search?q=mine.tuxfamily.org
In general, the advice seems to be usability based:
try to avoid putting controls which use Touch inside the PivotItem's
As an aside, if you are just using the web browser control for a very small amount of static html (so you don't need any scrolling at all) then you could just remove HitTesting from the web browser.
I do not know WP7 Pivot, but are there any Preview* events on the Pivot control that allow you to handle the touches and mark them as processed?
Call the below method and pass your parameter as PivotControl x:name and WebBrowserControl x:name to this method.
Here the WebBrowserControl is placed in second pivot item i.e. Pivot Index is 1 and I am trying to swipe left or right and reach to pivot index 2 or 1 respectively.
public static void SwipteLeftRight(Microsoft.Phone.Controls.Pivot pivotControl, Microsoft.Phone.Controls.WebBrowser webBrowserControl)
{
var gesListener = GestureService.GetGestureListener(webBrowserControl);
gesListener.Flick += ((sen, args) =>
{
if (args.Direction == System.Windows.Controls.Orientation.Horizontal)
{
if (args.HorizontalVelocity < 0)
{
if (((Microsoft.Phone.Controls.PivotItem)(pivotControl.SelectedItem)).Header.ToString().Trim() == "Pivot Item name")
{
pivotControl.SelectedIndex = 2; //Next Pivot item
}
}
else if (args.HorizontalVelocity > 0)
{
if ((Microsoft.Phone.Controls.PivotItem)(pivotControl.SelectedItem)).Header.ToString().Trim() == "Pivot Item name")
{
pivotControl.SelectedIndex = 0; // Previous Pivot Item
}
}
}
});
}
It worked for me. Cheers

Click DirectX Button from Windows Forms

I have a windows forms application where I would like to find the handle of a DirectX application, find a DirectX button in that window, and Click it.
Is this possible, and if so, where is the best place to start?
Thanks!
This is really not possible.
Unlike Windows Forms, a "DirectX Button" has no distinct windows handle. You don't actually "click" a button in a DirectX window, but rather send a mouse click to the entire DirectX window, and allow the application to do its own hit testing to "click" the "button" (which is just a graphic).
The closest you could do would be to send a mouse click to a location within the window - however, finding the location of a "button" could be very difficult.
Actually, it isn't too difficult if that is the case. A DX object can receive an click if you can isolate the object with the mouse through a reversal system, depending if it is 3D-based or 2D-based. 2D is using masking effects, and 3D adds on to translate to and from 2D/3D based space on certain properties utilized in vector calculus.
Pretty much from logical space, in 3D, a slice of the 3D object is mapped to 2D space, which is then mapped to camera space, which is then rendered. Crude, there is much more to it then that, but I'm keeping it as simple as it can be. Now the task is to find the 2D volume/per-pixel location, translate a copy of the 2D render of a 3D object on an image that will be/is already a DeviceContext for the monitor to show () to a map, and unionize a clickable object (which will run the intended code, just as a button should) to the 2D map object copy.
In other words, find where in the screen the object is rendered and generate a clickable mask over the rendered portion of the screen. Whether it is a bitmap mask, or a polygon mask, or a cube mask, or any other shape you can mathematically create; so long as the 2D clickable object actually interfaces with the mouse position and state in an constant-update system.
For example, say that application is full screen, that the resolution is 800 x 600 (keeping it simple, it could be anything), and that the object you wish to be able to interact, that is rendered in a context that doesn't permit it of it's own accord (*1), and that the rendered object shows a rectangle. Lets say that is the point of it, and the system you use for the translation outputs a Rectangle (C#.NET code, yea, but it's just an example, there are better floating around). So we can say that the mask rectangle coordinates are identical to to the rendered object coordinates.
So let's say: "Rectangle mask = new Rectangle(100, 100, 200, 100); // X starting point, Y starting point, Length, Width." Pretty self-explanatory. Add a per-frame cursor position compared with mask positions, will indicate if the cursor is above the mask, and with extra coding, can indicated if the cursor clicked (or other events) while being within the mask's range.
So let's say the button opens the main menu. And an event happens, particularly a "MouseClick" event, while the cursor hotspot is at Point(125, 200). Which of course was in the range of the mask. In this instance, through all that trivial code, opens the main menu. It is easy to add new clickable objects within this system if it is done right.
Yes, other, easier ways exist. But from them all, this is one of the more dynamic and flexible systems. Uses range from the cash you get as loot in a game that you have to click to pick up, to the UI, to the menu's, to anything clickable. The range isn't in just games, either. Custom UI designers who like to reinvent the wheel can and have taken advantage of similar systems, such as myself, like to define every aspect from the microcode to the macrocode. Precisely, to define the macrocode as it is needed, as it is expected and without unnecessary bloat through microcode management. Not saying I like microcode, as it can be way too bloody finicky, and often times, is. Worth it for the few hundred FPS you get from streamlining it right (the first time), though... >:-D
*1 = (predictable in 3D Rendering models, from the point of view Rendering is not Modifying (which seems to be including object selection (through the mouse/cursor position and all that), which is essentially what your looking for) and as such not included (directly). Through translation it becomes possible, with the finest precision if done right. Further to that, DirectX, OpenGL, and others like, are defaultly Renderers.)

Simultaneous updates across two display contexts in openGL

I have a C# .NET application with which I've created a custom image display control. Each image display represents its own display context and draws the image using glDrawPixels (Yes I know it would be better to use textures, I plan to in the futures but this app is already too far along and my time is limited).
I am now trying to have both images pan simultaneously. That is, when one image is moved down ten pixels, the second image moves down ten pixels. Like so:
imageOne.YPan -= 10;
imageTwo.YPan -= 10;
imageOne.Invalidate(); //This forces a redraw.
imageTwo.Invalidate(); //This forces a redraw.
Alright so here is the problem I am having. Only one of the images displays is redrawing. If I place a pause in between the two Invalidate calls and make the pause duration at least 110 milliseconds both will redraw, but not simultaneously. So it looks as if the second image is always trying to catch up to the first. Plus, a 110 millisecond pause slows down the motion too much.
I have tried placing the updating and invalidating of each image in its own thread but this did not help.
At the beginning of drawing I make the appropriate context is current, and at the end I am calling swapbuffers(). I tried adding a glFinish to the end of the draw function, but there was no change.
Could it be that its the graphics card that is the problem? I am stuck using an integrated gpu that only has openGL 1.4.
Hopefully, I have provided enough detail that the answer to my problem can be found.
Its difficult telling what's wrong with what you do since you give so little detail. Here are some pointers which may help.
- before doing something in a context, make sure you make it the current one. If you want to pan two contexts, make the first one current, pan it and then make the second one current and pan it. These is no real reason why this should not work.
- If it looks like there is a timing problem, adding glFinish() at strategic places may help weed the problem out
- As should always be done, on occasions call glError() and see that everything went well.
- I'm not sure how this is done in the framework you're talking about but you should make sure that both contexts get a swapBuffers() call for every frame.
Invalidate doesn't force an immediate redraw. It marks the window invalid, and when the message queue runs out of other messages, a paint message will be created and processed. But that won't happen until you finish processing the current message and return to the main message loop, and it may be delayed even more than that.
Generally OpenGL animation is an exception to the rule of doing all drawing inside Control.OnPaint (or in a handler for the Control.Paint event).

Categories