Evenly Spaced Dashes with StrokeDashArray - xaml

I'm trying to create a poker chip like the one here: http://www.casinowholesalers.com/shop/product_info.php?cPath=57&products_id=379 using Expression Blend 4 for a WP7.1 Silverlight 4 app.
I'm trying to create the six white "boxes" on the edge of the chip (ignoring for now the dice images and inner dashed line). The way I did it was two create two ellipses, one with no stroke, the other is the exact same size but with a stroke of 24, a color of White, and the StrokeDashArray to 1.8 (that's not "1 8", it's actually 1.8 with no second value). It looks pretty close to evenly sized and spaced (but not quite); I found it by trial and error. The XAML is below.
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Ellipse Fill="#FFC83838" Margin="112,253,128,275" Grid.Row="1" Stroke="#FFC83838" StrokeThickness="3"/>
<Ellipse Fill="#FFC83838" Margin="112,253,128,275" Grid.Row="1" Stroke="White" StrokeThickness="30" StrokeDashArray="1.79" StrokeDashOffset="6" RenderTransformOrigin="0.5,0.5"/>
</Grid>
I guess I have two questions:
Is there a better way to create this shape besides using two ellipses?
How can I mathematically determine what the StrokeDashArray value should be so the dashes are evenly spaced and sized instead of using trial and error?

I'll start from the second point.
First, the inner logic of StrokeDashArray is explained here. The important point is that the stroke dash array is not expressed in pixels, it's dependent upon stroke thickness to get the final pixel value for each number in the array.
So, for the math part, lets define some variables:
S - visible portion of the stroke (same as in the link).
G - the non-visible portion of the stroke (same as in the link).
r - the radius of your chip. It will be half of the actual width or half of the actual height.
n - the number of repetitions of S+G that you want. Integer.
T - stroke thickness
p - the mathematical pi (3.14...)
So we have:
2*p*r = n*(T*S+T*G)
Or,
S+G = 2pr/nT
In your case, and what I see from the image of the chip, the visible part of the stroke is square so S=1, there are six white squares with six gaps so n=6 and you decided for thickness of 30px so T=30. This gives you the value of G as:
G = 2pr/180 - 1
You can get the value of r from blend, the actual width and height will be written in parenthesis in the Width and Height boxes - divide it by two. From the details that you provided, I guess the radius is 102.55. And the final stroke dash array is:
StrokeDashArray="1,2.58"
For your first point, the answer is: it depends. If your chip is the same throughout the life-time of the application - this is the best way. It gives you the slight curvature on the outside to make the "square" flush with the outer contour of the chip and it requires a one-time calculation in design time.
Even if you have different sizes for the chip, this might be the best way to implement the graphics for the chip. Provided, you can design it with fixed size and then sticking it into a ViewBox and it still looks good.
If there's a need for variable sizes and the view box route doesn't work - there's another way to implement it (because Silverlight fails when you bind to ActualWidth\ActualHeight properties) - with Borders that hold rectangles. But it opens a whole new can of worms, and this answer is long enough. :)

Related

Line Profile Diagonal

When you make a line profile of all x-values or all y-values the extraction from each pixel is clear. But when you take a line profile along a diagonal, how does DM choose which pixels to use in the one dimensional readout?
Not really a scripting question, but I'm rather certain that it uses bi-linear interpolation between the grid-points along the drawn line. (And if perpendicular integration is enabled, it does so in an integral.) It's the same interpolation you would get for a "rotate" image.
In fact, you can think of it as a rotate-image (bi-linearly interpolated) with a 'cut-out' afterwards, potentially summed/projected onto the new X-axis.
Here is an example
Assume we have a 5 x 4 image, which gives the grid as shown below.
I'm drawing top-left corners to indicate the coordinates system pixel convention used in DigitalMicrgraph, where
(x/y)=(0/0) is the top-left corner of the image
Now extract a LineProfile from (1/1) to (4/3). I have highlighted the pixels for those coordinates.
Note, that a Line drawn from the corners seems to be shifted by half-a-pixel from what feels 'natural', but that is the consequence of the top-left-corner convention. I think, this is why a LineProfile-Marker is shown shifted compared to f.e. LineAnnotations.
In general, this top-left corner convention makes schematics with 'pixels' seem counter-intuitive. It is easier to think of the image simply as grid with values in points at the given coordinates than as square pixels.
Now the maths.
The exact profile has a length of:
As we can only have profiles with integer channels, we actually extract a LineProfile of length = 4, i.e we round up.
The angle of the profile is given by the arc-tangent of dX and dY.
So to extract the profile, we 'rotate' the grid by that angle - done by bilinear interpolation - and then extract the profile as grid of size 4 x 1:
This means the 'values' in the profile are from the four points:
Which are each bi-linearly interpolated values from four closest points of the original image:
In case the LineProfile is averaged over a certain width W, you do the same thing but:
extract a 2D grid of size L x W centered symmetrically over the line.i.e. the grid is shifted by (W-1)/2 perpendicular to the profile direction.
sum the values along W

