adamkdean

software engineering

Circle primitive class for XNA/MonoGame

By Adam K Dean on

I've just been playing a little with XNA (or MonoGame as it's called these days) and needed to draw circles. If you've used XNA then you'll know that nothing like that is provided for you. Drawing circles isn't too difficult really, they're basically just lots of little lines at different angles.

I've come up with the following class. It has a default number of points harcoded but you can overload that, allowing you to create triangles, rectangles, pentagons, hexagons etc.

Update: The number of points now is determined by the radius of the circle. The current calculation of Radius * Math.PI seems to work just fine. I don't know if there is any "golden" ratio, but I'm fine with this one.

Note, I've adopted my new style of putting fields at the bottom of the class. I like it, you get to the code much quicker.

public class Circle
{
    public Circle(float x, float y, int radius,
        GraphicsDeviceManager graphics)
        : this(x, y, radius, Color.White, graphics) { }

    public Circle(float x, float y, int radius,
        Color color, GraphicsDeviceManager graphics)
    {
        this.x = x;
        this.y = y;
        this.radius = radius;
        this.color = color;
        this.graphics = graphics;

        Initialize();
    }

    public void Draw()
    {
        effect.CurrentTechnique.Passes[0].Apply();
        graphics.GraphicsDevice.DrawUserPrimitives
            (PrimitiveType.LineStrip, vertices, 0, vertices.Length - 1);
    }

    private void Initialize()
    {
        InitializeBasicEffect();
        InitializeVertices();
    }

    private void InitializeBasicEffect()
    {
        effect = new BasicEffect(graphics.GraphicsDevice);
        effect.VertexColorEnabled = true;
        effect.Projection = Matrix.CreateOrthographicOffCenter
            (0, graphics.GraphicsDevice.Viewport.Width,
             graphics.GraphicsDevice.Viewport.Height, 0,
             0, 1);
    }

    private void InitializeVertices()
    {
        vertices = new VertexPositionColor[CalculatePointCount()];
        var pointTheta = ((float)Math.PI * 2) / (vertices.Length - 1);
        for (int i = 0; i < vertices.Length; i++)
        {
            var theta = pointTheta * i;
            var x = X + ((float)Math.Sin(theta) * Radius);
            var y = Y + ((float)Math.Cos(theta) * Radius);
            vertices[i].Position = new Vector3(x, y, 0);
            vertices[i].Color = Color;
        }
        vertices[vertices.Length - 1] = vertices[0];
    }

    private int CalculatePointCount()
    {
        return (int)Math.Ceiling(Radius * Math.PI);
    }

    private GraphicsDeviceManager graphics;
    private VertexPositionColor[] vertices;
    private BasicEffect effect;

    private float x;
    public float X
    {
        get { return x; }
        set { x = value; InitializeVertices(); }
    }
    private float y;
    public float Y
    {
        get { return y; }
        set { y = value; InitializeVertices(); }
    }
    private float radius;
    public float Radius
    {
        get { return radius; }
        set { radius = (value < 1) ? 1 : value; InitializeVertices(); }
    }
    private Color color;
    public Color Color
    {
        get { return color; }
        set { color = value; InitializeVertices(); }
    }
    public int Points
    {
        get { return CalculatePointCount(); }
    }
}

Using it is really easy. Create a Circle, and call circleObject.Draw().

Circle circle;

protected override void Initialize()
{
    // X, Y, Radius, Color (optional), GraphicsDeviceManager
    circle = new Circle(100f, 100f, 50f, Color.Violet, graphics);

    base.Initialize();
}

protected override void Draw(GameTime gameTime)
{
    GraphicsDevice.Clear(Color.Black);

    circle.Draw();

    base.Draw(gameTime);
}

You can change the radius and the position of the Circle via the properties. I'll probably add the ability to rotate it.

I might add this and other primitive helper classes to a class library. If so I'll link it here in the future.

Below: four circles of varying size and number of points.

four circles of varying size and number of points

Updated: 25th March 2013

FizzBuzz? More than one line doesn't count!

By Adam K Dean on

Just doing research over at r/cscareerquestions when I stumbled upon a thread about FizzBuzz.

I've heard of it, but I've never actually done it. I decided to do it and put myself to the test.

Basically the rule is:

Write a program that prints the numbers from 1 to 100. But for multiples of three print "Fizz" instead of the number and for the multiples of five print "Buzz". For numbers which are multiples of both three and five print "FizzBuzz".

