Evaluating an expression (like 45/12) from a textbox - vb.net

I need to be able to type a value in a textbox of either 45/12 or 3.75 which is a decimal inch conversion. Obviously the decimal value works. The code takes a different textbox value (a) and this value (b) subtracts b from a and multiplies the result by a shrink factor to populate in another textbox. Some know the decimal conversion some do not and resort to the 45/12 method. Value (a) is entered strictly by a decimal conversion 8'-1" would be 8.0833. Any help on this is appreciated. Value (b) however is used for more calculations further in the code which I can post if needed. This is part of the code, the value for b goes on and on to an expression of >4. Also this is my first ever VB design so it may not be the most efficient code. thanks
Option Explicit On
Public Class Form1
Dim a, b, c, d, r, w, h, x, y, z As Single
Dim s, t, u, v, f, g, j, k, l, m, n, o As Single
Private Sub radiobutton1_CheckedChanged(sender As Object, e As EventArgs) Handles RadioButton1.CheckedChanged
If (RadioButton1.Checked) = False Then
Button1.PerformClick()
End If
End Sub
Private Sub radiobutton3_CheckedChanged(sender As Object, e As EventArgs) Handles RadioButton3.CheckedChanged
If (RadioButton3.Checked) = False Then
Button1.PerformClick()
End If
End Sub
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
If Timer1.Interval = 1000 Then
Label9.Text = DateTime.Now
End If
End Sub
' Calculate Button Does This
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Error Boxes
If TextBox1.Text = "" Then
MsgBox("Please Input 'Wall Height' And/Or 'Depth'")
With TextBox1
.Focus()
.SelectAll()
End With
Exit Sub
End If
If TextBox2.Text = "" Then
MsgBox("Please Input 'Wall Height' And/Or 'Depth'")
With TextBox2
.Focus()
.SelectAll()
End With
Exit Sub
End If
If (RadioButton1.Checked Or RadioButton3.Checked) = False Then
MsgBox("Please Select 'N/A' or 'Yes")
End If
If TextBox1.Text < TextBox2.Text Then
MsgBox("Re-check Depth and Wall Height")
With TextBox1
.Focus()
.SelectAll()
End With
Exit Sub
End If
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Values For Depth And Wall Height
a = Val(TextBox1.Text) 'Depth
b = Val(TextBox2.Text) 'Actual Wall Height
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Hopper Drop Shrink Calculation
If (RadioButton3.Checked) AndAlso ((a - b) <= 1) Then
r = Math.Round(((a - b) - 0.0833), 4)
ElseIf (RadioButton1.Checked) Then
r = Math.Round(((a - b) * 0.944), 4) ' Depth minus wall height .944 shrink factor
ElseIf (RadioButton3.Checked) Then
r = Math.Round(((a - b) * 0.89), 4) ' Depth minus wall height .89 shrink factor
End If
If r <= 0.01 Then
TextBox3.Text = "N/A"
Else : TextBox3.Text = r
End If
' Value For Hopper Drop after shrink
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Depth Minus Wall Height Ranges For Finish Wall Height
w = (b >= 0.0833 And b <= 3.25) ' Wall height between 12" and 39"
If w Then
h = Math.Round(((b - 0.0833) * 12), 2) ' Subtract 1" from wall height
End If
If w Then
t = 0
End If
If w Then
d = 0
End If
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
z = (b >= 3.26 And b <= 3.3332) ' Wall height between 39 1/4" and 39 3/4"
If z Then
h = 38 ' Wall height will be 38"
End If
If z Then
t = 0
End If
If z Then
d = 0
End If
TextBox4.Text = Int(h) & " " & DecToFraction(h - Int(h)) & "''" 'Finish Wall Height
TextBox6.Text = Int(t) & " " & DecToFraction(t - Int(t)) & "''" ' Strip Size
If CheckBox2.Checked Then
TextBox5.Text = "N/A"
ElseIf CheckBox2.Checked = False Then
TextBox5.Text = Int(t) & " " & DecToFraction(t - Int(t)) & "''" ' Wrap Size
End If
TextBox7.Text = Int(d) & " " & DecToFraction(d - Int(d)) & "''" ' Cut wall to (production wall height)

You could use a library like NCalc to treat the textbox input as a mathematical expression. This would handle 45/12 and 3.75 perfectly, as either will evaluate to a single number when executed through the expression engine.

Or you can use a Fraction struct like this:
class Program
{
static void Main(string[] args)
{
Fraction X=Fraction.Parse("45/12");
Console.WriteLine("X = {0} = {1} = {2}", X, X.GetReduced(),X.Value);
// X = 45/12 = 15/4 = 3.75
bool ok=X.Equals(3.75);
// true
}
}
/// <summary>
/// A Class to represent fraction from decimals using GCD and LCM.
/// </summary>
/// <remarks>Code taken from http://www.vcskicks.com/code-snippet/fraction.php</remarks>
[TypeConverter(typeof(ExpandableObjectConverter))]
public struct Fraction : IEquatable<Fraction>, IEquatable<double>, ICloneable
{
public static string DefaultFormat="G";
public readonly long numerator;
public readonly long denominator;
public static Fraction Zero=new Fraction(0, 1);
public Fraction(long numerator, long denominator)
{
this.numerator=numerator;
this.denominator=denominator;
//If denominator negative...
if(this.denominator<0)
{
//...move the negative up to the numerator
this.numerator=-this.numerator;
this.denominator=-this.denominator;
}
}
public Fraction(Fraction fraction)
{
this.numerator=fraction.numerator;
this.denominator=fraction.denominator;
}
public static Fraction Parse(string value)
{
long num=1;
long den=1;
string[] parts=value.Split('/');
bool is_den=false;
for(int i=0; i<parts.Length; i++)
{
if(is_den)
{
den*=long.Parse(parts[i]);
}
else
{
num*=long.Parse(parts[i]);
}
is_den=!is_den;
}
return new Fraction(num, den);
}
public static implicit operator Fraction(double value)
{
return Fraction.FromValue(value);
}
public static implicit operator double(Fraction rhs)
{
return rhs.Value;
}
public long Numerator { get { return numerator; } }
public long Denominator { get { return denominator; } }
public double Value { get { return (double)numerator/denominator; } }
public static Fraction operator+(Fraction lhs, Fraction rhs) { return lhs.Add(rhs); }
public static Fraction operator-(Fraction rhs) { return rhs.Negate(); }
public static Fraction operator-(Fraction lhs, Fraction rhs) { return lhs.Subtract(rhs); }
public static Fraction operator*(double lhs, Fraction rhs) { return rhs.Scale(lhs); }
public static Fraction operator*(Fraction lhs, double rhs) { return lhs.Scale(rhs); }
public static Fraction operator/(Fraction lhs, double rhs) { return lhs.Scale(1/rhs); }
public static Fraction operator/(double lhs, Fraction rhs) { return rhs.Reciprocal(lhs); }
public static Fraction operator*(Fraction lhs, Fraction rhs) { return lhs.Multiply(rhs); }
public static Fraction operator/(Fraction lhs, Fraction rhs) { return lhs.Divide(rhs); }
/// <summary>
/// Get the greatest common divisor
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <returns></returns>
private static long getGCD(long a, long b)
{
//Drop negative signs
a=Math.Abs(a);
b=Math.Abs(b);
//Return the greatest common denominator between two integers
while(a!=0&&b!=0)
{
if(a>b)
a%=b;
else
b%=a;
}
if(a==0)
return b;
else
return a;
}
/// <summary>
/// Get the least common measure
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <returns></returns>
private static long getLCM(long a, long b)
{
//Return the Least Common Denominator between two integers
return (a*b)/getGCD(a, b);
}
public Fraction ToDenominator(long targetDenominator)
{
//Multiply the fraction by a factor to make the denominator
//match the target denominator
//Fraction modifiedFraction=this;
long n=this.numerator;
long d=this.denominator;
//Cannot reduce to smaller denominators
if(targetDenominator<this.denominator)
return this;
//The target denominator must be a factor of the current denominator
if(targetDenominator%this.denominator!=0)
return this;
if(d!=targetDenominator)
{
long factor=targetDenominator/d;
n*=factor;
d=targetDenominator;
//modifiedFraction.denominator=targetDenominator;
//modifiedFraction.numerator*=factor;
}
return new Fraction(n, d);
}
public Fraction GetReduced()
{
//Reduce the fraction to lowest terms
//Fraction modifiedFraction=this;
long n=this.numerator;
long d=this.denominator;
//While the numerator and denominator share a greatest common denominator,
//keep dividing both by it
long gcd=0;
while(Math.Abs(gcd=getGCD(n, d))!=1)
{
n/=gcd;
d/=gcd;
}
//Make sure only a single negative sign is on the numerator
n=n*Math.Sign(d);
d=Math.Abs(d);
return new Fraction(n, d);
}
/// <summary>
/// Uses a continious fraction scheme to iteratively aproximate a number with a fraction.
/// The accuracy is taken from <see cref="GRE.Mathematics.Dbl.Calculator.ZeroTolerance"/>
/// </summary>
/// <remarks>See <see cref="FromValue(double,double)"/> to understand how it works</remarks>
/// <param name="number">The number to approximate</param>
/// <returns></returns>
public static Fraction FromValue(double number)
{
return FromValue(number, 15);
}
/// <summary>
/// Uses a continious fraction scheme to iteratively aproximate a number with a fraction
/// </summary>
/// <remarks>See <see cref="FromValue(double,double)"/> to understand how it works</remarks>
/// <param name="number">The number to approximate</param>
/// <param name="digits">The number if digits to use in the aproximation</param>
/// <returns></returns>
public static Fraction FromValue(double number, int digits)
{
double accuracy=Math.Pow(10.0, -digits);
return FromValue(number, accuracy);
}
/// <summary>
/// Uses a continious fraction scheme to iteratively aproximate a number with a fraction
/// </summary>
/// <remarks>
/// See documentation for <see cref="FromContiniousFractionCoefficients(long[])"/> to understand how this works.
/// </remarks>
/// <param name="number">The number to aproximate</param>
/// <param name="accuracy">The accuracy to use |fraction-value|<![CDATA[<]]>accuracy </param>
/// <returns></returns>
public static Fraction FromValue(double number, double accuracy)
{
int sign=Math.Sign(number);
number=Math.Abs(number);
int passes=0;
List<long> coef=new List<long>();
Fraction x;
double r=number; // remainder (example 8.22)
do
{
long c=(int)r; // integer of remainder (r=8.22 -> c=8)
r=1/(r-c); // new remainder from r -> 1/(0.22)=4.54
coef.Add(c); // adds c to the list
x=FromContiniousFractionCoefficients(coef.ToArray()); // reconstruct the fraction from all the n's
passes++; // increment counter and repeat
} while(!x.Equals(number, accuracy)&&passes<10);
if(sign<0)
{
x=x.Negate();
}
return x;
}
/// <summary>
/// Use recursion to take the integer coefficients of a continious fraction and simplify it to a regular fraction
/// </summary>
/// <example>The parameters in array <c>c</c> define the following value:<![CDATA[
/// 1
/// c[0] + -------------------- -> recursion on e[i] = c[i] + 1/e[i+1] , e[i]=r[i]/r[i+1]
/// 1
/// c[1] + --------------- seed is 1/e[N]=0 (r[N]=1, r[N+1]=0)
/// 1 final result is x = r[0]/r[1]
/// c[2] + ---------
/// c[3]+...
/// ]]></example>
/// <remarks>Here are some references
/// * http://www.friesian.com/golden.htm
/// * http://archives.math.utk.edu/articles/atuyl/confrac/intro.html
/// * http://www.trans4mind.com/personal_development/mathematics/numberTheory/continuedFractions.htm
/// </remarks>
/// <param name="coef">The integer coefficients for the fraction (see example)</param>
/// <returns>A Fraction object</returns>
public static Fraction FromContiniousFractionCoefficients(params long[] coef)
{
int N=coef.Length;
if(N>0)
{
long[] r=new long[N+2];
r[N+1]=0;
r[N+0]=1;
for(int i=N-1; i>=0; i--)
{
r[i]=coef[i]*r[i+1]+r[i+2];
}
return new Fraction(r[0], r[1]);
}
else
{
return Fraction.Zero;
}
}
public Fraction Flip()
{
//Flip the numerator and the denominator
return new Fraction(this.denominator, this.numerator);
}
public override bool Equals(object obj)
{
if(obj is Fraction)
{
return Equals((Fraction)obj);
}
return false;
}
public bool Equals(Fraction other, double tolerance)
{
return Math.Abs(Value-other.Value)<=tolerance;
}
public bool Equals(Fraction other)
{
var A=GetReduced();
var B=other.GetReduced();
return A.numerator==B.numerator&&A.denominator==B.denominator;
}
public override int GetHashCode()
{
unchecked
{
return 17*23*Value.GetHashCode();
}
}
public Fraction Clone() { return new Fraction(this); }
object ICloneable.Clone()
{
return Clone();
}
public Fraction Scale(double factor)
{
Fraction other=new Fraction(factor);
return Multiply(other);
}
public Fraction Divide(double factor)
{
Fraction other=new Fraction(factor);
return Divide(other);
}
public Fraction Reciprocal(double numerator)
{
Fraction other=new Fraction(numerator);
return other.Divide(this);
}
public Fraction Multiply(Fraction other)
{
return new Fraction(numerator*other.numerator, denominator*other.denominator).GetReduced();
}
public Fraction Divide(Fraction other)
{
return new Fraction(numerator*other.denominator, denominator*other.numerator).GetReduced();
}
public Fraction Add(Fraction other)
{
return new Fraction(other.denominator*numerator+other.numerator*denominator, denominator*other.denominator).GetReduced();
}
public Fraction Subtract(Fraction other)
{
return new Fraction(other.denominator*numerator-other.numerator*denominator, denominator*other.denominator).GetReduced();
}
public Fraction Negate()
{
return new Fraction(-numerator, denominator);
}
public override string ToString()
{
return ToString(DefaultFormat);
}
public string ToString(string format)
{
return ToString(format, null);
}
public string ToString(string format, IFormatProvider formatProvider)
{
if(numerator==0)
{
string fmt="{0:#}".Replace("#", format);
return string.Format(formatProvider, fmt, numerator);
}
else
{
string fmt="{0:#}/{1:#}".Replace("#", format);
return string.Format(formatProvider, fmt, numerator, denominator);
}
}
public bool Equals(double other)
{
return Value.Equals(other);
}
public bool Equals(double other, double tolerance)
{
return Math.Abs(Value-other)<=tolerance;
}
}