How to centre Image in Xamarin.Forms without stretching it

I've got this ContentPage:
<ContentPage.Content>
<Grid>
<Image
Source="background.png"
Aspect="AspectFill"
/>
<Image
Source="logo.png"
VerticalOptions="Center"
HorizontalOptions="Center"
/>
</Grid>
</ContentPage.Content>
But logo.png (while vertically and horizontally entered), stretches to take up the entire width of the screen.
How do I stop it from stretching and just maintaining its original size?
And yes, XAML solution definitely preferred.
Edit 1 (based on Paul Kertscher's answer):
If I set the Image source to a URL (e.g. https://via.placeholder.com/450x300.png?text=Computer+Says+No), I get the expected result, i.e the image does not stretch. However, if I save this same image to the specific platform directory (say Resources/ComputerSaysNo.png for iOS), it stretches to take up the entire screen width.
Tested on iPhone 7 simulator.
Edit 2
If I make #2x and #3x copies of my logo.png in the iOS Resources directory, and have all three images the same size, it works differently; the logo does not stretch to take up the entire width of the page.
From the documentation about AspectFill
Scale the image to fill the view. Some parts may be clipped in order to fill the view.
You should use AspectFit instead, it does not stretch the image to fill the control, but to fit the whole image in the control:
Scale the image to fit the view. Some parts may be left empty (letter boxing).
EDIT
I've tried the following
<Grid>
<Image HorizontalOptions="Center"
VerticalOptions="Center"
Source="http://lorempixel.com/output/abstract-q-c-200-200-6.jpg" />
</Grid>
and it yielded the following layout:
Hence it looks like what I've proposed is right - at least principally. I'd guess your image is simply too large.
Anyway, if you want to keep that image or would like to have more control over how the image is displayed, you could opt to either one of the following options.
Use the grid system to determine the size of the image
Within the Grid you can define columns and rows. Columns (and rows respectively) defined with the width (height) of * will take all the available space. If there are multiple columns or rows with * size, they will devide the remaining space equally. Furthermore you can give the * columns and rows weights. Ar column with the width 2* will have twice the width of one with the width *. Hence you could define columns with width 3*, *, and 3* and place your image in the second column (column index 1) for the image to take 1/7th of the screen width.
Use an AbsoluteLayout
Within an AbsoluteLayout you can define positions and sizes of child elements. Instead of positioning the images in a Grid, you could do the following
<AbsoluteLayout>
<Image AbsoluteLayout.LayoutFlags="All" AbsoluteLayout.LayoutBounds="0,0,1,1" /> <!-- Background -->
<Image AbsoluteLayout.LayoutFlags="All" AbsoluteLayout.LayoutBounds=".5,.5,.2,.2" /> <!-- Logo with 20% width/height -->
</AbsoluteLayout>
If you preferred setting the size of the image absolutely, you can do the following
<Image AbsoluteLayout.LayoutFlags="PositionProportional" AbsoluteLayout.LayoutBounds=".5,.5,150,150" />
Another option which I use quite often is AbsoluteLayout. Combining PositionProportional (LayoutFlags) with LayoutBounds="0.5,0.5,-1,-1 (X, Y, Width, Height) will put image in the center of the screen. The LayoutBounds "0.5" means it will be in the center of X and Y, and "-1" will help to ignore the width and height.
Make sure to set VerticalOptions to in your AbsoluteLayout.
Here is the code:
<AbsoluteLayout VerticalOptions="FillAndExpand">
<StackLayout AbsoluteLayout.LayoutBounds="0.5,0.5,-1,-1" AbsoluteLayout.LayoutFlags="PositionProportional">
<Image Source="http://lorempixel.com/output/abstract-q-c-200-200-6.jpg" />
</StackLayout>
</AbsoluteLayout>
I hope it helps.

Finding the length of a line through every pixel

I have a raster image with multiple polyline feature classes over it. The lines are not overlapping but they are in multiple different orientations. For every pixel in the raster, I want to calculate the length of the line through that pixel so that the result would be a raster with cells assigned a float value of zero to 2^0.5 times the cell size. What's the best way to do this? I'm using ArcPro with an advanced license.
You can have a look at the answers to a similar question here (using R --- but you have a license for that too)
https://gis.stackexchange.com/questions/119993/convert-line-shapefile-to-raster-value-total-length-of-lines-within-cell/120175

implement shape to display 2D laser scan data

I'm working on a Win8 editor which is basically based on a Canvas and Shapes like Line, Rectangle, etc. on it. Those shapes can be manipulated by the user. Now I want to implement a custom shape that take a list of 2D points from a laser scan (used in architecture).
So my question is, which base primitive would you use to display lets say 500 points? I was thinking of a Path but then I get rather a set of connected lines (path, polygone) instead of just the dots. So what else?
This picture illustrates what I want to achieve. All blue dots should be in one shape that can be dragged by the user.
My first guess would be the PathGeometry filled with a lot of RectangleGeometries or EllipseGeometries. But I wonder what this means in terms of performance.
<Path Fill="LemonChiffon" Stroke="Black" StrokeThickness="1">
<Path.Data>
<RectangleGeometry Rect="50,50,5,5" />
<RectangleGeometry Rect="60,50,5,5" />
<RectangleGeometry Rect="70,50,5,5" />
...
</Path.Data>
</Path>

Draw tiled images in CGContext with a scale transformation gives precision errors

I want to draw tiled images and then transform them by using the usual panning and zooming gestures. The problem that brings me here is that, whenever I have a scaling transformation of a large number of decimal places, a thin line of pixels (1 or 2) appears in the middle of the tiles. I managed to isolate the problem like this:
CGContextSaveGState(UIGraphicsGetCurrentContext());
CGContextSetFillColor(UIGraphicsGetCurrentContext(), CGColorGetComponents([UIColor redColor].CGColor));
CGContextFillRect(UIGraphicsGetCurrentContext(), rect);//rect from drawRect:
float scale = 0.7;
CGContextScaleCTM(UIGraphicsGetCurrentContext(), scale, scale);
CGContextDrawImage(UIGraphicsGetCurrentContext(), CGRectMake(50, 50, 100, 100), testImage);
CGContextDrawImage(UIGraphicsGetCurrentContext(), CGRectMake(150, 50, 100, 100), testImage);
CGContextRestoreGState(UIGraphicsGetCurrentContext());
With a 0.7 scale, the two images appear correctly tiled:
With a 0.777777 scale (changing line 6 to "float scale = 0.777777;"), the visual artifact appears:
Is there any way to avoid this problem? This happens with CGImage, CGLayer and primitive forms such as a rectangle. It also happens on MacOSx.
Thanks for the help!
edit: Added that this also happens with a primitive form, like CGContextFillRect
edit2: It also happens on MacOSx!
Quartz has a floating point coordinate system, so scaling may result in values that are not on pixel boundaries, resulting in visible antialiasing at the edges. If you don't want that, you have two options:
Adjust your scale factor so that all your scaled coordinates are integral. This may not always be possible, especially if you're drawing lots of things.
Disable anti-aliasing for your graphics context using CGContextSetShouldAntialias(UIGraphicsGetCurrentContext(), false);. This will result in crisp pixel boundaries, but anything but straight lines might not look very good.
When all is said and done, iOS is dealing with discrete pixels on integer boundaries. When your frames are reduced 0.7, the 50 is reduced to 35, right on a pixel boundary. At 0.777777 it is not - so iOS adapts and moves/shrinks/blends whatever.
You really have two choices. If you want to use scaling of the context, then round the desired value up or down so that it results in integral scaled frame values (your code shows 50 as the standard multiplication value.)
Otherwise, you can not scale the context, but scale the content one by one, and use CGIntegralRect to round all dimensions up or down as needed.
EDIT: If my suspicion is right, there is yet another option for you. Lets say you want a scale factor of .77777 and a frame of 50,50,100,100. You take the 50, multiply it by the scale, then round the return value up or down. Then you recompute the new frame by using that value divided by 0.7777 to get some fractional value, that when scaled by 0.7777 returns an integer. Quartz is really good at figuring out that you mean an integral value, so small rounding errors are ignored. I'd bet anything this will work just fine for you.