How to draw a continuous curved line from 3 given points at a time - apache-flex

I am trying to draw a continuous curved line in flash. There are many methods but none of the ones I have found so far quite fit my requirements. First of all, I want to use the flash graphic api's curveTo() method. I DO NOT want to simulate a curve with hundreds of calls to lineTo() per curved line segment. It is my experience and understanding that line segments are processor heavy. Flash's quadratic bezier curve should take less CPU power. Please challenge this assumption if you think I am wrong.
I also do not want to use a pre-made method that takes the entire line as an argument (eg mx.charts.chartClasses.GraphicsUtilities.drawPolyline()).
The reason is that I will need to modify the logic eventually to add decorations to the line I am drawing, so I need something I understand at its lowest level.
I have currently created a method that will draw a curve given 3 points, using the mid-point method found here.
Here is a picture:
The problem is that the lines do not actually curve through the "real" points of the line (the gray circles). Is there a way using the power of math that I can adjust the control point so that the curve will actually pass through the "real" point? Given only the current point and its prev/next point as arguments? The code to duplicate the above picture follows. It would be great if I could modify it to meet this requirement (note the exception for first and last point).
package {
import flash.display.Shape;
import flash.display.Sprite;
import flash.display.Stage;
import flash.geom.Point;
[SWF(width="200",height="200")]
public class TestCurves extends Sprite {
public function TestCurves() {
stage.scaleMode = "noScale";
var points:Array = [
new Point(10, 10),
new Point(80, 80),
new Point(80, 160),
new Point(20, 160),
new Point(20, 200),
new Point(200, 100)
];
graphics.lineStyle(2, 0xFF0000);
var point:Point = points[0];
var nextPoint:Point = points[1];
SplineMethod.drawSpline(graphics, point, null, nextPoint);
var prevPoint:Point = point;
var n:int = points.length;
var i:int;
for (i = 2; i < n + 1; i++) {
point = nextPoint;
nextPoint = points[i]; //will eval to null when i == n
SplineMethod.drawSpline(graphics, point, prevPoint, nextPoint);
prevPoint = point;
}
//straight lines and vertices for comparison
graphics.lineStyle(2, 0xC0C0C0, 0.5);
graphics.drawCircle(points[0].x, points[0].y, 4);
for (i = 1; i < n; i++) {
graphics.moveTo(points[i - 1].x, points[i - 1].y);
graphics.lineTo(points[i].x, points[i].y);
graphics.drawCircle(points[i].x, points[i].y, 4);
}
}
}
}
import flash.display.Graphics;
import flash.geom.Point;
internal class SplineMethod {
public static function drawSpline(target:Graphics, p:Point, prev:Point=null, next:Point=null):void {
if (!prev && !next) {
return; //cannot draw a 1-dimensional line, ie a line requires at least two points
}
var mPrev:Point; //mid-point of the previous point and the target point
var mNext:Point; //mid-point of the next point and the target point
if (prev) {
mPrev = new Point((p.x + prev.x) / 2, (p.y + prev.y) / 2);
}
if (next) {
mNext = new Point((p.x + next.x) / 2, (p.y + next.y) / 2);
if (!prev) {
//This is the first line point, only draw to the next point's mid-point
target.moveTo(p.x, p.y);
target.lineTo(mNext.x, mNext.y);
return;
}
} else {
//This is the last line point, finish drawing from the previous mid-point
target.moveTo(mPrev.x, mPrev.y);
target.lineTo(p.x, p.y);
return;
}
//draw from mid-point to mid-point with the target point being the control point.
//Note, the line will unfortunately not pass through the actual vertex... I want to solve this
target.moveTo(mPrev.x, mPrev.y);
target.curveTo(p.x, p.y, mNext.x, mNext.y);
}
}
Later I will be adding arrows and things to the draw method.