Related

Compare value stored in query to user's input

How do I get two input values compared to my query records?
For example, I enter 500 Double, and I want everyone who has over 500 Double on my list.
if I enter 300 Doubles and 150 Triples. Only display everybody who has more than 300 Doubles and more than 150 Triples. Right now, displays the doubles that are more than the input value.
namespace SQLiteIntegration
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
}
private void Button_Click(object sender, RoutedEventArgs e)
{
if (HasValidInput())
{
int doubles = int.Parse(DoublesTextBox.Text);
int triples = int.Parse(TriplesTextBox.Text);
//MARKER - Probably an error here
DataTable dt = new DataTable();
string datasource = #"Data Source=../../lahman2016.sqlite;";
//Batting.'2B' is the number of doubles a player hit in a season
//Batting.'3B' is the number of triples a player hit in a season
string sql = $"SELECT namefirst, namelast, sum(Batting.'2B'), sum(Batting.'3B') from Master JOIN Batting on Master.playerID = Batting.playerID GROUP BY Master.playerid HAVING SUM(Batting.'2B') AND SUM(Batting.'3B') > {doubles};";
using (SQLiteConnection conn = new SQLiteConnection(datasource))
{
conn.Open();
SQLiteDataAdapter da = new SQLiteDataAdapter(sql, conn);
da.Fill(dt);
conn.Close();
}
playerList.Clear();
foreach (DataRow row in dt.Rows)
{
// MARKER: Making something different show up
string playerRow = $"{row​[0].ToString()} {row​[1].ToString()} - 2B = {row​[2].ToString()}, 3B = {row​[3].ToString()}";
playerList.Add(playerRow);
}
populateList();
}
}
private List<string> playerList = new List<string>();
private void populateList()
{
ListView.Items.Clear();
foreach (string s in playerList)
{
ListView.Items.Add(s);
}
}
private string ValidateTextBox(TextBox box, string name)
{
string message = "";
string text = box.Text;
int amount = 0;
if (text == "")
box.Text = "0";
else
{
bool isNumber = int.TryParse(text, out amount);
if (!isNumber)
{
message += $"Invalid Input - {name} is not a number! ";
}
if (amount < 0)
{
message += $"Invalid Input - {name} is negative! ";
}
}
return message;
}
private bool HasValidInput()
{
string message = ValidateTextBox(DoublesTextBox, "Doubles") +
ValidateTextBox(TriplesTextBox, "Triples");
if (message == "")
{
return true;
}
else
{
MessageBox.Show(message);
return false;
}
}
}
}
I am expecting if I enter 300 Doubles and 150 Triples. Only display everybody who has more than 300 Doubles and more than 150 Triples. Right now, displays the doubles that are more than the input value.

Vertical Text in UWP apps with XAML

