# Friday, August 15, 2008

has an article stating that the next version of will support multiple displays.  I'm very excited about this enhancement.  Long Long ago, we went to dual head Matrox G200 cards and dual displays for all developers at Kanotech.  This was fantastic. Particularly since 95% of my time was spent doing AutoCAD development.  Whether it was Visual Lisp, VB, or C++ - debugging something in AutoCAD screamed for multiple monitors. The AutoCAD window would start up and switching between the IDE to step through code, and doing what needed to be done in the AutoCAD UI was a huge pain.

More recently, I was running quad 19" monitors, and Visual Studio was maximized (manually) across the two center monitors.  This was a bit of a pain - but left a lot of room for running other apps as well as debugging.  Now - I've got a Samsung 305T 30" monitor for primary, and a 24" and one remaining 19" (need to upgrade this one of these days so everything looks consistent =]).  Visual Studio is maximized on the 30" and I debug on the left or right monitor.

More details on the Multi-Display enhancement can be found - sadly it doesn't have much detail other than "Windows within Visual Studio should be docked by default and allow the user to undock any window and move it to another display on the system".  I really hope they knock this one out of the park though.

Technorati Tags:
Friday, August 15, 2008 9:41:54 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |   |  Trackback
# Tuesday, August 05, 2008

It's just about that time.  is December 2nd to 5th at in .  Signup begins on August 15th!  Before you register, try contacting your Autodesk rep, or Autodesk reseller and ask if they have any AU discount codes available.  If you register, and get a discount code after the face you can call up the helpful events staff, and they will apply the credit after the face.  If you are planning on attending, I strongly encourage you to book as close to the 15th as possible.  Rooms at the Venetian fill up quickly, and its a huge benefit to be staying in the hotel where the conference is located.  "Across the street" in Las Vegas units of measurement is a twenty minute walk =).

This will be my third AU, and I'm looking forward to it.  I was a bit concerned the first time I attended an AU about the technical level of the courses.  I was very pleasantly surprised to find that I was able to fill my week with courses targeting GIS developers, and that the course content was pretty good.  I really enjoy the classes put on by the Autodesk developers and technical staff. 

This year again the is putting on a full schedule of developer courses.  Hurray!  Autodesk Developer Network members can also sign up for the extra ADN Dev Day on December 1st wherein you get an NDA sneak peek at the up and coming 2010 releases.  The extra day is free, you only need to cover the cost of the additional night's stay.  Room rates are pretty decent for extra nights.  I believe my extra nights last year were around 160 a night.

Autodesk has released a complete list of the and additional information can be found on the .  

If you're planning on attending, mayhaps we could get some of the GIS nerds together for some drinks.  Drop me a note if this interest you.

Technorati Tags:
Tuesday, August 05, 2008 1:15:58 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |   |  Trackback
# Sunday, August 03, 2008

My friend and colleague recently wrote an article on the (sometimes known as @MAppDR, ATMapp or ATT_MApp).   A strange twist of events also resulted in me working very briefly with the most "recent" build of the product.  It had been many years since I really saw the application running - so I had a bit of a fresh eye.  This made me a little bit nostalgic, and also quite proud.  We had really made some amazing software when you got right down to it.  Unfortunately, in "internet years" it has sadly become a dinosaur.

Long ago (it seems like a lifetime) I worked for a company called Kanotech.  One of my first real development projects of scale was on the .  @MApp was a powerful extension built for AT&T/Comcast cable.  My first task was to head to Seattle and learn how field technicians would walk the existing RF Plant (fancy word for cabling and RF equipment) and map the existing assets, on paper.  The first task was devise a way to run @MApp on one of the early rugged .  I walked the streets of the greater Seattle area with some of the field technicians and got my first introduction into the world of cable TV networks.  At the end of this trip I had a collection of notes and enough information to design and implement the pen based version of @MApp.  This was the beginning of my life with @MApp.

With the bigger picture in mind, there were many underlying goals for @MAppDR, one of the key needs was standards enforcement (and creation -  Evan created the first solid standard which, though very much evolved is still in use today).  Like many organizations back in the day (and likely even today) the mapping data being generated was garbage.  Each division, each consultant, sometimes each drafter had their own set of "Standards".  As Evan put it, the mapping data was "Only good for printing" - and even that was a stretch in some of the sample data we saw.  Our top priority was to create a set of tools which facilitated drafting standards compliant drawings - as well as a method to test each drawing to ensure the drawing was truly compliant.

