convert between IMPERIAL & METRIC unit on button click C# - c#

I have this Edit Window
Edit Window Imperial. If we click on the Metric Values button all labels should replace the in with mm like
Metric,
Need to create a interface/BusinessLogic layer for this. I have this function in utility class. that works fine. But I need to use the same functionality in different screen so need this on each business object.
public static double UnitConversionCalculation(string strDimension, string strInputUnit, string strOutputUnit, double dblInputValue)
{
// This is a primitive conversion utility, we convert to metric units, then convert to output units
// (think about the number of combinations we avoid by doing the two-step handling)
double dblWork;
if (strInputUnit == strOutputUnit)
{
dblWork = dblInputValue;
return (dblInputValue);
}
if (strDimension.ToUpper() == "LENGTH")
{
// Convert to metric units
if (strInputUnit.ToUpper() == "FT")
dblWork = dblInputValue * 12 * 0.0254;
else if (strInputUnit.ToUpper() == "IN")
dblWork = dblInputValue * 0.0254;
else if (strInputUnit.ToUpper() == "M" || strInputUnit.ToUpper() == "MT")
dblWork = dblInputValue;
else if (strInputUnit.ToUpper() == "CM")
dblWork = dblInputValue / 100;
else if (strInputUnit.ToUpper() == "MM")
dblWork = dblInputValue / 1000;
else
{
// Unknown input unit, no conversion change
dblWork = dblInputValue;
}
// Convert to output units
if (strOutputUnit.ToUpper() == "FT")
{
dblWork = (dblWork / 12 / 0.0254);
}
else if (strOutputUnit.ToUpper() == "IN")
{
dblWork = dblWork / 0.0254;
}
else if (strOutputUnit.ToUpper() == "M" || strOutputUnit.ToUpper() == "MT")
{
}
else if (strOutputUnit.ToUpper() == "CM")
{
dblWork = dblWork * 100;
}
else if (strOutputUnit.ToUpper() == "MM")
dblWork = dblWork * 1000;
else
{
// Unknown output unit, no conversion change
dblWork = dblInputValue;
}
}
else if (strDimension.ToUpper() == "VOLUME")
{
//convert to SI Units
if (strInputUnit.ToUpper() == "GAL")
{
dblWork = dblInputValue * 3.7854;
}
else if (strInputUnit.ToUpper() == "OZ")
{
dblWork = dblInputValue * 0.02841306;
}
else if (strInputUnit.ToUpper() == "CUP")
{
dblWork = dblInputValue * 0.2365875;
}
else if (strDimension.ToUpper() == "L")
{
dblWork = dblInputValue;
}
else
{
dblWork = dblInputValue;
}
//Convert to output units
if (strOutputUnit.ToUpper() == "L")
{
dblWork = (dblWork * 1);
}
else if (strOutputUnit.ToUpper() == "GAL")
{
dblWork = dblWork * 0.2641729;
}
else if (strOutputUnit.ToUpper() == "OZ")
{
dblWork = dblWork * 35.19508;
}
else if (strOutputUnit.ToUpper() == "CUP")
{
dblWork = dblWork * 4.226766;
}
}
else if (strDimension.ToUpper() == "AREADENSITY")
{
if (strInputUnit.ToUpper() == "LB/SQUAREYARD")
dblWork = dblInputValue * 453.59237 / 0.8361274;
else if (strInputUnit.ToUpper() == "G/SQUAREMETER")
dblWork = dblInputValue;
else
{
// Unknown input unit, no conversion change
dblWork = dblInputValue;
}
// Convert to output units
if (strOutputUnit.ToUpper() == "LB/SQUAREYARD")
dblWork = dblWork / 453.59237 * 0.8361274;
else if (strOutputUnit.ToUpper() == "G/SQUAREMETER")
{
}
else
// Unknown output unit, no conversion change
dblWork = dblInputValue;
}
else if (strDimension.ToUpper() == "LINEARDENSITY")
{
if (strInputUnit.ToUpper() == "OZ/1000INCH")
dblWork = dblInputValue * 453.59237 / 25.4 / 16;
else if (strInputUnit.ToUpper() == "G/METER")
dblWork = dblInputValue;
else
// Unknown input unit, no conversion change
dblWork = dblInputValue;
// Convert to output units
if (strOutputUnit.ToUpper() == "OZ/1000INCH")
dblWork = dblWork / 453.59237 * 25.4 * 16;
else if (strOutputUnit.ToUpper() == "G/METER")
{
}
else
// Unknown output unit, no conversion change
dblWork = dblInputValue;
}
else if (strDimension.ToUpper() == "MASS")
{
// Convert to g
if (strInputUnit.ToUpper() == "LB")
dblWork = dblInputValue * 453.59237;
else if (strInputUnit.ToUpper() == "OZ")
dblWork = dblInputValue * 453.59237 / 16;
else if (strInputUnit.ToUpper() == "KG")
dblWork = dblInputValue * 1000;
else if (strInputUnit == "G")
dblWork = dblInputValue;
else
// Unknown input unit, no conversion change
dblWork = dblInputValue;
// Convert from g to output units
if (strOutputUnit.ToUpper() == "LB")
dblWork = dblWork / 453.59237;
else if (strOutputUnit.ToUpper() == "OZ")
dblWork = dblWork / 453.59237 * 16;
else if (strOutputUnit.ToUpper() == "KG")
dblWork = dblWork / 1000;
else if (strOutputUnit.ToUpper() == "G")
{
}
else
// Unknown output unit, no conversion change
dblWork = dblInputValue;
}
else if (strDimension.ToUpper() == "TEMPERATURE")
{
if (strInputUnit.ToUpper() == "F")
dblWork = (dblInputValue - 32) / 1.8;
else if (strInputUnit.ToUpper() == "C")
dblWork = dblInputValue;
else
// Unknown input unit, no conversion change
dblWork = dblInputValue;
// Convert to output units
if (strOutputUnit.ToUpper() == "F")
dblWork = dblWork * 1.8 + 32;
else if (strOutputUnit.ToUpper() == "C")
{
}
else
// Unknown output unit, no conversion change
dblWork = dblInputValue;
}
else if (strDimension.ToUpper() == "PRESSURE")
{
if (strInputUnit.ToUpper() == "PSI")
dblWork = dblInputValue / 14.696 * 1.01325;
else if (strInputUnit.ToUpper() == "BAR")
dblWork = dblInputValue;
else
// Unknown input unit, no conversion change
dblWork = dblInputValue;
// Convert to output units
if (strOutputUnit.ToUpper() == "PSI")
dblWork = dblWork / 1.01325 * 14.696;
else if (strOutputUnit.ToUpper() == "BAR")
{
}
else
// Unknown output unit, no conversion change
dblWork = dblInputValue;
}
else if (strDimension.ToUpper() == "FORCE")
{
// Convert to Newtons
if (strInputUnit.ToUpper() == "LBF")
dblWork = dblInputValue * 4.448222;
else if (strInputUnit.ToUpper() == "KGF")
dblWork = dblInputValue * 9.80665;
else
// Unknown input unit, no conversion change
dblWork = dblInputValue;
// Convert from Newtons to output units
if (strOutputUnit.ToUpper() == "LBF")
dblWork = dblWork / 4.448222;
else if (strOutputUnit.ToUpper() == "KGF")
dblWork = dblWork / 9.80665;
else
// Unknown output unit, no conversion change
dblWork = dblInputValue;
}
else
{
dblWork = dblInputValue;
}
// Unknown dimension, no conversion performed
return dblWork;
}