I want to write text vertically inside of a border element. As shown in this picture.
I've tried using RenderTransform with this code
<Border Width="80"
Background="Teal">
<TextBlock Text="CATEGORIES"
Foreground="White"
FontFamily="Segoe UI Black"
FontSize="30">
<TextBlock.RenderTransform>
<RotateTransform Angle="-90" />
</TextBlock.RenderTransform>
</TextBlock>
</Border>
This rotates the text vertically but the TextBlock takes the old values of height and width before Transform and doesn't display the text completely. So the text is cut off after 80 pixels (width of the border element). While searching I found using LayoutTransform can solve the problem but it is not available in UWP apps. How to do this in UWP XAML?
This worked for me on UWP as well. Just use the class posted here instead of the one from the post. And also copy the style from the blog post.
EDIT: The onedrive link no longer works. So I am posting the code here.
Create a new class LayoutTransformer
using System;
using System.Diagnostics.CodeAnalysis;
using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
namespace Common
{
/// <summary>
/// Represents a control that applies a layout transformation to its Content.
/// </summary>
/// <QualityBand>Preview</QualityBand>
[TemplatePart(Name = TransformRootName, Type = typeof(Grid))]
[TemplatePart(Name = PresenterName, Type = typeof(ContentPresenter))]
public sealed class LayoutTransformer : ContentControl
{
/// <summary>
/// Name of the TransformRoot template part.
/// </summary>
private const string TransformRootName = "TransformRoot";
/// <summary>
/// Name of the Presenter template part.
/// </summary>
private const string PresenterName = "Presenter";
/// <summary>
/// Gets or sets the layout transform to apply on the LayoutTransformer
/// control content.
/// </summary>
/// <remarks>
/// Corresponds to UIElement.LayoutTransform.
/// </remarks>
public Transform LayoutTransform
{
get { return (Transform)GetValue(LayoutTransformProperty); }
set { SetValue(LayoutTransformProperty, value); }
}
/// <summary>
/// Identifies the LayoutTransform DependencyProperty.
/// </summary>
public static readonly DependencyProperty LayoutTransformProperty = DependencyProperty.Register(
"LayoutTransform", typeof(Transform), typeof(LayoutTransformer), new PropertyMetadata(null, LayoutTransformChanged));
/// <summary>
/// Gets the child element being transformed.
/// </summary>
private FrameworkElement Child
{
get
{
// Preferred child is the content; fall back to the presenter itself
return (null != _contentPresenter) ?
(_contentPresenter.Content as FrameworkElement ?? _contentPresenter) :
null;
}
}
// Note: AcceptableDelta and DecimalsAfterRound work around double arithmetic rounding issues on Silverlight.
private const double AcceptableDelta = 0.0001;
private const int DecimalsAfterRound = 4;
private Panel _transformRoot;
private ContentPresenter _contentPresenter;
private MatrixTransform _matrixTransform;
private Matrix _transformation;
private Size _childActualSize = Size.Empty;
public LayoutTransformer()
{
// Associated default style
DefaultStyleKey = typeof(LayoutTransformer);
// Can't tab to LayoutTransformer
IsTabStop = false;
#if SILVERLIGHT
// Disable layout rounding because its rounding of values confuses things
UseLayoutRounding = false;
#endif
}
/// <summary>
/// Builds the visual tree for the LayoutTransformer control when a new
/// template is applied.
/// </summary>
protected override void OnApplyTemplate()
{
// Apply new template
base.OnApplyTemplate();
// Find template parts
_transformRoot = GetTemplateChild(TransformRootName) as Grid;
_contentPresenter = GetTemplateChild(PresenterName) as ContentPresenter;
_matrixTransform = new MatrixTransform();
if (null != _transformRoot)
{
_transformRoot.RenderTransform = _matrixTransform;
}
// Apply the current transform
ApplyLayoutTransform();
}
/// <summary>
/// Handles changes to the Transform DependencyProperty.
/// </summary>
/// <param name="o">Source of the change.</param>
/// <param name="e">Event args.</param>
private static void LayoutTransformChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
// Casts are safe because Silverlight is enforcing the types
((LayoutTransformer)o).ProcessTransform((Transform)e.NewValue);
}
/// <summary>
/// Applies the layout transform on the LayoutTransformer control content.
/// </summary>
/// <remarks>
/// Only used in advanced scenarios (like animating the LayoutTransform).
/// Should be used to notify the LayoutTransformer control that some aspect
/// of its Transform property has changed.
/// </remarks>
public void ApplyLayoutTransform()
{
ProcessTransform(LayoutTransform);
}
/// <summary>
/// Processes the Transform to determine the corresponding Matrix.
/// </summary>
/// <param name="transform">Transform to process.</param>
private void ProcessTransform(Transform transform)
{
// Get the transform matrix and apply it
_transformation = RoundMatrix(GetTransformMatrix(transform), DecimalsAfterRound);
if (null != _matrixTransform)
{
_matrixTransform.Matrix = _transformation;
}
// New transform means re-layout is necessary
InvalidateMeasure();
}
/// <summary>
/// Walks the Transform(Group) and returns the corresponding Matrix.
/// </summary>
/// <param name="transform">Transform(Group) to walk.</param>
/// <returns>Computed Matrix.</returns>
private Matrix GetTransformMatrix(Transform transform)
{
if (null != transform)
{
// WPF equivalent of this entire method:
// return transform.Value;
// Process the TransformGroup
TransformGroup transformGroup = transform as TransformGroup;
if (null != transformGroup)
{
Matrix groupMatrix = Matrix.Identity;
foreach (Transform child in transformGroup.Children)
{
groupMatrix = MatrixMultiply(groupMatrix, GetTransformMatrix(child));
}
return groupMatrix;
}
// Process the RotateTransform
RotateTransform rotateTransform = transform as RotateTransform;
if (null != rotateTransform)
{
double angle = rotateTransform.Angle;
double angleRadians = (2 * Math.PI * angle) / 360;
double sine = Math.Sin(angleRadians);
double cosine = Math.Cos(angleRadians);
return new Matrix(cosine, sine, -sine, cosine, 0, 0);
}
// Process the ScaleTransform
ScaleTransform scaleTransform = transform as ScaleTransform;
if (null != scaleTransform)
{
double scaleX = scaleTransform.ScaleX;
double scaleY = scaleTransform.ScaleY;
return new Matrix(scaleX, 0, 0, scaleY, 0, 0);
}
// Process the SkewTransform
SkewTransform skewTransform = transform as SkewTransform;
if (null != skewTransform)
{
double angleX = skewTransform.AngleX;
double angleY = skewTransform.AngleY;
double angleXRadians = (2 * Math.PI * angleX) / 360;
double angleYRadians = (2 * Math.PI * angleY) / 360;
return new Matrix(1, angleYRadians, angleXRadians, 1, 0, 0);
}
// Process the MatrixTransform
MatrixTransform matrixTransform = transform as MatrixTransform;
if (null != matrixTransform)
{
return matrixTransform.Matrix;
}
// TranslateTransform has no effect in LayoutTransform
}
// Fall back to no-op transformation
return Matrix.Identity;
}
/// <summary>
/// Provides the behavior for the "Measure" pass of layout.
/// </summary>
/// <param name="availableSize">The available size that this element can give to child elements.</param>
/// <returns>The size that this element determines it needs during layout, based on its calculations of child element sizes.</returns>
protected override Size MeasureOverride(Size availableSize)
{
FrameworkElement child = Child;
if ((null == _transformRoot) || (null == child))
{
// No content, no size
return Size.Empty;
}
//DiagnosticWriteLine("MeasureOverride < " + availableSize);
Size measureSize;
if (_childActualSize == Size.Empty)
{
// Determine the largest size after the transformation
measureSize = ComputeLargestTransformedSize(availableSize);
}
else
{
// Previous measure/arrange pass determined that Child.DesiredSize was larger than believed
//DiagnosticWriteLine(" Using _childActualSize");
measureSize = _childActualSize;
}
// Perform a mesaure on the _transformRoot (containing Child)
//DiagnosticWriteLine(" _transformRoot.Measure < " + measureSize);
_transformRoot.Measure(measureSize);
//DiagnosticWriteLine(" _transformRoot.DesiredSize = " + _transformRoot.DesiredSize);
// WPF equivalent of _childActualSize technique (much simpler, but doesn't work on Silverlight 2)
// // If the child is going to render larger than the available size, re-measure according to that size
// child.Arrange(new Rect());
// if (child.RenderSize != child.DesiredSize)
// {
// _transformRoot.Measure(child.RenderSize);
// }
// Transform DesiredSize to find its width/height
Rect transformedDesiredRect = RectTransform(new Rect(0, 0, _transformRoot.DesiredSize.Width, _transformRoot.DesiredSize.Height), _transformation);
Size transformedDesiredSize = new Size(transformedDesiredRect.Width, transformedDesiredRect.Height);
// Return result to allocate enough space for the transformation
//DiagnosticWriteLine("MeasureOverride > " + transformedDesiredSize);
return transformedDesiredSize;
}
/// <summary>
/// Provides the behavior for the "Arrange" pass of layout.
/// </summary>
/// <param name="finalSize">The final area within the parent that this element should use to arrange itself and its children.</param>
/// <returns>The actual size used.</returns>
/// <remarks>
/// Using the WPF paramater name finalSize instead of Silverlight's finalSize for clarity
/// </remarks>
protected override Size ArrangeOverride(Size finalSize)
{
FrameworkElement child = Child;
if ((null == _transformRoot) || (null == child))
{
// No child, use whatever was given
return finalSize;
}
//DiagnosticWriteLine("ArrangeOverride < " + finalSize);
// Determine the largest available size after the transformation
Size finalSizeTransformed = ComputeLargestTransformedSize(finalSize);
if (IsSizeSmaller(finalSizeTransformed, _transformRoot.DesiredSize))
{
// Some elements do not like being given less space than they asked for (ex: TextBlock)
// Bump the working size up to do the right thing by them
//DiagnosticWriteLine(" Replacing finalSizeTransformed with larger _transformRoot.DesiredSize");
finalSizeTransformed = _transformRoot.DesiredSize;
}
//DiagnosticWriteLine(" finalSizeTransformed = " + finalSizeTransformed);
// Transform the working size to find its width/height
Rect transformedRect = RectTransform(new Rect(0, 0, finalSizeTransformed.Width, finalSizeTransformed.Height), _transformation);
// Create the Arrange rect to center the transformed content
Rect finalRect = new Rect(
-transformedRect.Left + ((finalSize.Width - transformedRect.Width) / 2),
-transformedRect.Top + ((finalSize.Height - transformedRect.Height) / 2),
finalSizeTransformed.Width,
finalSizeTransformed.Height);
// Perform an Arrange on _transformRoot (containing Child)
//DiagnosticWriteLine(" _transformRoot.Arrange < " + finalRect);
_transformRoot.Arrange(finalRect);
//DiagnosticWriteLine(" Child.RenderSize = " + child.RenderSize);
// This is the first opportunity under Silverlight to find out the Child's true DesiredSize
if (IsSizeSmaller(finalSizeTransformed, child.RenderSize) && (Size.Empty == _childActualSize))
{
// Unfortunately, all the work so far is invalid because the wrong DesiredSize was used
//DiagnosticWriteLine(" finalSizeTransformed smaller than Child.RenderSize");
// Make a note of the actual DesiredSize
_childActualSize = new Size(child.ActualWidth, child.ActualHeight);
//DiagnosticWriteLine(" _childActualSize = " + _childActualSize);
// Force a new measure/arrange pass
InvalidateMeasure();
}
else
{
// Clear the "need to measure/arrange again" flag
_childActualSize = Size.Empty;
}
//DiagnosticWriteLine(" _transformRoot.RenderSize = " + _transformRoot.RenderSize);
// Return result to perform the transformation
//DiagnosticWriteLine("ArrangeOverride > " + finalSize);
return finalSize;
}
/// <summary>
/// Compute the largest usable size (greatest area) after applying the transformation to the specified bounds.
/// </summary>
/// <param name="arrangeBounds">Arrange bounds.</param>
/// <returns>Largest Size possible.</returns>
[SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification = "Closely corresponds to WPF's FrameworkElement.FindMaximalAreaLocalSpaceRect.")]
private Size ComputeLargestTransformedSize(Size arrangeBounds)
{
//DiagnosticWriteLine(" ComputeLargestTransformedSize < " + arrangeBounds);
// Computed largest transformed size
Size computedSize = Size.Empty;
// Detect infinite bounds and constrain the scenario
bool infiniteWidth = double.IsInfinity(arrangeBounds.Width);
if (infiniteWidth)
{
arrangeBounds.Width = arrangeBounds.Height;
}
bool infiniteHeight = double.IsInfinity(arrangeBounds.Height);
if (infiniteHeight)
{
arrangeBounds.Height = arrangeBounds.Width;
}
// Capture the matrix parameters
double a = _transformation.M11;
double b = _transformation.M12;
double c = _transformation.M21;
double d = _transformation.M22;
// Compute maximum possible transformed width/height based on starting width/height
// These constraints define two lines in the positive x/y quadrant
double maxWidthFromWidth = Math.Abs(arrangeBounds.Width / a);
double maxHeightFromWidth = Math.Abs(arrangeBounds.Width / c);
double maxWidthFromHeight = Math.Abs(arrangeBounds.Height / b);
double maxHeightFromHeight = Math.Abs(arrangeBounds.Height / d);
// The transformed width/height that maximize the area under each segment is its midpoint
// At most one of the two midpoints will satisfy both constraints
double idealWidthFromWidth = maxWidthFromWidth / 2;
double idealHeightFromWidth = maxHeightFromWidth / 2;
double idealWidthFromHeight = maxWidthFromHeight / 2;
double idealHeightFromHeight = maxHeightFromHeight / 2;
// Compute slope of both constraint lines
double slopeFromWidth = -(maxHeightFromWidth / maxWidthFromWidth);
double slopeFromHeight = -(maxHeightFromHeight / maxWidthFromHeight);
if ((0 == arrangeBounds.Width) || (0 == arrangeBounds.Height))
{
// Check for empty bounds
computedSize = new Size(arrangeBounds.Width, arrangeBounds.Height);
}
else if (infiniteWidth && infiniteHeight)
{
// Check for completely unbound scenario
computedSize = new Size(double.PositiveInfinity, double.PositiveInfinity);
}
else if (!MatrixHasInverse(_transformation))
{
// Check for singular matrix
computedSize = new Size(0, 0);
}
else if ((0 == b) || (0 == c))
{
// Check for 0/180 degree special cases
double maxHeight = (infiniteHeight ? double.PositiveInfinity : maxHeightFromHeight);
double maxWidth = (infiniteWidth ? double.PositiveInfinity : maxWidthFromWidth);
if ((0 == b) && (0 == c))
{
// No constraints
computedSize = new Size(maxWidth, maxHeight);
}
else if (0 == b)
{
// Constrained by width
double computedHeight = Math.Min(idealHeightFromWidth, maxHeight);
computedSize = new Size(
maxWidth - Math.Abs((c * computedHeight) / a),
computedHeight);
}
else if (0 == c)
{
// Constrained by height
double computedWidth = Math.Min(idealWidthFromHeight, maxWidth);
computedSize = new Size(
computedWidth,
maxHeight - Math.Abs((b * computedWidth) / d));
}
}
else if ((0 == a) || (0 == d))
{
// Check for 90/270 degree special cases
double maxWidth = (infiniteHeight ? double.PositiveInfinity : maxWidthFromHeight);
double maxHeight = (infiniteWidth ? double.PositiveInfinity : maxHeightFromWidth);
if ((0 == a) && (0 == d))
{
// No constraints
computedSize = new Size(maxWidth, maxHeight);
}
else if (0 == a)
{
// Constrained by width
double computedHeight = Math.Min(idealHeightFromHeight, maxHeight);
computedSize = new Size(
maxWidth - Math.Abs((d * computedHeight) / b),
computedHeight);
}
else if (0 == d)
{
// Constrained by height
double computedWidth = Math.Min(idealWidthFromWidth, maxWidth);
computedSize = new Size(
computedWidth,
maxHeight - Math.Abs((a * computedWidth) / c));
}
}
else if (idealHeightFromWidth <= ((slopeFromHeight * idealWidthFromWidth) + maxHeightFromHeight))
{
// Check the width midpoint for viability (by being below the height constraint line)
computedSize = new Size(idealWidthFromWidth, idealHeightFromWidth);
}
else if (idealHeightFromHeight <= ((slopeFromWidth * idealWidthFromHeight) + maxHeightFromWidth))
{
// Check the height midpoint for viability (by being below the width constraint line)
computedSize = new Size(idealWidthFromHeight, idealHeightFromHeight);
}
else
{
// Neither midpoint is viable; use the intersection of the two constraint lines instead
// Compute width by setting heights equal (m1*x+c1=m2*x+c2)
double computedWidth = (maxHeightFromHeight - maxHeightFromWidth) / (slopeFromWidth - slopeFromHeight);
// Compute height from width constraint line (y=m*x+c; using height would give same result)
computedSize = new Size(
computedWidth,
(slopeFromWidth * computedWidth) + maxHeightFromWidth);
}
// Return result
//DiagnosticWriteLine(" ComputeLargestTransformedSize > " + computedSize);
return computedSize;
}
/// <summary>
/// Returns true if Size a is smaller than Size b in either dimension.
/// </summary>
/// <param name="a">Second Size.</param>
/// <param name="b">First Size.</param>
/// <returns>True if Size a is smaller than Size b in either dimension.</returns>
private static bool IsSizeSmaller(Size a, Size b)
{
// WPF equivalent of following code:
// return ((a.Width < b.Width) || (a.Height < b.Height));
return ((a.Width + AcceptableDelta < b.Width) || (a.Height + AcceptableDelta < b.Height));
}
/// <summary>
/// Rounds the non-offset elements of a Matrix to avoid issues due to floating point imprecision.
/// </summary>
/// <param name="matrix">Matrix to round.</param>
/// <param name="decimals">Number of decimal places to round to.</param>
/// <returns>Rounded Matrix.</returns>
private static Matrix RoundMatrix(Matrix matrix, int decimals)
{
return new Matrix(
Math.Round(matrix.M11, decimals),
Math.Round(matrix.M12, decimals),
Math.Round(matrix.M21, decimals),
Math.Round(matrix.M22, decimals),
matrix.OffsetX,
matrix.OffsetY);
}
/// <summary>
/// Implements WPF's Rect.Transform on Silverlight.
/// </summary>
/// <param name="rect">Rect to transform.</param>
/// <param name="matrix">Matrix to transform with.</param>
/// <returns>Bounding box of transformed Rect.</returns>
private static Rect RectTransform(Rect rect, Matrix matrix)
{
// WPF equivalent of following code:
// Rect rectTransformed = Rect.Transform(rect, matrix);
Point leftTop = matrix.Transform(new Point(rect.Left, rect.Top));
Point rightTop = matrix.Transform(new Point(rect.Right, rect.Top));
Point leftBottom = matrix.Transform(new Point(rect.Left, rect.Bottom));
Point rightBottom = matrix.Transform(new Point(rect.Right, rect.Bottom));
double left = Math.Min(Math.Min(leftTop.X, rightTop.X), Math.Min(leftBottom.X, rightBottom.X));
double top = Math.Min(Math.Min(leftTop.Y, rightTop.Y), Math.Min(leftBottom.Y, rightBottom.Y));
double right = Math.Max(Math.Max(leftTop.X, rightTop.X), Math.Max(leftBottom.X, rightBottom.X));
double bottom = Math.Max(Math.Max(leftTop.Y, rightTop.Y), Math.Max(leftBottom.Y, rightBottom.Y));
Rect rectTransformed = new Rect(left, top, right - left, bottom - top);
return rectTransformed;
}
/// <summary>
/// Implements WPF's Matrix.Multiply on Silverlight.
/// </summary>
/// <param name="matrix1">First matrix.</param>
/// <param name="matrix2">Second matrix.</param>
/// <returns>Multiplication result.</returns>
private static Matrix MatrixMultiply(Matrix matrix1, Matrix matrix2)
{
// WPF equivalent of following code:
// return Matrix.Multiply(matrix1, matrix2);
return new Matrix(
(matrix1.M11 * matrix2.M11) + (matrix1.M12 * matrix2.M21),
(matrix1.M11 * matrix2.M12) + (matrix1.M12 * matrix2.M22),
(matrix1.M21 * matrix2.M11) + (matrix1.M22 * matrix2.M21),
(matrix1.M21 * matrix2.M12) + (matrix1.M22 * matrix2.M22),
((matrix1.OffsetX * matrix2.M11) + (matrix1.OffsetY * matrix2.M21)) + matrix2.OffsetX,
((matrix1.OffsetX * matrix2.M12) + (matrix1.OffsetY * matrix2.M22)) + matrix2.OffsetY);
}
/// <summary>
/// Implements WPF's Matrix.HasInverse on Silverlight.
/// </summary>
/// <param name="matrix">Matrix to check for inverse.</param>
/// <returns>True if the Matrix has an inverse.</returns>
private static bool MatrixHasInverse(Matrix matrix)
{
// WPF equivalent of following code:
// return matrix.HasInverse;
return (0 != ((matrix.M11 * matrix.M22) - (matrix.M12 * matrix.M21)));
}
}
}
In the App.xaml file
Add namespace common
xmlns:common="using:Common"
create a new style inside of ApplicationResources
<Application.Resources>
<Style TargetType="common:LayoutTransformer">
<Setter Property="Foreground" Value="#FF000000"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="common:LayoutTransformer">
<Grid x:Name="TransformRoot" Background="{TemplateBinding Background}">
<ContentPresenter
x:Name="Presenter"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Application.Resources>
Now to rotate a textblock anticlockwise by 90 degrees
Add namespace common
xmlns:common="using:Common"
And use this code
<common:LayoutTransformer>
<common:LayoutTransformer.LayoutTransform>
<RotateTransform Angle="-90" />
</common:LayoutTransformer.LayoutTransform>
<TextBlock Text="CATEGORIES"
FontSize="30"/>
</common:LayoutTransformer>
If you rotate the Border (the parent), TextBlock will be rotated as well since it is the child of the Border.
<Border Height="80"
Background="Teal">
<Border.RenderTransform>
<RotateTransform Angle="-90" />
</Border.RenderTransform>
<TextBlock Text="CATEGORIES"
Foreground="White"
FontFamily="Segoe UI Black"
FontSize="30">
</TextBlock>
</Border>

