normalizing real world data inside the canvas wpf - c#

I am working in a project in which I have to visualize certain points in real world coordinates into canvas inside ViewBox. Below is a sample of the data collection:
X Y
-40085.119 266560.373
-40084.72 266560.736
-40083.51165 266559.4097
-41606.37001 263437.3891
-40098.72351 266327.5417
-40075.57653 266399.5039
-40076.09771 266398.6382
-40629.41856 265374.2896
-40698.41477 265214.1637
To convert the real world data to fit inside the canvas. I am calling the following function.
public double changeScale(double point, double min, double max, double size){
double convertedValue;
convertedValue = (point - min) / (max - min);
convertedValue *= size;
return convertedValue;
}
I use the stated function as follows:
sc.changeScale(x, xmax, xmax, mycanvas.Width)
sc.changeScale(y, ymax, ymin, mycanavs.Height)
xmin, xmax and ymin, ymax are taken out from the table of real time data. Size of my canvas is 1280 X 720. For example: if an element has coordinate (XMax, YMax) then, it will be plotted on (1280,720) and likewise, if an element has coordinate (XMin, XMax), then it will be plotted on (0,0).
This is still working but I found that this is not correct because the noramlized map I am getting is stretched which is inaccurate visualization of real world. I have compared mine with another software's result. The following image is what I have created:
My expected result is:

You need to maintain the aspect ratio. This means you'll have to change the scale with the same size for both X and Y.
First find the Maximum-X size and Maximum-Y size, then take the larger one and use it as size.
UPDATE
Find the minimum X, maximum X, minimum Y and maximum Y of the entire set.
Find the maximum between (MaxX - MinX) and (MaxY - MinY).
Use that value as scale.

Related

WPF OxyPlot Zooming issue

In order to have the same scale on both axes, X and Y, I used PlotType.Cartesian which ensures that:
_model = new PlotModel();
_model.PlotType = PlotType.Cartesian;
I also have possibility to zoom in and out charts.
In order to control zooming I need to set AbsoluteMinimum and AbsoluteMaximum on both axes and specify minimum and maximum range.
Issues I have: how to keep the same scale when zooming? Because axes are zooming independently and often one axis is getting out of sync with the other axis (when one reaches its limits and the other still can expand).
Also, how to set appropriate values for both axes, because if I set all minimums and maximums, I expected correpsonding values on the other axes to be set, if I use PlotType.Cartesian, but it does not happen - this is the reason the issue arises, because i can't set appropriate values for both axes.
The closest I could get is:
subscribe to Loaded event of PlotView (_model field in this case)
in that method get ActualHeight and ActualWidth of PlotView
Having size of plot area, one can choose min and max of desired axe, then do all calculations required to keep scale the same on both axes. For example:
double xMin = -500;
double xMax = 800;
double xRange = xMax - xMin;
double yRange = xRange / ActualWidth * ActualHeight;
double yMin = 58;
double yMax = yMin + yRange;
_model.Axes[0].Minimum = xMin;
_model.Axes[0].AbsoluteMinimum = xMin;
_model.Axes[0].Maximum = xMax;
_model.Axes[0].AbsoluteMaximum = xMax;
// Analogically, define limits of Y axe
Also it is important to zoom both axes with the same zooming factor!
This will guarantee equal scales on both axes and keeping aspect ration through zooming.

Logarithmic growth with min and max values

I am trying to "fake 3D" in a game in WPF. Think of a road, and that the objects appear somewhere in the distant. As they get closer, they look bigger, and eventually they grow in size very fast.
I'm thinking that when the object appears, it's close to 0 in width and height. As it moves towards the player, it becomes closer to hundred percent of its true size.
I think I will need to solve this using logarithmic calculations, and there are several threads on that. What I would really want to do however, is to send in three values to a LogaritmicGrowth method:
the starting Y point
the point at which the object should appear at 100%
the y point where the object is at this very moment.
Thus, what I would like to get in return is the scaling factor for the object in question. So if it's halfway between the starting point and the ending point, then perhaps 0.3 (or so) should be returned.
I can write the method inputs and outputs myself, but need help with the calculation. Thanks!
I am not entirely sure about the use of log here. This is a simple geometry problem.
Think about a point P which is D distance in front of you, which has a height Y (from your line of observation). Your screen is d distance in front of you. The intersection point of the light from P on the screen is p, which makes a height y on screen.
Then, by considering the similar triangles, one can show that:
y = (Y/D) d
Just in case someone else is looking at this question in the future, here's the correct reply (I figured it out myself):
/// <summary>
/// Method that enlargens the kind of object sent in
/// </summary>
public void ExponentialGrowth2(string name, float startY, float endY)
{
float totalDistance = endY - startY;
float currentY = 0;
for (int i = 0; i < Bodies.Bodylist.Count; i++)
{
if (Bodies.Bodylist[i].Name.StartsWith(name)) //looks for all bodies of this type
{
currentY = Bodies.Bodylist[i].PosY;
float distance = currentY - startY + (float)Bodies.Bodylist[i].circle.Height;
float fraction = distance / totalDistance; //such as 0.8
Bodies.Bodylist[i].circle.Width = Bodies.Bodylist[i].OriginalWidth * Math.Pow(fraction, 3);
Bodies.Bodylist[i].circle.Height = Bodies.Bodylist[i].OriginalHeight * Math.Pow(fraction, 3);
}
}
}
The method could be worked on further, such as allowing randomized power-to values (say from 1.5 to 4.5). Note that the higher the exponential value, the greater the effect.

