Okay, I am pretty new to Kinect, I have the joints tracked and drawn however I cannot for the life of me draw the bones between each joint.
I have this code which will draw the joints of the skeleton
private void DrawBody(Body body) //takes body as argument
{
// Draw points
foreach (JointType type in body.Joints.Keys)
{
// Draw all the body joints
switch (type)
{
case JointType.Head:
case JointType.FootLeft:
case JointType.FootRight:
DrawJoint(body.Joints[type], 20, Brushes.Yellow, 2, Brushes.White);
break;
case JointType.ShoulderLeft:
case JointType.ShoulderRight:
case JointType.HipLeft:
case JointType.HipRight:
DrawJoint(body.Joints[type], 20, Brushes.YellowGreen, 2, Brushes.White);
break;
case JointType.ElbowLeft:
case JointType.ElbowRight:
case JointType.KneeLeft:
case JointType.KneeRight:
DrawJoint(body.Joints[type], 15, Brushes.LawnGreen, 2, Brushes.White);
break;
case JointType.HandLeft:
DrawHandJoint(body.Joints[type], body.HandLeftState, 20, 2, Brushes.White);
break;
case JointType.HandRight:
DrawHandJoint(body.Joints[type], body.HandRightState, 20, 2, Brushes.White);
break;
default:
DrawJoint(body.Joints[type], 15, Brushes.RoyalBlue, 2, Brushes.White);
break;
}
}
}
My DrawJoint Function:
private void DrawJoint(Joint joint, double radius, SolidColorBrush fill, double borderWidth, SolidColorBrush border)
{
//If Joint not tracked then return Joint
if (joint.TrackingState != TrackingState.Tracked) return;
// Map the CameraPoint to ColorSpace so they match
ColorSpacePoint colorPoint = kinectSensor.CoordinateMapper.MapCameraPointToColorSpace(joint.Position);
// Create the UI element based on the parameters
Ellipse El = new Ellipse();
El.Fill = fill;
El.Stroke = border;
El.StrokeThickness = borderWidth;
El.Width = 25;
El.Height = 25;
radius = 25;
// Add the Ellipse to the canvas
SkeletonCanvas.Children.Add(El);
// Avoid exceptions based on bad tracking
if (float.IsInfinity(colorPoint.X) || float.IsInfinity(colorPoint.X)) return;
// Allign ellipse on canvas
Canvas.SetLeft(El, colorPoint.X);
Canvas.SetTop(El, colorPoint.Y);
}
Now I am stuck, from this point onwards how would I draw the 'Bones' of the body between each joint on a canvas similiar to how I added the Eclipse for the Joints?.
Any help is appreciated thanks
In your DrawBody(Body body) function, you'll need to set up the "bones" that you want to draw. Eg:
private void DrawBody(Body body)
{
// left forearm
DrawBone(body.Joints[JointType.HandLeft], body.Joints[JointType.ElbowLeft]);
// right forearm
DrawBone(body.Joints[JointType.HandRight], body.Joints[JointType.ElbowRight]);
// ...etc...
}
The DrawBone(Joint, Joint) function would look something like this:
private void DrawBone(Joint first, Joint second)
{
Line line = new Line();
line.Stroke = Brushes.LightSteelBlue;
line.X1 = first.Position.X;
line.X2 = second.Position.X;
line.Y1 = first.Position.Y;
line.Y2 = second.Position.Y;
line.StrokeThickness = 2;
myCanvas.Children.Add(line);
}
I'm working from memory here so syntax might be off a little.
Related
I'm trying to pull text from a PDF using iText7. I'm using the IEventListener to get all the parts of the page, though some of the text is rotated. I can find examples for how to insert rotated text into a PDF, but can't find anything about how I can tell if a given text segment is rotated.
Can anyone help ?
public void EventOccurred(IEventData data, EventType type)
{
PdfPart part = null;
switch (type)
{
case EventType.BEGIN_TEXT:
break;
case EventType.RENDER_TEXT:
part = new PdfTextPart(PageNumber, data as TextRenderInfo);
Parts.Add(part);
break;
case EventType.END_TEXT:
break;
case EventType.RENDER_IMAGE:
var imageData = data as ImageRenderInfo;
//this.HandleImage(imageData);
break;
case EventType.RENDER_PATH:
part = new PdfLinePart(PageNumber, data as PathRenderInfo);
Parts.Add(part);
break;
case EventType.CLIP_PATH_CHANGED:
break;
default:
break;
}
}
public PdfTextPart(Int32 pageNumber, TextRenderInfo info) : base(pageNumber)
{
Text = info.GetText();
var font = info.GetFont().GetFontProgram().GetFontNames();
Font = font.GetFontName();
if (font.IsItalic()) { this.IsItalic = true; }
if (font.IsBold()) { this.IsBold = true; }
if (font.IsUnderline()) { this.IsUnderline = true; }
}
TextRenderInfo has a base line. This base line is a LineSegment and as such has a start point and an end point. Now you merely have to determine the angle of the line between those two points.
I.e. for a TextRenderInfo info:
LineSegment baseline = info.GetBaseline();
Vector startPoint = baseline.GetStartPoint();
Vector endPoint = baseline.GetEndPoint();
Vector direction = endLocation.Subtract(startLocation);
double angle = Math.Atan2(direction.Get(Vector.I2), direction.Get(Vector.I1));
The result obviously is in radian measure.
You may additionally have to take into account the page rotation which (if I recall correctly) is not calculated into the coordinates above.
I am creating custom controls that use the standard font color when disabled in a windows form application but am stumped at getting the DateTimePicker to work.
I've found a number of answers but they're 10+ years old and no longer seem to work. This is a simple answer from 2007, however when I replicate that it works to set the Font on enabled/disabled but the outlying combobox graphic is no longer painted.
Doing some more digging I've found some more complete code to draw the combobox graphics, which combined with the first simple answer I've created the following class:
public partial class CustomDatetimePicker : DateTimePicker
{
public CustomDatetimePicker()
{
InitializeComponent();
this.SetStyle(ControlStyles.UserPaint, true);
}
protected override void OnPaint(PaintEventArgs pe)
{
//Graphics g = this.CreateGraphics();
Graphics g = pe.Graphics;
//The dropDownRectangle defines position and size of dropdownbutton block,
//the width is fixed to 17 and height to 16. The dropdownbutton is aligned to right
Rectangle dropDownRectangle = new Rectangle(ClientRectangle.Width - 17, 0, 17, 16);
Brush bkgBrush;
Brush txtBrush;
ComboBoxState visualState;
//When the control is enabled the brush is set to Backcolor,
//otherwise to color stored in _backDisabledColor
if (this.Enabled)
{
bkgBrush = new SolidBrush(SystemColors.Window);
txtBrush = new SolidBrush(SystemColors.WindowText);
visualState = ComboBoxState.Normal;
}
else
{
bkgBrush = new SolidBrush(SystemColors.InactiveBorder);
txtBrush = new SolidBrush(SystemColors.WindowText);
visualState = ComboBoxState.Disabled;
}
// Painting...in action
//Filling the background
g.FillRectangle(bkgBrush, 0, 0, ClientRectangle.Width, ClientRectangle.Height);
//Drawing the datetime text
g.DrawString(this.Text, this.Font, txtBrush, 0, 2);
//Drawing the dropdownbutton using ComboBoxRenderer
if (ComboBoxRenderer.IsSupported)
{
ComboBoxRenderer.DrawDropDownButton(g, dropDownRectangle, visualState);
}
g.Dispose();
bkgBrush.Dispose();
}
}
But in my case the ComboBoxRenderer is not supported so it won't paint, and I don't see another easy way to draw it without building a control from scratch.
So am I going about this the right way? Is there a simple answer like in the first link provided, or with the code provided is there an alternative to using ComboBoxRenderer?
I have done something similar, but I didn't think it was necessary to paint the drop-down button when the control was disabled, as it can't be clicked anyway. When the control is disabled set the style to UserPaint, otherwise let the control paint itself.
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
var graphics = e.Graphics;
var clientRectangle = ClientRectangle;
var font = Font;
var text = Text;
var textSize = TextRenderer.MeasureText(text, font);
var textBounds = DrawingHelper.AlignInRectangle(clientRectangle, textSize, ContentAlignment.MiddleLeft);
graphics.FillRectangle(new SolidBrush(SystemColors.Control), ClientRectangle);
ControlPaint.DrawBorder(graphics, clientRectangle, SystemColors.ControlDark, ButtonBorderStyle.Solid);
TextRenderer.DrawText(graphics, text, font, textBounds, SystemColors.WindowText);
}
protected override void OnEnabledChanged(EventArgs e)
{
base.OnEnabledChanged(e);
SetStyle();
}
public void SetStyle()
{
if (DesignMode)
return;
SetStyle(ControlStyles.UserPaint, !Enabled);
Invalidate();
}
public static class DrawingHelper
{
public static Rectangle AlignInRectangle(Rectangle outer, Size inner, ContentAlignment alignment)
{
int x = 0;
int y = 0;
switch (alignment)
{
case ContentAlignment.BottomLeft:
case ContentAlignment.MiddleLeft:
case ContentAlignment.TopLeft:
x = outer.X;
break;
case ContentAlignment.BottomCenter:
case ContentAlignment.MiddleCenter:
case ContentAlignment.TopCenter:
x = Math.Max(outer.X + ((outer.Width - inner.Width) / 2), outer.Left);
break;
case ContentAlignment.BottomRight:
case ContentAlignment.MiddleRight:
case ContentAlignment.TopRight:
x = outer.Right - inner.Width;
break;
}
switch (alignment)
{
case ContentAlignment.TopCenter:
case ContentAlignment.TopLeft:
case ContentAlignment.TopRight:
y = outer.Y;
break;
case ContentAlignment.MiddleCenter:
case ContentAlignment.MiddleLeft:
case ContentAlignment.MiddleRight:
y = outer.Y + (outer.Height - inner.Height) / 2;
break;
case ContentAlignment.BottomCenter:
case ContentAlignment.BottomRight:
case ContentAlignment.BottomLeft:
y = outer.Bottom - inner.Height;
break;
}
return new Rectangle(x, y, Math.Min(inner.Width, outer.Width), Math.Min(inner.Height, outer.Height));
}
}
Is there any way of setting the Z-order of controls on a panel to always be on top when a new control is added? I am creating a card game and I have a Panel with the pictures of the cards in (a new picturebox for each card). When a new picture is added it automatically goes to the back of the panel. Is there any way so it will be always on top? I've tried 'SetChildIndex' but the name of each picturebox will be the same as I'm re-using code. Any help is appreciated. Thanks
private void DealPlayerCard(int cardNum)
{
string Card = Classes.Deck.GetCurrentCard();
PictureBox pb = new PictureBox() { Width = 172, Height = 240, SizeMode = PictureBoxSizeMode.StretchImage };
pb.ImageLocation = #"Cards\" + Card + ".png";
int order = 0;
switch (cardNum)
{
case 1:
pb.Location = new Point(0, 0);
order = 5;
break;
case 2:
pb.Location = new Point(60, 0);
order = 4;
break;
case 3:
pb.Location = new Point(120, 0);
order = 3;
break;
case 4:
pb.Location = new Point(180, 0);
order = 2;
break;
case 5:
pb.Location = new Point(240, 0);
order = 1;
break;
}
AddPlayerCard(pb, order);
}
public void AddPlayerCard(PictureBox pb, int order)
{
pnlPlayer.Controls.Add(pb);
pnlPlayer.Controls.SetChildIndex(pb, order);
}
EDIT
Using Sinatr's idea, I have now used the .Tag control property to give the z-order number to each of the controls and then whenever I add a control - simply loop through each control and set the z-order = .Tag property
private void DealPlayerCard(int cardNum)
{
string Card = Classes.Deck.GetCurrentCardPicture();
PictureBox pb = new PictureBox() { Width = 172, Height = 240, SizeMode = PictureBoxSizeMode.StretchImage };
pb.ImageLocation = #"Cards\" + Card + ".png";
switch (cardNum)
{
case 1:
pb.Location = new Point(0, 0);
pb.Tag = 5;
break;
case 2:
pb.Location = new Point(60, 0);
pb.Tag = 4;
break;
case 3:
pb.Location = new Point(120, 0);
pb.Tag = 3;
break;
case 4:
pb.Location = new Point(180, 0);
pb.Tag = 2;
break;
case 5:
pb.Location = new Point(240, 0);
pb.Tag = 1;
break;
}
AddPlayerCard(pb);
AddToHand("Player");
}
public void AddPlayerCard(PictureBox pb)
{
pnlPlayer.Controls.Add(pb);
foreach (Control Control in pnlPlayer.Controls)
{
pnlPlayer.Controls.SetChildIndex(Control, Int32.Parse(Control.Tag.ToString()));
}
}
You can use the BringToFront() method, available to every Winform control:
controlName.BringToFront();
This brings the control controlName to the top of the z-order, forcing it to have a z-order of 0.
You can SetChildIndex(System.Windows.Forms.Control child, int newIndex) to set the z-order.
A control with newIndex set to 0, is at the top of the z-order. Controls with higher newIndex will be positioned closer to the bottom.
I have the following code:
if (frame != null)
{
canvas.Children.Clear();
_bodies = new Body[frame.BodyFrameSource.BodyCount];
frame.GetAndRefreshBodyData(_bodies);
foreach (var body in _bodies)
{
if (body != null)
{
if (body.IsTracked)
{
// choose which hand to track
string whichHand = "right"; //change to "left" in order to track left hand
Joint handRight = body.Joints[JointType.HandRight];
if (whichHand.Equals("right"))
{
string rightHandState = "-"; //find the right hand state
switch (body.HandRightState)
{
case HandState.Open:
rightHandState = "Open";
break;
case HandState.Closed:
rightHandState = "Closed";
break;
default:
break;
}
canvas.DrawPoint(handRight, _sensor.CoordinateMapper);
}
Here is my DrawPoint code:
public static void DrawPoint(this Canvas canvas, Joint joint, CoordinateMapper mapper)
{
if (joint.TrackingState == TrackingState.NotTracked) return;
Point point = joint.Scale(mapper);
Ellipse ellipse = new Ellipse
{
Width = 20,
Height = 20,
Fill = new SolidColorBrush(Colors.LightBlue)
};
Canvas.SetLeft(ellipse, point.X - ellipse.Width / 2);
Canvas.SetTop(ellipse, point.Y - ellipse.Height / 2);
canvas.Children.Add(ellipse);
}
And Scale:
public static Point Scale(this Joint joint, CoordinateMapper mapper)
{
Point point = new Point();
ColorSpacePoint colorPoint = mapper.MapCameraPointToColorSpace(joint.Position);
point.X *= float.IsInfinity(colorPoint.X) ? 0.0 : colorPoint.X;
point.Y *= float.IsInfinity(colorPoint.Y) ? 0.0 : colorPoint.Y;
return point;
}
The problem that I have is that while the circle does get drawn, it is not drawn over my hand. Instead it stays in the top left corner (0,0), so I'm guessing that it's not getting updated properly. Could anybody tell me what is going on or what the problem is? I would like it to be in the center of my hand (which is being tracked fine because the state of the hand gets updated immediately) and follow my hand as I move it.
The _sensor is my Kinect sensor.
On MouseDownEvent I set upper left corner of Ellipse I'm trying to draw.
public MyCircle(Point location)
{
ellipseObject = new Ellipse
{
Stroke = Brushes.Black,
StrokeThickness = 2,
Margin = new Thickness(location.X, location.Y, 0, 0)
};
}
Then on MouseMoveEvent I update Width and Height properties and it works fine as long as I don't move mouse above or/and to the left of my Ellipse upper left corner, in that case I'm getting exception that these properties can't be negative (which of course makes perfect sense).
public void Draw(Point location)
{
if (ellipseObject != null)
{
ellipseObject.Width = location.X - ellipseObject.Margin.Left;
ellipseObject.Height = location.Y - ellipseObject.Margin.Top;
}
}
The problem doesn't exist with drawing lines:
public void Draw(Point location)
{
lineObject.X2 = location.X;
lineObject.Y2 = location.Y;
}
I know it's trivial, but I'm completely stuck on this. How should I handle drawing Ellipses?
I had this EXACT problem when trying to create a crop tool. Problem is that you need to create if statements for when the cursor goes negative X or negative Y from your starting point. For starters, you'll need to have a global Point that you mark as your 'start' point. Also specify a global current point position that we'll talk about in a minute.
public Point startingPoint;
public Point currentPoint;
Then, make sure you have an onMouseDown event on whatever control you are trying to put the ellipse on.
private void control_MouseDown(object sender, MouseEventArgs e)
{
startingPoint.X = e.X;
startingPoint.Y = e.Y;
}
Then, you need to create if statements in your MouseMove event to check with point (current mouse position, or starting point) has a lower X/Y value
private void control_MouseMove(object sender, MouseEventArgs e)
{
//The below point is what we'll draw the ellipse with.
Point ellipsePoint;
Ellipse ellipseObject = new Ellipse();
currentPoint.X = e.X;
currentPoint.Y = e.Y;
//Then we need to get the proper width/height;
if (currentPoint.X >= startingPoint.X)
{
ellipsePoint.X = startingPoint.X;
ellipseObject.Width = currentPoint.X - startingPoint.X;
}
else
{
ellipsePoint.X = currentPoint.X;
ellipseObject.Width = startingPoint.X - currentPoint.X;
}
if (currentPoint.Y >= startingPoint.Y)
{
ellipsePoint.Y = startingPoint.Y;
ellipseObject.Height = currentPoint.Y - startingPoint.Y;
}
else
{
ellipsePoint.Y = currentPoint.Y;
ellipseObject.Height = startingPoint.Y - currentPoint.Y;
}
ellipseObject.Stroke = Brushes.Black;
ellipseObject.StrokeThickness = 2;
ellipseObject.Margin = new Thickness(ellipsePoint.X, ellipsePoint.Y, 0, 0);
}
Hope this helps!
Save the origin point separately and set the X and Y properties of the Ellipse's Margin to the mouse position and the Width and Height to the distances between the mouse and origin point.
Untested:
public MyCircle(Point location)
{
ellipseObject = new Ellipse
{
Stroke = Brushes.Black,
StrokeThickness = 2,
Margin = new Thickness(location.X, location.Y, 0, 0)
Tag = new Point(location.X, location.Y)
};
}
public void Draw(Point location)
{
if (ellipseObject != null)
{
Point o = (Point)ellipseObject.Tag;
double x = Math.Min(location.X, o.Left);
double y = Math.Min(location.Y, o.Top);
double width = Math.Abs(Math.Max(location.X, o.Left) - x);
double height = Math.Abs(Math.Max(location.Y, o.Top) - y);
ellipseObject.Margin.X = x;
ellipseObject.Margin.Y = y;
ellipseObject.Width = width;
ellipseObject.Height = height;
}
}