Related

Visual C# method calls using too much memory?

I'm writing a game using the XNA 4.0 framework. I've written a set of methods that translates the 2D mouse coordinates to a line in the 3d world, then checks to see if that line intersects a plane, and if the intersection point is within the bounds of a face in that plane.
The math works, but for some reason when I do these calculations over 500 times a frame it brings the program to a halt. I can watch the memory usage climb from starting at 15 MB to about 130 MB before garbage collection decides to clean things up. I know specifically it is in this code because when I comment it out, everything else runs smoothly.
I'll paste my code below, any insight would be helpful and thank you!
The Loop:
GraphicObject me = new GraphicObject();
Intersection intersect;
double? dist = null;
foreach (GraphicObject obj in GraphicObjects)
{
intersect = obj.intersectMe(line);
if (intersect.Distance != null)
{
if (intersect.Distance < dist || dist == null)
{
dist = intersect.Distance;
me = obj;
}
else
{
obj.Highlight(false);
}
}
else
{
obj.Highlight(false);
}
}
if (dist != null)
{
me.Highlight(true);
}
intersectMe:
public override Intersection intersectMe(Ray _line)
{
GraphicHelper.Intersects(_line, rect.Vertices[0].Normal, rect.Vertices[0].Position, intersect);
if (intersect.Distance != null)
{
if (!rect.PointOnMe(intersect.X - position.X, intersect.Y - position.Y, intersect.Z - position.Z))
{
intersect.Distance = null;
}
}
return intersect;
}
GraphicsHelper.Intersects:
// _l = line, _n = normal to plane, _p = point on the plane
public static void Intersects(Ray _l, Vector3 _n, Vector3 _p, Intersection _i)
{
_i.Distance = null;
float num = (_n.X * (_p.X - _l.Position.X) + _n.Y * (_p.Y - _l.Position.Y) + _n.Z * (_p.Z - _l.Position.Z));
float denom = (_n.X * _l.Direction.X + _n.Y * _l.Direction.Y + _n.Z * _l.Direction.Z);
if (denom != 0 && num != 0)
{
float t = num / denom;
if (t > 0)
{
_i.X = _l.Position.X + _l.Direction.X * t;
_i.Y = _l.Position.Y + _l.Direction.Y * t;
_i.Z = _l.Position.Z + _l.Direction.Z * t;
_i.Distance = _i.X * _i.X + _i.Y * _i.Y + _i.Z * _i.Z;
}
}
}
PointOnMe:
public bool PointOnMe(float _x, float _y, float _z)
{
float ex = _x - Vertices[3].Position.X;
float ey = _y - Vertices[3].Position.Y;
float ez = _z - Vertices[3].Position.Z;
float ae = a.X * ex + a.Y * ey + a.Z * ez;
float be = b.X * ex + b.Y * ey + b.Z * ez;
ex = _x - Vertices[1].Position.X;
ey = _y - Vertices[1].Position.Y;
ez = _z - Vertices[1].Position.Z;
float ce = c.X * ex + c.Y * ex + c.Z * ez;
float de = d.X * ex + d.Y * ey + d.Z * ez;
if (ae > 0 && be > 0 && ce > 0 && de > 0)
{
return true;
}
else
{
return false;
}
}
Thank you all for taking some time to look at this for me. The error was actually in how I handle obj.Highlight(), TaW's kick in the butt to get a profiler setup helped me to figure that out.
public override void Highlight(bool toggle)
{
if(toggle)
{
rect.Texture = new Texture2D(GraphicsManager.Graphics.GraphicsDevice, 1, 1);
rect.Texture.SetData<Color>(new Color[] { Color.Yellow });
}
else
{
rect.Texture = new Texture2D(GraphicsManager.Graphics.GraphicsDevice, 1, 1);
rect.Texture.SetData<Color>(new Color[] { squareColor });
}
}
Every frame all the obj's were having new textures generated. A terrible way to do things.

