How to draw line until middle point using quadraticBezierTo in flutter? - flutter

I'm trying to draw a line between three points using quadraticsBezierTo but here is my problem.
Current result:
Current result
Expected result:
Expected result
Code:
final path = Path();
path.moveTo(p1.x, p1.y);
path.quadraticBezierTo(p2.x, p2.y, p3.x, p3.y);
//Also tried: path.cubicTo(p2.x, p2.y, p2.x, p2.y, p3.x, p3.y);
Do you know how to achieved this result?

Maybe,
path.quadraticBezierTo(
2.0 * p2.x - 0.5 * (p1.x + p3.x), 2.0 * p2.y - 0.5 * (p1.y + p3.y),
p3.x, p3.y);
or
path.cubicTo(
(4.0 * p2.x - p3.x) / 3.0, (4.0 * p2.y - p3.y) / 3.0,
(4.0 * p2.x - p1.x) / 3.0, (4.0 * p2.y - p1.y) / 3.0,
p3.x, p3.y);
Appendix
If you prefer sharper/blunter curves, throw away quadratics Bezier curve and take cubic Bezier curve. Then shift the control points evenly inwards/outwards.
double epsilon = -0.1;
path.cubicTo(
(4.0 * p2.x - p3.x - epsilon * (p3.x - p1.x)) / 3.0, (4.0 * p2.y - p3.y - epsilon * (p3.y - p1.y)) / 3.0,
(4.0 * p2.x - p1.x + epsilon * (p3.x - p1.x)) / 3.0, (4.0 * p2.y - p1.y + epsilon * (p3.y - p1.y)) / 3.0,
p3.x, p3.y);
This breaks tangents at end points of the curve, though.

Bezier curves aren't designed to pass through their control points, but if that's what you want you can do it by modifying the center point. From Wikipedia
For quadratic Bézier curves one can construct intermediate points Q0 and Q1 such that as t varies from 0 to 1:
Point Q0(t) varies from P0 to P1 and describes a linear Bézier curve.
Point Q1(t) varies from P1 to P2 and describes a linear Bézier curve.
Point B(t) is interpolated linearly between Q0(t) to Q1(t) and describes a quadratic Bézier curve.
Thus,
q0 = p0 * (1 - t) + p1 * t and q1 = p1 * (1 - t) + p2 * t and the actual curve is
b = q0 * (1 - t) + q1 * t
= p0 * (1 - t)^2 + p1 * t * (t - 1) + p1 * t * (t - 1) + p2 * t^2
= p0 * (1 - t)^2 + 2 * p1 * t * (t - 1) + p2 * t^2
Note that by ^ I mean exponent, not xor.
So if you want your curve to pass through some point c at time t = 1/2, then we can find what p1 should be.
c = p0 * 0.25 + p1 * 0.5 + p2 * 0.25
So,
p1 = 2 * c - 0.5 * (p0 + p2)

Related

Math behind some quaternion code and gimbal lock

