Calculate new position values in C# - c#

I have a document which containing some elements. The document is an INDD document. I am trying to show it in a webview but in a smaller size than the original size.
I am using ImageMapper (ASP.NET) to mark the different elements in the webview.
The problem is that I don´t get the correct positions in of the different spots in the webview.
I got the correct size of the new spots but not the position.
I made the calculations in the following way:
Original size (INDD document)
DocumentWidth = 768
DocumentHeight = 1024
New Size (Size of the webview)
Width = 522
Height = 696
percentW = newWidth(Webview)/DocumentWidth
percentH = newHeight(Webview)/DocumentHeight;
From these percent values I am calculating all the new values I will need in the ImageMapper (top,left,bottom,right).
Formula for that
myPrecent = (percentW/percentH) * 100;
result = myPrecent * ((top,left,right,bottom) / 100);
The result variable shall represent the new value which will be used in the spots within ImagMapper.
I suppose that I am thinking wrong in my calculation but I cant figured out what I´m doing wrong. So I will be appreciate if someone has any idea what I have doing wrong.

don't think of them as percentages, instead, think of them as scaling factors.
verticalScaling = Height/DocumentHeight
horizontalScaling = Width/DocumentWidth
newTop = Top * verticalScaling
newLeft = Left * horizontalScaling
newBottom = Bottom * verticalScaling
newRight = Right * horizontalScaling

Related

Scale WPF DrawingGroup to fit in the current Element

I have loaded a set of vector data into my application whose bounds extend from {-165835.328125, 6582072.5} to {-64674.02734375, 6609767} giving a Width of 101161.30078125 and a Height of 27694.5.
I want to show this data on my FrameworkElement which defaults to 663 pixels wide and 468 pixels high and obviously resize it when the element is resized. As far as I could judge in order scale my DrawingGroup I need to create a ScaleTransform and add it to a TransformGroup which I can then set as the Transform of the DrawingGroup - I figure I also need an offset in order to bring the origin location of my data to the top left corner of the view, although in retrospect I might be better off aligning the centres.
This is the code I have at the moment:
var transformWidth = this.drawingGroup.Bounds.Width;
var scale = width / transformWidth;
var left = this.drawingGroup.Bounds.Left * -1;
var top = this.drawingGroup.Bounds.Top * -1;
var translateTransform = new TranslateTransform(left, top);
var scaleTransform = new ScaleTransform();
scaleTransform.CenterX = (drawingGroup.Bounds.Width / 2);
scaleTransform.CenterY = (drawingGroup.Bounds.Height / 2);
scaleTransform.ScaleX = scale;
scaleTransform.ScaleY = scale;
var tg = new TransformGroup()
{
Children = new TransformCollection() { translateTransform, scaleTransform }
};
var oldTransform = this.drawingGroup.Transform;
this.drawingGroup.Transform = tg;
context.DrawDrawing(this.drawingGroup);
this.drawingGroup.Transform = oldTransform;
This is rough on multiple levels but the main one bothering me right now is that it doesn't work. I can adjust the data on input ( as in if I translate the points manually when generating the geometry ) and it will draw only slightly wrong so I think the geometry exists but is outside the visible area, as far as I can tell the translation just isn't doing anything. I tried pushing the transforms onto the DrawingContext too but that didn't seem to work either ( I would quite like to be able to maintain the original coordinates on the DrawingGroup so I can relate things back to them later, hence the possibly unnecessary Transform switcheroo ) and when I inspect the child collection of the DrawingGroup their geometry seems untranslated after the translate was applied- I don't know whether or not that is correct.
What do I need to do to get my data visible in my FrameworkElement?
The Bounds property takes the current transform into account.
Reset the Transform property before accessing the Bounds:
drawingGroup.Transform = Transform.Identity;
var bounds = drawingGroup.Bounds;
var scale = width / bounds.Width;
var matrix = new Matrix();
matrix.Translate(-bounds.X, -bounds.Y);
matrix.Scale(scale, scale);
drawingGroup.Transform = new MatrixTransform(matrix);
As a note, in order to keep the thickness of the Drawings' Pens, better transform the underlying Geometries instead of the Drawings.

Call function when chart y-value exceeds line's y-value

