vector point precision Error - c#

Our application contains .Net FrameWork3.5 and DirectX For Making 2d drawing.
we are stuck with precision problem.Please give solution to solve the precision problem.
we are using vector3f(vector points) to store the values. while we store the result of point in vector3f only 2 precision value is matched.But we need 5 precision value.
Here i have mentioned my code below..
//Function To find ARC Parameters from Bulge value
polylineVertStart=6919.602,18951.51,0 polylineVertEnd=6916.602,18951.51,0
Arc StartPoint=6919.602,18951.5177,0 Endpoint=6916.602,18951.51,0
public static Arc BulgeToArc(PolylineVertex3d polylineVertStart, PolylineVertex3d polylineVertEnd)
{
PolylineVertex3d polylineVertex3d = polylineVertEnd;
PolylineVertex3d polylineVertex3d1 = polylineVertStart; //get previous point
double x1 = polylineVertex3d1.Position.X; //Assign start and end points
double y1 = polylineVertex3d1.Position.Y;
double x2 = polylineVertex3d.Position.X;
double y2 = polylineVertex3d.Position.Y;
if (y1 == y2)
{
y2 += (y1 * 0.0000001);
}
if (x1 == x2)
{
x2 += (x1 * 0.0000001);
}
double bulge = polylineVertex3d1.Bulge;
double incAngle = 4 * System.Math.Atan(System.Math.Abs(bulge)); //included Angle
double chord = System.Math.Sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)); //Chord length
double r = 0.5 * chord / System.Math.Cos(0.5 * incAngle - 0.5 * System.Math.PI); //Calculate radius
double Radius = r;
double dx = x2 - x1;
double dy = y2 - y1;
double slope = dy / dx; //slope of two points
double slopeAng = System.Math.Atan(slope);
if (System.Math.Sign(dy) == -1 && System.Math.Sign(dx) == -1)
{
slopeAng = System.Math.PI + slopeAng;
}
else if (System.Math.Sign(dy) == -1 && System.Math.Sign(dx) == 1)
{
slopeAng = 2 * System.Math.PI + slopeAng;
}
else if (System.Math.Sign(dy) == 1 && System.Math.Sign(dx) == -1)
{
slopeAng = System.Math.PI + slopeAng;
}
double d1 = System.Math.Sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
double d2 = d1 / 2;
double startAng = System.Math.Acos(d2 / r); //calculate start angle
double sAngle;
if (System.Math.Abs(bulge) < 1) //get actual start angle based on bulge direction
{
if (System.Math.Sign(bulge) != -1)
{
sAngle = slopeAng + startAng;
}
else
{
sAngle = slopeAng - startAng;
}
}
else
{
if (System.Math.Sign(bulge) != -1)
{
sAngle = slopeAng - startAng;
}
else
{
sAngle = slopeAng + startAng;
}
}
double cx = x1 + r * System.Math.Cos(sAngle);
double cy = y1 + r * System.Math.Sin(sAngle);
Vector3F Center = new Vector3F((float)cx, (float)cy, 0f); //calculate center point
double dx1 = x1 - cx;
double dx2 = x2 - cx;
double dy1 = y1 - cy;
double dy2 = y2 - cy;
double sAng = System.Math.Atan(dy1 / dx1);
double eAng = System.Math.Atan(dy2 / dx2);
if (System.Math.Sign(dy1) == -1 && System.Math.Sign(dx1) == -1)
{
sAng = System.Math.PI + sAng;
}
else if (System.Math.Sign(dy1) == -1 && System.Math.Sign(dx1) != -1)
{
sAng = 2 * System.Math.PI + sAng;
}
else if (System.Math.Sign(dx1) == -1)
{
sAng = System.Math.PI + sAng;
}
if (System.Math.Sign(dy2) == -1 && System.Math.Sign(dx2) == -1)
{
eAng = System.Math.PI + eAng;
}
else if (System.Math.Sign(dy2) == -1 && System.Math.Sign(dx2) != -1)
{
eAng = 2 * System.Math.PI + eAng;
}
else if (System.Math.Sign(dx2) == -1)
{
eAng = System.Math.PI + eAng;
}
double StartAngle;
double EndAngle;
if (System.Math.Sign(bulge) != -1) //finalise start angle and end angle
{
StartAngle = sAng;
EndAngle = eAng;
}
else
{
StartAngle = eAng;
EndAngle = sAng;
}
Direction dir;
if (polylineVertStart.Bulge != 0)
dir = polylineVertStart.Bulge < 0 ? Direction.ClockWise : Direction.CounterClockWise;
else
dir = polylineVertEnd.Bulge < 0 ? Direction.ClockWise : Direction.CounterClockWise;
Arc arc = dir == Direction.ClockWise ? new Arc(Center, new Vector3F(0f, 0f, 1f), Radius, EndAngle, StartAngle, dir) : new Arc(Center, new Vector3F(0f, 0f, 1f), Radius, StartAngle, EndAngle, dir);
return arc;
}
//Function to find ARC from StartAngle,EndAngle,Radius
public RenderingEngine.Geometry GetGeomtry()
{
RenderingEngine.Geometry geometry = new RenderingEngine.Geometry
{
EntityPrimitiveType = EntityPrimitiveType.LineStrip
};
xPoints.Clear();
yPoints.Clear();
zPoints.Clear();
VertexList.Clear();
List<CustomVertex.PositionColored> vertices = new List<CustomVertex.PositionColored>();
if (direction == Direction.ClockWise)
{
#region clockwise
double WedgeAngle = 0.0; //clock wise
if (EndAngle != StartAngle)
{
if (EndAngle < StartAngle)
{
WedgeAngle = (StartAngle - EndAngle) / NUMPOINTS;
}
else
{
WedgeAngle = ((System.Math.PI * 2) - (EndAngle - StartAngle)) / NUMPOINTS;
}
}
double angle = StartAngle;
for (int i = 0; i <= NUMPOINTS; i++)
{
double theta = angle - (i * WedgeAngle);
double x = center.X + (radius * SystemMath.Cos(theta));
double y = center.Y + (radius * SystemMath.Sin(theta));
double z = center.Z;
CustomVertex.PositionColored positionColored = new CustomVertex.PositionColored
{
Position =
new Vector3((float) x, (float) y,
(float) z),
Color = Color.ToArgb()
};
vertices.Add(positionColored);
xPoints.Add((float)x);
yPoints.Add((float)y);
zPoints.Add((float)z);
VertexList.Add(new Vector3F((float)x, (float)y, (float)z));
}
double startx = Center.X + (Radius * System.Math.Cos(StartAngle));
double starty = Center.Y + (Radius * System.Math.Sin(StartAngle));
double startz = Center.Z;
double endx = Center.X + (Radius * System.Math.Cos(EndAngle));
double endy = Center.Y + (Radius * System.Math.Sin(EndAngle));
double endz = Center.Z;
startPoint = new Vector3F((float)startx, (float)starty, (float)startz);
endPoint = new Vector3F((float)endx, (float)endy, (float)endz);
#endregion clockwise
}
else
{
#region Counter ClockWise
double WedgeAngle = 0.0;
if (EndAngle != StartAngle)
{
if (EndAngle > StartAngle)
{
WedgeAngle = (EndAngle - StartAngle) / NUMPOINTS;
}
else
{
WedgeAngle = ((System.Math.PI * 2 - StartAngle) + EndAngle) / NUMPOINTS;
}
}
double angle = StartAngle;
for (int i = 0; i <= NUMPOINTS; i++)
{
double theta = angle + (i * WedgeAngle);
double x = center.X + (radius * SystemMath.Cos(theta));
double y = center.Y + (radius * SystemMath.Sin(theta));
double z = center.Z;
CustomVertex.PositionColored positionColored = new CustomVertex.PositionColored
{
Position =
new Vector3((float) x, (float) y,
(float) z),
Color = Color.ToArgb()
};
vertices.Add(positionColored);
xPoints.Add((float)x);
yPoints.Add((float)y);
zPoints.Add((float)z);
VertexList.Add(new Vector3F((float)x, (float)y, (float)z));
}
double startx = Center.X + (Radius * System.Math.Cos(StartAngle));
double starty = Center.Y + (Radius * System.Math.Sin(StartAngle));
double startz = Center.Z;
double endx = Center.X + (Radius * System.Math.Cos(EndAngle));
double endy = Center.Y + (Radius * System.Math.Sin(EndAngle));
double endz = Center.Z;
startPoint = new Vector3F((float)startx, (float)starty, (float)startz);
endPoint = new Vector3F((float)endx, (float)endy, (float)endz);
#endregion
}
geometry.Vertices.Add(vertices);
return geometry;
}
Here arc start point and endpoint x value always come correctly but y value is some precision problem.
Thanks in Advance..

