/// <summary> /// Takes a scalar in image space and returns a scalar in world space. /// Not suitable for geometry. /// </summary> public float GetScalar(float v) { PointF a = GetPoint(PointF.Empty); PointF b = GetPoint(new PointF(v, 0)); float d = GeometryHelper.GetDistance(a, b); return(v < 0 ? -d : d); }
/// <summary> /// Takes a scalar value in world space and return it in image space. /// Not suitable for geometry. /// </summary> public float GetImageScalar(float v) { PointF a = distortionHelper.Distort(calibrator.Untransform(PointF.Empty)); PointF b = distortionHelper.Distort(calibrator.Untransform(new PointF(v, 0))); float d = GeometryHelper.GetDistance(a, b); return(v < 0 ? -d : d); }
/// <summary> /// Takes two points in image coordinates and return the length of the segment in real world units. /// </summary> public string GetLengthText(PointF p1, PointF p2, bool precise, bool abbreviation) { float length = GeometryHelper.GetDistance(GetPoint(p1), GetPoint(p2)); string valueTemplate = precise ? "{0:0.00}" : "{0:0}"; string text = String.Format(valueTemplate, length); if (abbreviation) { text = text + " " + String.Format("{0}", UnitHelper.LengthAbbreviation(lengthUnit)); } return(text); }
public void WriteXml(XmlWriter w, SerializationFilter filter) { if (ShouldSerializeCore(filter)) { w.WriteElementString("Start", XmlHelper.WritePointF(points["a"])); w.WriteElementString("End", XmlHelper.WritePointF(points["b"])); TypeConverter enumConverter = TypeDescriptor.GetConverter(typeof(TrackExtraData)); string xmlExtraData = enumConverter.ConvertToString(trackExtraData); w.WriteElementString("ExtraData", xmlExtraData); w.WriteStartElement("MeasureLabel"); miniLabel.WriteXml(w); w.WriteEndElement(); } if (ShouldSerializeStyle(filter)) { w.WriteStartElement("DrawingStyle"); style.WriteXml(w); w.WriteEndElement(); } if (ShouldSerializeFading(filter)) { w.WriteStartElement("InfosFading"); infosFading.WriteXml(w); w.WriteEndElement(); } if (ShouldSerializeAll(filter)) { // Spreadsheet support. w.WriteStartElement("Measure"); PointF a = CalibrationHelper.GetPoint(new PointF(points["a"].X, points["a"].Y)); PointF b = CalibrationHelper.GetPoint(new PointF(points["b"].X, points["b"].Y)); float len = GeometryHelper.GetDistance(a, b); string value = String.Format("{0:0.00}", len); string valueInvariant = String.Format(CultureInfo.InvariantCulture, "{0:0.00}", len); w.WriteAttributeString("UserLength", value); w.WriteAttributeString("UserLengthInvariant", valueInvariant); w.WriteAttributeString("UserUnitLength", CalibrationHelper.GetLengthAbbreviation()); w.WriteEndElement(); } }
private void ComputeTotalDistance(TrajectoryKinematics kinematics, CalibrationHelper calibrationHelper) { float distance = 0; kinematics.TotalDistance[0] = distance; for (int i = 1; i < kinematics.Length; i++) { PointF a = kinematics.Coordinates(i - 1); PointF b = kinematics.Coordinates(i); float d = GeometryHelper.GetDistance(a, b); distance += d; kinematics.TotalDistance[i] = distance; } }
public void WriteXml(XmlWriter w, SerializationFilter filter) { if (ShouldSerializeCore(filter)) { w.WriteElementString("Start", XmlHelper.WritePointF(points["a"])); w.WriteElementString("End", XmlHelper.WritePointF(points["b"])); w.WriteElementString("MeasureVisible", ShowMeasurableInfo.ToString().ToLower()); } if (ShouldSerializeStyle(filter)) { w.WriteStartElement("DrawingStyle"); style.WriteXml(w); w.WriteEndElement(); } if (ShouldSerializeFading(filter)) { w.WriteStartElement("InfosFading"); infosFading.WriteXml(w); w.WriteEndElement(); } if (ShouldSerializeAll(filter)) { // Spreadsheet support. w.WriteStartElement("Measure"); PointF a = CalibrationHelper.GetPoint(new PointF(points["a"].X, points["a"].Y)); PointF b = CalibrationHelper.GetPoint(new PointF(points["b"].X, points["b"].Y)); float len = GeometryHelper.GetDistance(a, b); string value = String.Format("{0:0.00}", len); string valueInvariant = String.Format(CultureInfo.InvariantCulture, "{0:0.00}", len); w.WriteAttributeString("UserLength", value); w.WriteAttributeString("UserLengthInvariant", valueInvariant); w.WriteAttributeString("UserUnitLength", CalibrationHelper.GetLengthAbbreviation()); w.WriteEndElement(); } }
/// <summary> /// Build a quadrilateral from a single line. /// The quadrilateral will be a square with the original line at the bottom edge. /// </summary> private QuadrilateralF MakeQuad(PointF start, PointF end, CalibrationAxis calibrationAxis) { switch (calibrationAxis) { case CalibrationAxis.LineHorizontal: { // Rebuild a quadrilateral as a square, assuming the passed line is the bottom edge, left to right. // The base quadrilateral is defined as ABCD going CW from top-left, // the line is making up the DC vector which will map to the +X axis. PointF d = start; PointF c = end; PointF a = new PointF(d.X + (c.Y - d.Y), d.Y - (c.X - d.X)); PointF b = new PointF(a.X + (c.X - d.X), a.Y + (c.Y - d.Y)); return(new QuadrilateralF(a, b, c, d)); } case CalibrationAxis.LineVertical: { // Rebuild a quadrilateral as a square, assuming the passed line is the left edge, bottom to top. // The base quadrilateral is defined as ABCD going CW from top-left, // the line is making up the DA vector which will map to the +Y axis. PointF d = start; PointF a = end; PointF c = new PointF(d.X + (d.Y - a.Y), d.Y + (a.X - d.X)); PointF b = new PointF(a.X + (c.X - d.X), a.Y + (c.Y - d.Y)); return(new QuadrilateralF(a, b, c, d)); } case CalibrationAxis.ImageAxes: default: { // Rebuild a quadrilateral as a square aligned to the normal image axes (except Y goes up). // The base quadrilateral is defined as ABCD going CW from top-left, // the line length is giving the length of the DC edge of the square. float length = GeometryHelper.GetDistance(start, end); PointF d = start; PointF c = new PointF(d.X + length, d.Y); PointF a = new PointF(d.X + (c.Y - d.Y), d.Y - (c.X - d.X)); PointF b = new PointF(a.X + (c.X - d.X), a.Y + (c.Y - d.Y)); return(new QuadrilateralF(a, b, c, d)); } } }
private float GetDistance(PointF a, PointF b, Component component) { float d = 0; switch (component) { case Component.Magnitude: d = GeometryHelper.GetDistance(a, b); break; case Component.Horizontal: d = b.X - a.X; break; case Component.Vertical: d = b.Y - a.Y; break; } return(d); }
private static void PrepareImpacts(GenericPosture posture, int handle) { foreach (GenericPostureAbstractImpact impact in posture.Handles[handle].Impacts) { // If there is a KeepAngle impact, we'll later need to know the current angle. if (impact.Type == ImpactType.KeepAngle) { GenericPostureImpactKeepAngle impactKeepAngle = impact as GenericPostureImpactKeepAngle; PointF origin = posture.PointList[impactKeepAngle.Origin]; PointF leg1 = posture.PointList[impactKeepAngle.Leg1]; PointF leg2 = posture.PointList[impactKeepAngle.Leg2]; if (origin == leg1 || origin == leg2) { continue; } impactKeepAngle.OldAngle = GeometryHelper.GetAngle(origin, leg1, leg2); impactKeepAngle.OldDistance = GeometryHelper.GetDistance(origin, leg2); } } }
private static void MovePointHandleAtDistance(GenericPosture posture, int handle, PointF point, GenericPostureConstraintDistanceToPoint constraint, Keys modifiers) { if (constraint == null) { MovePointHandleFreely(posture, handle, point); return; } PointF parent = posture.PointList[constraint.RefPoint]; PointF child = posture.PointList[posture.Handles[handle].Reference]; float distance = GeometryHelper.GetDistance(parent, child); PointF temp = GeometryHelper.GetPointAtDistance(parent, point, distance); int constraintAngleSubdivisions = 8; // (Constraint by 45° steps). if ((modifiers & Keys.Shift) == Keys.Shift) { posture.PointList[posture.Handles[handle].Reference] = GeometryHelper.GetPointAtClosestRotationStepCardinal(parent, temp, constraintAngleSubdivisions); } else { posture.PointList[posture.Handles[handle].Reference] = temp; } }
private static CoordinateSystemGrid FindForPlaneCalibration(CalibrationHelper calibrationHelper) { CoordinateSystemGrid grid = new CoordinateSystemGrid(); RectangleF imageBounds = new RectangleF(PointF.Empty, calibrationHelper.ImageSize); RectangleF clipWindow = imageBounds; CalibrationPlane calibrator = calibrationHelper.CalibrationByPlane_GetCalibrator(); RectangleF plane = new RectangleF(PointF.Empty, calibrator.Size); int targetSteps = 15; float stepVertical = 1.0f; float stepHorizontal = 1.0f; // The extended plane is used for vanishing point replacement and iteration stop condition. QuadrilateralF extendedPlane; bool orthogonal; if (!calibrator.QuadImage.IsRectangle) { // If perspective plane, define as 2n times the nominal plane centered on origin. orthogonal = false; float n = 4; PointF a = new PointF(-calibrator.Size.Width * n, calibrator.Size.Height * n); PointF b = new PointF(calibrator.Size.Width * n, calibrator.Size.Height * n); PointF c = new PointF(calibrator.Size.Width * n, -calibrator.Size.Height * n); PointF d = new PointF(-calibrator.Size.Width * n, -calibrator.Size.Height * n); extendedPlane = new QuadrilateralF(a, b, c, d); QuadrilateralF quadImage = calibrator.QuadImage; float projectedWidthLength = GeometryHelper.GetDistance(quadImage.A, quadImage.B); float scaledTargetHorizontal = targetSteps / (calibrationHelper.ImageSize.Width / projectedWidthLength); stepHorizontal = RangeHelper.FindUsableStepSize(plane.Width, scaledTargetHorizontal); float projectedHeightLength = GeometryHelper.GetDistance(quadImage.A, quadImage.D); float scaledTargetVertical = targetSteps / (calibrationHelper.ImageSize.Height / projectedHeightLength); stepVertical = RangeHelper.FindUsableStepSize(plane.Height, scaledTargetVertical); } else { // If flat plane (and no distortion) we know there is no way to get any vanishing point inside the image, // so we can safely use the whole image reprojection as an extended plane. orthogonal = true; QuadrilateralF quadImageBounds = new QuadrilateralF(imageBounds); PointF a = calibrationHelper.GetPointFromRectified(quadImageBounds.A); PointF b = calibrationHelper.GetPointFromRectified(quadImageBounds.B); PointF c = calibrationHelper.GetPointFromRectified(quadImageBounds.C); PointF d = calibrationHelper.GetPointFromRectified(quadImageBounds.D); extendedPlane = new QuadrilateralF(a, b, c, d); float width = extendedPlane.B.X - extendedPlane.A.X; stepHorizontal = RangeHelper.FindUsableStepSize(width, targetSteps); float height = extendedPlane.A.Y - extendedPlane.D.Y; stepVertical = RangeHelper.FindUsableStepSize(height, targetSteps); } //------------------------------------------------------------------------------------------------- // There is a complication with points behind the camera, as they projects above the vanishing line. // The general strategy is the following: // Find out if the vanishing point is inside the image. Reminder: parallel lines share the same vanishing point. // If it is not inside the image, there is no risk, so we take two points on the line and draw an infinite line that we clip against the image bounds. // If it is inside the image: // Take two points on the line and project them in image space. They are colinear with the vanishing point in image space. // Find on which side of the quadrilateral the vanishing point is. // If the vanishing point is above the quad, draw a ray from the top of the extended quad, down to infinity. // If the vanishing point is below the quad, draw a ray from the bottom of the extended quad, up to infinity. // // Stepping strategy: // We start at origin and progress horizontally and vertically until we find a gridline that is completely clipped out. //------------------------------------------------------------------------------------------------- // Vertical lines. PointF yVanish = new PointF(0, float.MinValue); bool yVanishVisible = false; Vector3 yv = calibrator.Project(new Vector3(0, 1, 0)); if (yv.Z != 0) { yVanish = new PointF(yv.X / yv.Z, yv.Y / yv.Z); yVanishVisible = clipWindow.Contains(yVanish); } CreateVerticalGridLines(grid, 0, -stepHorizontal, calibrator, clipWindow, plane, extendedPlane, orthogonal, yVanishVisible, yVanish); CreateVerticalGridLines(grid, stepHorizontal, stepHorizontal, calibrator, clipWindow, plane, extendedPlane, orthogonal, yVanishVisible, yVanish); // Horizontal lines PointF xVanish = new PointF(float.MinValue, 0); bool xVanishVisible = false; Vector3 xv = calibrator.Project(new Vector3(1, 0, 0)); if (xv.Z != 0) { xVanish = new PointF(xv.X / xv.Z, xv.Y / xv.Z); xVanishVisible = clipWindow.Contains(xVanish); } CreateHorizontalGridLines(grid, 0, -stepVertical, calibrator, clipWindow, plane, extendedPlane, orthogonal, xVanishVisible, xVanish); CreateHorizontalGridLines(grid, stepVertical, stepVertical, calibrator, clipWindow, plane, extendedPlane, orthogonal, xVanishVisible, xVanish); return(grid); }
private void ComputeAngles(TimeSeriesCollection tsc, CalibrationHelper calibrationHelper, Dictionary <string, FilteredTrajectory> trajs, AngleOptions angleOptions) { for (int i = 0; i < tsc.Length; i++) { PointF o = PointF.Empty; PointF a = PointF.Empty; PointF b = PointF.Empty; if (trajs["o"].CanFilter) { o = trajs["o"].Coordinates(i); a = trajs["a"].Coordinates(i); b = trajs["b"].Coordinates(i); } else { o = trajs["o"].RawCoordinates(i); a = trajs["a"].RawCoordinates(i); b = trajs["b"].RawCoordinates(i); } // Compute the actual angle value. The logic here should match the one in AngleHelper.Update(). // They work on different type of inputs so it's difficult to factorize the functions. if (angleOptions.Supplementary) { // Create a new point by point reflection of a around o. PointF c = new PointF(2 * o.X - a.X, 2 * o.Y - a.Y); a = b; b = c; } float angle = 0; if (angleOptions.CCW) { angle = GeometryHelper.GetAngle(o, a, b); } else { angle = GeometryHelper.GetAngle(o, b, a); } if (!angleOptions.Signed && angle < 0) { angle = (float)(TAU + angle); } positions[i] = angle; radii[i] = GeometryHelper.GetDistance(o, b); tsc[Kinematics.AngularPosition][i] = calibrationHelper.ConvertAngle(angle); if (i == 0) { tsc[Kinematics.AngularDisplacement][i] = 0; tsc[Kinematics.TotalAngularDisplacement][i] = 0; } else { float totalDisplacementAngle = angle - positions[0]; float displacementAngle = angle - positions[i - 1]; tsc[Kinematics.AngularDisplacement][i] = calibrationHelper.ConvertAngle(displacementAngle); tsc[Kinematics.TotalAngularDisplacement][i] = calibrationHelper.ConvertAngle(totalDisplacementAngle); } } }