Recent Updates Toggle Comment Threads | Keyboard Shortcuts

  • Joel 5:18 PM on September 9, 2016 Permalink | Reply  

    Differentiate… or accept being average 

    “A product which fails to differentiate itself from other products in the same market can expect no better sales than any similar product.”

    This little thought crossed my mind, and I think it is fairly true.  So what are these factors differentiate a product between it and its competitors?  These are the ones that immediately came to mind:

    • Appearance
    • Usability
    • Effectiveness
    • Availability (often coupled to awareness)
    • Awareness
    • “Coolness” (social attractiveness) (or the hipster anti-trend)
    • Price
    • Quality (perceived or otherwise)

    I’m sure it is possible to come up with counter-examples for each of these, but in general, I think this hold true. Allow me to elaborate on each factor.

    Appearance

    The bulk of the fashion industry seems fixated around this one. If a product looks different than its competitors, it visually stands out from competitors.

    An example of this that I’ll never forget is an assignment I had in elementary school. Our teacher had us create our own breakfast cereal box (not the cereal inside of it, just the box). Her point was to prove how advertising works – things that are flashy or bright stand out. If everything is flashy and bright, than the one that isn’t is more likely to stand out. Basically, something must be visually different in order to stand out. If all products have an approximately equal appearance, it essentially becomes visual noise, and nothing stands out.

    The same could be said about any of the other sense – touch, taste, smell, or sound: if there’s a significant difference, it stands out.

    Usability

    If a product is easier to use than competitive products, that’s a selling feature. A prime example of this could be iOS vs. Android tablets. Huge amounts of effort have been put into making iOS easy to use. If a 90 year old grandma or a 2 year old kid can pick up a tablet and figure out how to do something on it in a short period of time, that says something about the product. This doesn’t necessarily mean that one is entirely superior (or the other entirely inferior), but usability is a selling point.

    Another great example here is the Nest thermostat. Compared to other programmable thermostats, it seems like a much easier to use product. I’d honestly love to rip my existing thermostat off the wall and replace it with something else. The user interface was definitely created by engineers who didn’t have a clue about usability.

    Effectiveness

    If usability is how easy (or hard) it is to use a product, effectiveness is how well it actually works. A prime example here is mosquito repellent spray. If all other factors are equal, but if one repels mosquitoes better than the other, there’s a very reasonable chance that the better repellent will sell better, provided that people learn that it does work better.

    The great thing about the internet is that finding information about how well a product actually works is, in some ways, easier than than it ever has been before. This assumes that online reviews can be trusted, which is a whole other topic of discussion. Between reviews on sites like Amazon, people posting video reviews on YouTube, and personal blogs where people talk about actually owning and using things, there’s a glut of information out there.

    Availability

    If a product isn’t available, customers will likely choose a competing product (again, if all other things are considered equal). Your customers shouldn’t have to spend inordinate amounts of time trying to find your product. Buying something shouldn’t have to be a treasure hunt.

    Awareness

    I think this is where a lot of advertising falls into – making people aware of a product. If you’ve heard of Product A before, but you’ve never heard of Product B, there’s a very good chance you’d rather go with A (assuming you didn’t hear anything bad about it). This really comes down to brand awareness. If people don’t know you are there, they won’t choose you.

    I find it somewhat interesting when you see a dozen different products being sold online, but only a few have reviews. I think, to a certain extent, it is a bit of herd mentality. If you see that someone else has chosen a previously untested product, and it worked out well for them, you’d be likely to follow. It’s always easier to follow than it is to lead.

    “Coolness”

    There are many consumers out there that will choose a socially attractive product over other ones, just for the sake of social standing. In some respects, I have to give credit to Apple. They’ve made it “cool” to own a MacBook and to have white headphones – and they’ve done this in an interesting way. Look at how often movies or shows feature Apple computers. They are easily recognizable from a distance, and appear very often in movies and shows.

    Another interesting example I’ve heard here is Audi during events like the Emmy Awards. I don’t know how they did it (maybe by offering free cars or free rides?), but it became the ‘cool’ thing to show up to the Emmy Awards being driven in a large, dark, German sedan. I’m sure Audi sold a goodly amount of cars because of this.

    Price

    If two products are the exact same, people will almost always choose the less expensive option. (There are a few people out there that think that quality is directly tied to price, but these people shouldn’t be your target market – unless you are selling overpriced HDMI or audio cables). If you can’t compete on anything else, beat your competitors on price.

    Quality

    Quality can be a huge differentiation between products. In almost any market, there seems to be a wide variety of products of differing quality – everything from wearable computers to fresh produce. It never makes sense to go with a lower quality product if the price is the same. More on this below.

    Legalities

    If choosing one product over another is easier to do because of existing laws, breaking into such a market will be more difficult. A classic example of this is Tesla’s sell-direct approach. Rather than going through the dealership model, Tesla allows a customer to buy a car directly, over the internet. Many U.S. states have laws which state that manufacturers can’t have stores that sell vehicles directly to consumers. Because of these existing pro-dealership laws, it is considerably more difficult to buy a Tesla in these areas. There’s essentially an existing legal barrier to customers who want the product. If laws exist such that it makes buying a give product more difficult, it acts as a deterrent to customers.

    Getting People to Make the Switch

    People won’t want to switch from a competing product unless there is some compelling benefit to switching. The greater the benefit to switching, the more likely it will happen. The cost of switching must outweigh any disadvantages to staying put.

    Similarly, huge advantages in one category can outweigh small disadvantages in other categories. For example, if I can easily go to the nearest corner store and buy a beverage there, rather than having to go hunting through the jungles of the Amazon, even if the Amazon beverage tastes better, I’m probably just going to go to the corner store. I see this happen often enough in my home town (a small farm town). There’s very few imported cars – the bulk of them are largely Ford, Chevrolet, and Dodge/Chrysler. This is because the nearest Toyota/Kia/Honda dealership is at least a 45 minute drive away. Many people aren’t willing to go the distance to investigate other products. It’s just easier to go to a local dealership and find something “good enough” there.

    Balancing Between Categories

    Part of difficulty comes from finding a balance between things. It’s entirely possible to have the highest quality product in the world, but if it is priced out of the stratosphere, no one is going to buy it. If a product is amazingly cheap, but fails to perform the given task, there’s a likely chance that whoever is selling it isn’t going to be selling it for very long. (Fool me once, shame on you. Fool me twice, shame on me).

     
  • 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. 

     
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