I think you're looking for a Catmull-Rom spline. I've googled an AS3 implementation for you but haven't tried it so use at your own discretion:
http://actionsnippet.com/?p=1031

Ok, the Catmull-Rom spline suggestion is a good one but not exactly what I am looking for.
The example from the link provided was a good starting point, but a bit inflexible. I have taken it and modified my original source code to use it. I am posting this as an answer because I think it is more modular and easier to understand than Zevan's blog post (no offense Zevan!). The following code will display the following image:
Here is the code:
package {
import flash.display.Shape;
import flash.display.Sprite;
import flash.display.Stage;
import flash.geom.Point;
[SWF(width="300",height="300")]
public class TestCurves extends Sprite {
public function TestCurves() {
stage.scaleMode = "noScale";
//draw a helpful grid
graphics.lineStyle(1, 0xC0C0C0, 0.5);
for (var x:int = 0; x <= 300; x += 10) {
graphics.moveTo(x, 0);
graphics.lineTo(x, 300);
graphics.moveTo(0, x);
graphics.lineTo(300, x);
}
var points:Array = [
new Point(40, 20),
new Point(120, 80),
new Point(120, 160),
new Point(60, 160),
new Point(60, 200),
new Point(240, 150),
new Point(230, 220),
new Point(230, 280)
];
SplineMethod.setResolution(5);
graphics.lineStyle(2, 0xF00000);
graphics.moveTo(points[0].x, points[0].y);
var n:int = points.length;
var i:int;
for (i = 0; i < n - 1; i++) {
SplineMethod.drawSpline(
graphics,
points[i], //segment start
points[i + 1], //segment end
points[i - 1], //previous point (may be null)
points[i + 2] //next point (may be null)
);
}
//straight lines and vertices for comparison
graphics.lineStyle(2, 0x808080, 0.5);
graphics.drawCircle(points[0].x, points[0].y, 4);
for (i = 1; i < n; i++) {
graphics.moveTo(points[i - 1].x, points[i - 1].y);
graphics.lineTo(points[i].x, points[i].y);
graphics.drawCircle(points[i].x, points[i].y, 4);
}
}
}
}
import flash.display.Graphics;
import flash.geom.Point;
internal class SplineMethod {
//default setting will just draw a straight line
private static var hermiteValues:Array = [0, 0, 1, 0];
public static function setResolution(value:int):void {
var resolution:Number = 1 / value;
hermiteValues = [];
for (var t:Number = resolution; t <= 1; t += resolution) {
var h00:Number = (1 + 2 * t) * (1 - t) * (1 - t);
var h10:Number = t * (1 - t) * (1 - t);
var h01:Number = t * t * (3 - 2 * t);
var h11:Number = t * t * (t - 1);
hermiteValues.push(h00, h10, h01, h11);
}
}
public static function drawSpline(target:Graphics, segmentStart:Point, segmentEnd:Point, prevSegmentEnd:Point=null, nextSegmentStart:Point=null):void {
if (!prevSegmentEnd) {
prevSegmentEnd = segmentStart;
}
if (!nextSegmentStart) {
nextSegmentStart = segmentEnd;
}
var m1:Point = new Point((segmentEnd.x - prevSegmentEnd.x) / 2, (segmentEnd.y - prevSegmentEnd.y) / 2);
var m2:Point = new Point((nextSegmentStart.x - segmentStart.x) / 2, (nextSegmentStart.y - segmentStart.y) / 2);
var n:int = hermiteValues.length;
for (var i:int = 0; i < n; i += 4) {
var h00:Number = hermiteValues[i];
var h10:Number = hermiteValues[i + 1];
var h01:Number = hermiteValues[i + 2];
var h11:Number = hermiteValues[i + 3];
var px:Number = h00 * segmentStart.x + h10 * m1.x + h01 * segmentEnd.x + h11 * m2.x;
var py:Number = h00 * segmentStart.y + h10 * m1.y + h01 * segmentEnd.y + h11 * m2.y;
target.lineTo(px, py);
}
}
}
This is not a perfect solution. But unfortunately, I cannot piece together how to accomplish what I want using curveTo(). Note that GraphicsUtilities.drawPolyLine() does accomplish what I am attempting to do--the problem there is that it is inflexible and I cannot parse the code (more importantly, it doesn't appear to properly draw acute angles--correct me if I am wrong). If anyone can provide any insight, please post. For now, the above is my answer.

I code this, I think it may help:
SWF: http://dl.dropbox.com/u/2283327/stackoverflow/SplineTest.swf
Code: http://dl.dropbox.com/u/2283327/stackoverflow/SplineTest.as
I left a lot of comments on the code. I wish it helps!
Here is the theory behind the code:
A and C are the first and last point, B is the "control point" in AS3 you can draw the curve like this:
graphics.moveTo(A.x, A.y);
graphics.curveTo(B.x, B.y, C.x, C.y);
Now, D is the mid-point of the vector AC. And the mid-point of DB is the mid-point of the curve. Now what I did in the code was to move B exactly to D+DB*2 so, if you draw the curve using that point as control point, the mid-point of the curve will be B.
PS: Sorry for my poor Enlgish

Related

QCustomPlot vertical line at axis

I am working QCustomPlot with Qt and need to change the color of a particular vertical grid line within the graph please let us know how we can change that I attached the image of my requirement.
The bleo code solve the issue
GraphTesting(QCustomPlot * customPlot)
{
// generate some data:
QVector<double> x(101), y(101); // initialize with entries 0..100
for (int i = 0; i < 101; ++i)
{
x[i] = i; //i / 50.0 - 1; // x goes from -1 to 1
y[i] = x[i]/2; // let's plot a quadratic function
}
// create graph and assign data to it:
customPlot->addGraph();
customPlot->graph(0)->setData(x, y);
// give the axes some labels:
customPlot->xAxis->setLabel("x");
customPlot->yAxis->setLabel("y");
customPlot->rescaleAxes();
QCPItemLine *step = new QCPItemLine(customPlot);
step->setPen(QPen(QColor(140, 0, 0)));
double begin = 25;
double first = customPlot->yAxis->range().lower;
double end = customPlot->yAxis->range().upper; //example values
step->start->setCoords(begin, first);
step->end->setCoords(begin, end);
customPlot->replot();
}

Find where line-segments intersect with a box

I am trying to figure out where a bunch of line-segments clip into a window around them. I saw the Liang–Barsky algorithm, but that seems to assume the segments already clip the edges of the window, which these do not.
Say I have a window from (0,0) to (26,16), and the following segments:
(7,6) - (16,3)
(10,6) - (19,6)
(13,10) - (21,3)
(16,12) - (19,14)
Illustration:
I imagine I need to extend the segments to a certain X or Y point, till they hit the edge of the window, but I don't know how.
How would I find the points where these segments (converted to lines?) clip into the edge of the window? I will be implementing this in C#, but this is pretty language-agnostic.
If you have two line segments P and Q with points
P0 - P1
Q0 - Q1
The line equations are
P = P0 + t(P1 - P0)
Q = Q0 + r(Q1 - Q0)
then to find out where they intersect after extension you need to solve the following equation for t and r
P0 + t(P1 - P0) = Q0 + r(Q1 - Q0)
The following code can do this. ( Extracted from my own code base )
public static (double t, double r )? SolveIntersect(this Segment2D P, Segment2D Q)
{
// a-d are the entries of a 2x2 matrix
var a = P.P1.X - P.P0.X;
var b = -Q.P1.X + Q.P0.X;
var c = P.P1.Y - P.P0.Y;
var d = -Q.P1.Y + Q.P0.Y;
var det = a*d - b*c;
if (Math.Abs( det ) < Utility.ZERO_TOLERANCE)
return null;
var x = Q.P0.X - P.P0.X;
var y = Q.P0.Y - P.P0.Y;
var t = 1/det*(d*x - b*y);
var r = 1/det*(-c*x + a*y);
return (t, r);
}
If null is returned from the function then it means the lines are parallel and cannot intersect. If a result is returned then you can do.
var result = SolveIntersect( P, Q );
if (result != null)
{
var ( t, r) = result.Value;
var p = P.P0 + t * (P.P1 - P.P0);
var q = Q.P0 + t * (Q.P1 - Q.P0);
// p and q are the same point of course
}
The extended line segments will generally intersect more than one box edge but only one of those intersections will be inside the box. You can check this easily.
bool IsInBox(Point corner0, Point corner1, Point test) =>
(test.X > corner0.X && test.X < corner1.X && test.Y > corner0.Y && test.Y < corner1.Y ;
That should give you all you need to extend you lines to the edge of your box.
I managed to figure this out.
I can extend my lines to the edge of the box by first finding the equations of my lines, then solving for the X and Y of each of the sides to get their corresponding point. This requires passing the max and min Y and the max and min X into the following functions, returning 4 values. If the point is outside the bounds of the box, it can be ignored.
My code is in C#, and is making extension methods for EMGU's LineSegment2D. This is a .NET wrapper for OpenCv.
My Code:
public static float GetYIntersection(this LineSegment2D line, float x)
{
Point p1 = line.P1;
Point p2 = line.P2;
float dx = p2.X - p1.X;
if(dx == 0)
{
return float.NaN;
}
float m = (p2.Y - p1.Y) / dx; //Slope
float b = p1.Y - (m * p1.X); //Y-Intercept
return m * x + b;
}
public static float GetXIntersection(this LineSegment2D line, float y)
{
Point p1 = line.P1;
Point p2 = line.P2;
float dx = p2.X - p1.X;
if (dx == 0)
{
return float.NaN;
}
float m = (p2.Y - p1.Y) / dx; //Slope
float b = p1.Y - (m * p1.X); //Y-Intercept
return (y - b) / m;
}
I can then take these points, check if they are in the bounds of the box, discard the ones that are not, remove duplicate points (line goes directly into corner). This will leave me with one x and one y value, which I can then pair to the corresponding min or max Y or X values I passed into the functions to make 2 points. I can then make my new segment with the two points.
Wiki description of Liang-Barsky algorithm is not bad, but code is flaw.
Note: this algorithm intended to throw out lines without intersection as soon as possible. If most of lines intersect the rectangle, then approach from your answer might be rather effective, otherwise L-B algorithm wins.
This page describes approach in details and contains concise effective code:
// Liang-Barsky function by Daniel White # http://www.skytopia.com/project/articles/compsci/clipping.html
// This function inputs 8 numbers, and outputs 4 new numbers (plus a boolean value to say whether the clipped line is drawn at all).
//
bool LiangBarsky (double edgeLeft, double edgeRight, double edgeBottom, double edgeTop, // Define the x/y clipping values for the border.
double x0src, double y0src, double x1src, double y1src, // Define the start and end points of the line.
double &x0clip, double &y0clip, double &x1clip, double &y1clip) // The output values, so declare these outside.
{
double t0 = 0.0; double t1 = 1.0;
double xdelta = x1src-x0src;
double ydelta = y1src-y0src;
double p,q,r;
for(int edge=0; edge<4; edge++) { // Traverse through left, right, bottom, top edges.
if (edge==0) { p = -xdelta; q = -(edgeLeft-x0src); }
if (edge==1) { p = xdelta; q = (edgeRight-x0src); }
if (edge==2) { p = -ydelta; q = -(edgeBottom-y0src);}
if (edge==3) { p = ydelta; q = (edgeTop-y0src); }
if(p==0 && q<0) return false; // Don't draw line at all. (parallel line outside)
r = q/p;
if(p<0) {
if(r>t1) return false; // Don't draw line at all.
else if(r>t0) t0=r; // Line is clipped!
} else if(p>0) {
if(r<t0) return false; // Don't draw line at all.
else if(r<t1) t1=r; // Line is clipped!
}
}
x0clip = x0src + t0*xdelta;
y0clip = y0src + t0*ydelta;
x1clip = x0src + t1*xdelta;
y1clip = y0src + t1*ydelta;
return true; // (clipped) line is drawn
}

Conditional Line Graph using Open Flash Charts

I am using Open Flash Charts v2. I have been trying to make Conditional line graph. But I couldn't find any straight forward way, example or any class for producing Conditional charts.
Example of Conditional Graph
So I thought to use some techniques to emulate conditional graph ,I made separate Line object for values above limit range and then this line is used to overlap the plotted line.
This techniques works some what ok ,but there are problems with it,
How to color or place the conditional colored line exactly above the limit.
Remove tooltip and dot from limit line.
Tooltip of conditional line(red) and plotted line(green) are both shown ,I only need tooltip of green line.
Conditional Line Graph Problem illustrated
Source Code: // C#
var chart = new OpenFlashChart.OpenFlashChart();
var data1 = new List<double?> { 1, 3, 4, 5, 2, 1, 6, 7 };//>4=
var overlap = new List<double?> { null, null, 4, 5, null, null, null, null };
var overlap2 = new List<double?> { null, null, null, null, null, null, 6, 7 };
var limitData = new List<double?> { 4, 4, 4, 4, 4, 4, 4, 4 };
var line1 = new Line();
line1.Values = data1;
//line1.HaloSize = 0;
line1.Width = 2;
line1.DotSize = 5;
line1.DotStyleType.Tip = "#x_label#<br>#val#";
line1.Colour = "#37c855";
line1.Tooltip = "#val#";
var overLine = new Line();
overLine.Values = overlap;
//overLine.HaloSize = 0;
overLine.Width = 2;
overLine.DotSize = 5;
overLine.DotStyleType.Tip = "#x_label#<br>#val#";
overLine.Colour = "#d81417";
overLine.Tooltip = "#val#";
var overLine2 = new Line();
overLine2.Values = overlap2;
//overLine2.HaloSize = 0;
overLine2.Width = 2;
overLine2.DotSize = 5;
//overLine2.DotStyleType.Tip = "#x_label#<br>#val#";
//overLine2.DotStyleType.Type = DotType.DOT;
overLine2.Colour = "#d81417";
overLine2.Tooltip = "#val#";
var limit = new Line();
limit.Values = limitData;
limit.Width = 2;
limit.Colour = "#ff0000";
limit.HaloSize = -1;
limit.DotSize = -1;
// limit.DotStyleType.Tip = "";
limit.DotStyleType.Type = null;
//limit.Tooltip = "";
chart.AddElement(line1);
chart.AddElement(overLine);
chart.AddElement(overLine2);
chart.AddElement(limit);
chart.Y_Legend = new Legend("Experiment");
chart.Title = new Title("Conditional Line Graph");
chart.Y_Axis.SetRange(0, 10);
chart.X_Axis.Labels.Color = "#e43456";
chart.X_Axis.Steps = 4;
chart.Tooltip = new ToolTip("#val#");
chart.Tooltip.Shadow = true;
chart.Tooltip.Colour = "#e43456";
chart.Tooltip.MouseStyle = ToolTipStyle.CLOSEST;
Response.Clear();
Response.CacheControl = "no-cache";
Response.Write(chart.ToPrettyString());
Response.End();
Note:
I have already downloaded the OFC (Open Flash Charts) source ,If I modify the OFC Line.as source than how would I be able to generate json for the changed graph ? ,b/c I'm currently using .Net library for the json generation for OFC charts,please do let me know this also.
Update:
I have modified the source code on the advice of David Mears I'm using FlashDevelop for ActionScript.
P.S: I'm open for ideas if another library can do this job.
If you don't mind a little rebuilding, you can get the source of OFC here and modify the Line.solid_line() method in open-flash-chart/charts/Line.as to do this fairly easily.
In order to set the extra chart details through JSON using the .NET library, you'll also have to modify OpenFlashChart/LineBase.cs to add alternative colour and boundary properties. I'm not hugely familiar with .NET, but based on the existing properties you might add something like this:
private double boundary;
private string altcolour;
[JsonProperty("boundary")]
public virtual double Boundary
{
set { this.boundary = value; }
get { return this.boundary; }
}
[JsonProperty("alt-colour")]
public virtual string AltColour
{
set { this.altcolour = value; }
get { return this.altcolour; }
}
Then I believe the following should work in Line.as:
public function solid_line(): void {
var first:Boolean = true;
var i:Number;
var tmp:Sprite;
var x:Number;
var y:Number;
var last_e:Element;
var ratio:Number;
for ( i=0; i < this.numChildren; i++ ) {
// Step through every child object.
tmp = this.getChildAt(i) as Sprite;
// Only include data Elements, ignoring extra children such as line masks.
if( tmp is Element )
{
var e:Element = tmp as Element;
if( first )
{
if (this.props.get('alt-colour') != Number.NEGATIVE_INFINITY) {
if (e._y >= this.props.get_colour('boundary'))
{
// Line starts below boundary, set alt line colour.
this.graphics.lineStyle( this.props.get_colour('width'), this.props.get_colour('alt-colour') );
}
else
{
// Line starts above boundary, set normal line colour.
this.graphics.lineStyle( this.props.get_colour('width'), this.props.get_colour('colour') );
}
}
// Move to the first point.
this.graphics.moveTo(e.x, e.y);
x = e.x;
y = e.y;
first = false;
}
else
{
if (this.props.get('alt-colour') != Number.NEGATIVE_INFINITY) {
if (last_e._y < this.props.get_colour('boundary') && e._y >= this.props.get_colour('boundary'))
{
// Line passes below boundary. Draw first section and switch to alt colour.
ratio = (this.props.get_colour('boundary') - last_e._y) / (e._y - last_e._y);
this.graphics.lineTo(last_e.x + (e.x - last_e.x) * ratio, last_e.y + (e.y - last_e.y) * ratio);
this.graphics.lineStyle( this.props.get_colour('width'), this.props.get_colour('alt-colour') );
}
else if (last_e._y >= this.props.get_colour('boundary') && e._y < this.props.get_colour('boundary'))
{
// Line passes above boundary. Draw first section and switch to normal colour.
ratio = (this.props.get_colour('boundary') - last_e._y) / (e._y - last_e._y);
this.graphics.lineTo(last_e.x + (e.x - last_e.x) * ratio, last_e.y + (e.y - last_e.y) * ratio);
this.graphics.lineStyle( this.props.get_colour('width'), this.props.get_colour('colour') );
}
}
// Draw a line to the next point.
this.graphics.lineTo(e.x, e.y);
}
last_e = e;
}
}
if ( this.props.get('loop') ) {
// close the line loop (radar charts)
this.graphics.lineTo(x, y);
}
}
With the new open-flash-chart.swf, you should be able to just set your new properties on line1:
line1.Boundary = 4;
line1.AltColour = "#d81417";

Kinect skeleton Scaling strange behaviour

I am trying to scale a skeleton to match to the sizes of another skeleton.
My algoritm do the following:
Find the distance between two joints of the origin skeleton and the destiny skeleton using phytagorean teorem
divide this two distances to find a multiply factor.
Multiply each joint by this factor.
Here is my actual code:
public static Skeleton ScaleToMatch(this Skeleton skToBeScaled, Skeleton skDestiny)
{
Joint newJoint = new Joint();
double distanciaOrigem = 0;
double distanciaDestino = 0;
double fator = 1;
SkeletonPoint pos = new SkeletonPoint();
foreach (BoneOrientation bo in skToBeScaled.BoneOrientations)
{
distanciaOrigem = FisioKinectCalcs.Distance3DBetweenJoint(skToBeScaled.Joints[bo.StartJoint], skToBeScaled.Joints[bo.EndJoint]);
distanciaDestino = FisioKinectCalcs.Distance3DBetweenJoint(skDestiny.Joints[bo.StartJoint], skDestiny.Joints[bo.EndJoint]);
if (distanciaOrigem > 0 && distanciaDestino > 0)
{
fator = (distanciaDestino / distanciaOrigem);
newJoint = skToBeScaled.Joints[bo.EndJoint]; // escaling only the end joint as the BoneOrientatios starts from HipCenter, i am scaling from center to edges.
// applying the new values to the joint
pos = new SkeletonPoint()
{
X = (float)(newJoint.Position.X * fator),
Y = (float)(newJoint.Position.Y * fator),
Z = (float)(newJoint.Position.Z * fator)
};
newJoint.Position = pos;
skToBeScaled.Joints[bo.EndJoint] = newJoint;
}
}
return skToBeScaled;
}
Every seems to work fine except for the hands and foots
Look at this images
I have my own skeleton over me, and my skeleton scaled to the sizes of another person, but the hands and foots still crazy. (but code looks right)
Any suggestion?
It's hard to say without running the code, but it somewhat "looks good".
What I would validate though, is your
if (distanciaOrigem > 0 && distanciaDestino > 0)
If distanciaOrigem is very close to 0, but even just epsilon away from 0, it won't be picked up by the if, and then
fator = (distanciaDestino / distanciaOrigem);
Will result in a very large number!
I would suggest to smooth the factor so it generally fits the proper scale. Try this code:
private static Dictionary<JointType, double> jointFactors = null;
static CalibrationUtils()
{
InitJointFactors();
}
public static class EnumUtil
{
public static IEnumerable<T> GetValues<T>()
{
return Enum.GetValues(typeof(T)).Cast<T>();
}
}
private static void InitJointFactors()
{
var jointTypes = EnumUtil.GetValues<JointType>();
jointFactors = new Dictionary<JointType, double>();
foreach(JointType type in jointTypes)
{
jointFactors.Add(type, 0);
}
}
private static double SmoothenFactor(JointType jointType, double factor, int weight)
{
double currentValue = jointFactors[jointType];
double newValue = 0;
if(currentValue != 0)
newValue = (weight * currentValue + factor) / (weight + 1);
else
newValue = factor;
jointFactors[jointType] = newValue;
return newValue;
}
When it comes to factor usage just use the SmoothenFactor method first:
public static Skeleton ScaleToMatch(this Skeleton skToBeScaled, Skeleton skDestiny, double additionalFactor = 1)
{
Joint newJoint = new Joint();
double distanceToScale = 0;
double distanceDestiny = 0;
double factor = 1;
int weight = 500;
SkeletonPoint pos = new SkeletonPoint();
Skeleton newSkeleton = null;
KinectHelper.CopySkeleton(skToBeScaled, ref newSkeleton);
SkeletonPoint hipCenterPosition = newSkeleton.Joints[JointType.HipCenter].Position;
foreach(BoneOrientation bo in skToBeScaled.BoneOrientations)
{
distanceToScale = Distance3DBetweenJoints(skToBeScaled.Joints[bo.StartJoint], skToBeScaled.Joints[bo.EndJoint]);
distanceDestiny = Distance3DBetweenJoints(skDestiny.Joints[bo.StartJoint], skDestiny.Joints[bo.EndJoint]);
if(distanceToScale > 0 && distanceDestiny > 0)
{
factor = (distanceDestiny / distanceToScale) * additionalFactor;
newJoint = skToBeScaled.Joints[bo.EndJoint]; // escaling only the end joint as the BoneOrientatios starts from HipCenter, i am scaling from center to edges.
factor = SmoothenFactor(newJoint.JointType, factor, weight);
pos = new SkeletonPoint()
{
X = (float)((newJoint.Position.X - hipCenterPosition.X) * factor + hipCenterPosition.X),
Y = (float)((newJoint.Position.Y - hipCenterPosition.Y) * factor + hipCenterPosition.Y),
Z = (float)((newJoint.Position.Z - hipCenterPosition.Z) * factor + hipCenterPosition.Z)
};
newJoint.Position = pos;
newSkeleton.Joints[bo.EndJoint] = newJoint;
}
}
return newSkeleton;
}
I also modified your ScaleToMatch method as you see. There was a need to move joints in relation to HipCenter position. Also new positions are saved to a new Skeleton instance so they are not used in further vector calculations.
Experiment with the weight but since our bones length is constant you can use big numbers like 100 and more to be sure that wrong Kinect readings do not disturb the correct scale.
Here's an example of how it helped with scaling HandRight joint position:
The weight was set to 500. The resulting factor is supposed to be around 2 (because the base skeleton was purposely downscaled by a factor of 2).
I hope it helps!

Rotate point from a given center in Flex

I'm trying to rotate a point in my Canvas from a given point (center). In my MouseDown handler, I save the point where user click (oldPos), and in my MouseMove handler, I'm doing this:
private function onMouseMove(event:MouseEvent):void
{
// Where the user pointer right now
var endPoint:Point = new Point(event.localX,event.localY);
// Calculate angle in radians from the user pointer
var angle:Number = getLineAngleFromHorizontal(oldPos,endPoint);
var rad:Number = Math.PI * (angle / 180);
// Point which I want to rotate
pTop = new Point(oldPos.x,oldPos.y - 30);
var distance:Number = Point.distance(oldPos,pTop);
// Calculate the translation point from previously distance and angle
var translatePoint:Point = Point.polar(distance, rad);
// New point coordinates (in theory)
pTop.x += translatePoint.x;
pTop.y += translatePoint.y;
// Then, draw the line...
}
Where getLineAngleFromHorizontal is a function that returns the angle formed by a center and a give point:
private function getLineAngleFromHorizontal(p1:Point,p2:Point):Number
{
var RotVecOrigen:Point = new Point((p2.x-p1.x),(p2.y-p1.y));
var ModRot:Number = Math.sqrt((RotVecOrigen.x*RotVecOrigen.x)+(RotVecOrigen.y*RotVecOrigen.y));
var ret:Number;
if(((RotVecOrigen.x < 0) && (RotVecOrigen.y <= 0))||((RotVecOrigen.x >= 0) && (RotVecOrigen.y < 0)))
{
ret = Math.round((180.0*(Math.acos(RotVecOrigen.x/ModRot))/Math.PI));
}else{
ret = Math.round((180.0*(-Math.acos(RotVecOrigen.x/ModRot))/Math.PI));
}
return ret;
}
To see an example, watch the image below:
But I don't know why isn't work. I mean, pTop point isn't move where I want, and I think that my calcs are correct.
Can anybody help me? (maybe someone with Math knowledge)
I'm not entirely sure what you want to accomplish. Do you want your new point to be at an 330 degree offset from your center point?
If you want to move your point 330 degrees, use this:
function directionalDistance($start:Point, $direction:Number, $distance:Number, $zeroDegreesUp:Boolean = false):Point{
if($zeroDegreesUp) $direction = ( $direction + 270)%360;
var x:Number = Math.cos($direction * Math.PI / 180) * $distance;
var y:Number = Math.sin($direction * Math.PI / 180) * $distance;
return new Point($start.x +x, $start.y + y);
}
//
var newPoint:Point = directionalDistance(new Point(event.localX,event.localY), 330, 50, true);

Resources