Updates from Joel Toggle Comment Threads | Keyboard Shortcuts

  • Joel 8:00 PM on July 19, 2016 Permalink | Reply  

    Key/Value Attribute Hierarchy 

    This is something that just crossed my mind this morning: when working with values that fit nicely in a key/value attribute system, what do you do when you start needing more hierarchy?

    I’m mostly just thinking out loud here, so bear with me.  Sometimes I find the cardboard programmer approach to be helpful.

    Let’s take a fairly generic example.  Let’s suppose I am modelling a car – not in the physical sense, but int he behavioral sense.  So we start this off by deciding that each car part will have a set of attributes, and each attribute will have a value.  For example, a tire has a property called internalPressure, and it has a specific value, say 0.5.  If we were to represent this in a JSON object, it’d look something like:

    {
        "internalPressure": 0.5
    }

    This works fine for our tire object.  But as we build more of the car, we run across another car part that also has an internalPressure property.  Our key is no longer unique enough to identify what our value is trying to say.  There’s two solutions here:

    1. We could modify our key to make it more unique.
    2. We could add some form of hierarchy.

    For #1, it could look something like:

    {
        "engineBlock_internalPressure": 19.3,
        "tire_internalPressure": 0.5
    }

    For #2, it might look like:

    {
        "engineBlock": {
            "internalPressure": 19.3
        },
        "tire": {
            "internalPressure": 0.5
        }
    }

    Which of these two approaches is ‘right’?  Well that depends.

    By making keys longer/more unique, you maintain a flat hierarchy.  If your data is stored in something like a hash table or a dictionary, this makes sense.  But maintaining those unique keys is also a bit of a pain in the butt.  What happens if you want to change what units you are storing your pressure values in?  If you need to select everything, how do you know that you’ve actually selected all parts that have an “internalPressure” property?  Basically, you’re relying in programmers following a difficult to enforce standard, which is always a bit of a scary practice.

    By using a hierarchy, you do keep the ability to use the same keys in multiple places, which is convenient.  But you may also have to think differently about how you are storing those values.  Rather than just using a single hash table, you might have to have more of a tree structure, which may take more effort to search.

    There’s always going to be some form of trade-off.  Depending on what you are trying to do, you want to pick the algorithm that is going to give you the benefits you want without having any drawbacks that you can’t deal with.  Sometimes it is as simple as choosing an existing algorithm, and sometimes you end up having to make your own solution cobbled together from various bits and pieces.

     
  • Joel 5:07 PM on June 23, 2016 Permalink | Reply
    Tags: ,   

    Programming is like your own little universe 

    I think this is one of the things that got me into programming (in particular – game development): programming is essentially creating your own little universe. You define the rules, and how things interact within that universe.

    I think when I was first getting into programming, I couldn’t really see the connection – books and tutorials would teach about variables and functions, or even classes and inheritance, but I still failed to see the connection to how those were basically creating rules. It slowly started to make sense, though. “When you click on this thing, this action happens”. “If the previous action happens three times in a row, make this other thing happen”. By gathering data from the user or from other sources – level files, random number generators, incoming network calls, etc., and processing that data using a set of rules, you can make more interesting and complex things happen.

    I’m always entertained by hearing stories from other games where players have managed to do things in a way that the developers never intended. For example, I don’t think the developers of the original Deus Ex planned on players playing through the entire game without killing a single thing – yet someone figured out that, within the constraints of the Deus Ex universe, it was possible. Or more oddly, players figured out that by placing mines on walls, you could slowly scale your way up walls that you shouldn’t be able to. I’ve heard this referred to the “unorthodox usage of objects” in a games, and have thought that its presence is generally a good indicator of a great game design.

    I don’t do game development as a full time job. Instead, I’m currently writing software for the agriculture industry. It’s still similar in a sense – I’ve got my data, my set of rules, and there’s a small universe in which you have total control.

    That is, at least until a product owner requests something you’ve never intended…

     
  • Joel 9:02 AM on July 8, 2015 Permalink | Reply  

    Troubles with Azure 

    You may want to take the following with a grain of salt, but I do think there are a few valid concerns expressed herein.

    Recently, I’ve been working on a little project for my wife – a website where she can keep track of upcoming running races. I figured it’d be an interesting little project that wouldn’t take me that long, and it would give me a chance to test out my recently re-vamped (non-entity framework) back end. Given that I’ve currently got a bunch of Azure credit, I figured I’d be an idiot to not use it. I’m beginning to question whether that was a good decision or not.

    When working on Azure, I’ve come across the following issues:

    The entire Azure portal feels like a bad beta.

    The new Azure portal has a similar interface to Windows 8. This isn’t necessarily a bad thing, but navigating it is a pain in the butt. On Amazon, to navigate between resources, there’s a single menu down the left hand side that lets you quickly switch between resources. Want to look at instances? Click on the left. Want to look at elastic IPs? Click on the left. If you do want to look at some of the other services, you do have to navigate to the top menu, mouse down, then select whatever other service it is, but at least everything that is somewhat related is grouped together. Perhaps I’m nitpicking here, but I’m certainly not with my next point.

    The Azure portal seems slow as molasses in January.

    I don’t know what they’ve done, but it seems to take an inordinate amount of time to bring up any sort of details on a particular resource. Click on a web app, wait five seconds while the details load. And when they do load, they push whatever was previously selected off to the left. Want to see your web app settings? Click on a button, wait a few more seconds, and everything again gets pushed to the left, while in the mean time, you’ve got acres of screen real estate to the right that isn’t being utilized, sitting there completely empty. It seems like any time you want to do something, you have to wait several seconds for things to shuffle around, and a few more seconds for things to actually load from Azure. Yes, a second or two here or there doesn’t matter too much, but it does! And don’t think that this is something to do with my computer. I’m running a 30 mbps internet connection on a quad core i7 with 9 GB of RAM, and only one Chrome extension loaded (Ghostery). I suspect what it is that takes so long is the UI, or actually getting data from Azure itself. Next time I pull it open perhaps I’ll do a bit of profiling.

    It isn’t just the UI that is slow, either.

    A few days ago I was wanting a new database. I created a new database server, then created a new database. Once the sort of wizard-ish thing was over, an icon appeared on my Azure portal home screen saying that the creation was still in progress. This went on… and on… and on. Finally, after 45 minutes or so, I switched back over to the old Portal, and sure enough, it had finished shortly after I had started it. For whatever reason, the new portal didn’t get the hint that the job was actually done. There’s some seriously broken behaviour between the old and new Portal, and so far the new Portal seems not great.

    Half the documentation references the old Azure portal, and half references the new portal.

    This is especially true for documentation outside of Microsoft. Want to figure out how do some particular thing? Chances are, the first few Google search results will show you how to do it – on the old Azure portal. Microsoft really could do themselves a favour by asking site owners to update their documentation to the new Portal for, say, a $20 Azure credit. It’d cost them next to nothing, and they’d get consistent documentation so that everything references the new Azure portal.

    The notification system doesn’t work well.

    I understand the desire for a central notification system. I do. But when you start sending notifications for every little thing, it gets annoying. It seems that even something as simple as setting a web app configuration setting? That’s a notification. And whenever a notification does come in, there’s no way of telling whether it is something good or bad without having to actually open the notifications tab. This kind of freaks me out, as my first reaction is usually “oh crap, what went wrong now?”. Oh, it was just saving my web app settings? Then why didn’t it tell me that on the same UI when I clicked on the Save button?

    They seem to have done away with the free 20 MB SQL database

    When I first started poking around with Azure, I could have sworn there was a free 20 MB database option. I can’t find any trace of it at all through the new Azure portal. Plenty of blogs mention it, but nothing on the new portal. Is this a problem with the new portal, or is it something that isn’t offered anymore? I have no idea. And good luck trying to find out.

    The difference between SQL Server and SQL on Azure is annoying

    Maybe I’m just old-school, but there’s some subtle things about SQL databases on Azure that annoy me. First of all, I have to create a server before I can create a database. Given how Azure seems to isolate you from a lot of things, I’m surprised this step is necessary. 99.9% of the time, I bet most people don’t care about server specific settings, and only want to deal with database specific settings. Also, try to deploy an existing SQL Express database to Azure. You’ll find how to do this in the documentation, but it’s a completely convoluted process. The process for deploying a web app? Right click on the solution, deploy to Azure. Getting this to work with a SQL Express database was a real chore. First, I was getting a convoluted error message, which, turns out, meant that I needed a newer version of SQL Server Management Studio. Once I had that installed, it still didn’t work, and required a hotfix in order to actually display the correct wizard options when deploying. It seems like there’s a real disconnect between how the Visual Studio team and the SQL Server team went about implementing deployments.

    Custom domains seems half-baked.

    Yesterday I tried registering a custom domain through Azure. This was the cherry on the top of an already frustration frosted cake. I put all my info in, tried clicking OK/Save/Submit (or whatever it was the button said)… and it turns out I had forgotten to enter a country code. Once I did that… the OK/Save/Submit button was still greyed out. I had to close the tab/wizard thing, then re-open it, then click. Then, what did it do? Who knows? It sent me a notification saying that it had been submitted. Well that’s great, but I want the domain. There was also no indication of how the domain would be paid, or how much it would cost. And checking back a while later, there’s still no sign of the domain. It seems like custom domains is totally half-baked.

    Pricing seems out of whack

    Pricing with Amazon EC2 is pretty straightforward – they quite clearly list the prices for individual services in terms of hours. Want a t2.micro? That’s $0.02/hour. Pricing on Azure seems to be stated by the month (despite being charged by the minute?). Also, there’s some pretty huge jumps in pricing for certain services. For example, take a look at the pricing for ElasticSearch. The first tier is free. The second tier jumps up to several hundred dollars a month, and there’s nothing in between. (Or at least there’s no visible tiers between them). That’s brutal.
    Again, perhaps half of these points are unfounded. In my day job, I deal with Amazon EC2 (and related) services, Python, Django, and PostgreSQL. At home, I’m attempting to do everything on Azure, C#, ASP.Net, and Microsoft SQL Server. That’s a lot to learn/take in, so perhaps a lot of this is just my own stupidity or lack of knowledge. But what I have experienced so far has made me incredibly frustrated with Azure as a whole, and makes me want to avoid it for future projects.

     
  • Joel 11:00 PM on April 20, 2015 Permalink | Reply  

    Rope Bridge Philosphy 

    Although I’ve mentioned the rope bridge philosophy a time or two, I don’t think I’ve ever written about it, and it looks like the original post over at gamedev.net describing it is long since gone.  So here it is:

    Imagine that you are a traveler, and you are exploring a new land – one which has many rivers, creeks, canyons, and so on. Often you aren’t sure of which route to take, but you have a general idea of where you are trying to get. This often involves crossing rivers and canyons. Rather than investing the time and money to build a large concrete and steel bridge every time you encounter a river, you first build a rope bridge. This allows you to explore a little further before deciding that you are indeed headed in the right direction.

    The idea is to only spend time making bridges that you actually need, and only improving the bridges that you cross often. By doing so, you are able to explore further and faster than if you built ever bridge out of concrete. This also saves you the time and effort of building concrete bridges where such a bridge isn’t necessary. This does mean that, as time goes on, some of your rope bridges will need to be pulled up and replaced with more permanent counterparts. This does involve some waste, but perhaps not as much waste as if you built every bridge out of concrete from the start.

    As you gain more experience with exploring, you get a better feel for which bridges should initially be built out of concrete and which ones should only be rope bridges. Again, there is always the risk of building something more expensive that what you need, so if you undecided, it is best to go with the rope bridge.

    As you may have guesed, the rope bridge fits in perfectly with programming. Far too often programmers spend time writing code that will either never be used. This may be because a feature get axed or a gets used a lot less often than originally anticipated. It may also be because plans change, or you discover that your initial designs weren’t quite correct. In such cases you’ll want to minimize the amount of loss. By only developing what is necessary when it is necessary, you save yourself any sort of loss. Yes, you may need to revisit code to add more features or improve performance after a period of time, but the time and effort doing so is offset by the time and effort saved by developing features that were never needed.

     
  • Joel 9:50 PM on February 14, 2015 Permalink | Reply  

    Thesis: Voxel Octree Intersection Based 3D Scanning 

    I figured I might as well put this out there. It’s a copy of my master’s thesis, entitled Voxel Octree Intersection Based 3D Scanning

    Voxel Octree Intersection Based 3D Scanning.

    The idea behind it was to use low-cost hardware to make a 3D scanner that would generate watertight 3D meshes. The technique I developed was less than ideal, but it did work. If I could have done it over again, I would have used a homemade laser scanner and a different technique.

    The technique creates an octree, and treats individual regions of 3D space as being either empty or solid. It gathers 3D data from a Kinect sensor, creates a set of triangles from that data, and intersects it into the tree. When all the data has been gathered, a process then runs the marching tetrahedrons algorithm on the tree data to generate a final 3D mesh. It certainly isn’t efficient, but it worked well enough to generate some 3D scans like this:

    FinalPrints_Small

    The dragon is missing the top of its head, as the 3D printer ran out of filament during printing.

    Really though, I see this more about learning to learn than learning specifics. It’s amazing how many other ideas came out of doing my master’s. I’m also a lot more interested in the underlying techniques of how things work and how to make them more efficient, rather than just coding. While doing my master’s, I met a ton of great people and had some great experiences – including going to an academic conference abroad, creating a prototype of a system called Pylons, and winning a business plan competition.

    Most importantly, though, doing a master’s brought me back to Lethbridge where I met my then-future/now current wife. The circumstances which it took to get me back to Lethbridge were interesting, but I’m so very glad that things have worked out the way they have.

     
  • Joel 9:38 PM on February 14, 2015 Permalink | Reply  

    Axis-Aligned Bounding Box (AABB) to Triangle Collision Detection in C# 

    For my thesis work, I needed a way of determining collisions between an axis-aligned bounding box (AABB) and a triangle. I was working in C#, and discovered that there isn’t a whole lot of code examples out there. I ended up adapting some C++ code into C#, but it seems to work quite well. Here’s a dump of the code. It does involve some bits used in other parts of my work, but it should still work.

    My triangle class:


    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Microsoft.Xna.Framework;

    namespace Voxelizer5Common
    {
    public class Triangle
    {
    private Vector3 a;
    private Vector3 b;
    private Vector3 c;
    private Vector3 normal;

    #region Properties

    ///
    /// A
    ///

    public Vector3 A
    {
    get { return a; }
    set { a = value; }
    }

    ///
    /// B
    ///

    public Vector3 B
    {
    get { return b; }
    set { b = value; }
    }

    ///
    /// C
    ///

    public Vector3 C
    {
    get { return c; }
    set { c = value; }
    }

    ///
    /// Normal
    ///

    public Vector3 Normal
    {
    get { return normal; }
    set { normal = value; }
    }

    #endregion

    ///
    /// Returns true if all points are non-zero;
    ///

    ///
    public bool AllPointsNonZero()
    {
    bool result = true;

    if (a.X == 0.0f && a.Y == 0.0f && a.Z == 0.0f)
    {
    result = false;
    }
    else if (b.X == 0.0f && b.Y == 0.0f && b.Z == 0.0f)
    {
    result = false;
    }
    else if (c.X == 0.0f && c.Y == 0.0f && c.Z == 0.0f)
    {
    result = false;
    }

    return result;
    }

    ///
    /// Returns true if any of the points are zero.
    ///

    ///
    public bool AnyPointsZero()
    {
    bool result = false;

    if (a.X == 0.0f && a.Y == 0.0f && a.Z == 0.0f)
    {
    result = true;
    }
    else if (b.X == 0.0f && b.Y == 0.0f && b.Z == 0.0f)
    {
    result = true;
    }
    else if (c.X == 0.0f && c.Y == 0.0f && c.Z == 0.0f)
    {
    result = true;
    }

    return result;
    }

    ///
    /// Gets the minimum point of the AABB of this triangle.
    ///

    ///
    public Vector3 GetMinPoint()
    {
    Vector3 min = new Vector3(a.X, a.Y, a.Z);

    //X
    if (b.X < min.X)
    {
    min.X = b.X;
    }

    if (c.X < min.X)
    {
    min.X = c.X;
    }

    //Y
    if (b.Y < min.Y)
    {
    min.Y = b.Y;
    }

    if (c.Y < min.Y)
    {
    min.Y = c.Y;
    }

    //Z
    if (b.Z < min.Z)
    {
    min.Z = b.X;
    }

    if (c.Z < min.Z)
    {
    min.Z = c.Z;
    }

    return min;
    }

    ///
    /// Gets the maximum point in the AABB that would surround the triangle.
    ///

    ///
    public Vector3 GetMaxPoint()
    {
    Vector3 max = new Vector3(a.X, a.Y, a.Z);

    //X
    if (b.X > max.X)
    {
    max.X = b.X;
    }

    if (c.X > max.X)
    {
    max.X = c.X;
    }

    //Y
    if (b.Y > max.Y)
    {
    max.Y = b.Y;
    }

    if (c.Y > max.Y)
    {
    max.Y = c.Y;
    }

    //Z
    if (b.Z > max.Z)
    {
    max.Z = b.Z;
    }

    if (c.Z > max.Z)
    {
    max.Z = c.Z;
    }

    return max;
    }

    ///
    /// Gets the center of the triangle. (Essentially the average of all 3 points).
    ///

    ///
    public Vector3 GetCenter()
    {
    Vector3 center = new Vector3();

    center.X += A.X;
    center.Y += A.Y;
    center.Z += A.Z;

    center.X += B.X;
    center.Y += B.Y;
    center.Z += B.Z;

    center.X += C.X;
    center.Y += C.Y;
    center.Z += C.Z;

    center.X = center.X / 3.0f;
    center.Y = center.Y / 3.0f;
    center.Z = center.Z / 3.0f;

    return center;
    }

    ///
    /// Gets the hash code of the triangle.
    ///

    ///
    public override int GetHashCode()
    {
    return a.GetHashCode() + b.GetHashCode() + c.GetHashCode();
    }

    ///
    /// Determines if obj is equal to this triangle
    ///

    //////
    public override bool Equals(object obj)
    {
    bool result = false;

    if (obj.GetType() == typeof(Triangle))
    {
    Triangle t = (Triangle)obj;

    if (t.A == A && t.B == B && t.C == C)
    {
    result = true;
    }
    }

    return result;
    }
    }
    }

     

    The TriangleBoxIntersect method is on my Node class – where each node is a node in an octree. It has a min and max Vector3 representing the minimum and maximum points of the axis aligned bounding box:


    ///
    /// Uses the separating axis theorem to determine if there is overlap between the box and triangle.
    ///
    /// Original C++ source code from: http://fileadmin.cs.lth.se/cs/Personal/Tomas_Akenine-Moller/code/tribox3.txt
    ///
    /// Does the following tests:
    /// 1) The x, y, z directions
    /// 2) Normal of the triangle
    /// 3) Crossproduct (edge from triangle)
    ///

    ////////////
    public bool TriangleBoxIntersect(Triangle triangle)
    {
    Vector3 center = new Vector3(this.min.X + (size / 2.0f), this.min.Y + (size / 2.0f), this.min.Z + (size / 2.0f));
    Vector3 boxHalfSize = new Vector3(this.size, this.size, this.size);
    Vector3 v0 = triangle.A – center;
    Vector3 v1 = triangle.B – center;
    Vector3 v2 = triangle.C – center;
    Vector3 e0 = v1 – v0;
    Vector3 e1 = v2 – v1;
    Vector3 e2 = v0 – v2;

    //Point 1 in original paper: minimal AABB of triangle against AABB. Involves 3 tests against normals.
    float min, max;

    FindMinMax(v0.X, v1.X, v2.X, out min, out max);
    if (min > boxHalfSize.X || max < -boxHalfSize.X) { return false; } FindMinMax(v0.Y, v1.Y, v2.Y, out min, out max); if (min > boxHalfSize.Y || max < -boxHalfSize.Y) { return false; } FindMinMax(v0.Z, v1.Z, v2.Z, out min, out max); if (min > boxHalfSize.Z || max < -boxHalfSize.Z)
    {
    return false;
    }

    //Point 2 in original paper: Normal of triangle – uses plane/AABB overlap test.
    Vector3 normal = Vector3.Cross(e0, e1);

    if (!PlaneBoxOverlap(normal, v0, boxHalfSize))
    {
    return false;
    }

    //Point 3 in the original paper: 9 tests for edges.

    float fex = Math.Abs(e0.X);
    float fey = Math.Abs(e0.Y);
    float fez = Math.Abs(e0.Z);
    if (!AXISTEST_X01(e0.Z, e0.Y, fez, fey, v0, v1, v2, min, max, boxHalfSize)) { return false; }
    if (!AXISTEST_Y02(e0.Z, e0.X, fez, fex, v0, v1, v2, min, max, boxHalfSize)) { return false; }
    if (!AXISTEST_Z12(e0.Y, e0.X, fey, fex, v0, v1, v2, min, max, boxHalfSize)) { return false; }

    fex = Math.Abs(e1.X);
    fey = Math.Abs(e1.Y);
    fez = Math.Abs(e1.Z);
    if (!AXISTEST_X01(e1.Z, e1.Y, fez, fey, v0, v1, v2, min, max, boxHalfSize)) { return false; }
    if (!AXISTEST_Y02(e1.Z, e1.X, fez, fex, v0, v1, v2, min, max, boxHalfSize)) { return false; }
    if (!AXISTEST_Z0(e1.Y, e1.X, fey, fex, v0, v1, v2, min, max, boxHalfSize)) { return false; }

    fex = Math.Abs(e2.X);
    fey = Math.Abs(e2.Y);
    fez = Math.Abs(e2.Z);
    if (!AXISTEST_X2(e2.Z, e2.Y, fez, fey, v0, v1, v2, min, max, boxHalfSize)) { return false; }
    if (!AXISTEST_Y1(e2.Z, e2.X, fez, fex, v0, v1, v2, min, max, boxHalfSize)) { return false; }
    if (!AXISTEST_Z12(e2.Y, e2.X, fey, fex, v0, v1, v2, min, max, boxHalfSize)) { return false; }

    //If everything has passed up to this point, we are intersecting.
    return true;
    }

    And here are the AXISTEST methods, PlaneBoxOverlap method, and FindMinMax methods:

     

    ///
    /// AXISTEST_X01
    ///

    /////////////////////////////////
    private bool AXISTEST_X01(float a, float b, float fa, float fb, Vector3 v0, Vector3 v1, Vector3 v2, float min, float max, Vector3 boxHalfSize)
    {
    float p0 = a * v0.Y – b * v0.Z;
    float p2 = a * v2.Y – b * v2.Z;

    if (p0 < p2) { min = p0; max = p2; } else { min = p2; max = p0; } float rad = fa * boxHalfSize.Y + fb * boxHalfSize.Z; if (min > rad || max < -rad)
    {
    return false;
    }
    else
    {
    return true;
    }
    }

    ///
    /// AXISTEST_X2
    ///

    /////////////////////////////////
    private bool AXISTEST_X2(float a, float b, float fa, float fb, Vector3 v0, Vector3 v1, Vector3 v2, float min, float max, Vector3 boxHalfSize)
    {
    float p0 = a * v0.Y – b * v0.Z;
    float p1 = a * v1.Y – b * v1.Z;

    if (p0 < p1) { min = p0; max = p1; } else { min = p1; max = p0; } float rad = fa * boxHalfSize.Y + fb * boxHalfSize.Z; if (min > rad || max < -rad)
    {
    return false;
    }
    else
    {
    return true;
    }
    }

    ///
    /// AXISTEST_Y02
    ///

    /////////////////////////////////
    private bool AXISTEST_Y02(float a, float b, float fa, float fb, Vector3 v0, Vector3 v1, Vector3 v2, float min, float max, Vector3 boxHalfSize)
    {
    float p0 = -a * v0.X + b * v0.Z;
    float p2 = -a * v2.X + b * v2.Z;

    if (p0 < p2) { min = p0; max = p2; } else { min = p2; max = p0; } float rad = fa * boxHalfSize.X + fb * boxHalfSize.Z; if (min > rad || max < -rad)
    {
    return false;
    }
    else
    {
    return true;
    }
    }

    ///
    /// AXISTEST_Y1
    ///

    /////////////////////////////////
    private bool AXISTEST_Y1(float a, float b, float fa, float fb, Vector3 v0, Vector3 v1, Vector3 v2, float min, float max, Vector3 boxHalfSize)
    {
    float p0 = -a * v0.X + b * v0.Z;
    float p1 = -a * v1.X + b * v1.Z;

    if (p0 < p1) { min = p0; max = p1; } else { min = p1; max = p0; } float rad = fa * boxHalfSize.X + fb * boxHalfSize.Z; if (min > rad || max < -rad)
    {
    return false;
    }
    else
    {
    return true;
    }
    }

    ///
    /// AXISTEST_Z12
    ///

    /////////////////////////////////
    private bool AXISTEST_Z12(float a, float b, float fa, float fb, Vector3 v0, Vector3 v1, Vector3 v2, float min, float max, Vector3 boxHalfSize)
    {
    float p1 = a * v1.X – b * v1.Y;
    float p2 = a * v2.X – b * v2.Y;

    if (p2 < p1) { min = p2; max = p1; } else { min = p1; max = p2; } float rad = fa * boxHalfSize.X + fb * boxHalfSize.Y; if (min > rad || max < -rad)
    {
    return false;
    }
    else
    {
    return true;
    }
    }

    ///
    /// AXISTEST_Z0
    ///

    /////////////////////////////////
    private bool AXISTEST_Z0(float a, float b, float fa, float fb, Vector3 v0, Vector3 v1, Vector3 v2, float min, float max, Vector3 boxHalfSize)
    {
    float p0 = a * v0.X – b * v0.Y;
    float p1 = a * v1.X – b * v1.Y;

    if (p0 < p1) { min = p0; max = p1; } else { min = p1; max = p0; } float rad = fa * boxHalfSize.X + fb * boxHalfSize.Y; if (min > rad || max < -rad)
    {
    return false;
    }
    else
    {
    return true;
    }
    }

    ///
    /// PlaneBoxOverlap test
    ///

    ////////////
    private bool PlaneBoxOverlap(Vector3 normal, Vector3 vert, Vector3 maxBox)
    {
    Vector3 vMin, vMax;
    float v;

    //X
    v = vert.X;

    if (normal.X > 0.0f)
    {
    vMin.X = -maxBox.X – v;
    vMax.X = maxBox.X – v;
    }
    else
    {
    vMin.X = maxBox.X – v;
    vMax.X = -maxBox.X – v;
    }

    //Y
    v = vert.Y;

    if (normal.Y > 0.0f)
    {
    vMin.Y = -maxBox.Y – v;
    vMax.Y = maxBox.Y – v;
    }
    else
    {
    vMin.Y = maxBox.Y – v;
    vMax.Y = -maxBox.Y – v;
    }

    //Z
    v = vert.Z;

    if (normal.Z > 0.0f)
    {
    vMin.Z = -maxBox.Z – v;
    vMax.Z = maxBox.Z – v;
    }
    else
    {
    vMin.Z = maxBox.Z – v;
    vMax.Z = -maxBox.Z – v;
    }

    if (Vector3.Dot(normal, vMin) > 0.0f)
    {
    return false;
    }

    if (Vector3.Dot(normal, vMax) >= 0.0f)
    {
    return true;
    }

    return false;
    }

    ///
    /// Used to find the maximum AABB of a triangle
    ///

    ///////////////private void FindMinMax(float v0, float v1, float v2, out float min, out float max)
    {
    min = max = v0;

    if (v1 < min) { min = v1; } if (v1 > max)
    {
    max = v1;
    }

    if (v2 < min) { min = v2; } if (v2 > max)
    {
    max = v2;
    }
    }

    It probably isn’t optimal, but it does work.

     
  • Joel 8:11 AM on August 28, 2014 Permalink | Reply
    Tags: , , ,   

    Deciding Which Technology to Use 

    When developing a new product, it can be difficult to determine which technology to use. When working on Pylons, I ran into this problem. I had an idea of what I wanted, but wasn’t sure of the tools to use to get there. It’s a bit like envisioning a masterful statue, but not knowing which chisels to use, or when to use them.

    When it comes down to it, there’s probably a few questions you should ask yourself before getting too far into things when developing a technology related product:

    • Will the technology I choose allow me to create the product I envision?
    • Will it give a good user experience?
    • Will it scale up to the number of users that I’d like?
    • Will it be safe and secure? What are the risks associated with this particular technology with regards to data breaches, hacking, or general security?
    • Will it be supported for a long time, or will it be deprecated/outdated in a short period of time? (A related question: Does the company that produces the technology use it? Do they eat their own dog food?)
    • What will it be like for maintenance?
    • Am I already familiar enough with the technology, or will there be a substantial learning curve? If so, will the time it takes to learn it be worth it?

    I’m sure there are things missing in this list, but at least it gets a person thinking.

    When I first started prototyping Pylons, I was coming from a background of doing business software in .Net, although I was also learning Python at the time. To me, it made the most sense to choose .Net for the back-end. I had some experience with WCF, but after looking into using it to create a RESTful http service, and hearing the experiences of a fellow student, the MVC Web API looked like a better choice.

    I also hadn’t worked with any mapping services, and I didn’t want to get too tied to a specific mapping provider. I came across a product called Mapstraction, that would allow me to quickly switch providers if I felt the need. Unfortunately there wasn’t a ton of documentation around it, so it did take me a little longer to get things implemented.

    For the front end, I quickly discovered that just a bare web page wasn’t going to work well on a mobile device. From hearing about the experiences of the big guys (Facebook, etc.), they all seemed to be going away from HTML5 to native apps. Again, given that I had .Net experience, I went ahead and created a .Net Windows Phone app.

    Unfortunately for Pylons, the whole team has been pretty busy with other endeavors, so we haven’t had the time to sink into it that we’d all like. Given our limited time and experience, I’m not sure we’ve actually chosen the right route. In the end, we might be better off with a tool like Xamarin that would allow us to hit all the platforms at once with minimal code change. It will still let us get decent performance without having three different learning curves – one for each platform. Another option we need to investigate is using something like Leaflet, that is able to handle mobile maps better than Mapstraction.

    So I guess there is one more thing to consider:

    Once you’ve chosen a given technology, don’t forget to keep learning about new technology.

    In this business you can’t afford to rest on your laurels too long. Yes, getting things done is important, but so is having an idea of what is coming down the pipe.

     
  • Joel 6:24 PM on July 23, 2014 Permalink | Reply
    Tags: git, horrible bugs, please don't make me use linux, this is why I like C#   

    One of the strangest bugs… 

    One task that I’m currently working on is a linux shell script that sets up a bunch of stuff for a deployment environment. Part of the setup involves creating a bash script that is used on a post-receive hook in git. In short, any time something is received by git it runs the script.

    Things with the overall bash script were going well, until I noticed something odd. One particular line in the bash script was getting changed somewhere between the machine I was writing it on and the server. There was a single line of the script that contained the following line:

    git checkout -f

    Somehow, when looking at the results from running the bash script on the server, it was instead producing this:

    git checkout 96f

    Not even close to being the same! At first I thought it was something that Ubuntu was doing to that particular line. Could it be somehow mangling things because I wasn’t properly escaping the dash symbol? Could it be that I was having to run dos2unix to alter line endings after getting it to the server? No matter how much digging I did, there was no clue to what was going on. That was when I noticed something.

    When I examined the file immediately after transferring it over (through FileZilla), I noticed that it still said “96f” – even before running dos2unix on it. This meant that somewhere in the transfer it was getting mangled. But why would FileZilla care what the file contents were? Especially this one character? Something still seemed fishy. Just to make sure I was looking at the right file, I threw in a few other characters on either side, so it looked something like this:

    git checkout adasdf-fasdfas

    I sent that across to the server, and it by the time it got to the server side it looked like this:

    git checkout adasdf96fasdfas

    What the heck?! Even trying different ftp modes – ascii, binary – showed the same result. It then occurred to me…

    That little particular snippet of code was copied from a GitHub wiki page. That dash wasn’t actually a dash – it was some other strange unicode character! I promptly deleted the offending line, re-wrote it, and sent it across to the server, and voila – it all worked!

    I think this still stands out as being one of the most bizarre bugs I have seen in a long time.

     
  • Joel 1:02 PM on June 25, 2014 Permalink | Reply
    Tags: Entity Framework, MVC,   

    Pylons, the latest MVC, and Entity Framework 

    One of my goals over the summer was to push hard on Pylons and get the iOS (iPhone) client out.  Right now its looking like that isn’t going to happen – at least not during the summer.  The reason for this is that there have been some very substantial updates to the underlying frameworks that Pylons uses. 

    Pylons is built on the ASP.Net MVC framework.  Last summer, when I was creating the first version of Pylons, MVC 3 was the latest version.  MVC 4 came out just at the end of the summer.  Between it, and MVC 5, there have been some pretty substantial changes.  One of these changes makes it potentially a lot easier to use OAuth authentication.  Currently, Pylons does this through a third-party plugin.  It’s rough, but it works.  Because of the way things work with MVC 5, it doesn’t make sense to keep using our third-party plugin. Ideally, we want everything to be as secure as possible – which means using the latest version of the MVC framework and not relying on third-party plugins.

    Unfortunately, this also means that there’s some other big changes that need to happen.  The underlying mechanisms of MVC are built using something called the Entity Framework.  The Entity Framework provides a way of automatically generating all the boilerplate code – the stuff that creates, reads, updates, and deletes things in the database.  I’m currently quite happy with how Pylons does this, but in order to use MVC 5 and the new authentication bits, it makes sense to at least looking into using the Entity Framework as well.  

    So far it seems to be working out well, but it still means that I’m spending all my time reworking the back-end, rather than adding new clients.  Hopefully there won’t be too many other major changes to the underlying frameworks, and I can get on with putting out a better product. 

     
  • Joel 3:12 PM on June 16, 2014 Permalink | Reply  

    It’s All About the Experience 

    This is something that keeps coming to mind, so I figured it is high-time that I wrote about it.

    With a product, it’s all about the entire experience – not just the product.  By making the experience of finding, purchasing, and using a product as positive as possible, a customer is much more likely to A) pay more or B) make a repeat purchase.  This is something that some companies understand, and that others are completely oblivious to.  You’d think that given companies are in the business of making money, that they’d have figured this out by now.  Why do so many struggle with it?  I don’t know.

    Is finding the product a positive experience?

    There’s a lot to “the experience”.  It first begins by the customer finding the product.  Was it easy or was it difficult to find?  For some things, this can really go either way.  Take, for example, a restaurant.  There’s definitely a difference between finding a burger joint at the next exit on the highway and finding a hole-in-the-wall restaurant.  In almost every case, you want to make your product as accessible as possible.  

    Here’s a related example.  A few months back I needed to purchase a new bike tire.  I asked a friend (who is into cycling) where I should buy one.  He replied with the name of a local store, and told me to explicitly ask about the cheaper tires they had in the back of the store.  Sure enough, I went to the store and saw what they had displayed.  The only tires they had displayed were quite expensive – at least double what I was willing to pay.  I found an employee, and asked them about the tires they had in the back.  They took me into the back, and showed me the selection they had.  The tire I ended up purchasing was less than half the cost of the ones I had seen earlier.  Had I not asked, I would have seen only the expensive tires, and walked out without making a sale.  In this case, the experience of finding what I was looking for wasn’t necessarily a positive one.  Maybe they were trying to get people to buy the more expensive tires, but either way, I bet they had a number of customers walk back out the door because what they saw was too expensive.  

    Once a customer has found the product, does the product appear appealing?  

    Here’s another example: Another thing I’ve been looking for is a set of tires for my car.  I’ve looked through a lot of online postings, and it’s interesting to note how certain people attempt to sell things.  Some people post blurry pictures of a set of dirty tires taken in a dark corner of a garage.  Even if the tires are in good condition, and it’s a good deal, I’m a lot less likely to give the person a call.  Really, for the 20 minutes of work it would take to hall them outside, hose them off, and take a decent picture, it’d be worth doing so.  If the product looks unappealing, the customer is less likely to buy it.   

    Once the customer makes the purchase, is the experience of opening the packaging a positive one?

    Just the other day, my wife and I had to buy some new light bulbs – not the standard Compact Florescent or 60 watt bulbs, but some sort of special halogen bulbs.  One, in particular, was packaged in that evil sort of clear plastic packaging – the kind that, when cut, becomes sharper than the scissors that cut it.  The same kind that is also incredibly difficult to cut, and is sealed the entire way around the package.  (Now maybe they use this kind of packaging because they are so dang expensive, and so that people won’t open the package in the store and steal them, but still!).  I think I counted no less than 17 bits of plastic and cardboard left over after hacking the package open.  The experience of bringing the product home and opening it up was not a positive one.  I’m much less inclined to buy such a product again.  (Of course, if I had my own way, we’d be using LED or Compact Florescent bulbs, but we rent, so the choice in light fixtures isn’t exactly ours).  

    Does the product provide a positive experience when being used?

    Here’s something that has me a bit baffled lately.  I’m a Windows guy.  I’ve been developing software for various Microsoft platforms for years.  There are things with Windows that annoy the living heck out of me.  They make me want to switch to something else.  I’m sure the alternatives also have problems, but there’s some things that Microsoft still hasn’t gotten right.  Take for example, plugging in a USB memory stick or SD card into a laptop.  Even with Windows 8, there’s a little pop-up that comes up indicating that your device is ready to be used.  OK.  Sometimes there’s also an accompanying dialog with a progress bar that pops up.  That’s not necessarily a bad thing – it’s letting me know that the computer has detected a new device, and it’s trying to set it up.  Fine.  But when I go to eject the device, and pull it out, another pop-up comes up indicating that the device can now safely be removed.  This pop-up stays up… even long after the device has been removed.  It’s like “Hey Windows, thanks for letting me know that I can safely remove that SD card… that I removed an hour ago.”.  If the device has been removed, why on earth is it necessary that the pop-up stays there?  As a programmer, I understand why.  They are using built-in mechanisms for displaying pop-up (system tray) notifications.  That’s fine.  But the end result is an experience which isn’t positive.  Yes, it’s a completely trivial thing, but it shows that not a lot of thought went into crafting the experience of using the operating system.

    To make a long story short: If your customers aren’t having a good experience – from start to finish, they are a lot less likely to give you money.  

     
c
Compose new post
j
Next post/Next comment
k
Previous post/Previous comment
r
Reply
e
Edit
o
Show/Hide comments
t
Go to top
l
Go to login
h
Show/Hide help
shift + esc
Cancel
Follow

Get every new post delivered to your Inbox.

Join 94 other followers