I have the following matlab code that gives a Rotation matrix from Quaternion. The person who did this said he used some library and it is originally from this Rotation Matrix
The Rotation matrix according to the code looks like
The diagonal elements and the signs are changed. Can someonw explain to me the math or the conditions for the disparity between the two.
Q0 = Quat(1);
Q1 = Quat(2);
Q2 = Quat(3);
Q3 = Quat(4);
%% set f2q to 2*q0 and calculate products
f2q = 2 * Q0;
f2q0q0 = f2q * Q0;
f2q0q1 = f2q * Q1;
f2q0q2 = f2q * Q2;
f2q0q3 = f2q * Q3;
%% set f2q to 2*q1 and calculate products
f2q = 2 * Q1;
f2q1q1 = f2q * Q1;
f2q1q2 = f2q * Q2;
f2q1q3 = f2q * Q3;
%% set f2q to 2*q2 and calculate products
f2q = 2 * Q2;
f2q2q2 = f2q * Q2;
f2q2q3 = f2q * Q3;
f2q3q3 = 2 * Q3 * Q3;
%% calculate the rotation matrix assuming the quaternion is normalized
R(1, 1) = f2q0q0 + f2q1q1 - 1;
R(1, 2) = f2q1q2 + f2q0q3;
R(1, 3) = f2q1q3 - f2q0q2;
R(2, 1) = f2q1q2 - f2q0q3;
R(2, 2) = f2q0q0 + f2q2q2 - 1;
R(2, 3) = f2q2q3 + f2q0q1;
R(3, 1) = f2q1q3 + f2q0q2;
R(3, 2) = f2q2q3 - f2q0q1;
R(3, 3) = f2q0q0 + f2q3q3 - 1;
Also...
The Rotation Matrix is used to find Euler Angles that also deals with Gimbal lock
%%calculate the pitch angle -90.0 <= Theta <= 90.0 deg
pitchdeg = asin(-R(1, 3)) * (180 / pi);
%% calculate the roll angle range -180.0 <= Phi < 180.0 deg
rolldeg = atan2(R(2, 3), R(3, 3)) * (180 / pi);
%% map +180 roll onto the functionally equivalent -180 deg roll
if (rolldeg == 180)
rolldeg = -180;
end
%% calculate the yaw (compass) angle 0.0 <= Psi < 360.0 deg
if (pitchdeg == 90)
%% vertical upwards gimbal lock case
yawdeg = (atan2(R(3, 2), R(2, 2)) * (180 / pi)) + rolldeg;
elseif (pitchdeg == -90)
%% vertical downwards gimbal lock case
yawdeg = (Math.Atan2(-R(3, 2), R(2, 2)) * (180 / pi)) - rolldeg;
else
%% general case
yawdeg = atan2(R(1, 2), R(1, 1)) * (180 / pi);
end
%% map yaw angle Psi onto range 0.0 <= Psi < 360.0 deg
if (yawdeg < 0)
yawdeg = yawdeg + 360;
end
%% check for rounding errors mapping small negative angle to 360 deg
if (yawdeg >= 360)
yawdeg = 0;
end
Euler.Roll = rolldeg;
Euler.Pitch = pitchdeg;
Euler.Yaw = yawdeg;
Googling the formula to convert from Quaternion to Euler angles gave me a formula which i could not attach because i dont have enough reputation but you can find it in wiki Conversion_between_quaternions_and_Euler_angles
The terms are different comparing with the diagonal of Rotation matrix. Also, is there a math behind the compensation for gimbal lock?
The IMU uses North-East-Down system
I am using euler angles to visualize the gyro. Any kind of guidance is appreciable

Scaling a rotated ellipse

I have a function that draws an ellipse respecting some major axis (vx) and minor axis (vy) scales rotated clockwise by an angle a. I would like to adjust it so that the unrotated ellipse satisfies the equation:
(x / vx)^2 + (y / vy)^2 = s
For some value s which is passed in.
function [] = plotellipse(cx, cy, vx, vy, s, a)
t = linspace(0, 2 * pi);
x = cx + vx * cos(t) * cos(-a) - vy * sin(t) * sin(-a);
y = cy + vy * sin(t) * cos(-a) + vx * cos(t) * sin(-a);
plot(x,y,'y-');
The usual equation for an ellipse, which you have implemented correctly, is
To reduce the desired equation to the same form, divide through by s:
Now x and y become
vxs = vx / sqrt(s)
vys = vy / sqrt(s)
x = cx + vxs * cos(t) * cos(-a) - vys * sin(t) * sin(-a);
y = cy + vys * sin(t) * cos(-a) + vxs * cos(t) * sin(-a);

OpenGL ES: Translate a matrix to a particular point

Hi guys I am working on a app which requires the use of opengl es. However I have some questions. My task at hand is to rotate a matrix about an arbitrary point say (0,0,0). I did some research on google and the most common approach is
translate the matrix to (0,0,0)
Rotate the matrix
Translate the matrix back to its original position
Effectively
glTranslatef(centerX, centerY, centerZ);
glRotatef(angle, 0, 0, 1);
glTranslatef(-centerX, -centerY, -centerZ);
However my problem is I am using opengl es 2.0. The function translatef does not exist in opengl es 2.0. I have a function called as translateBy but I am unable to figure out how to use translateBy function to translate my matrix to a certain point
Thanks any help would be appreciated.
In OpenGL ES 2.0 you have to use vertex shader and just update the modelview matrix in every frame using
GLint modelviewmatrix = glGetUniformLocation(m_simpleProgram, "ModelviewMatrix");
matrx4 modelviewMatrix = rotation * translation;
glUniformMatrix4fv(modelviewmatrix, 1, 0, modelviewMatrix.Pointer());
assuming matrx4 as a matrix class of 4x4. and rotation and translation are the 4x4 matrix objects for rotation and translation.
Just make your own translate and rotate functions,
Translatef(x,y,z) is equivalent to
Matrx4 Translate( x, y, z)
{
Matrx4 m;
m = { 1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
x, y, z, 1 }
return m;
}
and Rotatef(degree, vector3 axis) is equivalent to
Matrx4 Rotate( float degree, vector3 axis)
{
float radians = degrees * 3.14159f / 180.0f;
float s = std::sin(radians);
float c = std::cos(radians);
Matrx4 m = Identity(); /// load identity matrix
m[0] = c + (1 - c) * axis.x * axis.x;
m[1] = (1 - c) * axis.x * axis.y - axis.z * s;
m[2] = (1 - c) * axis.x * axis.z + axis.y * s;
m[4] = (1 - c) * axis.x * axis.y + axis.z * s;
m[5] = c + (1 - c) * axis.y * axis.y;
m[6] = (1 - c) * axis.y * axis.z - axis.x * s;
m[8] = (1 - c) * axis.x * axis.z - axis.y * s;
m[9] = (1 - c) * axis.y * axis.z + axis.x * s;
m[10] = c + (1 - c) * axis.z * axis.z;
return m;
}