C#: How to generate random locations nearby map's center in GMap.NET?

Is there any way to generate random locations nearby map's center within a specific radius in my Form?
I can obtain the center of the map with the following line:
var center = gMapControl2.Position;
I did some research and came across to this post but it's in Java.
Generate a random number for R between RMax and RMin. Generate a different number for theta between 0 and 360. Now use basic trigonometry to convert to (x,y).
This approach seems most intuitive to me because the problem as stated is fundamentally radially symmetric. It also gives you (R, Theta) for any other computations you may want to do.
Assume that center is (x0,y0) and we are looking for a random location (x,y) with maximum distance maxDist from the center.
We know that
(x-x0)*(x-x0) + (y-y0)+(y-y0) <= maxDist *maxDist
So first we find a random value for x in the appropriate distance then find a random value for y:
int x = random.Next(-1* maxDist, maxDist);
int maxY =(int) Math.Floor(Math.Sqrt(maxDist * maxDist - x * x));
int y = random.Next(-1*maxY, maxY);
y += y0;
x += x0;

Animate an UV sphere with (4D?) noise

I am using a C# port of libnoise with XNA (I know it's dead) to generate planets.
There is a function in libnoise that receives the coordinates of a vertex in a sphere surface (latitude and longitude) and returns a random value (from -1 to 1).
So with that value, I can change the height of each vertex on the surface of the sphere (the altitude), creating some elevation, simulating the surface of a planet (I'm not simply wrapping a texture around the sphere, I'm actually creating each vertex from scratch).
An example of what I have:
Now I want to animate the sphere, like this
But the thing is, libnoise only works with 3D noise.
The "planet" function maps the latitude and longitude to XYZ coordinates of a cube.
And I believe that, to animate a sphere like I want to, I need an extra coordinate there, to be the "time" dimension. Am I right? Or is it possible to do this with what libnoise offers?
OBS: As I mentioned, I'm using an UV sphere, not an icosphere or a spherical cube.
EDIT: Here is the algorithm used by libnoise to map lat/long to XYZ:
public double GetValue(double latitude, double longitude) {
double x=0, y=0, z=0;
double PI = 3.1415926535897932385;
double DEG_TO_RAD = PI / 180.0;
double r = System.Math.Cos(DEG_TO_RAD * lat);
x = r * System.Math.Cos(DEG_TO_RAD * lon);
y = System.Math.Sin(DEG_TO_RAD * lat);
z = r * System.Math.Sin(DEG_TO_RAD * lon);
return GetNoiseValueAt(x, y, z);
}
An n dimensional noise function takes n independent inputs (i0, i1, ..., in-1, in) & returns a value v, thus 3D noise is sufficient to generate a height map that varies over time. In your case the inputs would be longitude, latitude & time and the output would be the height offset.
The simple general algorithm would be:
at each time step (t){
for each vertex (v) on a sphere centered on some point (c){
calculate the longitude & latitude
get the scalar noise value (n) for the longitude, latitude & time
calculate the new vertex position (p) as follows p = ((v-c)n)+c
}
}
Note: this assumes you are not replacing/modifiying the original vertex values. You could either save a copy of them (uses less computation, but more memory) or recalculate them them based on a distance from c (uses less memory, but more computation). Also, you might get a smoother animation by calculating 2 (or more) larger time steps & interpolating to get the intermediate frames.
To the best of my knowledge, this solution should work for a UV sphere, an icosphere or a spherical cube.
Ok I think I made it.
I just added the time parameter to the mapped XYZ coordinates.
Using the same latitude and longitude but incrementing time by 0.01d gave me a nice result.
Here is my code:
public double GetValue(double latitude, double longitude, double time) {
double x=0, y=0, z=0;
double PI = 3.1415926535897932385;
double DEG_TO_RAD = PI / 180.0;
double r = System.Math.Cos(DEG_TO_RAD * lat);
x = r * System.Math.Cos(DEG_TO_RAD * lon);
y = System.Math.Sin(DEG_TO_RAD * lat);
z = r * System.Math.Sin(DEG_TO_RAD * lon);
return GetNoiseValueAt(x + time, y + time, z + time);
}
If someone has a better solution please share it!
Sorry for the late answer, but I couldn't find a satisfactory answer elsewhere online, so I'm writing this up for anyone who has this problem in the future.
What worked for me was using multiple 3d perlin noise sources, and combining them into 1 single noise source. Adding time to the xyz coordinates just creates a very noticeable effect of terrain moving in the (-1,-1,-1) direction.
Averaging over 4 uncorrelated noise sources does change the noise characteristics a bit, so you might have to adapt some factors to your use case.
This solution still isn't perfect, but I haven't seen any visual artifacts.
Code is C++ libnoise, but it should translate equally well to other languages.
noise::module::Perlin perlin_noise[4];
float get_height(ofVec3f p, float time) {
p*=2;
time /= 10 ;
return (perlin_noise[0].GetValue(p.x, p.y, p.z) +
perlin_noise[1].GetValue(p.x, p.y, time) +
perlin_noise[2].GetValue(p.x, time, p.z) +
perlin_noise[3].GetValue(time, p.y, p.z))/2;
}
Ideally, for a single 3d noise source, you want to multiply you x,y,z coords with a monotonic function of t, such that it explores a constantly expanding sphere surface of the noise source, but I haven't figured out the math yet..
Edit: the framework I use (openframeworks) has a 4d perlin noise function built in ofSignedNoise(glm::vec4)

