I'm trying to convert a working VB class to Java, but it's giving incorrect results.
This is the VB class:
Public Class Triangle
Public A As PointF
Public B As PointF
Public C As PointF
''' <summary>
'''
''' </summary>
''' <param name="sideA">The length of the known side BC</param>
''' <param name="sideB">The length of the known side AC</param>
''' <param name="sideC">The length of the known side AB</param>
''' <param name="angleA">The internal angle in Radians at vertex A</param>
''' <param name="angleB">The internal angle in Radians at vertex B</param>
''' <param name="angleC">The internal angle in Radians at vertex C</param>
''' <remarks></remarks>
Public Sub New(ByVal sideA As Decimal, ByVal sideB As Decimal, ByVal sideC As Decimal, ByVal angleA As Decimal, ByVal angleB As Decimal, ByVal angleC As Decimal)
Dim bX As Decimal = CDec(Math.Cos(angleA) * sideC)
Dim bY As Decimal = CDec(Math.Sin(angleA) * sideC)
Me.A = PointF.Empty
Me.C = PointF.Add(A, New SizeF(sideB, 0))
Me.B = New PointF(bX, -bY)
If bX < 0 Then
Me.A = PointF.Add(Me.A, New SizeF(-bX, 0))
Me.B = PointF.Add(Me.B, New SizeF(-bX, 0))
Me.C = PointF.Add(Me.C, New SizeF(-bX, 0))
End If
End Sub
Public Sub ScaleToFit(ByVal maxWidthOrHeight As Decimal)
Dim xCoords() As Single = {Me.A.X, Me.B.X, Me.C.X}
Dim OverallWidth As Decimal = CDec(xCoords.Max - xCoords.Min)
Dim OverallHeight As Decimal = CDec(Math.Abs(Me.B.Y)) 'B.Y is negative owing to GDI+ coordinates
Dim scaleFactor As Decimal = If(OverallWidth > OverallHeight, _
maxWidthOrHeight / OverallWidth, _
maxWidthOrHeight / OverallHeight)
Scale(scaleFactor)
centreTriangle(25, 300)
End Sub
Private Sub Scale(ByVal scaleFactor As Decimal)
Me.A = ScalePointF(Me.A, scaleFactor)
Me.B = ScalePointF(Me.B, scaleFactor)
Me.C = ScalePointF(Me.C, scaleFactor)
End Sub
Private Function ScalePointF(ByVal pf As PointF, ByVal factor As Decimal) As PointF
Return New PointF(pf.X * factor, pf.Y * factor)
End Function
Private Sub centreTriangle(ByVal border As Integer, ByVal displaySize As Integer)
If B.Y > A.Y Then B.Y -= ((B.Y - A.Y) * 2)
Dim pts() As PointF = New PointF() {A, B, C}
Dim offset_X As Integer = pts.Min(Function(p) CInt(p.X)) - border
Dim offset_Y As Integer = pts.Max(Function(p) CInt(p.Y)) - (displaySize - border)
A = New PointF(A.X - offset_X, A.Y - offset_Y)
B = New PointF(B.X - offset_X, B.Y - offset_Y)
C = New PointF(C.X - offset_X, C.Y - offset_Y)
End Sub
End Class
This is the triangle the VB class plots:
Triangle plotted with VB class
This is the Java class:
public class Triangle
{
private Point A;
private Point B;
private Point C;
/**
* #return Point A
*/
public Point getA()
{
return this.A;
}
/**
* #return Point B
*/
public Point getB()
{
return this.B;
}
/**
* #return Point C
*/
public Point getC()
{
return this.C;
}
/**
#param sideA The length of the known side BC
#param sideB The length of the known side AC
#param sideC The length of the known side AB
#param angleA The internal angle in Radians at vertex A
#param angleB The internal angle in Radians at vertex B
#param angleC The internal angle in Radians at vertex C
*/
public Triangle(float sideA, float sideB, float sideC, float angleA, float angleB, float angleC)
{
float bX = (float)(Math.cos(angleA) * sideC);
float bY = (float)(Math.sin(angleA) * sideC);
this.A = new Point(0, 0);
this.C = new Point((int)(this.A.getX() + sideB), (int)this.A.getY());
this.B = new Point((int)bX, (int)-bY);
if (bX < 0)
{
this.A = new Point((int)(this.A.getX() - bX), (int)this.A.getY());
this.B = new Point((int)(this.B.getX() - bX), (int)this.B.getY());
this.C = new Point((int)(this.C.getX() - bX), (int)this.C.getY());
}
}
public final void ScaleToFit(float maxWidthOrHeight)
{
float[] xCoords = {(float)this.getA().getX(), (float)this.getB().getX(), (float)this.getC().getX()};
float min = 10000;
float max = -1;
for(int x = 0; x < 3; x++) {
if(xCoords[x] < min) {min = xCoords[x];}
if(xCoords[x] > max) {max = xCoords[x];}
}
float OverallWidth = (float)(max - min);
float OverallHeight = (float)Math.abs(this.getB().getY()); //B.Y is negative owing to Graphics coordinates
float scaleFactor = (float)(OverallWidth > OverallHeight ? maxWidthOrHeight / OverallWidth : maxWidthOrHeight / OverallHeight);
Scale(scaleFactor);
centreTriangle(25, 300);
}
private void Scale(float scaleFactor)
{
this.A = ScalePoint(this.A, scaleFactor);
this.B = ScalePoint(this.B, scaleFactor);
this.C = ScalePoint(this.C, scaleFactor);
}
private Point ScalePoint(Point p, float factor)
{
return new Point((int)(p.getX() * factor), (int)(p.getY() * factor));
}
private void centreTriangle(int border, int displaySize)
{
int y1 = (int)this.A.getY();
int y2 = (int)this.B.getY();
if(y2 > y1) {y2 -= ((y2 - y1) * 2);}
this.B = new Point((int)this.B.getX(), y2);
Point[] pts = new Point[] {this.A, this.B, this.C};
float min = 10000;
float max = -1;
for(int x = 0; x < 3; x++) {
if(pts[x].getX() < min) {min = (float)pts[x].getX();}
if(pts[x].getY() > max) {max = (float)pts[x].getY();}
}
int offset_X = (int)(min - border);
int offset_Y = (int)(max - (displaySize - border));
this.A = new Point((int)(this.A.getX() - offset_X), (int)(this.A.getY() - offset_Y));
this.B = new Point((int)(this.B.getX() - offset_X), (int)(this.B.getY() - offset_Y));
this.C = new Point((int)(this.C.getX() - offset_X), (int)(this.C.getY() - offset_Y));
}
}
This doesn't plot the triangle properly. This is a triangle plotted by the Java class, with the same inputs as the VB class:
Same triangle plotted with Java class
The answer is that converting float values to int was causing a noticeable difference. This is the fixed code...
package html.triangle;
import java.awt.Point;
import javax.swing.JOptionPane;
import html.shared.points.*;
/**
*
* #author Paul Long
*/
public class Triangle
{
private PointF A;
private PointF B;
private PointF C;
/**
* #return Point A
*/
public Point getA()
{
return new Point((int)this.A.getX(), (int)this.A.getY());
}
/**
* #return Point B
*/
public Point getB()
{
return new Point((int)this.B.getX(), (int)this.B.getY());
}
/**
* #return Point C
*/
public Point getC()
{
return new Point((int)this.C.getX(), (int)this.C.getY());
}
/**
#param sideA The length of the known side BC
#param sideB The length of the known side AC
#param sideC The length of the known side AB
#param angleA The internal angle in Radians at vertex A
#param angleB The internal angle in Radians at vertex B
#param angleC The internal angle in Radians at vertex C
*/
public Triangle(float sideA, float sideB, float sideC, float angleA, float angleB, float angleC)
{
float bX = (float)(Math.cos(angleA) * sideC);
float bY = (float)(Math.sin(angleA) * sideC);
this.A = new PointF(0, 0);
this.C = new PointF(this.A.getX() + sideB, this.A.getY());
this.B = new PointF(bX, bY);
if (bX < 0)
{
this.A = new PointF((this.A.getX() + Math.abs(bX)), this.A.getY());
this.B = new PointF((this.B.getX() + Math.abs(bX)), this.B.getY());
this.C = new PointF((this.C.getX() + Math.abs(bX)), this.C.getY());
}
}
public final void ScaleToFit(float maxWidthOrHeight)
{
float[] xCoords = {(float)this.A.getX(), (float)this.B.getX(), (float)this.C.getX()};
float min = 10000;
float max = -1;
for(int x = 0; x < 3; x++) {
if(xCoords[x] < min) {min = xCoords[x];}
if(xCoords[x] > max) {max = xCoords[x];}
}
float OverallWidth = (float)(max - min);
float[] yCoords = {(float)this.A.getY(), (float)this.B.getY(), (float)this.C.getY()};
min = 10000;
max = -1;
for(int x = 0; x < 3; x++) {
if(yCoords[x] < min) {min = yCoords[x];}
if(yCoords[x] > max) {max = yCoords[x];}
}
float OverallHeight = (float)(max - min);
float scaleFactor = (float)(OverallWidth > OverallHeight ? maxWidthOrHeight / OverallWidth : maxWidthOrHeight / OverallHeight);
Scale(scaleFactor);
centreTriangle(25, 300);
}
private void Scale(float scaleFactor)
{
this.A = ScalePoint(this.A, scaleFactor);
this.B = ScalePoint(this.B, scaleFactor);
this.C = ScalePoint(this.C, scaleFactor);
}
private PointF ScalePoint(PointF p, float factor)
{
return new PointF((p.getX() * factor), (p.getY() * factor));
}
private void centreTriangle(int border, int displaySize)
{
int y1 = (int)this.A.getY();
int y2 = (int)this.B.getY();
if(y2 > y1) {y2 -= ((y2 - y1) * 2);}
this.B = new PointF(this.B.getX(), y2);
PointF[] pts = new PointF[] {this.A, this.B, this.C};
float min = 10000;
float max = -1;
for(int x = 0; x < 3; x++) {
if(pts[x].getX() < min) {min = (float)pts[x].getX();}
if(pts[x].getY() > max) {max = (float)pts[x].getY();}
}
int offset_X = (int)(min - border);
int offset_Y = (int)(max - (displaySize - border));
this.A = new PointF((this.A.getX() - offset_X), (this.A.getY() - offset_Y));
this.B = new PointF((this.B.getX() - offset_X), (this.B.getY() - offset_Y));
this.C = new PointF((this.C.getX() - offset_X), (this.C.getY() - offset_Y));
}
}
package html.shared.points;
/**
*
* #author Paul Long
*/
public class PointF
{
private float X;
private float Y;
/**
* #return the X
*/
public float getX()
{
return X;
}
/**
* #return the Y
*/
public float getY()
{
return Y;
}
public PointF(float X, float Y) {
this.X = X;
this.Y = Y;
}
}
Related
those are 2 example cases of what I need to solve, it is just finding the coordinate of D, given position of A, and the direction vector of red and green line
red/green line vector (or direction) is known
point A is an intersection between the red line and red circle tangent point
point B is the center of the red circle with radius = R (known)
point C is an intersection between the green line and the green circle tangent point
point D is unknown and this one that needs to be calculated
point D will always located in green circle (radius of 2R from point B)
both red and green line has the same radius of R
V is the angle of the red line relative to north up
W is the angle of the green line relative to north up
the distance between point B and D is always 2R since the circle adjacent (touching each other)
much help and hint appreciated, preferred in some code instead of math equation
Having coordinates A,B,C, we can write two vector equations using scalar (dot) product:
AC.dot.DC = 0
DB.dot.DB = 4*R^2
The first one refers to perpendicularity between tangent to circle and radius to tangency point, the second one - just squared distance between circle centers.
In coordinates:
(cx-ax)*(cx-dx) + (cy-ay)*(cy-dy) = 0
(bx-dx)*(bx-dx) + (by-dy)*(by-dy) = 4*R^2
Solve this system for unknown dx, dy - two solutions in general case.
If A and C are not known, as #Mike 'Pomax' Kamermans noticed:
Let
cr = sin(v) sr = cos(v)
cg = sin(w) sg = cos(w)
So
ax = bx + R * cr
ay = by + R * sr
and
dx = cx - R * cg
dy = cy + R * sg
Substituting expressions into the system above we have:
(dx+R*cg-bx-R*cr)*cg - (dy-R*sg-by-R*sr)*sg = 0
(bx-dx)*(bx-dx) + (by-dy)*(by-dy) = 4*R^2
Again - solve system for unknowns dx, dy
As a hint: draw it out some more:
We can construct D by constructing the line segment AG, for which we know both the angle and length, because AC⟂AG, and the segment has length R.
We can then construct a line perpendicular to AG, through G, which gives us a chord on the blue circle, one endpoint of which is D. We know the distance from B to GD (because we know trigonometry) and we know that the distance BD is 2R (because that's a given). Pythagoras then trivially gives us D.
You know where A is and the angle θ it makes from vertical.
So specify the line though C called line(C) above and the offset the line by R in order to get line(D) above that goes through point D.
In C# code this is
Line line_C = Line.ThroughPointAtAngle(A, theta);
Line line_D = line_C.Offset(radius);
Now find the intersection of this line to the greater circle
Circle circle = new Circle(B, 2 * radius);
if (circle.Intersect(line_D, out Point D, alternate: false))
{
Console.WriteLine(D);
float d_BD = B.DistanceTo(D);
Console.WriteLine(d_BD);
}
else
{
Console.WriteLine("Does not intersect.");
}
This produces point D either above line(C) or below line(C) depending on the bool argument alternate.
The code example below produces the following output:
D=Point(-0.4846499,-1.94039)
|BD|=2
The source code is
Program.cs
using static Float;
static class Program
{
static void Main(string[] args)
{
float radius = 1;
Point A = new Point(-radius, 0);
Point B = new Point(0, 0);
float theta = deg(15);
Line line_C = Line.ThroughPointAtAngle(A, theta);
Line line_D = line_C.Offset(radius);
Circle circle = new Circle(B, 2 * radius);
if (circle.Intersect(line_D, out Point D, alternate: false))
{
Console.WriteLine($"D={D}");
float d_BD = B.DistanceTo(D);
Console.WriteLine($"|BD|={d_BD}");
}
else
{
Console.WriteLine("Does not intersect.");
}
}
}
Point.cs
Describes a point in cartesian space using two coordinates (x,y)
using static Float;
public readonly struct Point
{
readonly (float x, float y) data;
public Point(float x, float y)
{
this.data = (x, y);
}
public static Point Origin { get; } = new Point(0, 0);
public static Point FromTwoLines(Line line1, Line line2)
{
float x = line1.B * line2.C - line1.C * line2.B;
float y = line1.C * line2.A - line1.A * line2.C;
float w = line1.A * line2.B - line1.B * line2.A;
return new Point(x / w, y / w);
}
public float X => data.x;
public float Y => data.y;
public float SumSquares => data.x * data.x + data.y * data.y;
#region Algebra
public static Point Negate(Point a)
=> new Point(
-a.data.x,
-a.data.y);
public static Point Scale(float factor, Point a)
=> new Point(
factor * a.data.x,
factor * a.data.y);
public static Point Add(Point a, Point b)
=> new Point(
a.data.x + b.data.x,
a.data.y + b.data.y);
public static Point Subtract(Point a, Point b)
=> new Point(
a.data.x - b.data.x,
a.data.y - b.data.y);
public static float Dot(Point point, Line line)
=> line.A * point.data.x + line.B * point.data.y + line.C;
public static Point operator +(Point a, Point b) => Add(a, b);
public static Point operator -(Point a) => Negate(a);
public static Point operator -(Point a, Point b) => Subtract(a, b);
public static Point operator *(float f, Point a) => Scale(f, a);
public static Point operator *(Point a, float f) => Scale(f, a);
public static Point operator /(Point a, float d) => Scale(1 / d, a);
#endregion
#region Geometry
public Point Offset(float dx, float dy)
=> new Point(data.x + dx, data.y + dy);
public Point Offset(Vector2 delta) => Offset(delta.X, delta.Y);
public float DistanceTo(Point point)
=> sqrt(sqr(data.x - point.data.x) + sqr(data.y - point.data.y));
#endregion
#region Formatting
public string ToString(string formatting, IFormatProvider provider)
{
return $"Point({data.x.ToString(formatting, provider)},{data.y.ToString(formatting, provider)})";
}
public string ToString(string formatting)
=> ToString(formatting, null);
public override string ToString()
=> ToString("g");
#endregion
}
Line.cs
Describes a line in cartesian space using the coefficients (a,b,c) such that the equation of the line is a x + b y + c = 0
using static Float;
public readonly struct Line
{
readonly (float a, float b, float c) data;
public Line(float a, float b, float c) : this()
{
data = (a, b, c);
}
public static Line AlongX { get; } = new Line(0, 1, 0);
public static Line AlongY { get; } = new Line(-1, 0, 0);
public static Line ThroughPointAtAngle(Point point, float angle)
{
return new Line(cos(angle), -sin(angle), point.Y * sin(angle) - point.X * cos(angle));
}
public static Line ThroughTwoPoints(Point point1, Point point2)
=> new Line(
point1.Y - point2.Y,
point2.X - point1.X,
point1.X * point2.Y - point1.Y * point2.X);
public float A => data.a;
public float B => data.b;
public float C => data.c;
#region Algebra
public static float Dot(Line line, Point point)
=> line.data.a * point.X + line.data.b * point.Y + line.data.c;
#endregion
#region Geometry
public Line ParallelThrough(Point point)
{
return new Line(data.a, data.b, -data.a * point.X - data.b * point.Y);
}
public Line PerpendicularThrough(Point point)
{
return new Line(data.b, -data.a, -data.b * point.X + data.a * point.Y);
}
public Line Offset(float amount)
=> new Line(data.a, data.b, data.c - amount * sqrt(sqr(data.a) + sqr(data.b)));
public Line Offset(float dx, float dy)
=> new Line(data.a, data.b, data.c + data.a * dx + data.b * dy);
public Line Offset(Vector2 delta) => Offset(delta.X, delta.Y);
public float DistanceTo(Point point)
=> Dot(this, point) / (data.a * data.a + data.b * data.b);
#endregion
#region Formatting
public string ToString(string formatting, IFormatProvider provider)
{
return $"Line({data.a.ToString(formatting, provider)}x+{data.b.ToString(formatting, provider)}y+{data.c.ToString(formatting, provider)}=0)";
}
public string ToString(string formatting)
=> ToString(formatting, null);
public override string ToString()
=> ToString("g");
#endregion
}
Circle.cs
Describes a circle using the center and radius.
using static Float;
public readonly struct Circle
{
readonly (Point center, float radius) data;
public Circle(Point center, float radius)
{
this.data = (center, radius);
}
public static Circle FromTwoPoints(Point point1, Point point2)
{
float radius = point1.DistanceTo(point2) / 2;
Point center = (point1 + point2) / 2;
return new Circle(center, radius);
}
public static Circle FromThreePoints(Point point1, Point point2, Point point3)
{
float k_1 = point1.SumSquares / 2;
float k_2 = point2.SumSquares / 2;
float k_3 = point3.SumSquares / 2;
float dx_12 = point2.X - point1.X;
float dy_12 = point2.Y - point1.Y;
float dx_23 = point3.X - point2.X;
float dy_23 = point3.Y - point2.Y;
float det = dx_12 * dy_23 - dx_23 * dy_12;
Point center = new Point(
(dy_12 * (k_2 - k_3) + dy_23 * (k_2 - k_1)) / det,
(dx_12 * (k_3 - k_2) + dx_23 * (k_1 - k_2)) / det);
float radius = center.DistanceTo(point1);
return new Circle(center, radius);
}
public Point Center => data.center;
public float Radius => data.radius;
#region Geometry
public float DistanceTo(Point point)
=> data.center.DistanceTo(point) - data.radius;
public float DistanceTo(Line line)
{
float d = line.DistanceTo(Center);
if (d > 0)
{
return d - data.radius;
}
else
{
return d + data.radius;
}
}
public bool Intersect(Line line, out Point point, bool alternate = false)
{
line = line.Offset(-Center.X, -Center.Y);
int sign = alternate ? -1 : 1;
float discr = sqr(line.A * data.radius) + sqr(line.B * data.radius) - sqr(line.C);
if (discr >= 0)
{
float d = sign * sqrt(discr);
float ab = line.A * line.A + line.B * line.B;
point = new Point((line.B * d - line.A * line.C) / ab, -(line.A * d + line.B * line.C) / ab);
point += Center;
return true;
}
else
{
float ab = line.A * line.A + line.B * line.B;
point = new Point((-line.A * line.C) / ab, -(+line.B * line.C) / ab);
point += Center;
return false;
}
}
#endregion
#region Formatting
public string ToString(string formatting, IFormatProvider provider)
{
return $"Circle({data.center.ToString(formatting, provider)},{data.radius.ToString(formatting, provider)})";
}
public string ToString(string formatting)
=> ToString(formatting, null);
public override string ToString()
=> ToString("g");
#endregion
}
Float.cs
Helper functions dealing with float math which is lacking from System.Math.
public static class Float
{
/// <summary>
/// A factor of π.
/// </summary>
/// <param name="x">The factor.</param>
public static float pi(float x) => (float)(Math.PI * x);
/// <summary>
/// Degree to Radian conversion
/// </summary>
/// <param name="x">The angle in degrees.</param>
/// <returns>Angle in radians</returns>
public static float deg(float x) => pi(x) / 180;
/// <summary>
/// Radian to Degree conversion
/// </summary>
/// <param name="x">The angle in radians.</param>
/// <returns>Angle in degrees</returns>
public static float rad(float x) => x * 180 / pi(1);
public static float sqr(float x) => x * x;
public static float sqrt(float x) => (float)Math.Sqrt(x);
public static float sin(float x) => (float)Math.Sin(x);
public static float cos(float x) => (float)Math.Cos(x);
}
thx for all the answer (will upvote them), I did the work on it myself, I will share my result :
and here is length of d, to solve the equation :
This may be a strange one but I have a graphic of a triangle like this:
and in a survey platform, whenever one click on a point in this graphic an x,y coordinates in pixels are recorded like this (the origin for x,y is from the top-left of the image)
Note: the clicking is only allowed inside the green triangle.
Is there a way to convert these coordinates to barycentric coordinates (x,y,z) with respect to a simplex in 2D (this triangle)?
If so what is the appropriate equation given that we have the x,y in pixels.
Would it matter if they are in pixels or are they still considered Cartesian coordinates?
Thanks!
So you know the coordinates of the three vertex of the triangle
A: {ax, ay}
B: {bx, by}
C: {cx, cy}
and you want to take an arbitrary point
P: {px, py}
and find the three barycentric coordinates w_A, w_B, w_C such that
px = w_A * ax + w_B * bx + w_C * cx
py = w_A * ay + w_B * by + w_C * cy
1 = w_A + w_B + w_C
Turn this into a linear algebra problem
| px | | ax bx cx | | w_A |
| py | = | ay by cy | | w_B |
| 1 | | 1 1 1 | | w_C |
to be solved for {w_A,w_B,w_C}
Use the sample code below which I tested with the following results
Triangle A: <5, 0>
Triangle B: <2.5, 5>
Triangle C: <0, 0>
Random Point: <3.169941, 0.417091>
Barycentric: (0.5922791,0.08341819,0.3243028)
Target Point: <3.169941, 0.417091>
Triangle.cs
using System.Numerics;
namespace ConsoleApp2
{
public class Triangle
{
public Triangle(Vector2 a, Vector2 b, Vector2 c)
{
A = a;
B = b;
C = c;
}
public Vector2 A { get; set; }
public Vector2 B { get; set; }
public Vector2 C { get; set; }
public Vector2 GetPoint(float w_A, float w_B, float w_C) => GetPoint((w_A, w_B, w_C));
public Vector2 GetPoint((float w_A, float w_B, float w_C) coord)
{
return coord.w_A * A + coord.w_B * B + coord.w_C * C;
}
public (float w_A, float w_B, float w_C) GetBarycentric(Vector2 P)
{
float D = A.X * (B.Y - C.X) + A.Y * (B.X - C.X) + B.X * C.Y - B.Y * C.X;
float w_A = ((B.Y - C.Y) * P.X + (C.X - B.X) * P.Y + (B.X * C.Y - B.Y * C.X)) / D;
float w_B = ((C.Y - A.Y) * P.X + (A.X - C.X) * P.Y + (C.X * A.Y - C.Y * A.X)) / D;
float w_C = ((A.Y - B.Y) * P.X + (B.X - A.X) * P.Y + (A.X * B.Y - A.Y * B.X)) / D;
return (w_A, w_B, w_C);
}
public bool Contains(Vector2 point)
{
var (w_A, w_B, w_C) = GetBarycentric(point);
return w_A>=0 && w_A<=1
&& w_B>=0 && w_B<=1
&& w_C>=0 && w_C<=1;
}
}
}
Program.cs
using System;
using System.Numerics;
namespace ConsoleApp2
{
public static class Program
{
static readonly Random rng = new Random();
static Vector2 RandomVector(float minValue = 0, float maxValue = 1)
{
return new Vector2(
minValue + (maxValue - minValue) * (float)rng.NextDouble(),
minValue + (maxValue - minValue) * (float)rng.NextDouble());
}
static void Main(string[] args)
{
Vector2 A = new Vector2(5f,0f);
Vector2 B = new Vector2(2.5f,5f);
Vector2 C = new Vector2(0f,0f);
var triangle = new Triangle(A, B, C);
Console.WriteLine($"Triangle A: {A}");
Console.WriteLine($"Triangle B: {B}");
Console.WriteLine($"Triangle C: {C}");
Vector2 P = RandomVector(0f, 5f);
Console.WriteLine($"Random Point: {P}");
var (w_A, w_B, w_C) = triangle.GetBarycentric(P);
Console.WriteLine($"Barycentric: ({w_A},{w_B},{w_C})");
Vector2 T = triangle.GetPoint(w_A, w_B, w_C);
Console.WriteLine($"Target Point: {T}");
}
}
}
Pixels are just the specific unit, this triangle representation would still be in cartesian coordinates, so you just apply the same formula, i.e. (as specified in the comments )this
Use case: Streaming large amounts of event source data that may have inserts, updates, and deletes and has guaranteed order.
Assuming Welford's Algorithm in this form in an event stream for insert:
private double _count = 0;
private double _mean = 0;
private double _s = 0;
public void Insert(double value)
{
var prev_mean = _mean;
_count = _count + 1;
if (_count == 1)
{
_mean = value;
_s = 0;
}
else
{
_mean = _mean + (value - _mean) / _count;
_s = _s + (value - _mean) * (value - prev_mean);
}
}
public double Var => ((_count > 1) ? _s / (_count - 1) : 0.0);
public double StDev => Math.Sqrt(Var);
Would it be possible to change the online statistics given a known pre-existing value. Or would there be a more appropriate approach than Welford's Algorithm to accommodate the need?
public void Update(double previousValue, double value)
{
//I got this value correct
var prev_mean = (_count * _mean - value) / (_count - 1);
//I did the inversion, but this doesn't give the right values
var prev_s = -previousValue^2 + previousValue* prev_mean + _mean * previousValue - _mean * prev_mean + _s
}
public void Delete(double previousValue)
{
_count = _count - 1;
}
Edit
The specific questions are:
How can I calculate a correct value for _mean and _s in the case of an Update?
How can I calculate a correct value for _mean and _s in the case of an Delete?
Partial answer (will update if I finish the solve):
I got the inversion wrong on the Update originally.
Edit
Delete was trivial once I solved update
private void Update(double previousValue, double value)
{
if (_count == 1)
{
_mean = value;
_s = 0;
}
else
{
var prev_mean = (_count * _mean - previousValue) / (_count - 1);
var prev_s = -(_mean * prev_mean) + (_mean * previousValue) + (prev_mean * previousValue) - Math.Pow(previousValue, 2) + _s;
//Revert Mean and S
_mean = prev_mean;
_s = prev_s;
//Do same operation as Insert
_mean = _mean + (value - _mean) / _count;
_s = prev_s + (value - _mean) * (value - prev_mean);
}
}
public void Delete(double previousValue)
{
_count = _count - 1;
if (_count == 0)
{
_mean = 0;
_s = 0;
return;
}
if (_count == 1)
{
_mean = (_count * _mean - previousValue) / (_count - 1);
_s = 0;
return;
}
else
{
var prev_mean = (_count * _mean - previousValue) / (_count - 1);
var prev_s = -(_mean * prev_mean) + (_mean * previousValue) + (prev_mean * previousValue) - Math.Pow(previousValue, 2) + _s;
//Revert Mean and S
_mean = prev_mean;
_s = prev_s;
}
}
Edit
Okay found a better implementation of the original algorithm to base this off of, then with the help of Wolfram Mathematica I was able to solve for the inversions I needed. I did a test run locally with a million random activities (insert, update, delete in random order)
I used this as the logic
Assert.IsTrue(Math.Abs(x - y) < .0000001);
Where x is a native 2 pass algo in c# and y is the value from this implementation. It looks like the native implementation rounds a few things that this does not.
Insert method based on work here
https://www.johndcook.com/blog/skewness_kurtosis/
Remove method is my own work.
public class StatisticsTracker
{
private long n = 0;
private double _sum, _s, M1, M2, M3, M4 = 0.0;
public long Count => n;
public double Avg => (n > 2) ? M1 : 0.0;
public double Sum => _sum;
public double Var => M2 / (n - 1.0);
public double StDev => Math.Sqrt(Var);
//public double Skewness => Math.Sqrt(n) * M3 / Math.Pow(M2, 1.5);
//public double Kurtosis => (double)n * M4 / (M2 * M2) - 3.0;
public void Insert(double x)
{
double delta, delta_n, delta_n2, term1;
_sum += x;
long n1 = n;
n++;
delta = x - M1;
delta_n = delta / n;
term1 = delta * delta_n * n1;
M1 = M1 + delta_n;
M2 += term1;
//Required for skewness and Kurtosis
//Will solve later
//delta_n2 = delta_n * delta_n;
//M3 += term1 * delta_n * (n - 2) - 3 * delta_n * M2;
//M4 += term1 * delta_n2 * (n * n - 3 * n + 3) + 6 * delta_n2 * M2 - 4 * delta_n * M3;
}
public void Update(double previousvalue, double value)
{
Delete(previousvalue);
Insert(value);
}
public void Delete(double x)
{
var o = ((M1 * n) - x) / (n - 1.0);
var v = M2;
var y2 = (-(n - 1.0) * Math.Pow(o, 2.0) + (2.0 * (n - 1) * o * x) + (n * (v - Math.Pow(x, 2.0))) + Math.Pow(x, 2.0)) / n;
M1 = o;
M2 = y2;
n = n - 1;
_sum -= x;
}
}
Im having trouble finding a null pointer exception in some lejos code, which is for the EV3 lego robot.
Below is the class state and constructor:
public class Mapper {
private LineMap CurrentMap;
private Line[] lines;
private boolean[] userDrawn;
private Rectangle boundary = new Rectangle(0, 0, 594, 891);
private int counter;
/**
* Initializes an empty map with just a boundary
*
* #author Ben
*/
public Mapper(){
counter = 0;
lines = new Line[counter];
userDrawn = new boolean[counter];
CurrentMap = new LineMap(lines,boundary);
}
And the function causing me grief
public void addLine(float x1, float y1, float x2, float y2, boolean isUserDrawn){
counter++;
Line[] oldLines = lines;
boolean[] oldUserDrawn = userDrawn;
lines = new Line[counter];
userDrawn = new boolean[counter];
for(int i = 0; i < counter - 1; i++){
lines[i] = oldLines[i];
userDrawn[i] = oldUserDrawn[i];
}
lines[counter-1] = new Line(x1,y1,x2,y2);
if(isUserDrawn == true){
userDrawn[counter - 1] = true;
}
else{
userDrawn[counter - 1] = false;
}
CurrentMap = new LineMap(lines,boundary);
}
Any ideas for what might be a source of a null pointer exception:
Dont worry, problem not in this code. And has been solved.
I am trying to implement a UI like this one..
http://www.shrenikvikam.com/wp-content/uploads/2011/04/214e422a43E11S3.png-150x134.png
But i am having some trouble implementing this.. Could someone tell me mistakes in this...
public class Meter extends View{
static final int ORBIT_COLOR = Color.argb(255, 66, 66, 66);
static final double RAD_CIRCLE = 2*Math.PI; // Number radians in a circle
private Paint paint; // Paint object controlling format of screen draws
private ShapeDrawable planet; // Planet symbol
private int planetRadius = 7; // Radius of spherical planet (pixels)
private int sunRadius = 12; // Radius of Sun (pixels)
private float X0 = 0; // X offset from center (pixels)
private float Y0 = 0; // Y offset from center (pixels)
private float X; // Current X position of planet (pixels)
private float Y; // Current Y position of planet (pixels)
private float centerX; // X for center of display (pixels)
private float centerY; // Y for center of display (pixels)
private float R0; // Radius of circular orbit (pixels)
private int nsteps = 120; // Number animation steps around circle
private double theta; // Angle around orbit (radians)
private double dTheta; // Angular increment each step (radians)
private double direction = -1; // Direction: counter-clockwise -1; clockwise +1
private float lastTouchX; // x coordinate of symbol i at last touch
private float lastTouchY; // x coordinate of symbol i at last touch
private int divisions = 120; // Since it requires temperature change from 0 -120
private double oneSegmentLength = (2 * Math.PI * R0)/(double)120;
public Meter(Context context) {
super(context);
// Initialize angle and angle step (in radians)
theta = 30;
//dTheta = RAD_CIRCLE/((double) nsteps); // Angle increment in radians
dTheta = ((360-60)/(double)divisions);
planet = new ShapeDrawable(new OvalShape());
planet.getPaint().setColor(Color.WHITE);
planet.setBounds(0, 0, 2*planetRadius, 2*planetRadius);
paint = new Paint();
paint.setAntiAlias(true);
paint.setTextSize(14);
paint.setStrokeWidth(1);
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
int action = ev.getAction();
switch (action) {
// MotionEvent class constant signifying a finger-down event
case MotionEvent.ACTION_DOWN: {
final float x = ev.getX();
final float y = ev.getY();
lastTouchX = x;
lastTouchY = y;
newXY();
break;
}
// MotionEvent class constant signifying a finger-drag event
case MotionEvent.ACTION_MOVE: {
float newX = ev.getX();
float newY = ev.getY();
float dx = newX - lastTouchX;
float dy = newY - lastTouchY;
int diff = (int) (Math.abs(ev.getX()) % Math.abs(oneSegmentLength));
if(diff == 0){
if(Math.abs(dx) > Math.abs(dy)) {
if(dx>0) direction = 1;
else direction = -1;
newXY();
} else {
newXY();
}
Log.d("MOVE", "dx ->" + dx + " one seg->" + oneSegmentLength);
invalidate();
}
break;
}
// MotionEvent class constant signifying a finger-up event
case MotionEvent.ACTION_UP: {
Log.d("ACTION MOVE","Value ->");
final float x = ev.getX();
final float y = ev.getY();
lastTouchX = x;
lastTouchY = y;
newXY();
break;
}
}
return true;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawBackground(paint, canvas);
canvas.save();
canvas.translate(X + X0, Y + Y0);
planet.draw(canvas);
canvas.restore();
}
// Called by onDraw to draw the background
private void drawBackground(Paint paint, Canvas canvas){
paint.setColor(Color.YELLOW);
paint.setStyle(Paint.Style.FILL);
canvas.drawCircle(centerX + X0, centerY + Y0, sunRadius, paint);
paint.setStyle(Paint.Style.STROKE);
paint.setColor(ORBIT_COLOR);
canvas.drawCircle(centerX + X0, centerY + Y0, R0, paint);
}
//Method to increment angle theta and compute the new X and Y .
private void newXY(){
theta += dTheta;
Log.d("THETA VAL", "->" + theta);
//if(theta > RAD_CIRCLE) theta -= RAD_CIRCLE; // For convenience, keep angle 0-2pi
if(theta > 150)theta = 30;
if(theta > 30 && theta <120){
X = (float)(R0*Math.sin(direction*theta)) + centerX - planetRadius;
Y = centerY - (float)(R0*Math.cos(direction*theta)) - planetRadius;
}
//Log.i("ANIMATOR", "X="+X+" Y="+Y);
}
#Override
protected void onSizeChanged (int w, int h, int oldw, int oldh){
// Coordinates for center of screen
centerX = w/2;
centerY = h/2;
// Make orbital radius a fraction of minimum of width and height of display
R0 = (float) (0.90*Math.min(centerX, centerY));
oneSegmentLength = (2 * Math.PI * R0)/(double)120;
// Set the initial position of the planet (translate by planetRadius so center of planet
// is at this position)
X = centerX - planetRadius ;
Y = centerY - R0 - planetRadius;
}
}
I am referring this code to do this implementation...
http://eagle.phys.utk.edu/guidry/android/animatorDemo.html
I am just drawing a circle and trying to implement the same motion between 0 -120 degrees..