Draw not blurred path - c#

I have a path that maybe makes not much sense without some context, but I need it that way
<Path StrokeThickness="2" Stroke="Blue" >
<Path.Data>
<PathGeometry>
<PathFigure StartPoint="-10000,20">
<BezierSegment Point1="100,100"
Point2="120,120"
Point3="350, 350" />
<BezierSegment Point1="400,400"
Point2="450, 450"
Point3="200, 600" />
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
I've noticed that when I have a long path UWP by default optimizes the draw, my path gets pixelated
I don't want this behavior, is there any way to disable it?
I really need a path like this, I can't change the length of it to get a better quality.
In WPF I get what I need:

The reason for why you get the Blurry Lines in your XAML is because that you have used this StartPoint="-10000,20". Our WinRT has an issue rendering large polylines when the Polyline has any two points that are more than 2048 pixels apart it scales the polyline rather than rendering it normally.
The following explaination is quoted from Brendan Clark - MSFT in this thread:
In WinRT the size of each shape is limited by the hardware you're running your app on. The lowest common denominator is 2048 x 2048. This is large enough that everything will look sharp as long as you keep each component of your UI at roughly the same scale as a typical screen. As soon as you try to draw things that are significantly larger than the screen, the shapes will be clamped to the maximum size supported on your hardware, and will be scaled up from that point to the size you requested. Since the shape is clamped to a lower resolution than what you requested, scaling it up causes it to look blurry.
So if you change the StartPoint="-10000,20" to StartPoint="100,20", you will see it work fine.
Based on your description, I know that you do not want to change your path data, the only way to workaround this issue is to manually clip the Polyline based on the size of the viewing area, for more information, please check this code sample.

Related

Nozzle geometry WPF

I'm currently doing a CFD simple problem with C# in WPF analyzing a quasi-one-dimensional flow (only varying with x) and I want to represent the results in a "decent" way. Hence, imagine it as a rectangle with a given number of vertical sections. The form is not a rectangle, but a nozzle. What I was wondering is if there is a way of representing with Stackpanels or something similar a certain form.
In the image attached the shape can be seen, to help understand the problem.
Every section (a rectangle "cut" by the edges of the nozzle) has a temperature associated and already computed.Just to give an example, a temperature value of 250 for the section drawn, and for example I want to paint it with a Red color.
My question is: Is there any way of "shaping" stackpanels or something similar to display something like the shape shown?
I've searched for information and this is the most similar option found:
<Path Stroke="Black" StrokeThickness="1">
<Path.Data>
<PathGeometry>
<PathGeometry.Figures>
<PathFigureCollection>
<PathFigure StartPoint="10,100">
<PathFigure.Segments>
<PathSegmentCollection>
<QuadraticBezierSegment Point1="200,200" Point2="300,100" />
</PathSegmentCollection>
</PathFigure.Segments>
</PathFigure>
</PathFigureCollection>
</PathGeometry.Figures>
</PathGeometry>
</Path.Data>
</Path>
Which draws this image. What I would like to construct is the nozzle with this method and be able to divide it or place vertical segments inside it as suggested at the first image, painting them according to the value they have.
You have defined a pretty complex problem which may be too much for a single SO question. By no means am I providing a complete solution to your problem. But maybe it will be enough to point you in the right direction. From there, you can start on your own solution and ask further questions if you get stuck.
Your best solution is probably to manually draw shapes on the canvas using c# (or possibly XAML).
Here's the best link I could find after a quick search.
https://msdn.microsoft.com/en-us/library/ms751808(v=vs.100).aspx
It is a Microsoft tutorial of drawing Geometry and Geometric Shapes in XAML and code.
See the section about path geometries.
I would think that by combining two ArcSegments for the curved sides and LineSegments connecting the two sides that you could get the basic shape you are looking for.
I think that for your rectangular "cuts", you will have to build those explicitly in code as well. It will be tricky to match their shape exactly when overlaying them over the nozzle. One simple work around could be to create all your horizontal bars and paint them. Then create a top and a bottom white overlay that covers up the rectangles. One overlay would have the shape of the top nozzle and cover the parts of the rectangles you don't want shown. And similarly for another shape that makes up the bottom of the nozzle.