Related

How to find center point if startangle and sweep angle is changed

In android , I have drawn an arc based on startangle, sweepangle and radius. Let width be 400 and height be 500 as rectangle bounds in which radius is calculated as
var radius = Math.Min(Width,Height)/2;
Also if centre is calculated as
var x = (float)(Width * 0.5);
var y = (float)(Height * 0.5);
var centre = new PointF(x,y);
If above centre value is used, centre remains same for all start angle and sweepangle for rectangle. I need to change the centre if startangle and sweep angle changes
In the below image, rectangle bounds is 400,500 and the startangle is 0 and sweepangle is 360
If I change start angle to 180 and sweepangle to 180, centre remains same
I need the below image output,if I change startangle and sweepangle based on circle bounds, centre point should vary
I have done calculations for the above ,
private SystemPointF GetActualCenter(float x, float y, float radius)
{
SystemPointF actualCenter = new SystemPointF(x, y);
double startAngle1 = GetWrapAngle(StartAngle, -630, 630);
double endAngle1 = GetWrapAngle(EndAngle, -630, 630);
float[] regions = new float[] { -630, -540, -450, -360, -270, -180, -90, 0, 90, 180, 270, 360, 450, 540, 630 };
List<int> region = new List<int>();
if (startAngle1 < endAngle1)
{
for (int i = 0; i < regions.Length; i++)
{
if (regions[i] > startAngle1 && regions[i] < endAngle1)
region.Add((int)((regions[i] % 360) < 0 ? (regions[i] % 360) + 360 : (regions[i] % 360)));
}
}
else
{
for (int i = 0; i < regions.Length; i++)
{
if (regions[i] < startAngle1 && regions[i] > endAngle1)
region.Add((int)((regions[i] % 360) < 0 ? (regions[i] % 360) + 360 : (regions[i] % 360)));
}
}
double startRadian = 2 * Math.PI * (startAngle1) / 360;
double endRadian = 2 * Math.PI * (endAngle1) / 360;
SystemPointF startPoint = new SystemPointF((float)(x + radius * Math.Cos(startRadian)),
(float)(y + radius * Math.Sin(startRadian)));
SystemPointF endPoint = new SystemPointF((float)(x + radius * Math.Cos(endRadian)),
(float)(y + radius * Math.Sin(endRadian)));
switch (region.Count)
{
case 0:
float longX = Math.Abs(x - startPoint.X) > Math.Abs(x - endPoint.X) ? startPoint.X : endPoint.X;
float longY = Math.Abs(y - startPoint.Y) > Math.Abs(y - endPoint.Y) ? startPoint.Y : endPoint.Y;
SystemPointF midPoint = new SystemPointF(Math.Abs((x + longX)) / 2, Math.Abs((y + longY)) / 2);
actualCenter.X = x + (x - midPoint.X);
actualCenter.Y = y + (y - midPoint.Y);
break;
case 1:
SystemPointF point1 = new SystemPointF(), point2 = new SystemPointF();
float maxRadian = (float)(2 * Math.PI * region[0] / 360);
SystemPointF maxPoint = new SystemPointF((float)(x + radius * Math.Cos(maxRadian)),
(float)(y + radius * Math.Sin(maxRadian)));
switch (region[0])
{
case 270:
point1 = new SystemPointF(startPoint.X, maxPoint.Y);
point2 = new SystemPointF(endPoint.X, y);
break;
case 0:
case 360:
point1 = new SystemPointF(x, endPoint.Y);
point2 = new SystemPointF(maxPoint.X, startPoint.Y);
break;
case 90:
point1 = new SystemPointF(endPoint.X, y);
point2 = new SystemPointF(startPoint.X, maxPoint.Y);
break;
case 180:
point1 = new SystemPointF(maxPoint.X, startPoint.Y);
point2 = new SystemPointF(x, endPoint.Y);
break;
}
midPoint = new SystemPointF((point1.X + point2.X) / 2, (point1.Y + point2.Y) / 2);
actualCenter.X = x + ((x - midPoint.X) >= radius ? 0 : (x - midPoint.X));
actualCenter.Y = y + ((y - midPoint.Y) >= radius ? 0 : (y - midPoint.Y));
break;
case 2:
float minRadian = (float)(2 * Math.PI * region[0] / 360);
maxRadian = (float)(2 * Math.PI * (region[1]) / 360);
maxPoint = new SystemPointF((float)(x + radius * Math.Cos(maxRadian)),
(float)(y + radius * Math.Sin(maxRadian)));
SystemPointF minPoint = new SystemPointF((float)(x + radius * Math.Cos(minRadian)),
(float)(y + radius * Math.Sin(minRadian)));
if (region[0] == 0 && region[1] == 90 || region[0] == 180
&& region[1] == 270)
point1 = new SystemPointF(minPoint.X, maxPoint.Y);
else
point1 = new SystemPointF(maxPoint.X, minPoint.Y);
if (region[0] == 0 || region[0] == 180)
point2 = new SystemPointF(GetMinMaxValue(startPoint, endPoint, region[0]),
GetMinMaxValue(startPoint, endPoint, region[1]));
else
point2 = new SystemPointF(GetMinMaxValue(startPoint, endPoint, region[1]),
GetMinMaxValue(startPoint, endPoint, region[0]));
midPoint = new SystemPointF(Math.Abs(point1.X - point2.X) / 2 >= radius ? 0 : (point1.X + point2.X) / 2,
Math.Abs(point1.Y - point2.Y) / 2 >= radius ? 0 : (point1.Y + point2.Y) / 2);
actualCenter.X = x + (midPoint.X == 0 ? 0 : (x - midPoint.X) >= radius ? 0 : (x - midPoint.X));
actualCenter.Y = y + (midPoint.Y == 0 ? 0 : (y - midPoint.Y) >= radius ? 0 : (y - midPoint.Y));
break;
}
return actualCenter;
}
This works when startangle and sweep angle changed for all cases except the case startangle 179 and sweep angle changed to above 180. case 3 includes the region 180,270,0 . how to write calculations for regions 3.
Any help is really appreciated.
Thanks in advance
When you want to draw an object in the center of something you should do this :
Object.Point =
new Point((something.Width / 2) - (object.Widht /2) ,(something.Height / 2) - object.Height / 2));