C# and SFML game intersection

I have problem with my MoveEntity() method in a 2D platformer game (like PacMan). When player is on intersection path I want to make:
e.IsAtIntersection = true;
and then call UpdateDirection().
But he doesn't stop, instead he goes through paths and it doesn't matter if there are walls or empty paths. The program never reaches the above line. The member stays false. Maybe there is the possibility to write it in an easier way or that there is a simple mistake I made. Here is the complete method:
private void MoveEntity(Entity e)
{
int angle = 0;
if (e.currentDirection == Direction.RIGHT) angle = 0;
else if (e.currentDirection == Direction.DOWN) angle = 90;
else if (e.currentDirection == Direction.LEFT) angle = 180;
else if (e.currentDirection == Direction.UP) angle = 270;
var scalex = Math.Round(Math.Cos(angle * (Math.PI / 180.0)));
var scaley = Math.Round(Math.Sin(angle * (Math.PI / 180.0)));
var velocityx = (float)(e.Speed * scalex);
var velocityy = (float)(e.Speed * scaley);
Sprite sp = sprites[e.Name];
Vector2f v = new Vector2f(sp.Position.X + velocityx, sp.Position.Y + velocityy);
sp.Position = v;
var eCenterX = sp.Position.X + sp.TextureRect.Width / 2;
var eCenterY = sp.Position.Y + sp.TextureRect.Height / 2;
var tileY = Math.Floor((eCenterY) / TILEHEIGHT);
var tileX = Math.Floor((eCenterX) / TILEWIDTH);
var tileXpos = TILEWIDTH * Math.Floor(tileX + 1);
var tileYpos = TILEHEIGHT * Math.Floor(tileY + 1);
e.X = (int)tileY;
e.Y = (int)tileX;
if (eCenterX == tileXpos && eCenterY == tileYpos)
e.IsAtIntersection = true;
else
e.IsAtIntersection = false;
}
The == operator, with floating points, checks for exact equality. Often even floats that have gone through very similar operations will still not be equal. When you compare equality on floats the best practice is to do the following:
if(Math.Abs(floatA-floatB) <= someSmallFloat)
someSmallFloat here is often set to float.Epsilon but in your case you may want to use a higher number to allow a margin for error, more fun to allow the player to move even if they are slightly off, than punish the player for very small inaccuracies.
It is very unlikely that the floating point addition for e.X and e.Y hits exactly the target value. You should check if the entity moved across the according line:
E.g. something like this for the rightwards movement:
if(e.currentDirection == Direction.RIGHT
&& eCenterX - velocityx< tileXpos && eCenterX >= eCenterX)
e.IsAtIntersection = true;
You can also correct the position if you like.
...
e.IsAtIntersection = true;
e.X = tileXpos;
You could also move it along the y-coordinate to compensate for the back-movement along the x-coordinate.
Here is for you my edited working code:
private void MoveEntity(Entity e)
{
int angle = 0;
if (e.currentDirection == Direction.RIGHT) angle = 0;
else if (e.currentDirection == Direction.DOWN) angle = 90;
else if (e.currentDirection == Direction.LEFT) angle = 180;
else if (e.currentDirection == Direction.UP) angle = 270;
var scalex = Math.Round(Math.Cos(angle * (Math.PI / 180.0)));
var scaley = Math.Round(Math.Sin(angle * (Math.PI / 180.0)));
var velocityx = (float)(e.Speed * scalex);
var velocityy = (float)(e.Speed * scaley);
Sprite sp = sprites[e.Name];
Vector2f v = new Vector2f(sp.Position.X + velocityx, sp.Position.Y + velocityy);
sp.Position = v;
var tileY = (int)sp.Position.Y / 60;
var tileX = (int)sp.Position.X / 60;
var tileXpos = tileX * 60;
var tileYpos = tileY * 60;
e.X = (int)tileY;
e.Y = (int)tileX;
if (sp.Position.X == tileXpos && sp.Position.Y == tileYpos)
e.IsAtIntersection = true;
else
e.IsAtIntersection = false;
}