I have a candlestick chart which automatically updates with real time prices from a cryptocurrency exchange in the .NET forms. The goal is to make the bot preform actions when the price on chart passes one of the lines drawn by the user. So far I've come to the point of enabling line-drawing for users thanks to this article.
Could anyone please point me towards a method of detecting collision between the chart candles and the drawn lines? I feel like there must be an easier way than what I'm thinking of currently, just can't seem to figure out the way to it.
Using the exact solution for the line drawing as in the article, also posted code for the line-drawing below:
int index1 = 1;
int index2 = 4;
DataPoint left = chart.Series[0].Points[index1];
DataPoint right = chart.Series[0].Points[index2];
//Init the annotation
LineAnnotation line = new LineAnnotation();
line.AxisX = chart.ChartAreas[0].AxisX;
line.AxisY = chart.ChartAreas[0].AxisY;
line.IsSizeAlwaysRelative = false;
//Each point in a candlestick series has several y values, 0=high, 1=low, 2=open, 3=close
line.Y = left.YValues[1]; //low
line.X = left.XValue;
//If your data is indexed (your x values are Strings or you've set Series.IsXValueIndexed to true), use the data point index(+1) as the line X coordinate.
//line.X = index1 + 1;
//Use the width and height properties to determine the end position of the annotation.
line.Height = right.YValues[1] - left.YValues[1];
line.Width = right.XValue - left.XValue;
//Again, use the index if necessary
//line.Width = index2 - index1;
chart.Annotations.Add(line);
Just looking for a point in the direction of an easier solution, not the solution itself :) Thanks in advance!
So it sounds like you are asking is if a Point (Geometry) is above or below a line.
Here are the assumption (which you can change later to fit your needs):
an external resource is giving you a specific value (Y) at a specific point in time (X), which will call the Integral point XY.
The user has drawn a line which gives you a starting point (x1, y1) and an end point (x2, y2).
The graphs X component is in minutes, with each tick horizontally is 1 minute.
The graphs Y component is in dollars, with each tick is $25.
The user has drawn a line from (1:00pm, $50) to (1:05pm, $75).
We get an Integral Point XY at 1:10pm of $125.
What is the value of the line at 1:10pm so you can compare it to the Integral Point XY.
Based on my comments of Trigonometry..
We know the adjacent length is: 1:05 - 1:00 = 5
We know the opposite length is: 75 - 25 = 50
Using the formula: atan(opposite / adjacent) = angle
We calculate that the angle is: atan(50 / 5) = 1.47112767rad (radians)
Now we simply reverse our math:
We know the adjacent length is: 1:10 - 1:00 = 10
We know our Angle in Radians: 1.47112767
Using the formula: adjacent * tan(angle) = opposite
We calculate that the opposite is: 10 * tan(1.47112767) = ~$99.999999 or $100
$125 is above $100, do what you want.

Logical calculation issue

I have a control square with user defined height, top range and bottom range values.
There is a line in between the control which divides the top range and bottom range.
User will provide another value "fillValue" too.
Problem:
For instance:
height = 100;
topRange = 10;
bottom range= 10;
fillValueTop= 5;
Now here I have to decide what percentage 5 will be for the toprange. Basically the height of fill for upper side of the square.
with same height, toprange and bottomrange, the user can change fillValueTop = 40. In this case
what percentage should get filled for the upper side of the square?
Similarly, it could be,
height = 200;
topRange = 15;
bottomrange= 15;
fillValueBottom= 20;
Basically I need to calculate the percentage of fill depending on the above parameters.
Can someone help me with some formular or so.
I thought something like this.
var unit = height/(topRange + bottomrange);
var actualFillValue = unit*fillValueTop;
But I think it does not work.
Thanks & Regards,

UWP: Calculate Transformation based on ScrollViewer