Under the hood, @MAppDR was all database driven.  Layers, cable types and properties, even symbols and block attributes could be configured in the database.  Generic lisp calls were defined to allow simple wrapper functions to be created to add new entities to the application.  The application had been created using an extensive amount of , VB6, , Python, and SQL Server/Access databases.  Let me tell you, I still have nightmares about parentheses =).@MApp DR drafting tools

The drafting tools, in retrospect were good.  Damn good.  Obvious elements were there, select a cable, or equipment type using standard AutoCAD toolbar buttons.  @MAppDR went a step further.  It would create/set the layer, set the desired object snaps, draft the cable.  Network connected equipment would snap to the cable, rotate, trim and physically connect itself to the model.  In some circumstances, inserting a block/cable of a certain type also required an accompanying block.  If required, the user would be prompted to insert these as well.  In some cases - these blocks were placed automatically.  Using @MAppDR - a user could draft very clean RF drawings without having to really know  AutoCAD.  Every piece of possible equipment was available from a comprehensive set of toolbars - and only one click away. 

On insertion of blocks, the user was presented with a form powered by the attribute information stored in the databases.  Some attributes were required, some were populated programmatically based on nearby objects or other conditions, and some were selected from lookups or manually entered by the user. 

@MAppDR had a really cool connectivity process.  This process would perform physical connectivity on the network, following rules defined for equipment inputs and outputs.  In addition to this, rules were also defined to dictate what equipment could connect to other equipment.  This connectivity, in my opinion was one of the most powerful components of @MAppDR.  Connectivity information was stored on the entities.  When a trace was done, we could follow the network and do all kinds of great reporting.  I recall one situation where we knew that in situations where a specific combination of equipment was setup - it would cause service problems.  Within a few hours, I had a batch process created that would process hundreds of drawings and spit out a report of nodes, and locations where this combination existed.  The problems in the field were fixed even before customer complaints came in. 

One of the key requirements for @MAppDR was a quality assurance process.  We defined several "levels" of QA.  Each level of QA required a password to execute.  The first two levels of QA were for contractors doing mapping redraft, or drafting.  These levels would let the consultants know that the required data had been entered and would "stamp" the drawing.  The drawings were then submitted, and Comcast staff would run their password protected version of the QA routines - which would verify that indeed the contractor had done the required work.  If not, the drawing was rejected and the contractor had to fix it.  I can say with a great deal of certainty that Comcast, using @MAppDR is one of the few organizations with near perfect data.  And the things they do with that data are incredible.@MAppRF Drafting Enhancements

The final version of @MApp, @MappRF could have dominated the cable industry.  Sadly, it was never completed.  This release added RF design to the drafting.  A library of equipment was created, as well as design parameters which were sub-selection of the equipment that let the RF designer know what equipment was available to be used.  All of the equipment's operating parameters were captured.  As the user drafted equipment, the actual equipment model would be selected on the attributes.  This allowed us to increase the efficiency of populating attributes during the drafting phase all the while making the stored data even more accurate and complete.   

One of the coolest bits of @MAppRF was what came to be known as the TRID.  The TRID was a  multi-threaded C++ control was created that contained a tree-grid hybrid.  This form could be docked within AutoCAD or floating on a separate monitor.  As the user drafted, the RF signal and power calculations were performed in real-time, without interfering with the drafting process.  I recall being told, this project would be simple.  RF design is just table math.  And it is, but, mix in a multi-threaded C++ form running per entity calculations on a potentially infinite number of @MAppRF Design Diaglog - the TRIDfrequencies both going forward, and backwards - oh and sprinkle in a little bit of power draw calculations.  Then tell me its simple.  =)