SimplexNoise terrain in MonoGame

I'm making a randomly generated tile game in MonoGame, and I'm trying to use Simplex Noise to generate the terrain. Problem is, I've never used Simplex Noise before, so as you can probably guess, my code doesn't work. It only creates grass tiles. Here's the code I've tried:
public void Generate() {
Tiles = new List<Tile>();
Seed = GenerateSeed();
for (int x = 0; x < Width; x++) {
for (int y = 0; y < Height; y++) {
float value = Noise.Generate((x / Width) * Seed, (y / Height) * Seed) / 10.0f;
if (value <= 0.1f) {
Tiles.Add(new Tile(Main.TileGrass, new Vector2((int)x * Tile.Size, (int)y * Tile.Size)));
}
else if (value > 0.1f && value <= 0.5f) {
Tiles.Add(new Tile(Main.TileSand, new Vector2((int)x * Tile.Size, (int)y * Tile.Size)));
}
else {
Tiles.Add(new Tile(Main.TileWater, new Vector2((int)x * Tile.Size, (int)y * Tile.Size)));
}
}
}
}
public int GenerateSeed() {
Random random = new Random();
int length = 8;
int result = 0;
for (int i = 0; i < length; i++) {
result += random.Next(0, 9);
}
return result;
}
I'm using this implementation to generate noise.
Check line 133 in the SimplexNoise you are using:
// The result is scaled to return values in the interval [-1,1].
After you divide it by 10, the result would be in range from -0.1 to +0.1
You need a range from 0 to 1, so instead of dividing by 10, you need to:
Add 1 (the range would be from 0 to 2).
Divide by 2 (the range would be from 0 to 1).
float value = (Noise.Generate((x / Width) * Seed, (y / Height) * Seed) + 1) / 2.0f;
Or change your if/else to work with -1 to +1 ranges.
if (value <= -0.8f)
{
Tiles.Add(new Tile(Main.TileGrass, new Vector2((int)x * Tile.Size, (int)y * Tile.Size)));
}
else if (value <= 0)
{
Tiles.Add(new Tile(Main.TileSand, new Vector2((int)x * Tile.Size, (int)y * Tile.Size)));
}
else
{
Tiles.Add(new Tile(Main.TileWater, new Vector2((int)x * Tile.Size, (int)y * Tile.Size)));
}