Aligning text to a path in WPF

I'm working on a small part of an application that requires us to draw shapes for the user to see. I'm using a path to display the shape, specifically binding a PathSegmentCollection to the PathGeometry.Figures like this --
<Path Name="Shape"
Stretch="Uniform"">
<Path.Data>
<PathGeometry>
<PathGeometry.Figures>
<PathFigureCollection>
<PathFigure IsClosed="True"
Segments="{Binding Segments}"
StartPoint="{Binding StartPoint}" />
</PathFigureCollection>
</PathGeometry.Figures>
</PathGeometry>
</Path.Data>
Somewhere on that shape, a logo will be shown, but due to the variance in the shapes, I'm struggling to think of a solution where the logo text will always be shown on the shape (the shapes can be anything, even from a DXF file).
Here's an illustration of the problem --
The left image is what I have, but the right image is what I want.
Right now I'm drawing the logo as just a textblock on a grid that's bound to the size of the shape. I ended up going this route to keep the text automatically scaled to the correct height no matter the scaled units of the shape.
Ideally what I'd like to do is place a textblock inside a path, but I know that's not possible. I was wondering if anyone had any good ideas on how to align this text to the shape no matter what shapes come up.
In theory I'd like to be able to align it to all the regular orientations (top-left, top-center, bottom-right etc).
Thanks in advance!

WinRT: How do I ensure Images are drawn in a pixel-perfect way on a Canvas?

I am adding Image instances to a Canvas in Windows Runtime environment and my image keeps getting scaled up when in 140 and 180 scale resolution displays, it looks perfect in scale resolution 100. I tried creating 3 PNG images, one for each scale size: 100, 140, 180 but it still scales them up and they look blurry. I created a test image with 4 black pixels on a cyan background and I took a screenshot from the simulator, see how the image is blurry, my original image has just 4 perfect black pixels:
I tried changing the stretch mode of my Image objects, but it does nothing. I'm using this code to add the images at runtime:
var bitmapImage = new BitmapImage();
StorageFile bitmapFile = await StorageFile.GetFileFromApplicationUriAsync(imageUri);
await bitmapImage.SetSourceAsync(await bitmapFile.OpenReadAsync());
Image image = new Image{ Source = bitmapImage};
image.SetValue(Canvas.LeftProperty, x);
image.SetValue(Canvas.TopProperty, y);
canvas.Children.Add(image);
How do I get the images to draw pixel perfectly in the canvas without scaling and at the exact x/y coordinates I want?
I think I have a workaround, but it requires two steps:
First I have to load the image using a more a standard way that doesn't involve getting the file path like so.
var bitmapImage = new BitmapImage(imageUri);
Somehow this must retain more information internally that this image came from a file with the corresponding ResolutionScale for the current display. Thus when it is drawn by the canvas it is not scaled at all. However this only solves half the problem.
The next problem is that the x, y coordinates used to specify where the image is drawn are being scaled so the image is drawn in the wrong place, further than where I wanted. The only thing I can figure to do is unscale them first like so:
var resScale = DisplayInformation.GetForCurrentView().ResolutionScale;
Image image = new Image{ Source = bitmapImage};
image.SetValue(Canvas.LeftProperty, (x * 100.0) / (int)resScale);
image.SetValue(Canvas.TopProperty, (y * 100.0) / (int)resScale);
canvas.Children.Add(image);
The whole thing seems a bit crazy but it seems to work so far... Anyone have a better solution or an explanation why all this is necessary? Seems like the Canvas class needs an unscaled mode that doesn't mess with the images or coordinates across different resolution displays.
UPDATE: This doesn't work perfectly, using a double to store the value results in precision loss and sometimes there are anti-aliasing artifacts. This is not acceptable if you want pixel perfect graphics. I am still looking for a perfect solution.
There are a few more things that might help with your solution.
Use UseLayoutRounding="False" on your image.
Put your Canvas in a full-screen Viewbox, then set the Canvas Width and Height to the screen resolution. You'd use unscaled Canvas.Left/Top values in this case.
Use Direct2D/Direct3D for rendering.
Good luck.
You can change the Stretch property to "None", If you image is still meshed-up:
You should look at what DPI it is saved on. WPF tries to be DPI-independend, so it tries to draw an image of 5"x5" on every monitor the same size. Even when the resolution is higher, it still should be 5"x5" only a high resolution would render(rasterize) the image in higher quality.
Here's some info: http://www.wpflearningexperience.com/?p=41
How do I convert a WPF size to physical pixels?
Here's a piece of xaml code
you can always use scale transform from code behind to scale the images to appropriate amount be it less or more.
<Image Canvas.Left="150" Height="170" Width="170" Visibility="Visible" Stretch="None">
<Image.Source >
<BitmapImage UriSource="ms-appx:///Assets/rollingDieSprite.png"></BitmapImage>
</Image.Source>
<Image.RenderTransform>
<ScaleTransform ScaleX="4" ScaleY="4" x:Name="scaleTfDie"></ScaleTransform>
</Image.RenderTransform>
</Image>
in c# code behind you can go for the following
ScaleTransform sc = new ScaleTransform();
sc.ScaleX = 0.9;
sc.ScaleY = 0.9;
imgDieRolling.RenderTransform = sc;
this will control the scaling . try using fill=none . Let me know if it works.
I found this issue quite problematic as well. I'm creating custom bitmaps and drawing them at different positions on the canvas. I couldn't find a way in the XAML, but I found a way using Direct2D. When you set up your D2DContext, there's a function called SetUnitMode(). The default unit mode is "DIPS" which causes all drawing to be scaled. By switching to PIXELS mode, the system stops scaling the drawing and does everything 1:1.
m_d2dContext->SetUnitMode(D2D1_UNIT_MODE_PIXELS);