Drawing Images to fit circle

I'm making an inventory screen for a game I'm working on, and I'd like to be able to draw a series of panels representing each item in the inventory. I want to be able to fit those panels on a circular path.
Here's a mock up I made of what I mean
http://fc02.deviantart.net/fs70/f/2010/280/7/2/khmp_magic_menu_concept_by_magna_alphamon-d30a7em.png
basically I'd like to be able to, give a radius, a center point, and the y co-ordinate to start drawing at, draw this series of panels so they align with the path of the circle like in the image.
Computing the y dimension is easy, its just the startposition y + panel height * panel index, but I'm unsure how to compute the x for a variable radius/center point circle.
Any help would be appreciated.
This is in C#, but something similar in C/C++ will be fine as long as I can convert it
Thanks in advance
EDIT: To calirify, y's position is relative to the top or bottom of the screen and is independent of the circle. If a given y does not map to a point on the circle, then I'll discard that point and not draw the panel.
While ideally I'd like to be able to use any elliptical shape (given two radii), a circle would be good too
Let cx, cy be the coordinates of the center point. Let r be the radius of the circle. Let y be the drawing y-coordinate and x, the x-coordinate. You observe that y = cy + panel height * panel index. By the magic of right triangles, this means that x^2 + y^2 = r^2. Solving for x, we get x = cx + sqrt(r^2 - (y-cy)^2).
EDIT: Converting to code:
#include <math>
float ordinate(float cx, float cy, float r, float y) {
// assumes cx and cy are in the same coordinate system as x and y
// assumes the coordinate origin is in the lower left corner.
return cx + sqrtf(powf(r,2) - powf(y-cy,2));
}
I'm dumb. After seeing Eric's answer, I remembered I can just rearrange and solve the equations of a circle or elipse as necessary.
Thanks
You can use a rotational matrix for this. Here is a simple algorithm that finds the next point {x, y} such that it is rotated theta radians around a circle. You can start with the first item at x=radius and y=radius (wherever really, just a point that you know will contain an item), and then just continue to increment theta as you loop through your items.
Point Rotate(int x, int y, float theta)
int x_p = (x * Math.Cos(theta)) - (y * Math.Sin(theta));
int y_p = (y * Math.Cos(theta)) + (x * Math.Sin(theta));
return new Point(x_p, y_p);
end
On a side note; I always preferred "Bolt1, Bolt2, Bolt3" to "Thunder, Thundara, Thundaga" =P

Categories