c# move point along an arc

Please see this picture:
I need to move by mouse one of the two points along an arc of 90°
Please have in mind that I can rotate the Arrow and the whole thing will rotate as well.
What I did:
public override bool HandleMouseMove(MouseEventArgs e)
{
double angleRad = 0;
double new_cx = 0;
double new_cY = 0;
double currentAngle = Arrow.Rotation.Angle;
Point pt = TMEMControl.ScreenToWorld(new Point(e.X, e.Y));
Point center = TMEMControl.ScreenToWorld(new Point(Arrow.Translation.X, Arrow.Translation.Y));
Point c = new Point(center.X + 25, center.Y);
angleRad = (-currentAngle) * (Math.PI / 180);
new_cx = center.X + Math.Cos(angleRad) * 25;
new_cY = center.Y + Math.Sin(angleRad) * 25;
c = new Point(new_cx, new_cY);
Vector CenterPt = new Vector((pt.X-center.X),(pt.Y-center.Y));
Vector CenterC = new Vector((c.X - center.X),(c.Y - center.Y));
fieldOfView = Vector.AngleBetween(CenterPt, CenterC);
if (fieldOfView >= 90) fieldOfView = 90;
if (fieldOfView <= 0) fieldOfView = 0;
TMEMControl.Settings.VideoOverlayHelper.FieldOfView = (float)SmartFrame.Basic.BaseAngle.Deg2Rad(fieldOfView*2);
updateFieldofView = (float)fieldOfView;
if (updateFieldofView > 87) updateFieldofView = 87;
if (updateFieldofView < 0) updateFieldofView = 0;
return true;
}
public void Reset(int id, double x, double y, double angle)
{
double angleInRadians = 0;
Point center = new Point(x + 15, y + 20);
Point refP = new Point(x + 15, (y - 80));
distance = Point.Subtract(refP, center).Length;
double new_x = 0;
double new_y = 0;
ControlPoint cpi = CameraCtrl.getCP(id);
if (null != cpi)
{
switch (id)
{
case 0:
cpi.point = new Point(center.X, center.Y);
cpi.state = ControlPoint.States.Selectable;
break;
case 1:
cpi.point = new Point(x + 15, (y + 80));
angleInRadians = (float)SmartFrame.Basic.BaseAngle.Deg2Rad((angle + (87 - updateFieldofView)));
new_x = center.X + Math.Cos(-angleInRadians) * distance;
new_y = center.Y + Math.Sin(-angleInRadians) * distance;
cpi.point = new Point(new_x, new_y);
cpi.state = ControlPoint.States.Fixed;
break;
case 2:
cpi.point = new Point(x + 15, (y - 80));
angleInRadians = (float)SmartFrame.Basic.BaseAngle.Deg2Rad((angle + (180 - (87 - updateFieldofView))));
new_x = center.X + Math.Cos(-angleInRadians) * distance;
new_y = center.Y + Math.Sin(-angleInRadians) * distance;
cpi.point = new Point(new_x, new_y);
cpi.state = ControlPoint.States.Selectable;
break;
}
}
}
It's working 90% the problem is that once I snap/click on one of the red dots and move the mouse, the red dot is always few degrees ahead from the the mouse cursor. and I need to move it with the cursor Position.
And just for the info why I set always the angle to max 87°, is because I want to keep a little distance between the Arrow and my two lines.