Kinect joints angles

I am working in Kinect and I am trying to find the angels between joints, for example: the angle of elbow in Z and Y coordinated. i found this code for calculating angles in X and Y coordinate but It did not works well because i do not know what is the "rotational offset" is.
http://www.embedded101.com/Blogs/JamesYWilson/tabid/70/entryid/167/Default.aspx
I read about some codes that in stackoverflow such as the bellow but it did not works well and I did not understand how they did not ignore the z value.
/// <summary>
/// Return the angle between 3 Joints
/// Regresa el ángulo interno dadas 3 Joints
/// </summary>
/// <param name="j1"></param>
/// <param name="j2"></param>
/// <param name="j3"></param>
/// <returns></returns>
public static double AngleBetweenJoints(Joint j1, Joint j2, Joint j3)
{
double Angulo = 0;
double shrhX = j1.Position.X - j2.Position.X;
double shrhY = j1.Position.Y - j2.Position.Y;
double shrhZ = j1.Position.Z - j2.Position.Z;
double hsl = vectorNorm(shrhX, shrhY, shrhZ);
double unrhX = j3.Position.X - j2.Position.X;
double unrhY = j3.Position.Y - j2.Position.Y;
double unrhZ =j3.Position.Z - j2.Position.Z;
double hul = vectorNorm(unrhX, unrhY, unrhZ);
double mhshu = shrhX * unrhX + shrhY * unrhY + shrhZ * unrhZ;
double x = mhshu / (hul * hsl);
if (x != Double.NaN)
{
if (-1 <= x && x <= 1)
{
double angleRad = Math.Acos(x);
Angulo = angleRad *(180.0 / Math.PI);
}
else
Angulo = 0;
}
else
Angulo = 0;
return Angulo;
}
/// <summary>
/// Euclidean norm of 3-component Vector
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <param name="z"></param>
/// <returns></returns>
private static double vectorNorm(double x, double y, double z)
{
return Math.Sqrt(Math.Pow(x, 2) + Math.Pow(y, 2) + Math.Pow(z, 2));
}
pleas could someone help me in that
I found the method that i was looking for :)
public static double myMethodZY(Joint j1, Joint j2, Joint j3)
{
Vector3 a = new Vector3(0, j1.Position.Y- j2.Position.Y, j1.Position.Z- j2.Position.Z);
Vector3 b = new Vector3(0, j3.Position.Y - j2.Position.Y, j3.Position.Z - j2.Position.Z);
a.Normalize();
b.Normalize();
double dotProduct = Vector3.Dot(a,b);
double angle= Math.Acos(dotProduct);
angle = angle * 180 / Math.PI;
//angle = 180 - angle;
return angle;
}

Convert OSGB 36 co-ordinates to Latitude/Longitude

