Ok. I admit it. I sometimes use text based debugging. It’s ugly and when there is a better way, I jump to the alternative, but sometimes "printf"s hidden behind a preprocessor define are the fast tool to figuring out what is going on.
Generally I prefer using trace breakpoints, visual breakpoints (described in an early blog), or assertions to test hypotheses about what went wrong. Other times, a fancy tool ( memory access checker, profiler, thread safety checker) is just the thing. Basically, I look at the bug description, reproduce the issue, and then visualize it. Given reasonable knowledge about what the code is trying to do, a picture usually gets me a short list of what could be wrong. Then I try to eliminate possibilities.
But sometimes, the test cases to reproduce problems are too big for visual breakpoints to tell the whole story. In these cases, "some breadcrumbs" from the call stack is just the thing I need. If the edge facets went wrong, I log all the places where the faceter made an AF_POINT. If the quad tree didn’t work, log each step of its creation to see where we made an unnecessary split or failed to make a necessary one.
A good text editor and "diff" like program gives you some leverage that you wouldn’t otherwise get. Together with pictures of the problem, this can be just the thing.
So: do you have any guilty secrets related to debugging?
Posted: March 22nd, 2012 |
Last August, I made a huge change in my life - I decided to forego a stable, mature relationship and go long-distance. No, not my husband . . . Spatial. My family and I moved to Ireland and I began working for Spatial remotely. At first it was really hard. I missed our time together (all those meetings in the board room, sigh), sharing common experiences (no more bathroom chat, sniff), and all the little things you take for granted until they're gone (bagel Fridays, never running out of milk for your (decaf) coffee, a printer). What made it even harder was the magnitude of the distance - I had moved to a country far away from everyone (only 1 Spatial customer), 7 hours away from headquarters, and not a single decent cup of decaf to be found in the whole country. On top of that, I'd taken on a new role as a Technical Account Manager. I'd never worked directly with customers before, I hadn't done development in quite some time, and now I was responsible for ensuring their success . . . from Ireland! The first week of working in my new 'office' (a cheap IKEA desk in the corner of the living room), I was asking myself, "What have I done?"
Joking aside, the change has been extremely interesting and probably not dissimilar to what our customers experience every day. We sell technically advanced products with somewhat of a learning curve and for the majority of my workday, I'm on my own if I get stuck.
A few things I've learned to do:
- Leverage every resource available - our docs, our samples, always keeping the latest packages, free viewers, wikipedia, our internal wiki, you name it.
- Be prompt - When I was in development, I would often focus intently on one project and let other emails and requests slide. This allowed me to concentrate, and somehow I could always get caught up afterwards. I can't do that anymore because I know that I only have a short window of time to interact with people (whether customers or developers), which could cause big delays. I now think of myself as the person that keeps everything moving, and I try to do whatever communication I can to ensure that even if questions aren't answered, at least the other party is still able to proceed with their work. Heck I have organized my Inbox for the first time in 10 years.
- Do my homework - On the flip side of replying to every email, I also try to make sure that when I do have time to look at a problem, I take it as far as I possibly can. Did I look at that file in Catia? Did I open it with the latest version of Interop? Have I tried an old one too? Have I looked at it in both ACIS and CGM? Should I look up affine transforms before I write to somebody to ask how to scale them? Is that file really corrupt? Maybe I'd better download it again to check.
- Ask the dumb question - When I've gotten as far as I can, I have to get on the phone and in blunt terms, explain to somebody that no, I really don't know how to scale a transform from mm to inches and what does affine mean, anyway? I don't have much time for communication, so the more direct I can be about my shortcomings, the better the likelihood that I'll get what I want. And often it turns out that the reason I can't find the answer is because the problem isn't straightforward, and, similar to many challenges we get from our customers, the asking of the question gives development new information about how to improve our products.
- Make the most of contact time - skype, IM, phone calls. If I'm on the computer late at night doing something personal, taking 5 minutes to talk to somebody can possibly eliminate 1 hour of working solo the next day (and I can go to yoga!)
Its funny how getting further away from Spatial has actually brought me closer to the customers and prospects I work with. These may be things that they've already learned to do. I'd encourage any of you out there to definitely keep doing more of the same: use all of Spatial's resources to go as far as you can, don't hesitate to call, or email, ask your TAM lots of questions, even ones that seem dumb, and above all, go to yoga.
Posted: March 19th, 2012 |
We’ve known for a long time that the integrity of B-rep data plays a major role in the success of downstream modeling operations; but it has always been a difficult task communicating this back to our users in a meaningful manner. For ACIS we have had an external geometry and topology checker since the beginning of the product; it serves the function of defining illegal state(s) of the model. It has, and still does, serve its purpose. But I knew something was amiss when I kept seeing in-house debugging tools written by developers that reported back B-rep pathologies that were never a part of our external checker. The ACIS developer would see a pathology using these tools and, more often than not, deal with the situation by placing a “fix” in the algorithm to detect the pathology and correct the situation by some form of data manipulation (e.g., re-computing secondary geometry) or expanding the algorithm to handle more numerical inaccuracies / bad data. Although this is one way of doing business (and it shields the application developers from the immediate problem), you trend towards a slower modeler on good data, and bloated B-rep data size on bad data. What’s worse, the application developer never understands why.
So it’s been a long standing issue with ACIS and other modelers I imagine: how do you assess data that is legal, but simply, bad? After observing ACIS developers using their in-house tools the notion of B-rep health (and a future operator) started to crystallize, largely based on the following:
Principle #1: There is a notion of legal, but unhealthy B-rep data. In B-rep modeling, we all would like to live in a black and white world. Tell me, is the data bad or is it not? Well, things are not that simple. For example; it’s not uncommon that we receive models that have edges in them that are slightly greater than the modeling tolerance (sliver edges). They almost always don’t reflect design intent and cause significant difficulties in downstream operations, especially during Boolean operations when the tolerance of the blank (second model in the Boolean operation) might be larger than the length of the sliver edge in the tool (the first model in the Boolean operation). But in the pure definition of the B-rep they are not illegal. They can have a purpose and sometimes do reflect design intent. So we say they are legal, but largely bad (or unhealthy).
Principle #2: The health of your B-rep data is context sensitive. What might be unhealthy B-rep data for a future local operation is not necessarily unhealthy data for a future Boolean operation. For example; almost all local operations, move, taper, remove face require surface extensions. Booleans do not. So imagine a B-Spline surface with parameterization such as below:
Figure 1: Converging parameter lines
The surface will pass any industry standard checker; by all mathematical requirements, it’s legal in the state that it’s in. Booleans should be fine, as well as other operations such as Body Point distance, etc. So, for a lot of application domains the model will work. But extending this surface, you get this:
Figure 2: Surface after extension
It quickly self-intersects. Any operation that requires an extension will fail (depending on the extension distance required). In all my discussions with the development team, we describe this surface (before extension) as being legal, but unhealthy. (Principle #1 again as well.)
Principle #3: B-rep health is measured as a continuous spectrum. We just discussed two cases that are legal, but unhealthy. It’s also the case that many forms of pathologies in B-rep data are very localized. In the case of a high curvature on a surface or bad parameterization, it might not affect the next 100 modeling operations that one performs because you never hit it precisely. If 1 of only 1000 surfaces in your model has high curvature, how unhealthy, really, is your data? Additionally, as I stated earlier, ACIS has a great deal of code to deal with bad data, so your modeling operation might work, albeit less efficiently. So it’s not a discrete value we can state; again, it’s not all good or all bad. For us, it's best expressed using a continuous spectrum. I have been using the analogy I see every year when I use TurboTax® to do my taxes. When completing your taxes they give you an indicator of your chances of being audited. They do not say your tax return is wrong or illegal, or that you will get audited; just the chance that you might.
Principle #4: Make sure the basics are right or forget about it. We recently had model data from a customer that had all analytic geometries represented in the form of B-splines. That is, what should have been an analytic sphere was represented as a (poorly crafted) B-spline. Although not illegal, this has obvious, serious, implications; it’s much heavier on model size for just the representation of the surface itself, not to mention you now have to have p-curves etc. All downstream atomic modeling operations like point-perp and intersections go through general algorithms and don’t benefit from special casing; surface extensions are not natural, etc. But none of this, really, is the main point. To assess the B-rep health of this model was akin to checking the cholesterol level of a patient suffering total organ failure. The model, in this case, was a product of a third-party translator. The lesson here: pick your InterOp solution wisely! The basics have to be right; or the measurement of health is all nonsense. And by using the term basics, I do not mean to imply they are self-evident or easy. We have done a great deal of work on the ACIS translators to make sure the fundamentals are maintained. (Like a math book with the word “elementary” in the title; never, ever, associate that with, “oh, this will be an easy read”. Fundamentals / basics can be very difficult.)
So, as you might assume, (or if you have attended our 3D Insiders’ Summits) a B-rep health operator is coming out in ACIS R23. I hope this gives you an idea of the thought process behind the work. It should also foreshadow potential behaviors, such as context setting and how data might be returned. Additionally, this effort will take on many forms, from the operator itself, to the continual advancement of the healing operators in our InterOp translation suite, and eventually, other various forms of correction. For now, you can play with an early version of the operator in Spatial Labs.
Posted: March 8th, 2012 |
Here’s a quick poll: How many of you have figured out by now that 16,777,217 = 2^24+1, and that the "24" refers to the 3 RGB bytes in RGBA32?
An alternate title I considered for this post was "NoColor is a color", which would have been an inside joke for people who go to science fiction conventions. Considering the audience, I decided to stick with the computer science reference :)
So, what am I talking about? The fact that, for 24-bit RGB colors, there are actually 2^24+1 possible states, since the absence of color is itself a state. This in turn causes problems because it’s very difficult to jam 2^24+1 states into 24 bits. The more subtle problem here is that people often aren’t thinking about the extra state when they write their code, which can lead to "Happy Path" algorithms. So the question is, "How do we provide an interface to customers that manages the NoColor issue in the best way possible".
Let me give a concrete example. In our CGM product, we provide the ability to attach "properties" (such as color) to geometric objects – basically we provide SetColor and GetColor methods. If no color is present, then the object takes on the color of its parent object (or the default color if it is a root object). The problem we had to deal with was how GetColor should indicate the absence of color. More precisely, what should the signature of GetRed be, and what should it do when color is absent?
First, the evil answer: int GetRed() returns a “magic (invalid) value” such as -1 when no color is set:
The reason this is evil is that the server (the Color1 class) is intentionally returning an invalid result, and relying on the person writing the client code to remember he needs to check for a special state, then go down a different code branch in that case. I remember reading somewhere (but can’t find the reference) the "Tiger Trap" principle of interface design: that using the interface correctly should be like a tiger trap – consumers of the interface naturally fall into it. With this interface choice, the tiger trap is in the direction of using the interface incorrectly. An insidious variation on this design which might even be worse is to return a valid value for red in the NoColor case. The reason this might be worse is that an invalid value can be detected by a contract check (in DisplayRedValue() in the example). A valid (but arbitrary) value is undetectable, and can lead to weird results that are difficult to track down.
Next, the answer from my last post: create a Nullable<T> template class and have the GetColor query on an object return a Nullable<Color>:
There are several nice things about this approach:
- The color class is now responsible for only 2^24 states – the NoColor state is managed by the Nullable class.
- The Nullable class is designed for exactly this situation, so the approach is intuitive.
- The tiger trap is now in the correct direction –the compiler won’t let the customer call GetRed() on a Nullable<Color>.
Although the Nullable approach is appropriate in certain circumstances, it still has a drawback: the client still needs to write an if statement when actually getting the RGB values. This problem is solved by the last approach: pass the RGB values by reference, and don’t change them if the color is unset:
The nice thing about this interface is that it caters to the client’s workflow. Basically, the client calculates the RGB values that will be used if the color is unset (typically by looking at parent objects and/or the default color). The client then calls GetRGB – if the color is unset, then the previously calculated colors are left alone, otherwise they’re overridden. This is the interface that we chose to use for color (and other, similar) properties in our CGM product.
We have found this signature idiom to be really useful in a lot of places. For example, it’s a natural fit for a chain-of-responsibility pattern:
(Yes, I know I could reduce this to a single line, but I’m conservative about these things J ) I’m sure many of you are already using this one in your code, but for those of you that aren’t, I hope you find it useful as well.
One last thing: if anyone out there knows the correct tiger-trap reference could you please post it in a reply? I’d really like to track it down for proper attribution.
Posted: March 1st, 2012 |
Contributed by Linda Lokay, VP Marketing and Business Development
It is so exciting to talk with people when they have an experience that lets them finally understand what you do. Today was one of those days. My husband, a musician, had to go to the orthopedist to be fitted for orthotics. His doctor gave him special socks to wear and explained how he was going to record his movement as he walked and ran. He got to see images of his feet in motion and was shown how all of this would be sent through a program to analyze his gait and finally with a press of a button, his orthotics would be made, right there in the same office!
When my husband came home he was so excited to tell me about this amazing process and how this doctor, who built this system himself, must have something revolutionary. He asked me what seemed like a million questions about how someone could make a sock to gather information and then produce the final product with one click of a button. In fact, he said it reminded him of being able to print, but it was 3D.
For those who are familiar with the technologies, the story is not so surprising. Scans producing point cloud data are sent into specialized analysis programs, files are saved and the results are sent to a 3D printer. To be able to explain how one can go from a set of what seemed to be random points on a screen to produce custom orthotics gave me the perfect opportunity to explain how different components (point clouds, modeling/analysis engines, data exchange, etc) are all brought together by a very creative individual, to be able to create custom solutions for every patient. After many years and too many technical ways of trying to explain what Spatial does, all it took was one very personal experience and he FINALLY got it!
I would love to hear other stories about when or how your friends, family, or associates really grasped what you do.
Do you have a real life 3D Experience?
Posted: February 23rd, 2012 |