Seems simple enough:

static void EasyFizzBuzz()
{
    for (int i = 1; i <= 100; i++)
    {
        if (i % 3 == 0 && i % 5 == 0) Debug.WriteLine("FizzBuzz");
        else if (i % 3 == 0) Debug.WriteLine("Fizz");
        else if (i % 5 == 0) Debug.WriteLine("Buzz");
        else Debug.WriteLine(i);
    }
}

But that's too easy. I'm sure everyone comes up with that solution. I'd rather stand out if I ever get asked, and nothing stands out more than a giant line of ternary operators. (Does it count as one line if I've put it onto the next line for appearance sake? Only has one semi-colon!)

static void OneLineFizzBuzz()
{
    for (int i = 1; i <= 100; i++) Debug.WriteLine((i % 3 == 0 && i % 5 == 0) ?
        "FizzBuzz" : (i % 3 == 0) ? "Fizz" : (i % 5 == 0) ? "Buzz" : i.ToString());
}

Maybe I can come up with something more inventitive yet, just how creative can you be with such a simple problem?

Using caller information for verbose logging

By Adam K Dean on

A cool feature that has been added in Visual Studio 2012 and C# 5.0 is Caller Information attributes. Basically it allows you to see where your method was called from without having to sift through stack traces upon stack traces.

You simply prefix an optional parameter with one of the three attributes:

[CallerMemberName] provides the method or property name of the caller as a string.
[CallerFilePath] provides the full path of the source file that contains the caller as a string.
[CallerLineNumber] provides the line number in the source file at which the method is called as an int.

Learn by example. Here I've made a simple logging method, we pass to it a string, and the compiler will fill in the rest. Make sure to including System.Runtime.CompilerServices in your using statements.

static void VerboseLog(string value,
    [CallerMemberName] string callerMemberName = "",
    [CallerFilePath] string callerFilePath = "",
    [CallerLineNumber] int callerLineNumber = -1)
{
    int index = callerFilePath.LastIndexOf(Path.DirectorySeparatorChar);
    string localPath = callerFilePath.Substring(index + 1);
    Debug.WriteLine("{0} {1}:{2} {3}",
        localPath, callerMemberName, callerLineNumber, value);
}

Let's test it with a simple Console Application. Notice in the above method that I remove the full path to make it more readable. Not necessarily needed but pleasant nonetheless.

static void Main(string[] args)
{
    VerboseLog("this is a test");
    DoSomething();
}

static void DoSomething()
{
    for (int i = 0; i < 5; i++)
    {
        VerboseLog(string.Format("something {0}", i));
    }
}

This outputs:

Program.cs Main:16 this is a test
Program.cs DoSomething:24 something 0
Program.cs DoSomething:24 something 1
Program.cs DoSomething:24 something 2
Program.cs DoSomething:24 something 3
Program.cs DoSomething:24 something 4

So very simple, and yet very, very useful.

Happy Birthday - programmer style.

By Adam K Dean on

Today I decided to wish my good friend @Farkie happy birthday: programmer style.

Here's to you, ol' bean.

using System;
using System.Text;

public class HappyBirthday
{
    public static void Main(string[] args)
    {
        Console.WriteLine("{0} {1}{2} {3}",
            GetRandomString(-1045111850),
            GetRandomString(554696058),
            GetRandomString(99640),
            GetRandomString(-2146856402));

        Console.ReadKey();
    }

    public static string GetRandomString(int seed)
    {
        var rnd = new Random(seed);
        var sb = new StringBuilder();
        for (; ; )
        {
            int c = rnd.Next(0, 27);
            if (c == 0) break;
            sb.Append((char)(96 + c));
        }
        return sb.ToString();
    }
}

And, because you probably won't be bothered to compile it, I've done that for you too.

Happy Birthday Alan

Keep focus on an input with jQuery

By Adam K Dean on

The most hair-loss-inducing problems usually have the simplest solutions, and such can be said for my latest shortcut to male pattern baldness.

I'm working on my forever project, and part of it requires that an input keep focus all of the time. User experience out of the window, this is the way it has to be, but .blur() is not cancel-able, nor is .focusout(). This means you can't just call .focus() in the .blur() function. You have to trick it.

Set initial focus first:

$("#input").focus();

And then set the re-focus:

$("#input").blur(function() {
    setTimeout(function() { $("#input").focus(); }, 0);
});

Works a treat.