How do I animate a PathGeometry to show itself slowly?

Hi have the following piece of XAML
<Path Stroke="#FF000000" StrokeThickness="3" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeDashCap="Round" StrokeLineJoin="Round" StrokeMiterLimit="4" Name="kvg_0994c_s1">
<Path.Data>
<PathGeometry FillRule="Nonzero" Figures="M28.27,12.64C28.32,13.27 28.52,14.32 28.17,15.16 25.86,20.7 19.22,31.55 9.81,39.71" />
</Path.Data>
</Path>
I wish to animate the PathGemorty to reveal itself slowly (over 2 seconds or so). Basically the effect that I am after is drawing a line on the screen automatically, in particular the path that is specified in the code above.
I need to do this in C# code as I am loading the XAML dynamically from an external file. Any help would be greatly appreciated.
You must use WPF animation for it. Look here: http://msdn.microsoft.com/en-us/library/ms752312.aspx More information about animation you can find in excellent book "Windows Presentation Foundation Unleashed" by Adam Nathan.
I think you can find exact answer on your question here: http://social.msdn.microsoft.com/Forums/en/wpf/thread/19a7bd4b-cf28-4b31-a329-a5f58b9ec374
what do you mean by 'reveal itself slowly' ? You mean like it was drawn bit by bit ? Then you'll have to decompose the Data, then re-compose a geometry adding elements one by one. So you might, using the Path's name (kvg_0994c_s1) in code behind, (and assuming the Path.Data is always a PathGeometry, so you can cast it to PathGeometry) you get the PathGeometry.Figures in an initial List, then clear the figures in the displayed Path. Then you set-up a timer (a DispatchTimer might be enough) to call a function every 200ms or so and in this function you add one by one the figures to the PathGeometry.Figures of the displayed path. You might have to adjust both the number of parts you add each time, and timer values to get the effect you want. And if you want constant 'speed' -> you have to compute the length of each part and adjust. But it might be nice to have non-constant speed to look more like hand-drawing.