I want to convert British OSGB 36 co-ordinates to WGS 84 (i.e. "standard" latitude and longitude), in order to plot them into a KML file for Google Earth.
What would be the best way to go about this? I'm implementing in VB .NET.
I should probably add that my question is not "How do I write a KML file?". My question is "How do I convert between these 2 co-ordinate systems?"!!
I was hoping there would be a library that I could use, rather than rolling my own function - it seems like the sort of thing some-one else would have implemented.
The company I work for have just open sourced a library to do exactly this: http://code.google.com/p/geocoordconversion/
You need to implement a Helmert transformation. I wrote a conversion in Javascript which you may be able to adapt. The algorithm used by the script for WGS84-OSGB36 conversions is derived from an OSGB spreadsheet with permission. Conversion accuracy is in the order of 7m for 90% of Great Britain, and should be be similar to the conversion made by a typical GPS reciever.
See the documentation and source for more details.
Edit: you might like to check out this OCX which includes source.
First, according to this page linked from OSGB 36:
Myth 4: ‘There are exact mathematical formulae to change between coordinate systems’
Second, following from the same link: "From one coordinate system to another : geodetic transformations" includes a section "Approximate WGS84 to OSGB36/ODN transformation"
EDIT: Note, when OS says "approximate", they mean with errors >5m.
//=======================================================================
/* Project: Geocode.Service
* Author: Steve Loughran
* Copyright (C) 2000 Steve Loughran
* See license.txt or license.html for license and copyright information
* RCS $Header: /cvsroot/geocode/geocode.net/src/library/Osgb.cs,v 1.4 2002/04/23 05:12:37 steve_l Exp $
* jedit:mode=csharp:tabSize=4:indentSize=4:syntax=true:
*/
//=======================================================================
using System;
namespace net.sourceforge.geocode {
/// <summary>
/// OSGB conversion routines. xlated from C++ to Java to C#
/// </summary>
public class OsgbGridReference: GeoMath
{
private string _gridSquare="";
private long _easting=0;
private long _northing=0;
/// <summary>
/// empty constructor
/// </summary>
public OsgbGridReference() {}
/// <summary>
/// constructor from gridref
/// </summary>
public OsgbGridReference(String gridSquare,
long easting,
long northing) {
SetGridRef(gridSquare,northing,easting);
}
/// <summary>
/// constructor from co-ordinates
/// </summary>
public OsgbGridReference(double latitude, double longitude) {
SetPosition(latitude,longitude);
}
/// <summary>
/// constructor from position
/// </summary>
public OsgbGridReference(Position position)
: this(position.Latitude,position.Longitude) {
}
/// <summary>grid square property</summary>
public string GridSquare {
get {return _gridSquare;}
set {_gridSquare=value;}
}
/// <summary>northing property</summary>
public long Northing {
get {return _northing;}
set {_northing=value;}
}
/// <summary>easting property</summary>
public long Easting {
get {return _easting;}
set {_easting=value;}
}
/// <summary>
/// set the grid refernce
/// </summary>
/// <returns> </returns>
public void SetGridRef(String gridSquare,
long northing,
long easting) {
_gridSquare=gridSquare;
_northing=northing;
_easting=easting;
}
/// <summary>
/// rudimentary validity test. A better one is to
/// extract the position
/// </summary>
/// <returns>true iff there is a gridsquare </returns>
public bool IsValid()
{return _gridSquare.Length==2;}
/// <summary>
/// get a position object from a location
/// </summary>
/// <returns> Position </returns>
public Position ToPosition() {
double lat,lon;
ConvertOSGBtoLL(_gridSquare,_northing,_easting,
out lat, out lon);
Position p=new Position(lat,lon);
p.Name=ToString();
return p;
}
/// <summary>
/// set a gridref from a lat/long tuple
/// </summary>
/// <returns> success flag </returns>
public bool SetPosition(double latitude, double longitude) {
_gridSquare=ConvertLLtoOSGB(latitude,
longitude,
out _northing,
out _easting);
return IsValid();
}
/// <summary>
/// set a gridref from a position
/// </summary>
/// <returns> success flag </returns>
public bool SetPosition(Position position) {
return SetPosition(position.Latitude,position.Longitude);
}
/// <summary>
/// stringify
/// </summary>
public override string ToString() {
return String.Format("{0} {1:000} {2:000}",
_gridSquare,Easting,Northing);
}
/// <summary>
/// equality test: works on lat and long
/// </summary>
public override bool Equals(object o) {
OsgbGridReference pos=(OsgbGridReference)o;
return _gridSquare==pos._gridSquare &&
_northing==pos._northing &&
_easting==pos._easting;
}
/// <summary>
/// hash code builder
/// </summary>
public override int GetHashCode() {
return (int)(_easting+_northing);
}
/// <summary>
/// determines base co-ordinates of a square like "ST"
/// </summary>
/// <parameter name="OSGBGridSquare"> square </parameter>
/// <parameter name="easting"> easting</parameter>
/// <parameter name="northing"> northing</parameter>
/// <returns>true if the coordinates were in range</returns>
static bool ConvertOSGBSquareToRefCoords(string OSGBGridSquare,
out long easting,
out long northing) {
int pos, x_multiplier=0, y_multiplier=0;
string GridSquare = "VWXYZQRSTULMNOPFGHJKABCDE";
bool trouble=false;
long east,north;
easting=northing=0;
//find 500km offset
OSGBGridSquare=OSGBGridSquare.ToUpper();
char ch = OSGBGridSquare[0];
switch(ch) {
case 'S': x_multiplier = 0; y_multiplier = 0; break;
case 'T': x_multiplier = 1; y_multiplier = 0; break;
case 'N': x_multiplier = 0; y_multiplier = 1; break;
case 'O': x_multiplier = 1; y_multiplier = 1; break;
case 'H': x_multiplier = 0; y_multiplier = 2; break;
case 'J': x_multiplier = 1; y_multiplier = 2; break;
default: trouble=true; break;
}
if(!trouble) {
east=x_multiplier * 500000L;
north=y_multiplier * 500000L;
//find 100km offset and add to 500km offset to get coordinate of
//square point is in
char subsquare=OSGBGridSquare[1];
pos = GridSquare.IndexOf(subsquare);
if(pos>-1) {
east += ((pos % 5) * 100000L);
north += ((pos / 5) * 100000L);
easting=east;
northing=north;
}
else {
trouble=true;
}
}
return !trouble;
}
///<summary>
///convert a internal OSGB coord to lat/long
///Equations from USGS Bulletin 1532
///East Longitudes are positive, West longitudes are negative.
///North latitudes are positive, South latitudes are negative
///Lat and Long are in decimal degrees.
///Written by Chuck Gantz- chuck.gantz#globalstar.com
///</summary>
/// <parameter name="OSGBEasting">easting </parameter>
/// <parameter name="OSGBEasting">northing </parameter>
/// <parameter name="OSGBZone"> gridsquare</parameter>
/// <parameter name="latitude"> latitude</parameter>
/// <parameter name="longitude"> longitude</parameter>
static void ConvertOSGBtoLL(string OSGBZone,
double OSGBNorthing,
double OSGBEasting,
out double latitude,
out double longitude) {
double k0 = 0.9996012717;
double a;
double eccPrimeSquared;
double N1, T1, C1, R1, D, M;
double LongOrigin = -2;
double LatOrigin = 49;
double LatOriginRad = LatOrigin * deg2rad;
double mu, phi1, phi1Rad;
double x, y;
long northing;
long easting;
//Airy model of the ellipsoid.
double majoraxis = a = 6377563.396;
double minoraxis = 6356256.91;
double eccSquared = (majoraxis * majoraxis - minoraxis * minoraxis) /
(majoraxis * majoraxis);
double e1 = (1-sqrt(1-eccSquared))/(1+sqrt(1-eccSquared));
//only calculate M0 once since it is based on the origin of the OSGB projection, which is fixed
double M0 = a*((1 - eccSquared/4 - 3*eccSquared*eccSquared/64 - 5*eccSquared*eccSquared*eccSquared/256)*LatOriginRad
- (3*eccSquared/8 + 3*eccSquared*eccSquared/32 + 45*eccSquared*eccSquared*eccSquared/1024)*sin(2*LatOriginRad)
+ (15*eccSquared*eccSquared/256 + 45*eccSquared*eccSquared*eccSquared/1024)*sin(4*LatOriginRad)
- (35*eccSquared*eccSquared*eccSquared/3072)*sin(6*LatOriginRad));
ConvertOSGBSquareToRefCoords(OSGBZone, out easting, out northing);
//remove 400,000 meter false easting for longitude
x = OSGBEasting - 400000.0 + easting;
//remove 100,000 meter false easting for longitude
y = OSGBNorthing + 100000.0 + northing;
eccPrimeSquared = (eccSquared)/(1-eccSquared);
M = M0 + y / k0;
mu = M/(a*(1-eccSquared/4-3*eccSquared*eccSquared/
64-5*eccSquared*eccSquared*eccSquared/256));
phi1Rad = mu + (3*e1/2-27*e1*e1*e1/32)*sin(2*mu)
+ (21*e1*e1/16-55*e1*e1*e1*e1/32)*sin(4*mu)
+(151*e1*e1*e1/96)*sin(6*mu);
phi1 = phi1Rad*rad2deg;
N1 = a/sqrt(1-eccSquared*sin(phi1Rad)*sin(phi1Rad));
T1 = tan(phi1Rad)*tan(phi1Rad);
C1 = eccPrimeSquared*cos(phi1Rad)*cos(phi1Rad);
R1 = a*(1-eccSquared)/pow(1-eccSquared*sin(phi1Rad)*sin(phi1Rad), 1.5);
D = x/(N1*k0);
latitude = phi1Rad - (N1*tan(phi1Rad)/R1)*(D*D/2-(5+3*T1+10*C1-4*C1*C1-9*eccPrimeSquared)*D*D*D*D/24
+(61+90*T1+298*C1+45*T1*T1-252*eccPrimeSquared-3*C1*C1)*D*D*D*D*D*D/720);
latitude *= rad2deg;
longitude = (D-(1+2*T1+C1)*D*D*D/6+(5-2*C1+28*T1-3*C1*C1+8*eccPrimeSquared+24*T1*T1)
*D*D*D*D*D/120)/cos(phi1Rad);
longitude = LongOrigin + longitude * rad2deg;
}
/// <summary>
/// converts lat/long to OSGB coords. Equations from USGS Bulletin 1532
/// East Longitudes are positive, West longitudes are negative.
/// North latitudes are positive, South latitudes are negative
/// Lat and Long are in decimal degrees
/// </summary>
/// Written by Chuck Gantz- chuck.gantz#globalstar.com
/// <parameter name="latitude"> IN latitude</parameter>
/// <parameter name="longitude">IN longitude </parameter>
/// <parameter name="OSGBEasting"> OUT easting</parameter>
/// <parameter name="OSGBNorthing"> OUT northing</parameter>
static public string ConvertLLtoOSGB(double latitude,
double longitude,
out long OSGBNorthing,
out long OSGBEasting) {
double a;
double eccSquared;
double k0 = 0.9996012717;
double LongOrigin = -2;
double LongOriginRad = LongOrigin * deg2rad;
double LatOrigin = 49;
double LatOriginRad = LatOrigin * deg2rad;
double eccPrimeSquared;
double N, T, C, A, M;
double LatRad = latitude*deg2rad;
double LongRad = longitude*deg2rad;
double easting, northing;
double majoraxis = a = 6377563.396;//Airy
double minoraxis = 6356256.91;//Airy
eccSquared = (majoraxis * majoraxis - minoraxis * minoraxis) /
(majoraxis * majoraxis);
//only calculate M0 once since it is based on the origin
//of the OSGB projection, which is fixed
double M0 = a*((1 - eccSquared/4 - 3*eccSquared*eccSquared/64 - 5*eccSquared*eccSquared*eccSquared/256)*LatOriginRad
- (3*eccSquared/8 + 3*eccSquared*eccSquared/32 + 45*eccSquared*eccSquared*eccSquared/1024)*sin(2*LatOriginRad)
+ (15*eccSquared*eccSquared/256 + 45*eccSquared*eccSquared*eccSquared/1024)*sin(4*LatOriginRad)
- (35*eccSquared*eccSquared*eccSquared/3072)*sin(6*LatOriginRad));
eccPrimeSquared = (eccSquared)/(1-eccSquared);
N = a/sqrt(1-eccSquared*sin(LatRad)*sin(LatRad));
T = tan(LatRad)*tan(LatRad);
C = eccPrimeSquared*cos(LatRad)*cos(LatRad);
A = cos(LatRad)*(LongRad-LongOriginRad);
M = a*((1 - eccSquared/4 - 3*eccSquared*eccSquared/64- 5*eccSquared*eccSquared*eccSquared/256)*LatRad
- (3*eccSquared/8 + 3*eccSquared*eccSquared/32 + 45*eccSquared*eccSquared*eccSquared/1024)*sin(2*LatRad)
+ (15*eccSquared*eccSquared/256 + 45*eccSquared*eccSquared*eccSquared/1024)*sin(4*LatRad)
- (35*eccSquared*eccSquared*eccSquared/3072)*sin(6*LatRad));
easting = (double)(k0*N*(A+(1-T+C)*A*A*A/6
+ (5-18*T+T*T+72*C-58*eccPrimeSquared)*A*A*A*A*A/120));
easting += 400000.0; //false easting
northing = (double)(k0*(M-M0+N*tan(LatRad)*(A*A/2+(5-T+9*C+4*C*C)*A*A*A*A/24
+ (61-58*T+T*T+600*C-330*eccPrimeSquared)*A*A*A*A*A*A/720)));
northing -= 100000.0;//false northing
return ConvertCoordsToOSGBSquare(easting, northing,out OSGBEasting, out OSGBNorthing);
}
/// <summary>
/// convert a internal OSGB coord to a gridsquare and internal values.
/// </summary>
/// <parameter name="easting"> easting</parameter>
/// <parameter name="northing"> northing</parameter>
/// <parameter name="OSGBEasting">OSGBEasting out </parameter>
/// <parameter name="OSGBNorthing">OSGBNorthing out </parameter>
static string ConvertCoordsToOSGBSquare(double easting,
double northing,
out long OSGBEasting,
out long OSGBNorthing)
{
string GridSquare = "VWXYZQRSTULMNOPFGHJKABCDE";
long posx, posy; //positions in grid
OSGBEasting = (long)(easting + 0.5); //round to nearest int
OSGBNorthing = (long)(northing + 0.5); //round to nearest int
string OSGBGridSquare="";
//find correct 500km square
posx = OSGBEasting / 500000L;
posy = OSGBNorthing / 500000L;
if(posx<0 || posx>4 || posy<0 || posy>4)
return "";
long offset=posx + posy * 5 + 7;
OSGBGridSquare+= GridSquare[(int)offset];
//find correct 100km square
posx = OSGBEasting % 500000L;//remove 500 km square
posy = OSGBNorthing % 500000L;//remove 500 km square
posx = posx / 100000L;//find 100 km square
posy = posy / 100000L;//find 100 km square
if(posx<0 || posx>4 || posy<0 || posy>4)
return "";
offset=posx + posy * 5;
OSGBGridSquare+= GridSquare[(int)offset];
//remainder is northing and easting
OSGBNorthing = OSGBNorthing % 500000L;
OSGBNorthing = OSGBNorthing % 100000L;
OSGBEasting = OSGBEasting % 500000L;
OSGBEasting = OSGBEasting % 100000L;
return OSGBGridSquare;
}
/// <summary>
/// turn the latitude and longitude into a string
/// </summary>
/// <parameter name="latitude"> lat</parameter>
/// <parameter name="longitude"> long</parameter>
/// <parameter name="infill"> text between coordinates</parameter>
/// <returns>return something like E004 N123</returns>
static string GetSensibleLatLongstring(double latitude,
double longitude,
int decimals,
string infill) {
bool bNorth=latitude>=0;
bool bWest=longitude<=0;
latitude=Math.Abs(latitude);
longitude=Math.Abs(longitude);
double multiplier=(int)pow(10,decimals);
int hiLat=(int)latitude;
int lowLat=(int)((latitude-hiLat)*multiplier);
double newLat=lowLat/multiplier+hiLat;
int hiLong=(int)longitude;
int lowLong=(int)((longitude-hiLong)*multiplier);
double newLong=lowLong/multiplier+hiLong;
return (bNorth?"N":"S")+newLat+infill+
(bWest?"W":"E")+newLong;
}
/* legacy java test harness
public static void main(string[] args)
{
string message;
if(args.length!=3)
{
message="need a grid reference like ST 767 870";
}
else
{
LongRef north=new LongRef();
LongRef east=new LongRef();
bool b=ConvertOSGBSquareToRefCoords(args[0],east,north);
double easting=Double.valueOf(args[1]).doubleValue();
double northing=Double.valueOf(args[2]).doubleValue();
DoubleRef rlatitude=new DoubleRef ();
DoubleRef rlongitude=new DoubleRef ();
OSGBtoLL(easting,northing,args[0],rlatitude,rlongitude);
double latitude=rlatitude.getValue();
double longitude=rlongitude.getValue();
bool bNorth=latitude>=0;
bool bWest=longitude<=0;
message="Latitude & Longitude ="+latitude+" , " + longitude;
message+="\r\n or "+GetSensibleLatLongstring(latitude,
longitude,
3,
" ");
string square=new string();
square=LLtoOSGB(latitude,longitude,north,east);
message+="\r\n Grid ="+square+" "+east+" "+north;
// message="evaluation failure on "+args[0];
}
System.out.print(message);
}
*/
}; //class
};//namespace
We use proj.4 library for WGS84 <-> OSGB36 <-> OSGBGRID coordinate transformations and it works very well. But we use C++ so I don't know if you can get it to work under VB.NET. There may be wrappers or something? (On the link above it mentions PROJ.4 VB Wrappers).