Find intersection of circle and line

I am trying to find a line is intersecting a circle or not.
I write code but seems some issues with that code.
private Point2d[] IntersectionPoint(Point2d p1, Point2d p2, Point2d sc, double r)
{
Point2d[] sect = null;
double a, b, c;
double bb4ac;
double mu1, mu2;
Point2d dp;
dp = p2 - p1;
a = dp.X * dp.X + dp.Y * dp.Y;
b = 2 * (dp.X * (p1.X - sc.X) + dp.Y * (p1.Y - sc.Y));
c = sc.X * sc.X + sc.Y * sc.Y;
c += p1.X * p1.X + p1.Y * p1.Y;
c -= 2 * (sc.X * p1.X + sc.Y * p1.Y);
c -= r * r;
bb4ac = b * b - 4 * a * c;
if (Math.Abs(a) < Double.Epsilon || bb4ac < 0)
{
return new Point2d[0];
}
mu1 = (-b + Math.Sqrt(bb4ac)) / (2 * a);
mu2 = (-b - Math.Sqrt(bb4ac)) / (2 * a);
// no intersection
if ((mu1 < 0 || mu1 > 1) && (mu2 < 0 || mu2 > 1))
{
sect = new Point2d[0];
}
// one point on mu1
else if (mu1 > 0 && mu1 < 1 && (mu2 < 0 || mu2 > 1))
{
sect = new Point2d[1];
sect[0] = p1 + ((p2 - p1) * mu1);
}
// one point on mu2
else if (mu2 > 0 && mu2 < 1 && (mu1 < 0 || mu1 > 1))
{
sect = new Point2d[1];
sect[0] = p1 + ((p2 - p1) * mu2);
}
// one or two points
else if (mu1 > 0 && mu1 < 1 && mu2 > 0 && mu2 < 1)
{
// tangential
if (mu1 == mu2)
{
sect = new Point2d[1];
sect[0] = p1 + ((p2 - p1) * mu1);
}
// two points
else
{
sect = new Point2d[2];
sect[0] = p1 + ((p2 - p1) * mu1);
sect[1] = p1 + ((p2 - p1) * mu2);
}
}
else
{
// should NEVER get here
sect = new Point2d[0];
}
return sect;
}
And calling this function like
Point ptOld = points[oldPoint];
Point ptNew = points[newPoint];
Point2d p1 = new Point2d((float)ptOld.latitude, (float)ptOld.longitude);
Point2d p2 = new Point2d((float)ptNew.latitude, (float)ptNew.longitude);
Point2d sc = new Point2d((float)loc.latitude, (float)loc.longitude);
It fails when i am trying with these co-ordinates
30,-30
80,-40
10
https://www.dropbox.com/s/38r9eylt2p4xfvw/graph.png
You could do some linear algebra:
Express the line as an origin point P1 and a normalized direction vector N
Project the center C of the circle onto the line: PC = P1 + dot(C - P1, N) * N
Compute the distance squared dSquared between points C and PC.
If equal (with some small tolerance) to radiusSquared, PC is on the circle and is the single intersection point.
If greater than radiusSquared, no intersection.
Otherwise, the two intersections are given by
offset = sqrt(radiusSquared - dSquared).
Intersections = PC +/- offset * N.
Edit: Vectors are now available in C#.
There is my code for intersecting:
public static Vector3? IntersectRayCircle(Vector3 rayStart, Vector3 rayPoint, Vector3 circlePosition, float circleRadiusSquared)
{
if (rayStart == rayPoint || circleRadiusSquared <= 0)
{
return null;
}
Vector3 nearest = GetNearestPoint(circlePosition, rayStart, rayPoint, false, false);
float distanceSquared = Vector3.DistanceSquared(nearest, circlePosition);
if (distanceSquared > circleRadiusSquared)
{
return null;
}
Vector3 offset = Vector3.Normalize(rayPoint - rayStart) * (float)Math.Sqrt(circleRadiusSquared - distanceSquared);
if (Vector3.DistanceSquared(circlePosition, rayStart) < circleRadiusSquared)
{
return nearest + offset;
}
else
{
return nearest - offset;
}
}
public static Vector3 GetNearestPoint(Vector3 location, Vector3 segmentStart, Vector3 segmentEnd, bool trimStart, bool trimEnd)
{
if (segmentStart == segmentEnd)
{
throw new ArgumentException("segmentStart cannot be equal to segmentEnd.");
}
Vector3 AP = location - segmentStart;
Vector3 AB = segmentEnd - segmentStart;
float magnitudeAB = AB.LengthSquared();
float ABAPproduct = Vector3.Dot(AP, AB);
float distance = ABAPproduct / magnitudeAB;
return (distance < 0 && trimStart) ? segmentStart : (distance > 1 && trimEnd) ? segmentEnd : segmentStart + AB * distance;
}

