I am not sure if this is the right place to ask for such concept information advice, so I apologise if it's unrelated or off-topic to ask in Stack Overflow.
I want to develop an application in WPF which has the ability to draw polygons with the functionality of a regular control, they may change shape by adding, removing or moving vertices, change brushes all by run-time, from data-binding or perhaps direct manipulating from C# code (still not sure about that).
What I am trying to achieve is an application which draws a map and the shapes on it are the entities with the dynamic borders over the map (for instance say political borders). The polygons also have to be clickable controls with collision test (not just a bounding box, but exactly by the shape of the entity on the map). I can expect the shapes to be very detailed because of borders which found by rivers and mountains or other natural objects which not just a straight line of two vertices, so it's performance should be an important factor here because one polygon may contain hundreds of vertices).
What I've concluded that it is possible to achieve via WPF such an application. But my uncertainty is on the most efficient way to implement the map drawing, perhaps I should implement D3D hosting like SharpDX but I don't want it, it would make things even more complicated and difficult.
I prefer everything in this map to be functional as a regular WPF control with it's data-binding and stylising abilities. I've developed with WPF some several small test projects for months to learn the basics and its main concept. But now comes the main interest of mine to develop with WPF. I need some advice please, because drawing complicated and dynamic shapes is still not really clear to me to just go on and start develop it.
I would use WPF, indeed I would say WPF is perfect for this, though there will be considerable amount to learn. WPF uses DirectX so is preformant enough I imagine (provided you have the hardware).
You will need to become familiar with:
UserControl
DependencyProperties
Polygon
Canvas
However if you are not already familiar with Dependency Properties, they can be a headache to learn, so rather than creating your own UserControl with them, you can get away with a Canvas in your Window and build things programmatically or at design time in XAML.
As for actually drawing shapes; if you know ahead of time what the shapes will look like you can draw them ahead of time using tool like Blend (or by yourself in XAML - you will need to become familiar with the Path Markup Syntax) then you can use transforms such as a ScaleTransform to transform them at run-time, or if you want to build them at run-time you can do so programmatically adding points to a Polygon
e.g. from (Polygon)
//Add the Polygon Element
myPolygon = new Polygon();
myPolygon.Stroke = System.Windows.Media.Brushes.Black;
myPolygon.Fill = System.Windows.Media.Brushes.LightSeaGreen;
myPolygon.StrokeThickness = 2;
myPolygon.HorizontalAlignment = HorizontalAlignment.Left;
myPolygon.VerticalAlignment = VerticalAlignment.Center;
System.Windows.Point Point1 = new System.Windows.Point(1, 50);
System.Windows.Point Point2 = new System.Windows.Point(10,80);
System.Windows.Point Point3 = new System.Windows.Point(50,50);
PointCollection myPointCollection = new PointCollection();
myPointCollection.Add(Point1);
myPointCollection.Add(Point2);
myPointCollection.Add(Point3);
myPolygon.Points = myPointCollection;
myGrid.Children.Add(myPolygon);
Related
This is more of a "Is it possible (with a reasonable amount of time and work)" than a "how exactly is it possible" question. I'm getting into WPF at the moment and am interested in graphical applications in an MVVM approach. In the meaning of an ms-paint like application. Now I see that and how I can draw e.g. a ractangle on a canvas, store those rectangles in a list etc.
But I am wondering if I can do that more advanced. For example extend the rectangle so I can give it more infos (I can't extend the rectangle itself since it's a sealed class), have existing shapes on the canvas able to drag them around, make the shapes complex (e.g. I double click one to open a new Window that represents the "inside" of that shape) etc.
Is such an application possible with a reasonable amount of work and time in WPF or would I rather use some different library/framework for this?
Yes, It is possible, Actually, you are listing CAD specifications, In fact, I work on this type of technology, so I'll suggest you some resources to have a clue..
Take a look at this project(WPF, 2D)
And this one(WPF, 3D)
And this one(WPF, 2D)
The previous projects are WPF-based, also, you might host a WinForm control in your WPF app, take a look at this one(WinForms, 2D)
If you change the specification a bit and say: "I don't want to edit the drawings on the canvas", then you could go with this option: convert your shapes to PathFigureCollection and EllipseGeometry objects, then construct Paths from these objects and add the Paths to the Canvas, this is a pure WPF approach. Indeed, you can add traditinal controls like TextBlocks as children to your Canvas, I have done such one like this..
Hope it helps.
i am refactoring some code that used System.Drawing classes and GDi in order to draw a complex map image. The image consists of objects like lines and polygons.
In order to clip the objects, we used a implementation of a clipping algorithm, that first checked wether the object ist within the borders of a bitmap or not. If it was intersecting, the object got clipped.
We now want to draw the same map image with WPF methods. I am using drawinggroups to create the geometry drawings. DrawingGroups offer the possibility of adding a ClipGeometry, like that:
TileSize = new RectangleGeometry(new Rect(tileOrigin, new Size(Width, Height)));
mapDrawing.ClipGeometry = TileSize;
The result looks good, and i can "feel" no difference in performance. Problem is, i have a hard time to measure that. I can definetly say how long it took to clip the objects with our algorithem, but i cant measure what time is needed for the clipping with the ClipGeometry. I guess the clipping is done when the UI starts rendering the drawings.
My questions:
How could i measure the time needed for clipping with WPF ClipGeometry?
Does anyone know how exactly ClipGeometry does the clipping?
Thanx for your input!
I'm working on an application that has a graphic editor. Aside from some other graphic components the main feature are some shapes (rectangles, triangles, stars etc.). The thing I would like to do is to have the ability to resize them after a double click, so there should be a container shown with points that can be dragged to resize the shape. There are many great tutorials out in the internet but mainly for rectangles or for other shapes that are "packed" into rectangle viewboxes.
The issue is that I need to have my resize points exactly on the vertexes, so for example I can't have a triangle inside a rectangle viewbox, but I need exactly three points - one on every vertex. The same applies for the other shapes like stars and arrows which are much more complicated.
Here's what I mean:
So I think I have two ways. Either pass a dynamic list of points after a double click and display them as separate shapes or binding them with my shape inside my shape class, but I cannot figure out how to add multiple shapes to a viewbox so that they keep their abilities. Here is a simplified snippet of how my shape classes look like:
public class RectangleObject : ShapeObject
{
private Rectangle _rectangle;
private Viewbox _viewbox;
public RectangleObject(Color fillColor)
{
_rectangle = new Rectangle()
{
Fill = new SolidColorBrush(fillColor),
Stretch = Stretch.Fill
};
_viewbox.child = _rectangle;
}
public void SetDimensions(){}
//... and some other methods
}
A nice solution would be if the viewbox could contain my shape and the resize points but I will appreciate any advice. I know that a canvas would be a better solution but all other components are packed in viewboxes so it would be problematic because of inheritance and would need many changes. Thanks in advance!
Yes I know exactly what you mean. I used CorelDraw back in the day and then Adobe Illustrator and both had the concept of shape transformation mode (your image on the right) as well as vertex edit mode (your image on the left). UWP is similar to WPF and WPF has a concept of adorners which you can customise to do whatever you want including what I just described.
So when you enter one of these modes, rather than modify your existing shape to show selectors; instead you create adorners that are superimposed over the shape. That way one doesn't clobber the other and you may have custom behavior for each as you indicated.
See also
Adorners - MSDN, https://msdn.microsoft.com/en-us/library/ms743737(v=vs.110).aspx, retrieved 2017-1-12
In a WPF standalone-application I need to draw an image based on a series of 'commands' such as "text a at position x,y" and "draw line from x1,y1 to x2,y2".
My problems and considerations are outlined below - any help and comments are most appreciated!
The image is of a water pump constructed by our company.
The commands are generated by a proprietory system within our company.
There are no problems interpreting the commands.
My issue is with
a) what WPF control should I choose to draw it 'on' ?
b) how can I move the major part of the code to unit-testable classes?
a1) I have tried with PathGeometry, which is excellent for drawing geometric shapes but can't draw text.
a2) I have tried with Shape, which supports drawing text, but is less advanced with respect to geometry.
a3) Could I use the strength in each of the two, and 'apply' a PathGeometry to a Shape?
a4) I need to handle MouseOver after the drawing to highlight based on the mouse position. It can be done through computing 'behind the scenes' the object nearest mouse position (though possible, it's heavy!) but can the choice of rendering Control help me out?
b1) I do not expect the end drawing to be subjectable to test?
b2) How 'deep' should I reference controls belonging in the GUI? Gut feeling says no deeper than ViewModel (not business level), but the higher I keep it, the more code remains in places where they can't be unit tested.
Here are answers specific to WPF:
You can draw on a Canvas, wich lets you set element's position (Canvas.SetLeft, Canvas.SetTop, ...)
And you can perfectly use PathGeometry, Shape, etc... you should also have a loop at GeometryGroup which allows to group all geometry as one.
For the text, if you want text as a Geometry, you can use FormattedText with the BuildGeometry method..
About unit testing.
WPF databinding is very good with binding data, such as string to text box. It is less good with user commands. It is even worse with telling UI to do things, such as "draw line" - you may be able to come up with some funky ItemPresenter bound to collection of shape view models, but I imagine it would be hard and will introduce too many unnecessary artifacts. Bottom line: MVVM is probably not for this project.
Instead, you may use the "passive view" approach. You define a control-agnostic "virtual machine" interface for your view. Something like
interface IView
{
void AddLine(int x1, int y1, int x2, int y2);
void DrawText(...);
}
Your view should have a straightforward implementation of this interface with minimum logic: each method is maximum 2-3 lines, no conditions or loops. This is a "dumb" passive view which is not testable.
The rest of the system (namely, Presenter) talks to the IView interface and knows nothing about WPF or controls. Well, it may use some simple WPF types such as Color or Rectangle for convenience.
You can use mock library (e.g. Rhino Mocks) to write tests that make sure your Presenter makes the right calls to your passive view. You create a "mock" view and pass it to the presenter.
I have written a chart that displays financial data. Performance was good while I was drawing less than 10.000 points displayed as a connected line using PathGeometry together with PathFigure and LineSegments. But now I need to display up to 100.000 points at the same time (without scrolling) and it's already very slow with 50.000 points. I was thinking of StreamGeometry, but I am not sure since it's basically the same as a PathGeometry stroring the information as byte stream. Does any one have an idea to make this much more performant or maybe someone has even done something similar already?
EDIT: These data points do not change once drawn so if there is potential optimizing it, please let me know (line segments are frozen right now).
EDIT: I tried StreamGeometry. Creating the graphic took even longer for some reason, but this is not the issue. Drawing on the chart after drawing all the points is still as slow as the previous method. I think it's just too many data points for WPF to deal with.
EDIT: I've experimented a bit and I noticed that performance improved a bit by converting the coordinates which were previously in double to int to prevent WPF anti-aliasing sub-pixel lines.
EDIT: Thanks for all the responses suggesting to reduce the number of line segments. I have reduced them to at most twice the horizontal resolution for stepped lines and at most the horizontal resolution for simple lines and the performance is pretty good now.
I'd consider downsampling the number of points you are trying to render. You may have 50,000 points of data but you're unlikely to be able to fit them all on the screen; even if you charted every single point in one display you'd need 100,000 pixels of horizontal resolution to draw them all! Even in D3D that's a lot to draw.
Since you are more likely to have something like 2,048 pixels, you may as well reduce the points you are graphing and draw an approximate curve that fits onto the screen and has only a couple thousand verts. If for example the user graphs a time frame including 10000 points, then downsample those 10000 points to 1000 before graphing. There are numerous techniques you could try, from simple averaging to median-neighbor to Gaussian convolution to (my suggestion) bicubic interpolation. Drawing any number of points greater than 1/2 the screen resolution will simply be a waste.
As the user zooms in on a part of a graph, you can resample to get higher resolutions and more accurate curve fitting.
When you start dealing with hundreds of thousands of distinct vertices and vectors in your geometry, you should probably consider migrating your graphics code to use a graphics framework instead of depending on WPF (which, while built on top of Direct3D and therefore capable of remarkably efficient vector graphics rendering, has a lot of extra overhead going on that hampers its efficiency). It's possible to host both Direct3D and OpenGL graphics rendering windows within WPF -- I'd suggest moving that direction instead of continuing to work solely within WPF.
(EDIT: changed "DirectX" in original answer to "Direct3D")
Just ran into this question, but as I mentioned in this thread, the most performant approach might be to program against WPF's Visual layer.
Everything Visual in WPF eventually goes against this layer ... and so it is the most lightweight approach of them all.
See this and this for more info. Chapter 14 of Matthew MacDonald's Pro WPF in C# 2008 book also has a good section on it.
As another reference ... see Chapter 2 of Pavan Podila's book WPF Control Development Unleashed. On page 13, he discusses how DrawingVisuals would be an excellent choice for a charting component.
Finally, I just noticed that Charles Petzold wrote an MSDN Magazine article where the best overall (performant anyway) solution (to a scatter plot) was a DrawingVisual approach.
Another idea would be to use the Image control with the Source property set to a DrawingImage that you've dynamically created.
According to Pavan Podila in WPF Control Development Unleashed, this approach can be very helpful when you have thousands and thousands of visuals that don't need any interactivity. Check out page 25 of his book for more info.
This is an old thread, but I thought it was worth mentioning that you could attain interactivity with the above method by using the MouseUp() event. You know the size of the image's viewport, the resolution of the image, and the mouse's position. For example, you could maintain the collection actualScreenPoints through a timer attached to your UserControl_SizeChanged event:
double xworth = viewport.ActualWidth / (XEnd - XStart);
double xworth = viewport.ActualHeight / (YEnd - YStart);
List<Point> actualScreenPoints = new List<Point>();
for (var i = 0; i < points.Count; i++)
{
double posX = points[i].X * xworth;
double posY = points[i].Y * yworth;
actualScreenPoints.Add(posX, posY);
}
And then when your MouseUp() event fires, check if any of the points in the collection are within +-2px. There's your MouseUp on a given point.
I don't know how well it scales, but I've had some success using ZedGraph in WPF (WinForms control inside a WindowsFormsPresenter). I'm surprised no one mentioned it yet. It's worth taking a look at, even if you're not planning on using it for your current project.
ZedGraph
Good luck!
I believe the only method that might be faster while remaining in the WPF framework would be to override OnRender in a custom control. You can then render your geometry directly to the persisted scene, culling anything out of view. If the user can only see a small part of the data set at a time, culling could be enough on its own.
With this many data points, it's unlikely that the user can see full detail when the entire dataset is in view. So it might also be worthwhile to consider simplifying the dataset for full view and then showing a more detailed view if and when they zoom in.
Edit: Also, give StreamGeometry a shot. Its whole reason for existing is performance, and you never know until you try.
This is a very good question, and at it's heart begs the question "Can any user make practical use of, or business descisions from, a screen containing 100,000 discrete points?".
Following best practice in GUI design philosphy, the answer should be No, which would lead me to question whether there isn't a different way to meet the requirement for the application.
If there really is a bona-fide case for displaying 100,000 points on screen, with no scrolling, then using an off-screen buffer is the way to go. Composite your image to a bitmap, than whack that bitmap onto your Window / Page as needed. This way the heavy lifting is only done once, after which the hardware acceleration can be used every time the window needs to be drawn.
Hope this helps.
I haven't worked with WPF (disclaimer), but I suspect that your performance problem is because your code is trying to fit a smooth curved line through all of your data, and the time required increases geometrically (or worse) with the number of data points.
I don't know if this would be acceptable appearance-wise, but try graphing your data by connecting each point to the last with a straight line. This should make the time-to-graph proportional to the number of data points, and with as many points as you have the graph may end up looking exactly the same anyway.
Another idea would be to use the Image control with the Source property set to a DrawingImage that you've dynamically created.
According to Pavan Podila in WPF Control Development Unleashed, this approach can be very helpful when you have thousands and thousands of visuals that don't need any interactivity. Check out page 25 of his book for more info.