CPU Emulation and locking to a specific clock speed

If you had read my other question, you'll know I've spent this weekend putting together a 6502 CPU emulator as a programming exercise.
The CPU emulator is mostly complete, and seems to be fairly accurate from my limited testing, however it is running incredibly fast, and I want to throttle it down to the actual clock speed of the machine.
My current test loop is this:
// Just loop infinitely.
while (1 == 1)
{
CPU.ClockCyclesBeforeNext--;
if (CPU.ClockCyclesBeforeNext <= 0)
{
// Find out how many clock cycles this instruction will take
CPU.ClockCyclesBeforeNext = CPU.OpcodeMapper.Map[CPU.Memory[CPU.PC]].CpuCycles;
// Run the instruction
CPU.ExecuteInstruction(CPU.Memory[CPU.PC]);
// Debugging Info
CPU.DumpDebug();
Console.WriteLine(CPU.OpcodeMapper.Map[CPU.Memory[CPU.PC]].ArgumentLength);
// Move to next instruction
CPU.PC += 1 + CPU.OpcodeMapper.Map[CPU.Memory[CPU.PC]].ArgumentLength;
}
}
As you can tell, each opcode takes a specific amount of time to complete, so I do not run the next instruction until I count down the CPU Cycle clock. This provides proper timing between opcodes, its just that the entire thing runs way to fast.
The targeted CPU speed is 1.79mhz, however I'd like whatever solution to the clock issue to keep the speed at 1.79mhz even as I add complexity, so I don't have to adjust it up.
Any ideas?
I wrote a Z80 emulator many years ago, and to do cycle accurate execution, I divided the clock rate into a number of small blocks and had the core execute that many clock cycles. In my case, I tied it to the frame rate of the game system I was emulating. Each opcode knew how many cycles it took to execute and the core would keep running opcodes until the specified number of cycles had been executed. I had an outer run loop that would run the cpu core, and run other parts of the emulated system and then sleep until the start time of the next iteration.
EDIT: Adding example of run loop.
int execute_run_loop( int cycles )
{
int n = 0;
while( n < cycles )
{
/* Returns number of cycles executed */
n += execute_next_opcode();
}
return n;
}
Hope this helps.
Take a look at the original quicktime documentation for inspiration.
It was written a long time ago, when displaying video meant just swapping still frames at high enough speed, but the Apple guys decided they needed a full time-management framework. The design at first looks overengineered, but it let them deal with widely different speed requirements and keep them tightly synchronized.
you're fortunate that 6502 has deterministic time behaviour, the exact time each instruction takes is well documented; but it's not constant. some instructions take 2 cycles, other 3. Just like frames in QuickTime, a video doesn't have a 'frames per second' parameter, each frame tells how long it wants to be in screen.
Since modern CPU's are so non-deterministic, and multitasking OS's can even freeze for a few miliseconds (virtual memory!), you should keep a tab if you're behind schedule, or if you can take a few microseconds nap.
As jfk says, the most common way to do this is tie the cpu speed to the vertical refresh of the (emulated) video output.
Pick a number of cycles to run per video frame. This will often be machine-specific but you can calculate it by something like :
cycles = clock speed in Hz / required frames-per-second
Then you also get to do a sleep until the video update is hit, at which point you start the next n cycles of CPU emulation.
If you're emulating something in particular then you just need to look up the fps rate and processor speed to get this approximately right.
EDIT: If you don't have any external timing requirements then it is normal for an emulator to just run as fast as it possibly can. Sometimes this is a desired effect and sometimes not :)
I would use the clock cycles to calculate time and them sleep the difference in time. Of course, to do this, you need a high-resolution clock. They way you are doing it is going to spike the CPU in spinning loops.
Yes, as said before most of the time you don't need a CPU emulator to emulate instructions at the same speed of the real thing. What user perceive is the output of the computation (i.e. audio and video outputs) so you only need to be in sync with such outputs which doesn't mean you must have necessarily an exact CPU emulation speed.
In other words, if the frame rate of the video input is, let's say, 50Hz, then let the CPU emulator run as fast as it can to draw the screen but be sure to output the screen frames at the correct rate (50Hz). From an external point of view your emulator is emulating at the correct speed.
Trying to be cycle exact even in the execution time is a non-sense on a multi-tasking OS like Windows or Linux because the emulator instruction time (tipically 1uS for vintage 80s CPUs) and the scheduling time slot of the modern OS are comparable.
Trying to output something at a 50Hz rate is a much simpler task you can do very good on any modern machine
Another option is available if audio emulation is implemented, and if audio output is tied to the system/CPU clock. In particular I know that this is the case with the 8-bit Apple ][ computers.
Usually sound is generated in buffers of a fixed size (which is a fixed time), so operation (generation of data etc) of these buffers can be tied to CPU throughput via synchronization primitives.
I am in the process of making something a little more general use case based, such as the ability to convert time to an estimated amount of instructions and vice versa.
The project homepage is # http://net7mma.codeplex.com
The code starts like this: (I think)
#region Copyright
/*
This file came from Managed Media Aggregation, You can always find the latest version # https://net7mma.codeplex.com/
Julius.Friedman#gmail.com / (SR. Software Engineer ASTI Transportation Inc. http://www.asti-trans.com)
Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction,
* including without limitation the rights to :
* use,
* copy,
* modify,
* merge,
* publish,
* distribute,
* sublicense,
* and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
*
* JuliusFriedman#gmail.com should be contacted for further details.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
*
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE,
* ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* v//
*/
#endregion
namespace Media.Concepts.Classes
{
//Windows.Media.Clock has a fairly complex but complete API
/// <summary>
/// Provides a clock with a given offset and calendar.
/// </summary>
public class Clock : Media.Common.BaseDisposable
{
static bool GC = false;
#region Fields
/// <summary>
/// Indicates when the clock was created
/// </summary>
public readonly System.DateTimeOffset Created;
/// <summary>
/// The calendar system of the clock
/// </summary>
public readonly System.Globalization.Calendar Calendar;
/// <summary>
/// The amount of ticks which occur per update of the <see cref="System.Environment.TickCount"/> member.
/// </summary>
public readonly long TicksPerUpdate;
/// <summary>
/// The amount of instructions which occured when synchronizing with the system clock.
/// </summary>
public readonly long InstructionsPerClockUpdate;
#endregion
#region Properties
/// <summary>
/// The TimeZone offset of the clock from UTC
/// </summary>
public System.TimeSpan Offset { get { return Created.Offset; } }
/// <summary>
/// The average amount of operations per tick.
/// </summary>
public long AverageOperationsPerTick { get { return InstructionsPerClockUpdate / TicksPerUpdate; } }
/// <summary>
/// The <see cref="System.TimeSpan"/> which represents <see cref="TicksPerUpdate"/> as an amount of time.
/// </summary>
public System.TimeSpan SystemClockResolution { get { return System.TimeSpan.FromTicks(TicksPerUpdate); } }
/// <summary>
/// Return the current system time in the TimeZone offset of this clock
/// </summary>
public System.DateTimeOffset Now { get { return System.DateTimeOffset.Now.ToOffset(Offset).Add(new System.TimeSpan((long)(AverageOperationsPerTick / System.TimeSpan.TicksPerMillisecond))); } }
/// <summary>
/// Return the current system time in the TimeZone offset of this clock converter to UniversalTime.
/// </summary>
public System.DateTimeOffset UtcNow { get { return Now.ToUniversalTime(); } }
//public bool IsUtc { get { return Offset == System.TimeSpan.Zero; } }
//public bool IsDaylightSavingTime { get { return Created.LocalDateTime.IsDaylightSavingTime(); } }
#endregion
#region Constructor
/// <summary>
/// Creates a clock using the system's current timezone and calendar.
/// The system clock is profiled to determine it's accuracy
/// <see cref="System.DateTimeOffset.Now.Offset"/>
/// <see cref="System.Globalization.CultureInfo.CurrentCulture.Calendar"/>
/// </summary>
public Clock(bool shouldDispose = true)
: this(System.DateTimeOffset.Now.Offset, System.Globalization.CultureInfo.CurrentCulture.Calendar, shouldDispose)
{
try { if (false == GC && System.Runtime.GCSettings.LatencyMode != System.Runtime.GCLatencyMode.NoGCRegion) GC = System.GC.TryStartNoGCRegion(0); }
catch { }
finally
{
System.Threading.Thread.BeginCriticalRegion();
//Sample the TickCount
long ticksStart = System.Environment.TickCount,
ticksEnd;
//Continually sample the TickCount. while the value has not changed increment InstructionsPerClockUpdate
while ((ticksEnd = System.Environment.TickCount) == ticksStart) ++InstructionsPerClockUpdate; //+= 4; Read,Assign,Compare,Increment
//How many ticks occur per update of TickCount
TicksPerUpdate = ticksEnd - ticksStart;
System.Threading.Thread.EndCriticalRegion();
}
}
/// <summary>
/// Constructs a new clock using the given TimeZone offset and Calendar system
/// </summary>
/// <param name="timeZoneOffset"></param>
/// <param name="calendar"></param>
/// <param name="shouldDispose">Indicates if the instace should be diposed when Dispose is called.</param>
public Clock(System.TimeSpan timeZoneOffset, System.Globalization.Calendar calendar, bool shouldDispose = true)
{
//Allow disposal
ShouldDispose = shouldDispose;
Calendar = System.Globalization.CultureInfo.CurrentCulture.Calendar;
Created = new System.DateTimeOffset(System.DateTime.Now, timeZoneOffset);
}
#endregion
#region Overrides
public override void Dispose()
{
if (false == ShouldDispose) return;
base.Dispose();
try
{
if (System.Runtime.GCSettings.LatencyMode == System.Runtime.GCLatencyMode.NoGCRegion)
{
System.GC.EndNoGCRegion();
GC = false;
}
}
catch { }
}
#endregion
//Methods or statics for OperationCountToTimeSpan? (Estimate)
public void NanoSleep(int nanos)
{
Clock.NanoSleep((long)nanos);
}
public static void NanoSleep(long nanos)
{
System.Threading.Thread.BeginCriticalRegion();
NanoSleep(ref nanos);
System.Threading.Thread.EndCriticalRegion();
}
static void NanoSleep(ref long nanos)
{
try
{
unchecked
{
while (Common.Binary.Clamp(--nanos, 0, 1) >= 2)
{
/* if(--nanos % 2 == 0) */
NanoSleep(long.MinValue); //nanos -= 1 + (ops / (ulong)AverageOperationsPerTick);// *10;
}
}
}
catch
{
return;
}
}
}
}
Once you have some type of layman clock implementation you advance to something like a Timer
/// <summary>
/// Provides a Timer implementation which can be used across all platforms and does not rely on the existing Timer implementation.
/// </summary>
public class Timer : Common.BaseDisposable
{
readonly System.Threading.Thread m_Counter; // m_Consumer, m_Producer
internal System.TimeSpan m_Frequency;
internal ulong m_Ops = 0, m_Ticks = 0;
bool m_Enabled;
internal System.DateTimeOffset m_Started;
public delegate void TickEvent(ref long ticks);
public event TickEvent Tick;
public bool Enabled { get { return m_Enabled; } set { m_Enabled = value; } }
public System.TimeSpan Frequency { get { return m_Frequency; } }
internal ulong m_Bias;
//
//Could just use a single int, 32 bits is more than enough.
//uint m_Flags;
//
readonly internal Clock m_Clock = new Clock();
readonly internal System.Collections.Generic.Queue<long> Producer;
void Count()
{
System.Threading.Thread Event = new System.Threading.Thread(new System.Threading.ThreadStart(() =>
{
System.Threading.Thread.BeginCriticalRegion();
long sample;
AfterSample:
try
{
Top:
System.Threading.Thread.CurrentThread.Priority = System.Threading.ThreadPriority.Highest;
while (m_Enabled && Producer.Count >= 1)
{
sample = Producer.Dequeue();
Tick(ref sample);
}
System.Threading.Thread.CurrentThread.Priority = System.Threading.ThreadPriority.Lowest;
if (false == m_Enabled) return;
while (m_Enabled && Producer.Count == 0) if(m_Counter.IsAlive) m_Counter.Join(0); //++m_Ops;
goto Top;
}
catch { if (false == m_Enabled) return; goto AfterSample; }
finally { System.Threading.Thread.EndCriticalRegion(); }
}))
{
IsBackground = false,
Priority = System.Threading.ThreadPriority.AboveNormal
};
Event.TrySetApartmentState(System.Threading.ApartmentState.MTA);
Event.Start();
Approximate:
ulong approximate = (ulong)Common.Binary.Clamp((m_Clock.AverageOperationsPerTick / (Frequency.Ticks + 1)), 1, ulong.MaxValue);
try
{
m_Started = m_Clock.Now;
System.Threading.Thread.BeginCriticalRegion();
unchecked
{
Start:
if (IsDisposed) return;
switch (++m_Ops)
{
default:
{
if (m_Bias + ++m_Ops >= approximate)
{
System.Threading.Thread.CurrentThread.Priority = System.Threading.ThreadPriority.Highest;
Producer.Enqueue((long)m_Ticks++);
ulong x = ++m_Ops / approximate;
while (1 > --x /*&& Producer.Count <= m_Frequency.Ticks*/) Producer.Enqueue((long)++m_Ticks);
m_Ops = (++m_Ops * m_Ticks) - (m_Bias = ++m_Ops / approximate);
System.Threading.Thread.CurrentThread.Priority = System.Threading.ThreadPriority.Lowest;
}
if(Event != null) Event.Join(m_Frequency);
goto Start;
}
}
}
}
catch (System.Threading.ThreadAbortException) { if (m_Enabled) goto Approximate; System.Threading.Thread.ResetAbort(); }
catch (System.OutOfMemoryException) { if ((ulong)Producer.Count > approximate) Producer.Clear(); if (m_Enabled) goto Approximate; }
catch { if (m_Enabled) goto Approximate; }
finally
{
Event = null;
System.Threading.Thread.EndCriticalRegion();
}
}
public Timer(System.TimeSpan frequency)
{
Producer = new System.Collections.Generic.Queue<long>((int)(m_Frequency = frequency).Ticks * 10);
m_Counter = new System.Threading.Thread(new System.Threading.ThreadStart(Count))
{
IsBackground = false,
Priority = System.Threading.ThreadPriority.AboveNormal
};
m_Counter.TrySetApartmentState(System.Threading.ApartmentState.MTA);
Tick = delegate { m_Ops += 1 + m_Bias; };
}
public void Start()
{
if (m_Enabled) return;
m_Enabled = true;
m_Counter.Start();
var p = System.Threading.Thread.CurrentThread.Priority;
System.Threading.Thread.CurrentThread.Priority = System.Threading.ThreadPriority.Lowest;
while (m_Ops == 0) m_Counter.Join(0); //m_Clock.NanoSleep(0);
System.Threading.Thread.CurrentThread.Priority = p;
}
public void Stop()
{
m_Enabled = false;
}
void Change(System.TimeSpan interval, System.TimeSpan dueTime)
{
m_Enabled = false;
m_Frequency = interval;
m_Enabled = true;
}
delegate void ElapsedEvent(object sender, object args);
public override void Dispose()
{
if (IsDisposed) return;
base.Dispose();
Stop();
try { m_Counter.Abort(m_Frequency); }
catch (System.Threading.ThreadAbortException) { System.Threading.Thread.ResetAbort(); }
catch { }
Tick = null;
//Producer.Clear();
}
}
Then you can really replicate some logic using something like
/// <summary>
/// Provides a completely managed implementation of <see cref="System.Diagnostics.Stopwatch"/> which expresses time in the same units as <see cref="System.TimeSpan"/>.
/// </summary>
public class Stopwatch : Common.BaseDisposable
{
internal Timer Timer;
long Units;
public bool Enabled { get { return Timer != null && Timer.Enabled; } }
public double ElapsedMicroseconds { get { return Units * Media.Common.Extensions.TimeSpan.TimeSpanExtensions.TotalMicroseconds(Timer.Frequency); } }
public double ElapsedMilliseconds { get { return Units * Timer.Frequency.TotalMilliseconds; } }
public double ElapsedSeconds { get { return Units * Timer.Frequency.TotalSeconds; } }
//public System.TimeSpan Elapsed { get { return System.TimeSpan.FromMilliseconds(ElapsedMilliseconds / System.TimeSpan.TicksPerMillisecond); } }
public System.TimeSpan Elapsed
{
get
{
switch (Units)
{
case 0: return System.TimeSpan.Zero;
default:
{
System.TimeSpan taken = System.DateTime.UtcNow - Timer.m_Started;
return taken.Add(new System.TimeSpan(Units * Timer.Frequency.Ticks));
//System.TimeSpan additional = new System.TimeSpan(Media.Common.Extensions.Math.MathExtensions.Clamp(Units, 0, Timer.Frequency.Ticks));
//return taken.Add(additional);
}
}
//////The maximum amount of times the timer can elapse in the given frequency
////double maxCount = (taken.TotalMilliseconds / Timer.Frequency.TotalMilliseconds) / ElapsedMilliseconds;
////if (Units > maxCount)
////{
//// //How many more times the event was fired than needed
//// double overage = (maxCount - Units);
//// additional = new System.TimeSpan(System.Convert.ToInt64(Media.Common.Extensions.Math.MathExtensions.Clamp(Units, overage, maxCount)));
//// //return taken.Add(new System.TimeSpan((long)Media.Common.Extensions.Math.MathExtensions.Clamp(Units, overage, maxCount)));
////}
//////return taken.Add(new System.TimeSpan(Units));
}
}
public void Start()
{
if (Enabled) return;
Units = 0;
//Create a Timer that will elapse every OneTick //`OneMicrosecond`
Timer = new Timer(Media.Common.Extensions.TimeSpan.TimeSpanExtensions.OneTick);
//Handle the event by incrementing count
Timer.Tick += Count;
Timer.Start();
}
public void Stop()
{
if (false == Enabled) return;
Timer.Stop();
Timer.Dispose();
}
void Count(ref long count) { ++Units; }
}
Finally, create something semi useful e.g. a Bus and then perhaps a virtual screen to emit data to the bus...
public abstract class Bus : Common.CommonDisposable
{
public readonly Timer Clock = new Timer(Common.Extensions.TimeSpan.TimeSpanExtensions.OneTick);
public Bus() : base(false) { Clock.Start(); }
}
public class ClockedBus : Bus
{
long FrequencyHz, Maximum, End;
readonly Queue<byte[]> Input = new Queue<byte[]>(), Output = new Queue<byte[]>();
readonly double m_Bias;
public ClockedBus(long frequencyHz, double bias = 1.5)
{
m_Bias = bias;
cache = Clock.m_Clock.InstructionsPerClockUpdate / 1000;
SetFrequency(frequencyHz);
Clock.Tick += Clock_Tick;
Clock.Start();
}
public void SetFrequency(long frequencyHz)
{
FrequencyHz = frequencyHz;
//Clock.m_Frequency = new TimeSpan(Clock.m_Clock.InstructionsPerClockUpdate / 1000);
//Maximum = System.TimeSpan.TicksPerSecond / Clock.m_Clock.InstructionsPerClockUpdate;
//Maximum = Clock.m_Clock.InstructionsPerClockUpdate / System.TimeSpan.TicksPerSecond;
Maximum = cache / (cache / FrequencyHz);
Maximum *= System.TimeSpan.TicksPerSecond;
Maximum = (cache / FrequencyHz);
End = Maximum * 2;
Clock.m_Frequency = new TimeSpan(Maximum);
if (cache < frequencyHz * m_Bias) throw new Exception("Cannot obtain stable clock");
Clock.Producer.Clear();
}
public override void Dispose()
{
ShouldDispose = true;
Clock.Tick -= Clock_Tick;
Clock.Stop();
Clock.Dispose();
base.Dispose();
}
~ClockedBus() { Dispose(); }
long sample = 0, steps = 0, count = 0, avg = 0, cache = 1;
void Clock_Tick(ref long ticks)
{
if (ShouldDispose == false && false == IsDisposed)
{
//Console.WriteLine("#ops=>" + Clock.m_Ops + " #ticks=>" + Clock.m_Ticks + " #Lticks=>" + ticks + "#=>" + Clock.m_Clock.Now.TimeOfDay + "#=>" + (Clock.m_Clock.Now - Clock.m_Clock.Created));
steps = sample;
sample = ticks;
++count;
System.ConsoleColor f = System.Console.ForegroundColor;
if (count <= Maximum)
{
System.Console.BackgroundColor = ConsoleColor.Yellow;
System.Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("count=> " + count + "#=>" + Clock.m_Clock.Now.TimeOfDay + "#=>" + (Clock.m_Clock.Now - Clock.m_Clock.Created) + " - " + DateTime.UtcNow.ToString("MM/dd/yyyy hh:mm:ss.ffffff tt"));
avg = Maximum / count;
if (Clock.m_Clock.InstructionsPerClockUpdate / count > Maximum)
{
System.Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("---- Over InstructionsPerClockUpdate ----" + FrequencyHz);
}
}
else if (count >= End)
{
System.Console.BackgroundColor = ConsoleColor.Black;
System.Console.ForegroundColor = ConsoleColor.Blue;
avg = Maximum / count;
Console.WriteLine("avg=> " + avg + "#=>" + FrequencyHz);
count = 0;
}
}
}
//Read, Write at Frequency
}
public class VirtualScreen
{
TimeSpan RefreshRate;
bool VerticalSync;
int Width, Height;
Common.MemorySegment DisplayMemory, BackBuffer, DisplayBuffer;
}
Here is how I tested the StopWatch
internal class StopWatchTests
{
public void TestForOneMicrosecond()
{
System.Collections.Generic.List<System.Tuple<bool, System.TimeSpan, System.TimeSpan>> l = new System.Collections.Generic.List<System.Tuple<bool, System.TimeSpan, System.TimeSpan>>();
//Create a Timer that will elapse every `OneMicrosecond`
for (int i = 0; i <= 250; ++i) using (Media.Concepts.Classes.Stopwatch sw = new Media.Concepts.Classes.Stopwatch())
{
var started = System.DateTime.UtcNow;
System.Console.WriteLine("Started: " + started.ToString("MM/dd/yyyy hh:mm:ss.ffffff tt"));
//Define some amount of time
System.TimeSpan sleepTime = Media.Common.Extensions.TimeSpan.TimeSpanExtensions.OneMicrosecond;
System.Diagnostics.Stopwatch testSw = new System.Diagnostics.Stopwatch();
//Start
testSw.Start();
//Start
sw.Start();
while (testSw.Elapsed.Ticks < sleepTime.Ticks - (Common.Extensions.TimeSpan.TimeSpanExtensions.OneTick + Common.Extensions.TimeSpan.TimeSpanExtensions.OneTick).Ticks)
sw.Timer.m_Clock.NanoSleep(0); //System.Threading.Thread.SpinWait(0);
//Sleep the desired amount
//System.Threading.Thread.Sleep(sleepTime);
//Stop
testSw.Stop();
//Stop
sw.Stop();
var finished = System.DateTime.UtcNow;
var taken = finished - started;
var cc = System.Console.ForegroundColor;
System.Console.WriteLine("Finished: " + finished.ToString("MM/dd/yyyy hh:mm:ss.ffffff tt"));
System.Console.WriteLine("Sleep Time: " + sleepTime.ToString());
System.Console.WriteLine("Real Taken Total: " + taken.ToString());
if (taken > sleepTime)
{
System.Console.ForegroundColor = System.ConsoleColor.Red;
System.Console.WriteLine("Missed by: " + (taken - sleepTime));
}
else
{
System.Console.ForegroundColor = System.ConsoleColor.Green;
System.Console.WriteLine("Still have: " + (sleepTime - taken));
}
System.Console.ForegroundColor = cc;
System.Console.WriteLine("Real Taken msec Total: " + taken.TotalMilliseconds.ToString());
System.Console.WriteLine("Real Taken sec Total: " + taken.TotalSeconds.ToString());
System.Console.WriteLine("Real Taken μs Total: " + Media.Common.Extensions.TimeSpan.TimeSpanExtensions.TotalMicroseconds(taken).ToString());
System.Console.WriteLine("Managed Taken Total: " + sw.Elapsed.ToString());
System.Console.WriteLine("Diagnostic Taken Total: " + testSw.Elapsed.ToString());
System.Console.WriteLine("Diagnostic Elapsed Seconds Total: " + ((testSw.ElapsedTicks / (double)System.Diagnostics.Stopwatch.Frequency)));
//Write the rough amount of time taken in micro seconds
System.Console.WriteLine("Managed Time Estimated Taken: " + sw.ElapsedMicroseconds + "μs");
//Write the rough amount of time taken in micro seconds
System.Console.WriteLine("Diagnostic Time Estimated Taken: " + Media.Common.Extensions.TimeSpan.TimeSpanExtensions.TotalMicroseconds(testSw.Elapsed) + "μs");
System.Console.WriteLine("Managed Time Estimated Taken: " + sw.ElapsedMilliseconds);
System.Console.WriteLine("Diagnostic Time Estimated Taken: " + testSw.ElapsedMilliseconds);
System.Console.WriteLine("Managed Time Estimated Taken: " + sw.ElapsedSeconds);
System.Console.WriteLine("Diagnostic Time Estimated Taken: " + testSw.Elapsed.TotalSeconds);
if (sw.Elapsed < testSw.Elapsed)
{
System.Console.WriteLine("Faster than Diagnostic StopWatch");
l.Add(new System.Tuple<bool, System.TimeSpan, System.TimeSpan>(true, sw.Elapsed, testSw.Elapsed));
}
else if (sw.Elapsed > testSw.Elapsed)
{
System.Console.WriteLine("Slower than Diagnostic StopWatch");
l.Add(new System.Tuple<bool, System.TimeSpan, System.TimeSpan>(false, sw.Elapsed, testSw.Elapsed));
}
else
{
System.Console.WriteLine("Equal to Diagnostic StopWatch");
l.Add(new System.Tuple<bool, System.TimeSpan, System.TimeSpan>(true, sw.Elapsed, testSw.Elapsed));
}
}
int w = 0, f = 0;
var cc2 = System.Console.ForegroundColor;
foreach (var t in l)
{
if (t.Item1)
{
System.Console.ForegroundColor = System.ConsoleColor.Green;
++w; System.Console.WriteLine("Faster than Diagnostic StopWatch by: " + (t.Item3 - t.Item2));
}
else
{
System.Console.ForegroundColor = System.ConsoleColor.Red;
++f; System.Console.WriteLine("Slower than Diagnostic StopWatch by: " + (t.Item2 - t.Item3));
}
}
System.Console.ForegroundColor = System.ConsoleColor.Green;
System.Console.WriteLine("Wins = " + w);
System.Console.ForegroundColor = System.ConsoleColor.Red;
System.Console.WriteLine("Loss = " + f);
System.Console.ForegroundColor = cc2;
}
}