Chamfer two lines by give distances using C#

I am working on a simple tool in C#. I have three points which makes two lines meeting at point P. So that PP1 and PP2. I want to Chamfer the lines at meeting point such that distance d1 is trimmed from line PP1 and distance d2 is trimmed from line PP2 and then join the trimmed lines.
I have Problem as i can't get exact result. Any idea whats the problem in my code.
Thanks
Result1
Result2
private void Chamfer(Graphics g,PointF P,PointF P1,PointF P2,double d1,double d2)
{
//Vector 1 Length
double PP1 = Math.Sqrt((Math.Pow((P.X - P1.X), 2) + Math.Pow((P.Y - P1.Y), 2)));
//Vector 2 Length
double PP2 = Math.Sqrt((Math.Pow((P.X-P2.X), 2) + Math.Pow((P.Y - P2.Y), 2)));
//Slopes & Angles
double m1 = (P.Y-P1.Y) / (P.X - P1.X);
double angle1 = Math.Atan(m1) * (180 / Math.PI);
double m2 = (P.Y - P2.Y) / (P.X - P2.X);
double angle2 = Math.Atan(m2) * (180 / Math.PI);
//Coordinates of points of Chamfer
if(P1.X>P.X && P1.Y > P.Y)
{
int Pd1X = Convert.ToInt32(P.X + d1 * Math.Cos(angle1));
int Pd1Y = Convert.ToInt32(P.Y + d1 * Math.Sin(angle1));
Chp1 = new Point(Pd1X, Pd1Y);
}
else if (P1.X > P.X && P1.Y < P.Y)
{
int Pd1X = Convert.ToInt32(P.X + d1 * Math.Cos(angle1));
int Pd1Y = Convert.ToInt32(P.Y - d1 * Math.Sin(angle1));
Chp1 = new Point(Pd1X, Pd1Y);
}
else if (P1.X < P.X && P1.Y < P.Y)
{
int Pd1X = Convert.ToInt32(P.X - d1 * Math.Cos(angle1));
int Pd1Y = Convert.ToInt32(P.Y - d1 * Math.Sin(angle1));
Chp1 = new Point(Pd1X, Pd1Y);
}
else if (P1.X < P.X && P1.Y > P.Y)
{
int Pd1X = Convert.ToInt32(P.X - d1 * Math.Cos(angle1));
int Pd1Y = Convert.ToInt32(P.Y + d1 * Math.Sin(angle1));
Chp1 = new Point(Pd1X, Pd1Y);
}
if (P2.X > P.X && P2.Y > P.Y)
{
int Pd2X = Convert.ToInt32(P.X + d2 * Math.Cos(angle2));
int Pd2Y = Convert.ToInt32(P.Y + d2 * Math.Sin(angle2));
Chp2 = new Point(Pd2X, Pd2Y);
}
else if (P2.X > P.X && P2.Y < P.Y)
{
int Pd2X = Convert.ToInt32(P.X + d2 * Math.Cos(angle2));
int Pd2Y = Convert.ToInt32(P.Y - d2 * Math.Sin(angle2));
Chp2 = new Point(Pd2X, Pd2Y);
}
else if (P2.X < P.X && P2.Y < P.Y)
{
int Pd2X = Convert.ToInt32(P.X - d2 * Math.Cos(angle2));
int Pd2Y = Convert.ToInt32(P.Y - d2 * Math.Sin(angle2));
Chp2 = new Point(Pd2X, Pd2Y);
}
else if (P2.X < P.X && P2.Y > P.Y)
{
int Pd2X = Convert.ToInt32(P.X - d2 * Math.Cos(angle1));
int Pd2Y = Convert.ToInt32(P.Y + d2 * Math.Sin(angle1));
Chp2 = new Point(Pd2X, Pd2Y);
}
Pen penPre = new Pen(Color.Green);
penPre.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
g.Clear(this.BackColor);
g.DrawLine(Pens.Black, P1, Chp1);
g.DrawLine(penPre, P1, P);
g.DrawLine(penPre, P2, P);
g.DrawString("P1", this.Font, Brushes.Red, new Point(Convert.ToInt32(P1.X + 2), Convert.ToInt32(P1.Y - 2)));
g.DrawLine(Pens.Black, P2, Chp2);
g.DrawString("P2", this.Font, Brushes.Red, new Point(Convert.ToInt32(P2.X + 2), Convert.ToInt32(P2.Y - 2)));
g.DrawString("P", this.Font, Brushes.Red, new Point(Convert.ToInt32( P.X + 3),Convert.ToInt32( P.Y - 2)));
g.DrawLine(Pens.Black, Chp1, Chp2);
}
what i got at a specific coordinates, my code is working as you can see from photo attached. I can't figure if i don't have these golden coordinate.
Result from golden coordinates
//Vector 1 Length
double PP1 = Math.Sqrt((Math.Pow((P.X - P1.X), 2) + Math.Pow((P.Y - P1.Y), 2)));
//unit direction vector
upx1 = (P1.X - P.X) / PP1
upy1 = (P1.Y - P.Y) / PP1
// chpoint coordinates
chx1 = P.X + upx1 * d;
chy1 = P.Y + upy1 * d;
// now the same for PP2