If I could do it over again.  Wow, what a difference the current technology would make.  By far the single largest flaw @MApp has is its dependence on drawing based storage.  Given the timeline, we didn't have a choice.  was available, but immature.  Going with Oracle at that time would have likely been more grief than it was worth.   Seamless map access would be a must.  Given the times we used a special piece of ObjectARX code called the SPE.  This gave us spatial analysis abilities that rival even Oracle Spatial.  One of the major downfalls here is that it required AutoCAD to run.  Therefore - most of the calculations had to occur within AutoCAD itself.  This became a problem as other applications could benefit from these operations - but couldn't take advantage of them without also being AutoCAD based. 

Leveraging a multi-tiered architecture, a lot of the common functions could be moved to a more like architecture.  Now, though the TRID could still be a multi-threaded form in AutoCAD - the calculations could be done on the server side - thereby making the AutoCAD portion a presentation layer - instead of a business logic layer.  Now the RF design calculations could be done in any user interface - instead of having to opening a drawing in AutoCAD. 

And that my dear reader, concludes my epic tale on @MApp.  Even this large novel like piece only scratched the surface of this project.  It was my life for many years.  I slept under my desk a number of times - but it was a great project.  It was fun to think about it again and put together something to share with you. =)

Technorati Tags: ,,
Sunday, August 03, 2008 12:51:26 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |   |  Trackback
# Wednesday, July 30, 2008

Everyone knows there is a , right?  Well ok, maybe you didn't - but there is.  What that limit is depends on the browser.  There is a lot of conflicting information out there on the magical .  An RFC defines it, but no one really seems to pay attention to those anyhow.  (Are you listening Microsoft, of course you are! =]).  Anyhow, for IE, the query string length is usually around 2000 characters.

However, in most cases you're better off using a form and posting your data up to the server side that way, as the limitations on data are so large you will likely not need to worry about them.  Sometimes, query strings can also show your users just a little too much information - though I'm by no means a proponent of "security through obscurity" hiding a little bit more from your users will keep the curious ones a little more in check =).

When working with / we need to grab some potentially massive XML strings from the MgMap object and pass these along to the server side for processing.  Take the selection XML from the MgMap object, even a single entity selection can use a significant portion of the characters available in the query string.  On top of that, passing this data via query string requires that the data be URL encoded, using even more of our precious query string characters.

Depending on the design of your application it may not always be feasible to define a hard coded form, or even a form defined server side using ASP.NET.  In some cases (you guessed it - my case) you may want to use javascript and do all the work on the client side to define a form and pass the data long that way.

Well you're in luck, I found a pretty nice solution (WELL, at least I'm liking it  =]).   I'm kicking myself for not realizing this long ago, but oh well.  So the following javascript function demonstrates how to build, add, populate, and submit a form on the fly using some information from the MgMap object.

   1: function postData()   
   2: {   3: //get the map   
   3: mapObj = GetMap();   
   4:  
   5: //define the new form   
   6: var newForm = document.createElement("form");   
   7: //set the method to POST - the opposite of query strings..   
   8: newForm.method="POST";  
   9:  //add the new form to the current document  
  10:  document.body.appendChild(newForm);  
  11:  
  12:  //lets get some data and add it to the form  
  13:  AddFormElement(newForm, "MapName", oMap.GetMapName());  
  14:  AddFormElement(newForm, "SID", oMap.GetSessionId());  
  15:  //be sure you escape the selection XML - or you will get an error on post about a   
  16:  //"potentially dangerous form value".  Remember on the server side to Server.UrlDecode() it  
  17:  AddFormElement(newForm, "sel", escape(oMap.GetSelectionXML()));  
  18:  
  19:  //lets create our new window  
  20:  var szTarget = "targetWin"  
  21:  newForm.target = szTarget;  
  22:  //set the name/path of the ASPX file you want to process your form with  
  23:  newForm.action = "/url_to_open/file.aspx"  
  24:  
  25:  //open a new window to submit the form to.  Its a good idea to have a blank.htm so you don't get a file not found error  
  26:  var oWin = window.open("blank.htm",szTarget,'menubar=yes, resizable=yes,scrollbars=yes, status=no,toolbar=no,width=300, height=300');  
  27:  
  28:  //give the window focus.  Users like this  
  29:  oWin.focus();  
  30:  
  31:  //submit the form - it will now open in the new window  
  32:  newForm.submit();  
  33:  //remove the form from the document, we're done with it  
  34:  document.body.removeChild(newForm);  
  35:  }  
  36:  
  37:  function AddFormElement(form, elementName, elementVal)  
  38:  {  
  39:      var newElement = document.createElement("<input name='" + elementName + "' type='hidden'/>");  
  40:      newElement.value = elementVal;  
  41:      form.appendChild(newElement);  
  42:      return form;  
  43:  }

 