What is kAccelerometerMinStep?

I have been looking at the Accelerometer Graph example in the iOS Developer library and I have a question about one of the variables that is used...
#define kAccelerometerMinStep 0.02
What is the Accelerometer Min Step? and what role does it have?
Here is how it is being used in the Low Pass Filter...
-(void)addAcceleration:(UIAcceleration*)accel
{
double alpha = filterConstant;
if(adaptive)
{
double d = Clamp(fabs(Norm(x, y, z) - Norm(accel.x, accel.y, accel.z)) / kAccelerometerMinStep - 1.0, 0.0, 1.0);
alpha = (1.0 - d) * filterConstant / kAccelerometerNoiseAttenuation + d * filterConstant;
}
x = accel.x * alpha + x * (1.0 - alpha);
y = accel.y * alpha + y * (1.0 - alpha);
z = accel.z * alpha + z * (1.0 - alpha);
}
And here is how it is being used in the High Pass Filter...
-(void)addAcceleration:(UIAcceleration*)accel
{
double alpha = filterConstant;
if(adaptive)
{
double d = Clamp(fabs(Norm(x, y, z) - Norm(accel.x, accel.y, accel.z)) / kAccelerometerMinStep - 1.0, 0.0, 1.0);
alpha = d * filterConstant / kAccelerometerNoiseAttenuation + (1.0 - d) * filterConstant;
}
x = alpha * (x + accel.x - lastX);
y = alpha * (y + accel.y - lastY);
z = alpha * (z + accel.z - lastZ);
lastX = accel.x;
lastY = accel.y;
lastZ = accel.z;
}
If someone could tell me what the min step is responsible for I would be very grateful...
I would like to capture accelerations ranging in magnitude from 0.05 to 2.00 g force with a frequency response of 0.25-2.50 Hz
Thanks.!

Drawing triangle/arrow on a line with CGContext