I have a windows universal app where I am rendering a scene with DirectX. I want to make use of the Scrollviewer and therefore I render my scene behind the Scrollviewer and want to calculate the scene transformation based on the Scrollviewer. It works fine so far, especially the translation and scrolling. But when I zoom in, the scene jumps around in two special situations:
The scene had enough space and was centered and now scrolling is required.
The opposite direction.
More or less I use the following code:
float zoom = scrollViewer.ZoomFactor;
float inverseZoom = 1f / scrollViewer.ZoomFactor;
float scaledContentW = Document.Size.X * scrollViewer.ZoomFactor;
float scaledContentH = Document.Size.Y * scrollViewer.ZoomFactor;
float translateX;
float translateY;
if (scaledContentW < scrollViewer.ViewportWidth)
{
translateX = ((float)scrollViewer.ViewportWidth * inverseZoom - Document.Size.X) * 0.5f;
}
else
{
translateX = -inverseZoom * (float)scrollViewer.HorizontalOffset;
}
if (scaledContentH < scrollViewer.ViewportHeight)
{
translateY = ((float)scrollViewer.ViewportHeight * inverseZoom - Document.Size.Y) * 0.5f;
}
else
{
translateY = -inverseZoom * (float)scrollViewer.VerticalOffset;
}
float visibleX = inverseZoom * (float)scrollViewer.HorizontalOffset;
float visibleY = inverseZoom * (float)scrollViewer.VerticalOffset; ;
float visibleW = Math.Min(Document.Size.X, inverseZoom * (float)scrollViewer.ViewportWidth);
float visibleH = Math.Min(Document.Size.Y, inverseZoom * (float)scrollViewer.ViewportHeight);
Rect2 visibleRect = new Rect2(visibleX, visibleY, visibleW, visibleH);
transform =
Matrix3x2.CreateTranslation(
translateX,
translateY) *
Matrix3x2.CreateScale(zoom);
You can get an example here: https://github.com/SebastianStehle/Win2DZoomTest
To be sure that my eyes are not broken I was zooming around and have written the translation and zoom values to a file. You can see it here:
https://www.dropbox.com/s/9ak6ohg4zb1mnxa/Test.png?dl=0
The meaning of the columns is the following:
Column 1: The computed zoom value of the transformation matrix (M11) = ScrollViewer.ZoomFactor
Column 2: The computed x offset of the matrix (See above)
Column 3: The x value of the result of matrix * vector (500, 500), here: Colum1 * 500 + Column2
You see, that the matrix values look good, but when applying the transformation you get this little jump to the right for some milliseconds. One theory was, that the viewport might change because the scrollbar becomes visible. But this is not the case. I also tried fixed values here, made the scrollbars visible and even created a custom template for the scrollviewer with no scrollbars at all.
Btw: This is a cross post, I also asked the question here: https://github.com/Microsoft/Win2D/issues/125
You see this behavior because when you zoom bigger than the ScrollViewer's size, the zoom center point is moved. To fix this, you just need to subscribe to the ScrollViewer's LayoutUpdated event and inside the handler, manually keep its content in the center.
private void ScrollViewer_LayoutUpdated(object sender, object e)
{
this.ScrollViewer.ChangeView(this.ScrollViewer.ScrollableWidth / 2, this.ScrollViewer.ScrollableHeight / 2, this.ScrollViewer.ZoomFactor, true);
}
This should fix the jumpy movement on the two drawed Rectangles from Win2D.
Update
Just to prove my point, the jumpy behavior is most likely due to unusual translate x and/or y value change when the content size goes over the size of the ScrollViewer. So I wrote some code to log these values on the screen as shown below -
...
this.Test1.Text += ((float)translateX).ToString() + " ";
this.Test2.Text += ((float)translateY).ToString() + " ";
session.Transform =
Matrix3x2.CreateTranslation(
(float)translateX,
(float)translateY) *
Matrix3x2.CreateScale((float)zoom);
Now look at the numbers on the image above. What I did was I tried zooming in until the jumpy scene occurred. See the highlighted translate y value? It is slightly greater than its previous value, which is against the declining trend.
So to fix this, you will need to be able to skip these unusual values caused by ScrollViewer.

Drawing a chart in which I manipulate the zoom in and out

I am drawing a chart which I populate with the data I obtain from different procedures. I want to make two buttons to zoom in and out. I saw that I can use different functions from AxisX.ScaleView and I am playing a bit with those. I am almost there but I have a problem at the moment of drawing the chart:If you see the image 1, this is the chart after executing the different procedures and drawing it for the first time. When I do a zoom in and a zoom out, the last bars (Week 22 from image 2) are cut in half and doesn't go to its original size.
Does anyone have any idea how can I manipulate the start and end position for the Axis X in order to make the zoom? Does anyone know how to get the initian values of start and end of the Chart Area? I place the code of my function to make the zoom of the chart:
private void setSize(int zoom)
{
int blockSize = (Convert.ToInt32(tbZoom.Text) + zoom) / 100;
// set view range to [0,max]
chartReport.ChartAreas[0].AxisX.Minimum = 0;
chartReport.ChartAreas[0].AxisX.Maximum = chartReport.Series[0].Points.Count;
// enable autoscroll
chartReport.ChartAreas[0].CursorX.AutoScroll = true;
chartReport.ChartAreas[0].CursorX.IsUserSelectionEnabled = true;
// let's zoom to [0,blockSize] (e.g. [0,100])
chartReport.ChartAreas[0].AxisX.ScaleView.Zoomable = true;
chartReport.ChartAreas[0].AxisX.ScaleView.SizeType = DateTimeIntervalType.Number;
int actualHeight = chartReport.Height;
int actualWidth = chartReport.Width;
int position = 0;
int size = blockSize;
chartReport.ChartAreas[0].AxisX.ScaleView.Zoom(position, size);
// disable zoom-reset button (only scrollbar's arrows are available)
chartReport.ChartAreas[0].AxisX.ScrollBar.ButtonStyle = ScrollBarButtonStyles.SmallScroll;
// set scrollbar small change to blockSize (e.g. 100)
chartReport.ChartAreas[0].AxisX.ScaleView.SmallScrollSize = blockSize;
tbZoom.Text = (blockSize * 100).ToString();
}
Your first line is setting the maximum of the axis wrong: chartReport.ChartAreas[0].AxisX.Maximum = chartReport.Series[0].Points.Count; sets it to 22, when it really should be 23 (based on the first image).
If your data will always look like this, simply add 1:
chartReport.ChartAreas[0].AxisX.Maximum = chartReport.Series[0].Points.Count + 1;
Unfortunately, using the automatic min/max values won't give you the actual values until the chart is actually drawn. If your chart has few DataPoints this isn't a problem, as you can just call chartReport.Refresh(); or something similar and then get the values from the axes. But, if you have a lot of points, the Refresh() will take a long time which is undesirable. In my extensive use of the charts, I wound up setting the axis ranges myself so I have full control, rather than using the automatic min/max values.

Categories

Resources