Line clipping by LiangBarsky algorithm c#

I have a Liang Barsky algorithm implemented in c# but there's something wrong because it sometimes returns points outside the rectangle bounds like in this case:
p1=(516,546) and p2=(0,0)
R=0;
L=511;
T=511;
B=0;
also how can i indicate that the line is totally outside the rectangle
private void LiangBarsky( PointF P1,PointF P2,float R,float L,float T,float B)
{
try
{
float Tmin = 0;
float Tmax = 1;
float Tl, Tr, Tt, Tb;
Tl = (L - P1.X) / (P2.X - P1.X);
Tr = (R - P1.X) / (P2.X - P1.X);
Tt = (T - P1.Y) / (P2.Y - P1.Y);
Tb = (B - P1.Y) / (P2.Y - P1.Y);
if (0 < Tl && Tl < 1.0)
{
if (InnerProduct(P1, P2, new Point(0, 1)) == EnteringPoint)
Tmin = Tl;
else
Tmax = Tl;
test = true;
}
if (0 < Tr && Tr < 1)
{
if (InnerProduct(P1, P2, new Point(0, -1)) == EnteringPoint)
Tmin = Tr;
else
Tmax = Tr;
test = true;
}
if (0 < Tt && Tt < 1)
{
if (InnerProduct(P1, P2, new Point(1, 0)) == EnteringPoint)
Tmin = Tt;
else
Tmax = Tt;
test = true;
}
if (0 < Tb && Tb < 1)
{
if (InnerProduct(P1, P2, new Point(-1, 0)) == EnteringPoint)
Tmin = Tb;
else
Tmax = Tb;
test = true;
}
if ((Tmin < Tmax) /*&& (Tmin!=0 )&&(Tmax!=1)*/)
{
P1 = new PointF((P1.X + (P2.X - P1.X) * Tmin), (P1.Y + (P2.Y - P1.Y) * Tmin));
P2 = new PointF((P1.X + (P2.X - P1.X) * Tmax), (P1.Y + (P2.Y - P1.Y) * Tmax));
Indtxt.BackColor = Color.Blue;
}
else
{
if(P1.Y>T && P1.X>L && P2.X>L && P2.Y>T)
Indtxt.BackColor = Color.Red;
}
}
catch (Exception ex)
{
}
}
private int InnerProduct(PointF LineP1, PointF LineP2, Point NormalVector)
{
PointF P1_P2 = new PointF(LineP2.X - LineP1.X, LineP2.Y - LineP1.Y);
if (((P1_P2.X * NormalVector.X) + (P1_P2.Y * NormalVector.Y)) <= 0)
return EnteringPoint;//0 as entering point ans 1 as exiting point
else
return ExitingPoint;
}
i translated the algorith into the previous code so i might missed some concepts

Categories