I know there has already been a lot of questioning about spline extrapolation in Matlab. I have an example where this works great in 2D and I want to understand this behaviour to programm it in C# using Math.Net. Here is my example:
matrix = zeros(128,128);
barWidth = 10;
%Calculate Midpoints
midpointX = floor(size(matrix,2)/2) + 1;
midpointY = floor(size(matrix,1)/2) + 1;
matrix(midpointY-barWidth:midpointY+barWidth,:) = 1;
% Windowing (I know it could be shortened...)
distanceMatY = -midpointY+1:midpointY-2;
distanceMatY = abs(repmat(distanceMatY',1,size(matrix,2)));
Factor = 0.5*(cos(pi*distanceMatY/barWidth)+1);
index = distanceMatY > barWidth;
Factor(index) = 0;
matrix = matrix.*Factor;
% Rotate matrix
alpha = 30 * pi/180;
y = -midpointY+1:midpointY-2; y = y';
x = -midpointX+1:midpointX-1; %set new COS for rotation in Midpoint
xRot = x*cos(alpha) - y*sin(alpha) + nMP; %Determine X and Y matrices for
yRot = x*sin(alpha) + y*cos(alpha) + mMP; %Roatation with angle alpha
rotMatrix = interp2(matrix,xRot,yRot,'linear'); %Interpolate rotated matrix
I have a matrix of zeros with a bar over the whole length in the middle.
I applied a Hann Window to the bar to smooth the edges and then rotated the matrix by 30 degrees with bilinear interpolation.
Now I have values outside the boundaries which are set to NaN. I could set all the NaN values to zero but what I really want is that the bar will be extended automatically. Now I could pad the matrix before rotation and cut it again after rotation to the input matrix size.
Much easier it is to just use interp2(matrix,xRot,yRot,'spline') and the rotated matrix looks exactly as I want for each angle.
How does the 2D spline interpolation does it and is there a way to program that manually?
Related
I'm setting up an automatic system to be able to attach a sprite and it will gather all its colours and the world position of each sprite. A list/class of all the colours used has been set up but how would get the position of all these sprites?
I have already tried doing this mathematically like getting the complete size of the sprite and then working out the size of each pixel and then working out the position from that. But this seems flawed due to the position of the sprite possibly changing.
Sprite ColouredSpriteTexture = ColoredSprite.GetComponent<SpriteRenderer>().sprite;
Texture2D ColouredTexture = ColouredSpriteTexture.texture;
float XsizeF = ColoredSprite.transform.localScale.x;
int Xsize = (int)XsizeF;
float YsizeF = ColoredSprite.transform.localScale.y;
int Ysize = (int)YsizeF;
List<Color> TempList = new List<Color>();
//Could spawn pixels by getting x and y size and dividing them by 100 50/100 = 0.50f
//if the tile has a color then spawn pixel if not 0.50 += 0.50
//TODO test if this logic will work
float PixelSize = XsizeF / 100;
float currentPos = PixelSize;
for (int x = 0; x < Xsize; x++)
{
for (int y = 0; y < Ysize; y++)
{
int listAmount = TempList.Count;
Color ColoredTex = ColouredTexture.GetPixel(x, y);
float TextureAlpha = ColoredTex.a;
if (!TempList.Contains(ColoredTex) && TextureAlpha != 0)
{
TempList.Add(ColoredTex);
ColorByNumber tempColor = new ColorByNumber();
tempColor.Color = ColoredTex;
tempColor.ColorNumber = listAmount;
ColorOptions.Add(tempColor);
}
if(TextureAlpha == 1)
{
GameObject ColorPixel = Instantiate(PixelPrefab);
ColorPixel.transform.localScale = new Vector3(XsizeF, YsizeF, 0);
ColorPixel.transform.SetParent(this.transform);
ColorPixel.name = "Pixel (" + x.ToString() + "," + y.ToString() + ")";
}
}
}
All I would need is somehow each pixel returning its position so I can store this data and be able to spawn anything on top of this pixel.
I haven't had a chance to test this math yet so there may be some mistakes in it:
Every graphical image in Unity has a PPU, this and the object scale are going to be a huge factor. For argument sake I am going to clearly define these for 1 object.
Image dimensions : 128x128
PPU: 64
Scale: 1,1,1
Object Bounds: would
come from the renderer, which I am unsure if that bounds already
takes in account the scale(Most likely) however in the case you
cannot use that you can calculate the ObjectBoundsWidth or height
just by dividing the width or height of the texture by the PPU.
This should give you bounds of the texture in world space.
We are also going to make an assumption that we are only working on the X and Y axis and ignore the Z axis, if you want to use Z instead of Y then just make the necessary changes to be Z Scale and Z position and Z Bounds.
World position of a pixel located at 2,10. Per the documentation the pixel coordinates start at the lower left this means 0,0 is the bottom left corner, and 2,10 is 2 pixels left and 10 pixels up.
EDIT:
So I plugged all of this into a google sheet and determined the previous algorithm I provided was wrong here is the correct one in a pseudo code format
// This function takes in either the x or y, and the width or height of
// the bounds, then the x or y position of the object attached to.
// It also assumes the pivot is the center of the sprite.
float CalculateWorldPosOfPixelCoordinate(int coord, float boundsSize, float position, float scale)
{
float PixelInWorldSpace = 1.0f / PPU;
float startPos= position - (boundsSize* 0.5f * scale);
return startPos + (PixelInWorldSpace * coord) * scale;
}
This is using objectBounds we determined ourselves that is why we are multiply by scale.
this would give use a world position of: -0.97, -0.84
The algorithm i believe is the same for Y, just replace the coord with the Y position, and the bounds with the height instead of the width.
Like I said this could be wrong as I havent had a chance to test it, this also does not account for rotation either.
I want to use Path to draw a partly circle like 25% circle (1/4, 90degree circle, 360 degree is a full circle)
I can use ArcSegment to do that, but 25% is easy because the number is simple and you can easily guess the point. But when I want to draw a 20% circle 1/5 72degree circle) I can't guess anymore be cause the is not a float value so I came up with 4 Equations
For 0->90 degree (unit value = Degree (Eg: 20degree)) x,y = ArcSegment.Point(x,y)
x = (PathWidth / 2) + [Sin(value) *50]
y = [Sin(value) *50]
For 90->180 degree
x, y= (PathWidth / 2) + [Sin(value) *50]
For 180->270 : Sorry I don't know ;(
For example I want a 25% circle in a 100x100 Path (Start point is 50,0) then 25% is 1/4 = 90 degree:
Apply my equation I mention above, We have:
x = (100/2) + Sin(90) * 50 = 100
y = Sin(90) * 50 = 50
So the ArcSegment.Point="100,50" and we a 50% circle
But I think the equation is not effective and maybe( I not verify yet) Inaccurate and we need 4 equations to accomplish the a partly circle (1->99%) circle. So Could you improve the equation I use above
Sorry for my bad English because English is not my first language.
The following method creates a PathGeometry with a single circular ArcSegment, which will work from 0 up to, but not including, 360 degrees. The center of the circle is a coordinates (0, 0).
It is important to set the ArcSegment's IsLargeArc property to true if the angle is larger than 180 degrees.
private Geometry CreateArc(double radius, double angle)
{
var endPoint = new Point(
radius * Math.Sin(angle * Math.PI / 180),
radius * -Math.Cos(angle * Math.PI / 180));
var segment = new ArcSegment(
endPoint, new Size(radius, radius), 0,
angle >= 180, SweepDirection.Clockwise, true);
var figure = new PathFigure { StartPoint = new Point(0, -radius) };
figure.Segments.Add(segment);
var geometry = new PathGeometry();
geometry.Figures.Add(figure);
return geometry;
}
If you need to draw a full circle, you'll have to add a second ArcSegment, or return an EllipseGeometry.
i writing a sample program in c# who drawing some point in page
i set center point with calculate distance of point
but how can found most distance point from center point ?
sample code :
void draw(string label,float x,float y)
{
Graphics g = panel1.CreateGraphics();
Pen p = new Pen(Color.YellowGreen, 5);
Random randomGen = new Random(Convert.ToInt32(label));
KnownColor[] names = (KnownColor[])Enum.GetValues(typeof(KnownColor));
KnownColor randomColorName = names[randomGen.Next(names.Length)];
Color randomColor = Color.FromKnownColor(randomColorName);
SolidBrush s = new SolidBrush(randomColor);
g.FillEllipse(s, x * 1, y * 1, 10, 10);
}
The best and simplest approach for this problem what I can think of is:
1) scan the image/coordinate system horizontally and vertically
2) For each row/column store the lowest and the highest coordinates with non-zero intensity
that will be your boundary points
You can define the furthest point of an angle. This can solve the problem of convex hull, but this technique fits well only in a circle space, very like yours.
for each angle you have to find the furthest point and then assign it the red color.
You can Use as much angle as you want.
PSEUDO...
npoints = 10;
furthestPts = zeros(npoints );//Initialize vectors with 0
distances = zeros(npoints );
for each pt in points
angle = atan((pt.y - c.y)/pt.x - c.x) * 360 / ( 2 * pi); //degres
angle = (int) (angle/npoints); //we will have only 10 points separated by 36 degrees
d = distance(pt,center);
if(distances[angle] < d){
distances[angle] = d; //Updating furthest point
furthestPts.[angle] = (pt); //Updating furthest point
}
You will see that this algoritm has a few problems if the point are to far from center or if the points are to far from each other.
Alright, so today I decided to try to further optimize my collision detection code for my tile engine.
This is what I did:
Circle class checks if there are points within range. If there are, then check for collision between player and tile.
Code:
int tileWidth = 128;
int tileHeight = 128;
int[,] Layer3 = { 1, 1, 1, etc... };
int tileMapWidth = Layer3.GetLength(1);
int tileMapHeight = Layer3.GetLength(0);
Rectangle tile, tile2;
for (int x = 0; x < tileMapWidth; x++)
{
for (int y = 0; y < tileMapHeight; y++)
{
int wallIndex = Layer3[y, x];
if (wallIndex == 1) //Full-sized Tile Collision (128 x 128)
{
if (collisionCircle.Contains(new Vector2(x * tileWidth + (tileWidth / 2) + (int)Player.camera.Position.X,
y * tileHeight + (tileHeight / 2) + (int)Player.camera.Position.Y))) //+ tile / 2 is for centering the point
{
tile = new Rectangle(x * tileWidth + (int)Player.camera.Position.X, y * tileHeight + (int)Player.camera.Position.Y, tileWidth, tileHeight);
Collide(tile);
}
}
}
}
This would check throughout layer3 if there is a "1". If there is, assign rectangle and check for collision if point is inside collision radius.
Also, I checked this code(with a draw method), and I know it's working properly, at least the behavior.
I added in about 120,000(32 x 3888) tiles to try to make it lag, and before the code, it lagged a little bit. But after I added in the code, it lagged even more so.
I thought that since it would only check for collision between tiles(points) that are within the radius it wouldn't even remotely lag, but that's not the case...
Any help/ideas on how to optimize this would be great.
Thanks a lot,
Shyy
EDIT:
Cirlce.Contains() code:
public bool Contains(Vector2 Point)
{
return ((Point - position).Length() <= radius);
}
I used a circle because I've heard it's faster than using a rectangle.
Another possible optimization is instead of
return ((Point - position).Length() <= radius);
use
return ((Point - position).LengthSquared() <= radius * radius);
This is faster because Vector2.Length() has to perform a costly square root operation. Vector2.LengthSquared() does not have to perform that slow operation. The radius has to be multiplied by itself to account for the length from the vector being squared.
It sounds like you're trying to determine what tiles you don't need to use for collision with the player. Another optimization you could do is that if a tile at (X=5,Y=5) is above and to the left of the player, then you don't need to check a tile at (X=4,Y=4). Similarly if (X=5,Y=5) is below and to the right, (X=6,Y=6) is guaranteed to be too far as well. Try to determine when you've passed the player and no longer need to check collisions.
I suggest to loop only over visible tiles in screen to check collision using movement offset.
i will try something from my head..
for x as integer = 0 + offSetX to tilesInWidth + offSetX
for y as integer = 0 + offSetY to tilesInHeight + offSetY
if player.insideCircle(player.position, radius) '
object = layer(y,x);
if player.collideWith(object) then Collide()
end if
next
next
I am writing a program in which I need to draw polygons of an arbitrary number of sides, each one being translated by a given formula which changes dynamically. There is some rather interesting mathematics involved but I am stuck on this probelm.
How can I calculate the coordinates of the vertices of a regular polygon (one in which all angles are equal), given only the number of sides, and ideally (but not neccessarily) having the origin at the centre?
For example: a hexagon might have the following points (all are floats):
( 1.5 , 0.5 *Math.Sqrt(3) )
( 0 , 1 *Math.Sqrt(3) )
(-1.5 , 0.5 *Math.Sqrt(3) )
(-1.5 , -0.5 *Math.Sqrt(3) )
( 0 , -1 *Math.Sqrt(3) )
( 1.5 , -0.5 *Math.Sqrt(3) )
My method looks like this:
void InitPolygonVertexCoords(RegularPolygon poly)
and the coordinates need to be added to this (or something similar, like a list):
Point[] _polygonVertexPoints;
I'm interested mainly in the algorithm here but examples in C# would be useful. I don't even know where to start. How should I implement it? Is it even possible?!
Thank you.
for (i = 0; i < n; i++) {
printf("%f %f\n",r * Math.cos(2 * Math.PI * i / n), r * Math.sin(2 * Math.PI * i / n));
}
where r is the radius of the circumsribing circle. Sorry for the wrong language No Habla C#.
Basically the angle between any two vertices is 2 pi / n and all the vertices are at distance r from the origin.
EDIT:
If you want to have the center somewher other than the origin, say at (x,y)
for (i = 0; i < n; i++) {
printf("%f %f\n",x + r * Math.cos(2 * Math.PI * i / n), y + r * Math.sin(2 * Math.PI * i / n));
}
The number of points equals the number of sides.
The angle you need is angle = 2 * pi / numPoints.
Then starting vertically above the origin with the size of the polygon being given by radius:
for (int i = 0; i < numPoints; i++)
{
x = centreX + radius * sin(i * angle);
y = centreY + radius * cos(i * angle);
}
If your centre is the origin then simply ignore the centreX and centreY terms as they'll be 0,0.
Swapping the cos and sin over will point the first point horizontally to the right of the origin.
Sorry, I dont have a full solution at hand right now, but you should try looking for 2D-Rendering of Circles. All classic implementations of circle(x,y,r) use a polygon like you described for drawing (but with 50+ sides).
Say the distance of the vertices to the origin is 1. And say (1, 0) is always a coordinate of the polygon.
Given the number of vertices (say n), the rotation angle required to position the (1, 0) to the next coordinate would be (360/n).
The computation required here is to rotate the coordinates. Here is what it is; Rotation Matrix.
Say theta = 360/n;
[cos(theta) -sin(theta)]
[sin(theta) cos(theta)]
would be your rotation matrix.
If you know linear algebra you already know what i mean. If dont just have a look at Matrix Multiplication
One possible implementation to generate a set of coordinates for regular polygon is to:
Define polygon center, radius and first vertex1. Rotate the vertex n-times2 at an angle of: 360/n.
In this implementation I use a vector to store the generated coordinates and a recursive function to generate them:
void generateRegularPolygon(vector<Point>& v, Point& center, int sidesNumber, int radius){
// converted to radians
double angRads = 2 * PI / double(sidesNumber);
// first vertex
Point initial(center.x, center.y - radius);
rotateCoordinate(v, center, initial, angRads, sidesNumber);
}
where:
void rotateCoordinate(vector<Point>& v, Point& axisOfRotation, Point& initial, double angRads, int numberOfRotations){
// base case: number of transformations < 0
if(numberOfRotations <= 0) return;
else{
// apply rotation to: initial, around pivot point: axisOfRotation
double x = cos(angRads) * (initial.x - axisOfRotation.x) - sin(angRads) * (initial.y - axisOfRotation.y) + axisOfRotation.x;
double y = sin(angRads) * (initial.x - axisOfRotation.x) + cos(angRads) * (initial.y - axisOfRotation.y) + axisOfRotation.y;
// store the result
v.push_back(Point(x, y));
rotateCoordinate(v, axisOfRotation, Point(x,y), angRads, --numberOfRotations);
}
}
Note:
Point is a simple class to wrap the coordinate into single data structure:
class Point{
public:
Point(): x(0), y(0){ }
Point(int xx, int yy): x(xx), y(yy) { }
private:
int x;
int y;
};
1 in terms of (relative to) the center, radius. In my case the first vertex is translated from the centre up horizontally by the radius lenght.
2 n-regular polygon has n vertices.
The simple method is:
Let's take N-gone(number of sides) and length of side L. The angle will be T = 360/N.
Let's say one vertices is located on origin.
* First vertex = (0,0)
* Second vertex = (LcosT,LsinT)
* Third vertex = (LcosT+Lcos2T, LsinT+Lsin2T)
* Fourth vertex = (LcosT+Lcos2T+Lcos3T, LsinT+Lsin2T+Lsin3T)
You can do in for loop
hmm if you test all the versions that are listed here you'll see that the implementation is not good. you can check the distance from the center to each generated point of the polygon with : http://www.movable-type.co.uk/scripts/latlong.html
Now i have searched a lot and i could not find any good implementation for calculating a polyogon using the center and the radius...so i went back to the math book and tried to implement it myself. In the end i came up with this...wich is 100% good:
List<double[]> coordinates = new List<double[]>();
#region create Polygon Coordinates
if (!string.IsNullOrWhiteSpace(bus.Latitude) && !string.IsNullOrWhiteSpace(bus.Longitude) && !string.IsNullOrWhiteSpace(bus.ListingRadius))
{
double lat = DegreeToRadian(Double.Parse(bus.Latitude));
double lon = DegreeToRadian(Double.Parse(bus.Longitude));
double dist = Double.Parse(bus.ListingRadius);
double angle = 36;
for (double i = 0; i <= 360; i += angle)
{
var bearing = DegreeToRadian(i);
var lat2 = Math.Asin(Math.Sin(lat) * Math.Cos(dist / earthRadius) + Math.Cos(lat) * Math.Sin(dist / earthRadius) * Math.Cos(bearing));
var lon2 = lon + Math.Atan2(Math.Sin(bearing) * Math.Sin(dist / earthRadius) * Math.Cos(lat),Math.Cos(dist / earthRadius) - Math.Sin(lat) * Math.Sin(lat2));
coordinates.Add(new double[] { RadianToDegree(lat2), RadianToDegree(lon2) });
}
poly.Coordinates = new[] { coordinates.ToArray() };
}
#endregion
If you test this you'll see that all the points are at the exact distance that you give ( radius ). Also don't forget to declare the earthRadius.
private const double earthRadius = 6371.01;
This calculates the coordinates of a decagon. You see the angle used is 36 degrees. You can split 360 degrees to any number of sides that you want and put the result in the angle variable.
Anyway .. i hope this helps you #rmx!