Tiling rectangles seamlessly in WPF while maintaing subpixel accuracy?

I have had the problem described in the question Tiling rectangles seamlessly in WPF, but am not really happy with the answers given there.
I am painting a bar chart by painting lots of rectangles right next to each other. Depending on the scale of the canvas containing them, there are small gaps visible between some of them as a result from sub-pixel rendering.
I learned from the above question how to make my rectangles fit with the screen pixels, removing that effect.
Unfortunately, my chart may display way more bars than there are pixels. Apart from the tiny gaps (which manifest as a periodic change in color saturation), this works well. If I snap each bar with the screen pixels, most of the bars vanish, though, so I am looking for another solution.
Thanks in advance!
Cause of the problem
Subpixel shapes use alpha blending within the pixel. Unfortunately there is no alpha blending algorithm that results in the rectangles blending seamlessly when abutted.
For example, if:
The background color is white
The foreground color is black, and
You have two rectangles, each covering half of a single pixel
Each rectangle will be painted as black with 50% opacity. The first converts the white pixel to gray. The second converts it to a darker gray, but not black. If these rectangles continue black in adjacent pixels you see a dark gray pixel among the black.
Two types of solutions
There are two general ways to solve this problem:
Use a single Geometry to define all your rectangles, or
Force the initial rendering to be at a high enough resolution your user won't see the problem.
How to use a single Geometry
If you just have a set of Rectangles, you can create a simple control that paints over the whole set of rectangles with a single PathGeometry containing the combined shape. To illustrate the idea, if you had two rectangles beside each other of different heights, like this:
<Rectangle Canvas.Left="0" Canvas.Top="0" Width="1.5" Height="2" Fill="Red" />
<Rectangle Canvas.Left="1.5" Canvas.Top="0" Width="1.5" Height="4" Fill="Red" />
You could render it with a single PathGeometry like this:
<Path Data="M0,0 L0,2 L1.5,2 L1.5,4 L3,4 L3,0 Z" Fill="Red" />
A practical way to implement this is to:
Paint your rectangles with a Transparent brush so they will be clickable but not visable
Add a Path control underneath the rectangles in Z order
Data binding the Data property of your Path control to your data source with a converter that constructs the geometry.
If you are using the layout system to position your rectangles, you may instead want to use an AdornerLayer by creating an Adorner for each rectangles, then when rendering the adorners compute the combined path for the first one and make the rest invisible.
The above assumes it is easy to generate the PathGeometry from the source data. For more complex scenarios, the Path control can be subclassed to search the visual tree of its parent for specified shapes and use general geometricl algorithms to compute a PathGeometry that represents the union of them with no extra edges.
If your rectangles will have multiple colors, you can use multiple Path controls one per color, or you can construct a Drawing object and show that.
Here is the structure of the code to construct a PathGeometry:
var geo = new PathGeometry();
var figure = new PathFigure();
var segment = new PolyLineSegment();
segment.Points.Add(...);
segment.Points.Add(...);
segment.Points.Add(...);
segment.Points.Add(...);
segment.Points.Add(...);
figure.Segments.Add(segment);
geo.Figures.Add(figure);
How to force the initial rendering to be at high resolution
To force rendering at higher resolution:
Internally construct your chart several times larger than you want to display it, for example by wrapping it in a ViewBox.
Use a VisualBrush or RenderTargetBitmap to force your chart to be rendered separately
Add a Rectangle painted with that VisualBrush to your UI
Note that normally WPF is clever about rendering at the actual resolution required when you use a ViewBrush, but it can be tricked by having the actual chart actually display on the screen at the larger size, but then be clipped by a parent control so you don't actually see the too-big version.
This problem doesn't exist with RenderTargetBitmap, of course, since you specify the resolution you want, but it can be tricky knowing when to re-render the bitmap. If you only re-render on data changes you can use an event, but if you want any visual change to trigger a re-render it is more difficult.

Categories

Resources