On the server side, you can now access this data from ASP.NET using Request.Form, for example Request.Form("MapName") would give you the map name.  Don't forget when retrieving the selection XML to run that through Server.UrlDecode, or HttpUtility.UrlDecode.

As usual, any comments, bugs, or rotten fruit - send em my way.  Enjoy!

  Technorati Profile
Wednesday, July 30, 2008 3:22:27 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |   |  Trackback
# Tuesday, July 29, 2008

Tonight I came across the .  I had read about it, and made a mental note that one day it would be an issue.  That note wasn't very good, and I completely forgot about it.   I was wrapping up the updates around the report this eve and fortunately I bothered to select the entire map and run through a report.

RADE Report - but what, only 20 records returned?

Report looked good.  The results were sorting, checkboxes working.   Wait a minute, I selected the entire map.  There should be more than twenty items returned.  So a quick search of my twelve thousand saved e-mails from the turned up what needed to be done.  Fortunately Autodesk added a GenerateFilters call to MgSelection.  This call returns an MgStringCollection of filters.

Basically the solution to this problem is to use GenerateFilters instead of GenerateFilter, and loop through the results.  Each time, appending the returned keys to the complete list.  For example:

   1: Public Shared Function GetSelectedKeysString(ByRef siteConn As MgSiteConnection, _
   2:     ByRef resSvc As MgResourceService, ByVal oMap As MgMap, ByVal SessionId As String, _
   3:     ByVal SelectionXML As String, ByVal layerResID As MgResourceIdentifier, _
   4:     ByVal keyFieldName As String) As String
   5:  
   6:     Dim szKeys As String = ""
   7:     Dim oSel As New MgSelection(oMap)
   8:     oSel.FromXml(SelectionXML)
   9:     Dim curLay As MgLayerBase
  10:     'isolate the layer
  11:     For Each layerItem As MgLayerBase In oSel.GetLayers
  12:         If layerItem.Name = layerResID.Name Then
  13:             curLay = layerItem
  14:         End If
  15:     Next
  16:  
  17:     Dim featSvc As MgFeatureService = siteConn.CreateService(MgServiceType.FeatureService)
  18:     Dim queryOptions As New MgFeatureQueryOptions
  19:     Dim featureClassName As String = curLay.GetFeatureClassName
  20:     'workaround using GenerateFilters and looping through the results as needed
  21:     Dim featureReader As MgFeatureReader
  22:     Dim filters As MgStringCollection = oSel.GenerateFilters(curLay, featureClassName, 20)
  23:     Dim filterCnt As Integer = 0
  24:     While filterCnt < filters.GetCount
  25:         queryOptions.SetFilter(filters.GetItem(filterCnt))
  26:         featureReader = featSvc.SelectFeatures(New MgResourceIdentifier(curLay.GetFeatureSourceId), featureClassName, queryOptions)
  27:         While featureReader.ReadNext
  28:             If szKeys = "" Then
  29:                 szKeys = ConvertPropertyToString(featureReader, keyFieldName)
  30:             Else
  31:                 szKeys &= "," & ConvertPropertyToString(featureReader, keyFieldName)
  32:             End If
  33:         End While
  34:         featureReader.Close()
  35:         featureReader.Dispose()
  36:         filterCnt += 1
  37:     End While
  38:     Return szKeys
  39: End Function

 

In this code, we get the selection from the MgMap object and then isolate the layer in question.  Then we generate the collection of filters and loop through them.  Each time, adding the appropriate value to the list of keys.  Note the use of ConverPropertyToString, this needs to be used to ensure that the various data types are converted over to string.

I've included this function as well as a couple other handy related ones in the attached zip file

.  If you're looking for a C# example of how to use GenerateFilters one is provided in the .

After making these changes my reports now look all proper! hurray.  Maybe I can hit the sack now?  nahh.

RADE report - but this time everything looks ok 

Tuesday, July 29, 2008 10:37:46 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |   |  Trackback