I am using the framework of route-me for working with locations.
In this code the path between two markers(points) will be drawn as a line.
My Question: "What code should I add if I want to add an arrow in the middle(or top) of the line, so that it points the direction"
Thanks
- (void)drawInContext:(CGContextRef)theContext
{
renderedScale = [contents metersPerPixel];
float scale = 1.0f / [contents metersPerPixel];
float scaledLineWidth = lineWidth;
if(!scaleLineWidth) {
scaledLineWidth *= renderedScale;
}
//NSLog(#"line width = %f, content scale = %f", scaledLineWidth, renderedScale);
CGContextScaleCTM(theContext, scale, scale);
CGContextBeginPath(theContext);
CGContextAddPath(theContext, path);
CGContextSetLineWidth(theContext, scaledLineWidth);
CGContextSetStrokeColorWithColor(theContext, [lineColor CGColor]);
CGContextSetFillColorWithColor(theContext, [fillColor CGColor]);
// according to Apple's documentation, DrawPath closes the path if it's a filled style, so a call to ClosePath isn't necessary
CGContextDrawPath(theContext, drawingMode);
}
- (void) drawLine: (CGContextRef) context from: (CGPoint) from to: (CGPoint) to
{
double slopy, cosy, siny;
// Arrow size
double length = 10.0;
double width = 5.0;
slopy = atan2((from.y - to.y), (from.x - to.x));
cosy = cos(slopy);
siny = sin(slopy);
//draw a line between the 2 endpoint
CGContextMoveToPoint(context, from.x - length * cosy, from.y - length * siny );
CGContextAddLineToPoint(context, to.x + length * cosy, to.y + length * siny);
//paints a line along the current path
CGContextStrokePath(context);
//here is the tough part - actually drawing the arrows
//a total of 6 lines drawn to make the arrow shape
CGContextMoveToPoint(context, from.x, from.y);
CGContextAddLineToPoint(context,
from.x + ( - length * cosy - ( width / 2.0 * siny )),
from.y + ( - length * siny + ( width / 2.0 * cosy )));
CGContextAddLineToPoint(context,
from.x + (- length * cosy + ( width / 2.0 * siny )),
from.y - (width / 2.0 * cosy + length * siny ) );
CGContextClosePath(context);
CGContextStrokePath(context);
/*/-------------similarly the the other end-------------/*/
CGContextMoveToPoint(context, to.x, to.y);
CGContextAddLineToPoint(context,
to.x + (length * cosy - ( width / 2.0 * siny )),
to.y + (length * siny + ( width / 2.0 * cosy )) );
CGContextAddLineToPoint(context,
to.x + (length * cosy + width / 2.0 * siny),
to.y - (width / 2.0 * cosy - length * siny) );
CGContextClosePath(context);
CGContextStrokePath(context);
}
The drawing of the actual triangle/arrow is easy once you have two points on your path.
CGContextMoveToPoint( context , ax , ay );
CGContextAddLineToPoint( context , bx , by );
CGContextAddLineToPoint( context , cx , cy );
CGContextClosePath( context ); // for triangle
Getting the points is a little more tricky. You said path was a line, as opposed to a curve or series of curves. That makes it easier.
Use CGPathApply to pick two points on the path. Probably, this is the last two points, one of which may be kCGPathElementMoveToPoint and the other will be kCGPathElementAddLineToPoint. Let mx,my be the first point and nx,ny be the second, so the arrow will point from m towards n.
Assuming you want the arrow at the tip of the line, bx,by from above will equal nx,ny on the line. Choose a point dx,dy between mx,my and nx,ny to calculate the other points.
Now calculate ax,ay and cx,cy such that they are on a line with dx,dy and equidistant from path. The following should be close, although I probably got some signs wrong:
r = atan2( ny - my , nx - mx );
bx = nx;
by = ny;
dx = bx + sin( r ) * length;
dy = by + cos( r ) * length;
r += M_PI_2; // perpendicular to path
ax = dx + sin( r ) * width;
ay = dy + cos( r ) * width;
cx = dx - sin( r ) * width;
cy = dy - cos( r ) * width;
Length is the distance from the tip of the arrow to the base, and width is distance from the shaft to the barbs, or half the breadth of the arrow head.
If path is a curve, then instead of finding mx,my as the previous point or move, it will be the final control point of the final curve. Each control point is on a line tangent to the curve and passing through the adjacent point.
I found this question as I had the same. I took drawnonward's example and it was so close... But with a flipping of cos and sin, I was able to get it to work:
r = atan2( ny - my , nx - mx );
r += M_PI;
bx = nx;
by = ny;
dx = bx + cos( r ) * length;
dy = by + sin( r ) * length;
r += M_PI_2; // perpendicular to path
ax = dx + cos( r ) * width;
ay = dy + sin( r ) * width;
cx = dx - cos( r ) * width;
cy = dy - sin( r ) * width;
Once I did that, my arrows were pointed exactly the wrong way. So I added that second line (r += M_PI;)
Thanks go to drawnonward!
And here is Swift 4+ version for Friedhelm Brügge answer: (I'll draw it on image)
func drawArrow(image: UIImage, ptSrc: CGPoint, ptDest: CGPoint) {
// create context with image size
UIGraphicsBeginImageContext(image.size)
let context = UIGraphicsGetCurrentContext()
// draw current image to the context
image.draw(in: CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height))
var slopY: CGFloat, cosY: CGFloat, sinY: CGFloat;
// Arrow size
let length: CGFloat = 35.0;
let width: CGFloat = 35.0;
slopY = atan2((ptSrc.y - ptDest.y), (ptSrc.x - ptDest.x));
cosY = cos(slopY);
sinY = sin(slopY);
//here is the tough part - actually drawing the arrows
//a total of 6 lines drawn to make the arrow shape
context?.setFillColor(UIColor.white.cgColor)
context?.move(to: CGPoint(x: ptSrc.x, y: ptSrc.y))
context?.addLine(to: CGPoint(x: ptSrc.x + ( -length * cosY - ( width / 2.0 * sinY )), y: ptSrc.y + ( -length * sinY + ( width / 2.0 * cosY ))))
context?.addLine(to: CGPoint(x: ptSrc.x + (-length * cosY + ( width / 2.0 * sinY )), y: ptSrc.y - (width / 2.0 * cosY + length * sinY )))
context?.closePath()
context?.fillPath()
context?.move(to: CGPoint(x: ptSrc.x, y: ptSrc.y))
context?.addLine(to: CGPoint(x: ptDest.x + (length * cosY - ( width / 2.0 * sinY )), y: ptDest.y + (length * sinY + ( width / 2.0 * cosY ))))
context?.addLine(to: CGPoint(x: ptDest.x + (length * cosY + width / 2.0 * sinY), y: ptDest.y - (width / 2.0 * cosY - length * sinY)))
context?.closePath()
context?.fillPath()
// draw current context to image view
imgView.image = UIGraphicsGetImageFromCurrentImageContext()
//close context
UIGraphicsEndImageContext()
}