Rasterizing curves algorithms

My current application needs an algorithm to drawing lines, circles and rotated ellipses of a given image. I have searched on the internet and found this article Algorithm for Drawing Curves explain how to achieve it. I'm trying to implement a method describe in the Page 40 in C#, but in the Line 40 has an operation between Int and Bool.
The operation in question is:
x1 = 2 * err > dy; // <- this
y1 = 2 * (err + yy) < -dy); // <- this
if (2 * err < dx || y1) // <- this
{
y0 += sy;
dy += xy;
err += dx += xx;
}
if (2 * err > dx || x1) // <- this
{
x0 += sx;
dx += xy;
err += dy += yy;
}
The variables x1, y1 are integers and err, yy and dy are double. I don't know which programming language the author used, but apparently seems to be in C.
How to translated this operation in C#?
The Complete method I tried to implemented in C#:
private static Point[] plotQuadRationalBezierSeg(int x0, int y0, int x1, int y1, int x2, int y2, double w)
{
// plot a limited rational Bezier segment, squared weight
var points = new List<Point>();
int sx = x2 - x1, sy = y2 - y1; // relative values for checks
double dx = x0 - x2, dy = y0 - y2, xx = x0 - x1, yy = y0 - y1;
double xy = xx * sy + yy * sx, cur = xx * sy - yy * sx, err; // curvature
//assert(xx * sx <= 0.0 && yy * sy <= 0.0); // sign of gradient must not change
if (cur != 0.0 && w > 0.0)
{ /* no straight line */
if (sx * (long)sx + sy * (long)sy > xx * xx + yy * yy)
{ // begin with longer part
x2 = x0;
x0 -= (int)dx;
y2 = y0;
y0 -= (int)dy;
cur = -cur; //swap P0 P2
}
xx = 2.0 * (4.0 * w * sx * xx + dx * dx); //differences 2nd degree
yy = 2.0 * (4.0 * w * sy * yy + dy * dy);
sx = x0 < x2 ? 1 : -1; // x step direction
sy = y0 < y2 ? 1 : -1; // y step direction
xy = -2.0 * sx * sy * (2.0 * w * xy + dx * dy);
if (cur * sx * sy < 0.0)
{
// negated curvature?
xx = -xx;
yy = -yy;
xy = -xy;
cur = -cur;
}
dx = 4.0 * w * (x1 - x0) * sy * cur + xx / 2.0 + xy; //differences 1st degree
dy = 4.0 * w * (y0 - y1) * sx * cur + yy / 2.0 + xy;
if (w < 0.5 && (dy > xy || dx < xy))
{
// flat ellipse, algorithm fails
cur = (w + 1.0) / 2.0;
w = Math.Sqrt(w);
xy = 1.0 / (w + 1.0);
sx = (int)Math.Floor((x0 + 2.0 * w * x1 + x2) * xy / 2.0 + 0.5); //subdivide curve in half
sy = (int)Math.Floor((y0 + 2.0 * w * y1 + y2) * xy / 2.0 + 0.5);
dx = (int)Math.Floor((w * x1 + x0) * xy + 0.5);
dy = (int)Math.Floor((y1 * w + y0) * xy + 0.5);
points.AddRange(plotQuadRationalBezierSeg(x0, y0, (int)dx, (int)dy, sx, sy, cur)); //plot separately
dx = Math.Floor((w * x1 + x2) * xy + 0.5); dy = Math.Floor((y1 * w + y2) * xy + 0.5);
points.AddRange(plotQuadRationalBezierSeg(sx, sy, (int)dx, (int)dy, x2, y2, cur));
return points.ToArray();
}
//error 1.step
err = dx + dy - xy;
do
{
points.Add(new Point(x0, y0)); // plot curve
if (x0 == x2 && y0 == y2)
return points.ToArray(); // last pixel -> curve finished
x1 = 2 * err > dy;
y1 = 2 * (err + yy) < -dy); // save value for test of x step
if (2 * err < dx || y1)
{
y0 += sy;
dy += xy;
err += dx += xx;
}/* y step */
if (2 * err > dx || x1)
{
x0 += sx;
dx += xy;
err += dy += yy;
}/* x step */
} while (dy <= xy && dx >= xy); // gradient negates -> algorithm fails
}
// plot remaining needle to end
points.AddRange(
new Point[] {
new Point(x0, y0),
new Point(x2, y2),
});
return points.ToArray();
}

