I want to calcuate the distance of a BorderControl to the Grid in which it is added, but in rounded percentage.
I use this method:
internal static tPosition GetControlTPosition(Border tempInnerControl, Grid tempOuterGrid)
{
tPosition tempTPosition = new tPosition();
Point tempInnerControlCornerPoint = tempInnerControl.PointToScreen(new Point(0, 0));
Point tempOuterGridCornerPoint = tempOuterGrid.PointToScreen(new Point(0, 0));
//
//Top Left Corner
//Fist we calculate the Distance of the Top left Corners of both elements
double distanceLeft = tempInnerControlCornerPoint.X - tempOuterGridCornerPoint.X;
double distanceTop = tempInnerControlCornerPoint.Y - tempOuterGridCornerPoint.Y;
//Then we set the percentage of our position accordingly
tempTPosition.PositionLeft = (int)(((distanceLeft) * 100 / tempOuterGrid.ActualWidth));
tempTPosition.PositionTop = (int)((distanceTop) * 100 / tempOuterGrid.ActualHeight);
//
// Bottom Right Corner
//Now we calculate the distance of the bottom right corner to the outher grids bottom right corner
double distanceRight = (tempOuterGridCornerPoint.X + tempOuterGrid.ActualWidth) - (tempInnerControlCornerPoint.X + tempInnerControl.ActualWidth);
double distanceBottom = (tempOuterGridCornerPoint.Y + tempOuterGrid.ActualHeight) - (tempInnerControlCornerPoint.Y + tempInnerControl.ActualHeight);
tempTPosition.PositionRight = (int)((distanceRight)*100/tempOuterGrid.ActualWidth);
tempTPosition.PositionBottom = (int)((distanceBottom) * 100 / tempOuterGrid.ActualHeight);
return tempTPosition;
}
My problem is that the BorderControl keeps getting bigger, meaning there is a problem with the percentages being to low, i guess this happen because i lose precision. How can i avoid this?
I need the numbers as int, for various reasons.
tPosition is just left,top,right,bottom as ints
You most likely lose your precision when finding tempTPosition, instead of using double as you have been you are using int, which will round the value to a whole number
try it with doubles
//Then we set the percentage of our position accordingly
tempTPosition.PositionLeft = (double)(((distanceLeft) * 100 / tempOuterGrid.ActualWidth));
tempTPosition.PositionTop = (double)((distanceTop) * 100 / tempOuterGrid.ActualHeight);
Remember to also do this for PositionRight & PositionBottom
Related
Being not very good at math, I have a problem with my project.
The objective is boundary correction on 3D files.
In my application, the user moves a 3D point on X-axis in order to correct or modify the boundary of the object.
I want to move the nearest boundary points in the same direction but decreasingly. I mean no point should move more than the main point. The nearest points move most and, the farthest points should move less.
On the image, the red dots represent the initial status of points. And the user pulls the P0 in the x-direction. And the other points follow it. The last status of the points is represented by violet dots.
Here is what I tried.
//On point moved event
//Get nearest boundary Points (Uses Geometry3D to get boundary points).
(var clothDMesh, _) = Utilities3D.BuildDMesh(baseMesh);
CreateClothModel(clothDMesh);
var boundryVertices = nodes.Where(ro => ro.Value.isBorder).Select(ro => ro.Value.vertex).ToList();
var refPoint = CustomPoint.FromPoint3D(movedPoint);
//Gets the delta X.
var deltaX = p.X - initialX;
//Gets nearest country points, so 15 points above and 15 points below to move only a given number of points (I know maybe this should be calculated according to delta).
var nearestPoints = refPoint.GetNearesPoints(boundryVertices, 30);
foreach (var item in nearestPoints)
{
//This is only one of what I tried as a function. None of them worked correctly.
item.X += deltaX - (deltaX * 1/ Math.Pow(item.Distance, 2));
}
Any help will be appreciated.
Thanks in advance.
Here's the math part:
I call "a" your "deltaX".
We also need a second parameter: "b", the maximum height of the red dots. I assume it is symetrical and "-b" would be the minimum height of the red dots.
So, if you look for the value X, horizontal move, in fonction of the coordinate Y of the dot:
X = a - a * Y * Y / (b * b);
You can verify that for Y = 0, you obtain X = a and for Y = b (or -b) you get X = 0.
You have your parabola (X is function of Y^2).
I'm working on simulator, it has number of points. what i need is knowing how to specify the points which is the nearest one to any border of the four borders. I.e connect closed shape and ignore the points in the middle
Any suggestions?
If the boundaries form a rectangle shape which is axis aligned (like a monitor screen, for example), then you can take the four points with maximum and minimum x and y values.
You can enumerate all of the points and find the points nearest the boundaries.
Pseudocode:
var minimumX = int.MaxValue
var maximumX = int.MinValue
var minimumY = int.Maxvalue
var maximumY = int.MinValue
foreach(var point in points)
{
if (point.x < minimumX) minimumX = point.x;
if (point.x > maximumX) maximumX = point.x;
if (point.y < minimumY) minimumY = point.y;
if (point.y > maximumY) maximumY = point.y;
}
You can now use minimum and maximum x and y to create a bounding rectangle that contains all points.
A slightly more performant method would track the minimum and maximum x and y as each point is added to the field. This way, there would be no need to enumerate all points.
I have an array of points which all range from x(0-512) and y(0-384) which means an aspect ratio of 4:3.
If I want to display every points, perfectly, on a 16:9 monitor, what math would be needed to achieve this?
Let's say "ee" is my 4:3 point and "point" is the 16:9 point I need..
I thought since I'm trying to scale it on a 1920:1080 monitor, which is a 16:9 aspect ratio
point = new PointF(ee.x * (1920 / 512), ee.y * (1080 / 384));
But this seems to be off by abit.
Any help? Thanks.
You can't match exactly the aspect other than by multiplying each dimension by an integer. Here the only integer that would fit is 2 (cause 384 * 3 > 1080)...
so you would have to do:
point = new Point (ee.x * 2, ee.y * 2);
and you could center it with:
point = new Point (ee.x * 2 + ((1920 - 512*2)/2), ee.y * 2 + ((1080 - 384*2)/2)));
Hope that helps...
Edit: with floats, you have to take the minimum of the multiplier:
var multiplier = Math.Min(1920.0/512, 1080.0/384);
point = new Point (ee.x * multiplier + ((1920 - 512*multiplier)/2), ee.y * multiplier + ((1080 - 384*multiplier)/2)));
Could you elaborate what you mean by "off"?
If you mean that the image looks stretched horizontally, it is because the aspect ratio is larger than before. If you want the image to look like what it was before (but bigger), you'll need to scale one axis by the aspect ratio to fix it.
aspect_ratio_before = 4.0f / 3.0f;
aspect_ratio_after = 16.0f / 9.0f;
// This is equal to 4/3.
aspect_ratio_difference = aspect_ratio_after / aspect_ratio_before;
// I squish the X axis here.
point.x /= aspect_ratio_difference;
// Alternatively, you can also multiply point.y by the
// aspect_ratio_difference, though that will stretch the Y axis instead.
// Use only one!
// point.y *= aspect_ratio_difference;
Disclaimer: I have not worked with .net before, so I don't know all the details of its rendering engine. This is based off my experience working with OpenGL and scaling.
I have a program where I need to recursively generate new lines off of parent lines so that it ends up looking like a tree. The problem I'm having is that I don't know how to make the child line at angle A, where A is between 10 and 80 or 100 and 170 degrees, relative to its parent line.
My current algorithm steps are the following:
choose a random length (call it newBranchDist) from the parent's (x1, y1) point that is less than the total parent line's length (using distance formula)
Find the new line's x-coordinate using the Math.Cos(A) times newBranchDist
Find the new line's y-coordinate using Math.Sin(A) times newBranchDist
Now we have the (x1, y1) coordinate for one point of the line.
At this point, I need to calculate (x2, y2) that is at angle A relative to the parent line. Any suggestions?
EDIT: Also, my program will randomly choose which side of the parent line to draw the new line. So, sometimes it will be angle A, other times it will be A + 90.
Making some assumption on the result, as I'm not clear exactly what you're aiming for, I'd say that the calculation is as follows.
int x2 = x1 + newBranchDist * Math.Cos(a);
int y2 = y1 + newBranchDist * Math.Sin(a);
Then, you can verify the length by Pythagorean theorem.
double lengthSquared = Math.Pow(x2 - x1, 2) + Math.Pow(y2 - y1, 2);
double lengthRooted = Math.Pow(lengthSquared, 0.5);
you would need to know the angle of the parent line as well as the angle of the child line. Your terms are confusing so I am going to use a little different. And it needs to be noted that the angles of all the branches should be stored as angles relative to horizontal, although you will need to calculate them relative to the parent branch to do your 10-80,100-170 thing. But the calculation for the angle from horizontal is easy enough and given below:
1. figure out origin of the new branch<p>
a. BreakOffDistance = a random number less than the parent length (random distance from the start of the parent branch)
b. NewBranchOriginX = ParentBranchOriginX + BreakOffDistance * cos(ParentBranchAngle);
c. NewBranchOriginY = ParentBranchOriginY + BreakOffDistance * sin(ParentBranchAngle);
2. figure out a random angle to the new, child line;
a. figure out random angle between 10 and 80 or 100 and 170.
b. NewBranchAngle = ParentBranchAngle - 90 + RandomAngle.
(all branch angles relative to horizontal, right?)
3. figure out random length of new branch - less than parent?
4. The previous steps determine the new branch - origin point, angle and length. But to figure out its endpoint so you can draw it:
a. NewBranchEndX = NewBranchOriginX + NewBranchLength * cos(NewBranchAngle);
b. NewBranchEndY = NewBranchOriginY + NewBranchLength * sin(NewBranchAngle);
Because screen coordinates are turned upside down, you might need to replace the plus signs in steps 1b, 1c, and 4a, and 4b with minus signs.
Also, if you are trying to simulate a tree, I don't think it is right to choose the angle of a new branch as 10-80 or 100-170. Branches in a tree prefer to grow out and up, and it is not hard to do that in figuring out the angle for each new branch. Finally, your tree would be much more realistic if you thought of it in three dimensions. Have a tree that grows branches towards and away from you as well as to the sides. That too would be fairly simple, but more than you asked for.
With a class like this you could do the calculations first and draw the whole thing in a third step.
This code is completely untestet. There will be some errors, but you might get an idea how one could do this...
public class MyLine {
private Random random;
public MyLine(int Level, PointF Start, PointF End, int Angle) {
this.random = new Random();
this.Level = Level;
this.Start = Start;
this.End = End;
this.Angle = Angle;
}
public int Level{get;set;}
public PointF Start { get; set; }
public PointF End { get; set; }
public float MyLength {
get {
return (float)Math.Sqrt(Math.Pow(End.X - Start.X, 2) + Math.Pow(End.Y - Start.Y, 2));
}
}
public int Angle { get; set; }
public MyLine MySideLine { get; set; }
public void CalculateSideLine() {
float middleX = Start.X + (End.X - Start.X) / 2f;
float k = (End.Y - Start.Y) / (End.X - Start.X);
float d = (End.X * Start.Y - Start.X * End.Y) / (End.X - Start.X);
float middleY = k * middleX + d;
PointF newStart = new PointF(middleX, middleY);
int angle = random.Next(10, 80);
if (random.Next(0, 1) == 0)
angle = angle + 90;
float LengthPercentage = (float)random.NextDouble();
if (LengthPercentage < 0.5)
LengthPercentage = 0.5f;
float newLength = MyLength * LengthPercentage;
//Now we know the starting point of the new line, its angle and the length
//I do not have enough time to write the complete calculation down but it's result would be a new endPoint
//You think of a circle with its middle on "newStart" and its radius = "newLength".
//This circle you'll have to intersect with the line through "newStart" with the given angle.
//There are two results, you have to choose the one in the right direction
PointF newEnd = new PointF(0, 0); //This you'll have to find yourself...
this.MySideLine = new MyLine(this.Level++, newStart, newEnd, angle);
//this will calculate a new nested side line and - kind of recursively - go deeper and deeper.
//you'll have to find a break condition on a certain level.
this.MySideLine.CalculateSideLine();
//Be aware of randomly angle of 90 or 0. you might want to calculate two side lines on each twig (otherwise it will not look like a tree)
}
//This will draw the line to a Graphics (e.g. look at Form.CreateGraphics() )
//it will kind of recursively draw down the full tree.
public void DrawMeAndMySideLine(Graphics g){
g.DrawLine(Pens.Black,this.Start,this.End);
this.MySideLine.DrawMeAndMySideLine(g);
}
}
I am an architecture student trying to solve a spatial problem with C# in Grasshopper for Rhino.
The space I am trying to create is an exhibition space in an airport. The space will be made up of elements of similar length. The idea is to connect them with a hinge and thereby allow them to create spaces of different layout and size according to how many elements are used.
As you can see from the illustration I would like the space to end with an opening an element length away from the starting point.
My first attempt has been to create equilateral triangles depending on the number of segments (walls) needed.
In short, from the starting point, triangles are created, and then the sides of the triangle that form the outer border are added to a list of points. This point list is returned to the Grasshopper application, which draws lines between the points. A little point is that I made the creation of the next triangle randomly either from the side AC or BC from the last triangle.
Here is an example of the spaces created (for 12 - 8 - 14 - 20 elements):
Here is the source code that creates these point lists:
private void RunScript(double radius, int walls, ref object A)
{
//
List<Point3d> pointList = new List<Point3d>();
List<Point3d> lastList = new List<Point3d>();
bool alternate = true;
bool swapped = false;
Random turn = new Random();
// set up the first part of the triangle
Point3d point1 = new Point3d(0, 0, 0);
Point3d point2 = new Point3d(0, radius, 0);
pointList.Add(point1);
pointList.Add(point2);
Point3d calcPoint;
for(int i = 0; i < walls - 1; i++) // walls - 1, is because I need one less triangle to get to the amount of walls
{
// use the method to create two similar circles and return the intersection point
// in order to create an equilateral triangle
calcPoint = FindCircleIntersections(point1.X, point1.Y, point2.X, point2.Y, radius, alternate);
// random generator: will decide if the new triangle should be created from side BC or AC
bool rotate = turn.Next(2) != 0;
Print("\n" + rotate);
// set the 2nd and 3rd point as 1st and 2nd - depending on random generator.
if(rotate)
{
point1 = point2;
if(swapped == true)
swapped = false;
else
swapped = true;
}
// if the direction is swapped, the next point created will not be a part of the outer border
if(swapped)
lastList.Add(calcPoint);
else
pointList.Add(calcPoint);
point2 = calcPoint;
// swap direction of intersection
if(rotate)
{
if(alternate)
alternate = false;
else
alternate = true;
}
}
lastList.Reverse();
foreach (Point3d value in lastList)
{
pointList.Add(value);
}
A = pointList;
}
// Find the points where the two circles intersect.
private Point3d FindCircleIntersections(
double cx0, double cy0, double cx1, double cy1, double rad, bool alternate)
{
// Find the distance between the centers.
double dx = cx0 - cx1;
double dy = cy0 - cy1;
double dist = Math.Sqrt(dx * dx + dy * dy);
// Find a and h.
double a = (rad * rad - rad * rad + dist * dist) / (2 * dist);
double h = Math.Sqrt(rad * rad - a * a);
// Find P2.
double cx2 = cx0 + a * (cx1 - cx0) / dist;
double cy2 = cy0 + a * (cy1 - cy0) / dist;
// Get the points P3.
if(alternate)
return new Point3d((double) (cx2 + h * (cy1 - cy0) / dist), (double) (cy2 - h * (cx1 - cx0) / dist), 0);
else
return new Point3d((double) (cx2 - h * (cy1 - cy0) / dist), (double) (cy2 + h * (cx1 - cx0) / dist), 0);
}
What I would like to do, is to vary the creation of these shapes, so that they are not only corridors, but resemble my initial sketches. I would like an algorithm to take an input of segments (number and length) and then propose different space layouts which are possible to create with this number of segments. I guess because of tesselation the space would have to be created with triangles, squares or hexagons? Do you think I should look into this "maximum area" algorithm : Covering an arbitrary area with circles of equal radius here on stackoverflow?
I would greatly appreciate any help on this algorithm. Cheers, Eirik
If you're merely interested in a program to generate instances to be externally evaluated (and not all such instances), you could "inflate" your curve. For example, in the 14-segment instance in your second image, there is a place where the curve goes inward and doubles back -- so your list of points has one point repeated. For curves like this you could cut out everything between the two (identical) points (A and B), as well as one of the surrounding points (A or B), and you have reclaimed some points to expand your curve - possibly resulting in a non-corridor structure. You may have to work some magic to ensure it is a "closed" curve, though, buy alternately adding segments to the front and the back of the curve.
Another opportunity: if you can identify the curve's interior (and there are algorithms for this), then anywhere that two segments form a concave angle with respect to your curve, you could blow it out to make a non-corridorish area. E.g. the second and third segments of your 14-segment curve above could be blown out to the left.
Successively applying these two methods to your corridor-like curve should generate many of the shapes you're looking for. Good luck!