Tracking element changes - as they happen?

Hi guys,

Is there a means of tracking the changes being made to an element as hey happen? ie, you click on the start point of a line, say, and as you move it, you get notified (cursor position, the element being changed etc).

Is this possible?

I know of the IChangeTrackEvents interface, but I think that only pre/post notifies you of a change event, but not as it happens (dragging etc).

 

Regards

John.

  • Legacy C-style Global Variables

    John: What on earth is dgnBuf? Another cryptic microstation tag-along that the developers have not yet managed to factor out?

    MDL implements C; it is long in the tooth. MDL provides many public global variables, which Dan has illuminated in his table taken from the MDL documentation. dgnBuf is a scratchpad that you can use to store a temporary MSElement while your command is active.

    If you view object-oriented programming and encapsulation as good things, then C-style global variables are a bad thing. But they've worked for several decades and have permitted long-term portability of code which, along with the lack of DGN format changes, have benefitted MicroStation users and developers alike.

    The MicroStationAPI is C++. It emphasises object-oriented programming and encapsulation. It provides classes that avoid those public global variables. The VBA IPrimitiveCommandEvents interface provides a wrapper around the MicroStationAPI primitive command handler.

    With each new version of MicroStation, the MicroStationAPI contains more public classes that we can use. In some cases, they provide functionality not available with MDL; in other cases, they replace MDL functions.  They are at the same time making those public global variables less relevant.

    Regards, Jon Summers
    LA Solutions

     
    Regards, Jon Summers
    LA Solutions

  • Michael,

    Seems like you have developed an 'independent' way of dealing with 'dependencies'. Isn't this going to be a problem for interoperability, in the long term ?

    It sounds like Bentley hasn't thought through the way dependencies work within nested cells, or should they really be objects? I understand that dotNet does not have callback functions, but event functions which are associated with interfaces. The way you are programming does not sound very object or component oriented?

    End user programming tools like GC rely on scripting, but struggles to access stuff implemented in 'proper' compiled or semi-complied code like MDL, C++, C# etc. Apparently, C#, VBA and dotNet interOpts PInvokes provide a bridge. How will you ensure that your parametric elements can talk to, propagate to and from, other parametric objects? After all, the whole point of parametrics is going beyond the elements themselves to include the relationships between them. The last thing you want is for your elements, cells to be 'islands', I think?

    Too many callbacks: It sounds like MDL developers can ask for wake-up calls from any and every hotel in town. Do you know of a better way of doing things? This must cause problems. I hear Sketchup has an Observer class in Ruby, which sounds very much like callbacks, but a bit more OO? And they have some big performance and other issues. I wonder if LabView's StateCharts or MetaCase can be used to organise callbacks? StateCharts look like they are based on Petri graphs that define events in a dependency graph. I guess, if this is defined for your parametric 'cell' or object, then the call backs could be reduced or trapped locally? MetaCase sort of does the same, providing a 'better than UML' way of UI modeling.

    Dependencies graphs is central to GC, and the directed acyclic flavour seems to be a lot less complicated than the old state machine main loop environment. A lot of work on the 'front line' will rely on simple 'scripts' or 'batch file' type hacks to take the next step in productivity. Waiting around for developers to provide the plugin or vertical is not in itself enough. I guess its a Long Tail thing. GC and its DAG working promises to be a powerful middle ground and bridge between end-user and vendor programming.

  • johnds said:

    Errrrrrrrrrrrrrrrrrrrrrrrrrrrrrm, dgnBuf??? What on earth is dgnBuf? Another cryptic microstation tag-along that the developers have not yet managed to factor out?

    Hehe, no, seriously, what is dgnBuf? More importantly, will I find all your suggestions in the .NET (or as Jon would say - VB COM interop) API's?

    Time for sleep now, 12pm in london, yawn!

     

    MDL Variable Types

    Variable

    Type

    Description

    dgnBuf

    MSElement*

    Holds all the information on the current element in dgn-buf. All elements are loaded into this buffer by a locate or element manipulation commands.

    statedata

    MSStateData

    Contains all the information on the current state function. Defined in global.h

    tcb

    Tcb*

    “Terminal Control Block” holds all the information on the current DGN file.  Defined in tcb.h

    mgds_modes

    Mgds_modes

    Contains the mode information about the current execu-tion of MicroStation. Defined in <global.h>

    graphConfig

    MSGraphConfig

    Contains the graphics configuration.  Defined in global.h

    mdlCommandNumber

    long

    Contains the command number of the most recently started MDL application command.

    userPrefsP

    UserPrefs*

    Contains miscelaneous user preferences. Defined in userpref.h

    mgdsPrompt[35]

    char

    Holds the text for the prompt. The default is "uStn>".

    render_designLightP

    void*

    Allows to define custom light source for rendering. ligh source is defined in light.h

    msTransientElmP

    TransDescrP

    A general purpose transient descriptor

    mdlErrno

    int

    Error number for various MDL functions

     dgnBuf is defined in gen_dloadlib.h

    About .NET:

    In .NET is available almost all, but it depends on your level of knowledge of programming in native languages (pointers etc.), whether you will be able to use all correctly. The best bet for you would be to forget about .NET for a while and point to C/C++, because all we suggested here is MDL - not DGN COM Object.

    But if your pointer knowledge is good, following is the way to get dgnBufP in C#:

    [DllImport("kernel32.dll", SetLastError = true)]
    internal static extern IntPtr GetProcAddress(IntPtr hModule, string procName);

    [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
    public static extern IntPtr GetModuleHandle(string lpModuleName);

    IntPtr dgnBufPointer()
    {
      IntPtr ustndll = GetModuleHandle("ustation.dll");

      if (ustndll != null)
      {
        IntPtr dgnBufPAddr = GetProcAddress(ustndll, "dgnBufP");
        if (dgnBufPAddr != null)
        {
          return Marshal.ReadIntPtr(dgnBufPAddr);
        }
      }

      return IntPtr.Zero;

    }

    Then to get dgnBuf use:

    IntPtr dgnBufP = dgnBufPointer();
    IntPtr dgnBuf = Marshal.ReadIntPtr(dgnBufP);

    HTH, Dan

     

  • Nice one Dan, cheers.

    Errrrrrrrrrrrrrrrrrrrrrrrrrrrrrm, dgnBuf??? What on earth is dgnBuf? Another cryptic microstation tag-along that the developers have not yet managed to factor out?

    Hehe, no, seriously, what is dgnBuf? More importantly, will I find all your suggestions in the .NET (or as Jon would say - VB COM interop) API's?

    Time for sleep now, 12pm in london, yawn!

  • John

    my parametric application is not like the one you think of, in fact it is a parametric part-builder for complex things (like a whole side of a building), but it has a strong alphanumerical component. Imagine a 3D office inventar, you can build up everything.

    At some time we wanted tables and chairs to keep their formation, i.e. when you move them, but on the other hand let each of them be touchable as single element. This is something you can achive with groups (named and unnamed) and the group lock (move single or all), but after copying the whole group the named group is gone (the numbered groups mostly stay).

    Meanwhile and after talking to our customers we decided to let this functionality stay as it is and use some other ways of filtering, accessing and grouping objects. There are sometimes different views at the importance of this and that in the view of a developer and a customer :)

    For real time changes the dependency API is worthless (as Jon said), but maybe you like to restrict changes to your elements and those you depend on, then it is really a good choice.

    Michael



  •  

    Unknown said:
    Take the tag functionality as an example: tag an element, then move that host element. The tags move only after you've provided a datapoint; they don't move while you move the host element.  In developer terminology, they don't update during dynamics events.

    OK, so they don't move because dynamics makes a copy of element, so the only way would be somehow monitor changes on dgnBuf and handle them together with all previously suggested stuff...

     

    John:

    You can try this:

    • register global input monitor
    • handle all changes on dgnBuf
    • or if you are not familiar with global input monitoring
    • if incomming command is modifier, save dgnBuf state and wait for input
    • if input begins with datapoint, start view motion callback (monitores same cursor moves as dynamics)
    • get element from dgnBuf and if it is different from saved state modify all another dependent elements
    • for mouse position in world coordinates use mdlSystem_getCursorPosition and correct transform
    • on each another datapoint check dgnBuf state, still global input monitor lets you know all needed

    Dan

  • Dan: Why to do it like this if there is dependency API made for it?

    The Dependency API provide post-change notification that something happened to another element. It doesn't tell that something is happening now, which is what John wants.

    [Edit] Take the tag functionality as an example …

    MicroStation V8i

    Tag an element, then move that host element. The tags move during dynamics. The move command has been enhanced to pick up dependent elements before showing them dynamically.

    MicroStation V8.5

    Tag an element, then move that host element. The tags move only after you've provided a datapoint; they don't move while you move the host element.  In developer terminology, they don't update during dynamics events.

    Regards, Jon Summers
    LA Solutions

     
    Regards, Jon Summers
    LA Solutions

  • johnds said:
    What I found very usefull, and in fact I could'nt have done without it, is that your acad plugin can tell acad that you want to monitor ALL mouse events, and therefore, whenever an acad entity gets modified (for e.g you drag a handle), you can then intruct all associated geometry to update itself based on whatever parametric constrains you may have attached to it- in real time.

    This is also possible in MicroStation, you can set mdlView_setFunction + VIEW_MOTION / VIEW_NOMOTION in combination with mdlSystem_getCursorPosition, mdlInput_waitForMessage or mdlInput_setFunction to know what command is now active and so on...

    But why to do it like this if there is dependency API made for it?

    Dan

  • Yeah, youre correct, dependency != parametrics.

    What I was hoping, after you suggested looking at the Dep api, was hopefully to leverage whatever functionality it may already have, and build on it.

    But it seems that all parameric logic will have to be done by me, which I dont mind doing, I had just thought that there may be a system inplace already that I could make use of.

    Thoughts?

    John

  • Thanks for the info Michael,

    It's interesting you say you have developed your own parametric elements for many years, but it seems you have encountered some difficulty in doing so, I suppose to a legacy of a 'progressing' Microstation.

    I have already developed a Parametric system for Autocad (well, I was until I got fedup with acad's terrible rendering capabilities and even worse export functionality).

    However, all the parametric logic controlling the acad geometry was completely written by me, no use of internals whatsoever.

    What I found very usefull, and in fact I could'nt have done without it, is that your acad plugin can tell acad that you want to monitor ALL mouse events, and therefore, whenever an acad entity gets modified (for e.g you drag a handle), you can then intruct all associated geometry to update itself based on whatever parametric constrains you may have attached to it- in real time.

    So this happens without having to firstly invoke some 'edit' command of my own creation.

    This is all done using the .net api too, so really easy peasy (no offense to c/c++ guys).

    Now, it is this functionality which I am trying to emulate in MS, which I hope is possible, otherwise my plugin will have to have it's own 'move' or 'modify' commands where i can use the IPrimitiveComandEvents blah blah interfaces to track 'dynamics' events.

    Hehe, oh happy days.

    John.