HSV triangle in C# [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
For my assignment I need to make to make a color picker that looks like this:
I've got the wheel part but can't figure out how to draw the triangle.
using System.Drawing;
using System.Drawing.Imaging;
void Main()
{
double hue = 3.3;
double sat = 0.4;
double val = 0.9;
var wheel = new ColorPicker(400);
var img = wheel.DrawImage(hue, sat, val);
using (var g = Graphics.FromImage(img))
{
var pen = val < 0.5 ? Pens.White : Pens.Black;
var wheelPosition = wheel.GetWheelPosition(hue);
g.DrawEllipse(pen, (float)wheelPosition.X - 5, (float)wheelPosition.Y - 5, 10, 10);
var trianglePosition = wheel.GetTrianglePosition(sat, val);
g.DrawEllipse(pen, (float)trianglePosition.X - 5, (float)trianglePosition.Y - 5, 10, 10);
}
img.Dump(); // LINQPad extension method
}
public class ColorPicker
{
public int Size { get; }
public int CenterX => Size / 2;
public int CenterY => Size / 2;
public int InnerRadius => Size * 5 / 12;
public int OuterRadius => Size / 2;
public ColorPicker(int size = 400)
{
Size = size;
}
public enum Area
{
Outside,
Wheel,
Triangle
}
public struct PickResult
{
public Area Area { get; set; }
public double? Hue { get; set; }
public double? Sat { get; set; }
public double? Val { get; set; }
}
public PickResult Pick(double x, double y)
{
var distanceFromCenter = Math.Sqrt((x - CenterX) * (x - CenterX) + (y - CenterY) * (y - CenterY));
var sqrt3 = Math.Sqrt(3);
if (distanceFromCenter > OuterRadius)
{
// Outside
return new PickResult { Area = Area.Outside };
}
else if (distanceFromCenter > InnerRadius)
{
// Wheel
var angle = Math.Atan2(y - CenterY, x - CenterX) + Math.PI / 2;
if (angle < 0) angle += 2 * Math.PI;
var hue = angle;
return new PickResult { Area = Area.Wheel, Hue = hue };
}
else
{
// Inside
var x1 = (x - CenterX) * 1.0 / InnerRadius;
var y1 = (y - CenterY) * 1.0 / InnerRadius;
if (0 * x1 + 2 * y1 > 1) return new PickResult { Area = Area.Outside };
else if (sqrt3 * x1 + (-1) * y1 > 1) return new PickResult { Area = Area.Outside };
else if (-sqrt3 * x1 + (-1) * y1 > 1) return new PickResult { Area = Area.Outside };
else
{
// Triangle
var sat = (1 - 2 * y1) / (sqrt3 * x1 - y1 + 2);
var val = (sqrt3 * x1 - y1 + 2) / 3;
return new PickResult { Area = Area.Triangle, Sat = sat, Val = val };
}
}
}
public Image DrawImage(double hue = 0.0, double sat = 1.0, double val = 1.0)
{
var img = new Bitmap(Size, Size, PixelFormat.Format32bppArgb);
for (int y = 0; y < Size; y++)
{
for (int x = 0; x < Size; x++)
{
Color color;
var result = Pick(x, y);
if (result.Area == Area.Outside)
{
// Outside
color = Color.Transparent;
}
else if (result.Area == Area.Wheel)
{
// Wheel
color = HSV(result.Hue.Value, sat, val, 1);
}
else
{
// Triangle
color = HSV(hue, result.Sat.Value, result.Val.Value, 1);
}
img.SetPixel(x, y, color);
}
}
return img;
}
private Color HSV(double hue, double sat, double val, double alpha)
{
var chroma = val * sat;
var step = Math.PI / 3;
var interm = chroma * (1 - Math.Abs((hue / step) % 2.0 - 1));
var shift = val - chroma;
if (hue < 1 * step) return RGB(shift + chroma, shift + interm, shift + 0, alpha);
if (hue < 2 * step) return RGB(shift + interm, shift + chroma, shift + 0, alpha);
if (hue < 3 * step) return RGB(shift + 0, shift + chroma, shift + interm, alpha);
if (hue < 4 * step) return RGB(shift + 0, shift + interm, shift + chroma, alpha);
if (hue < 5 * step) return RGB(shift + interm, shift + 0, shift + chroma, alpha);
return RGB(shift + chroma, shift + 0, shift + interm, alpha);
}
private Color RGB(double red, double green, double blue, double alpha)
{
return Color.FromArgb(
Math.Min(255, (int)(alpha * 256)),
Math.Min(255, (int)(red * 256)),
Math.Min(255, (int)(green * 256)),
Math.Min(255, (int)(blue * 256)));
}
public PointD GetWheelPosition(double hue)
{
double middleRadius = (InnerRadius + OuterRadius) / 2;
return new PointD
{
X = CenterX + middleRadius * Math.Sin(hue),
Y = CenterY - middleRadius * Math.Cos(hue)
};
}
public PointD GetTrianglePosition(double sat, double val)
{
var sqrt3 = Math.Sqrt(3);
return new PointD
{
X = CenterX + InnerRadius * (2 * val - sat * val - 1) * sqrt3 / 2,
Y = CenterY + InnerRadius * (1 - 3 * sat * val) / 2
};
}
}
public class PointD
{
public double X { get; set; }
public double Y { get; set; }
}
Result:

Categories

Resources