Author Topic: Duplicating an existing associative hatch in C#  (Read 4154 times)

0 Members and 1 Guest are viewing this topic.

akaranta

  • Guest
Duplicating an existing associative hatch in C#
« on: November 19, 2015, 04:55:57 AM »
I need to create an identical hatch to a given one (using C#). In the real case this is done in a different process on a different computer so I can't use clipboard, copy commands or such - I need to read the object's properties and recreate a new instance based on those.

I already posted a related question here: http://www.theswamp.org/index.php?topic=50188.0 (link provided for reference - no need to read through that, I'll make this post self explanatory).
With the kind help from theswamp users I got the access violation problem solved and everything seemed to work. Now after some testing it turns out that the code only works on associative hatches that have a single object as their boundary. If the associative hatch is bounded by several objects the call to AppendLoop causes eInvalidInput (see the attached code, lines 82-87):

Code: [Select]
    // option 1: add the hatch loop as it is in the original hatch.
    //           Problem: call to AppendLoop throws eInvalidInput

    using ( var boundaryColl = new ObjectIdCollection( associatedObjectIds ) ) {
        h.AppendLoop( ltype, boundaryColl );                   
    }

I also tried adding all the boundaries as separate loops (see the attached code, lines 89-99):

Code: [Select]
    // option 2: add each boundary object as a separate loop
    //           ( as in the second code sample in http://www.theswamp.org/index.php?topic=20832.msg253807#msg253807 )
    //           Problem: the hatch is created in the wrong place
   
    using ( var boundaryColl = new ObjectIdCollection() ) {
        foreach ( var oid in associatedObjectIds ) {
            boundaryColl.Clear();
            boundaryColl.Add( oid );
            h.AppendLoop( ltype, boundaryColl );
        }
    }

The problem with this approach is that the hatch is created in the wrong intersection of the given objects.
   

Attached is a drawing and code to easily reproduce the problem. Here's what to do:

  * comment out either option 1 or option 2 in the source code provided (you can find them easily by searching for e.g. "option 1") depending on which of the given problems you wish to reproduce
  * compile the given source code and load it to AutoCAD to make the commands defined therein to be available
  * open the attached drawing (hatch_with_circular_boundary.dwg)
  * select the hatch inside the rectangle that does not intersect with any other object and run command NSASSOCHATCH (that invokes the provided code). This works fine with both option 1 and option 2 code
    as there is only a single boundary object
  * now select the hatch in the intersection of the circle and and a rectangle
  * using code in option 1 results in eInvalidInput thrown from AppendLoop
  * using code in option 2 results in the new hatch being created in the wrong intersection of the circle and the square

 
Any ideas on how to successfully recreate an associative hatch with several boundary objects using C# are highly appreciated.
 
 
My environment: AutoCAD 2015 64-bit on Windows 7

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Duplicating an existing associative hatch in C#
« Reply #1 on: November 23, 2015, 06:20:14 AM »
There appears to be numerous generations of the hatch in that drawing ...

because you're performing this process on 'different process on a different computer' , have you considered simply writing a DXF of the selected entities then reading the DXF into the control drawing.
Document naming would depend on your work flow I imagine.



kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

akaranta

  • Guest
Re: Duplicating an existing associative hatch in C#
« Reply #2 on: November 24, 2015, 04:14:54 AM »
Thanks for your response.

I pondered about that approach but that does not seem feasible for several reasons. First of all, I need to track the creation and changes on all the objects in the drawing. Doing so by creating small dxf files would get difficult (e.g. what to delete from the current drawing once a change comes along) and I imagine the performance would get pretty bad with hundreds of thousands of entities.

So I believe I really need a programmatic way to reproduce an associative hatch. Preferably in C# but C++ would also be fine.


Here's a brief glance at what the app I am working on actually does:

http://neromsoft.com/nsd.htm


Here's some more information I have figured out analyzing this case:

The hatch in question should be a fairly basic associative hatch. It is created simply by drawing two intersecting objects, e.g. circles, squares or boths, running H (=hatch) command and clicking inside the intersection. A few of these can be found in the attached drawing but they are trivial to produce in any drawing.

The single loop that a hatch like that contains has such data that I can't figure out how it could be reproduced with the current AutoCAD C# API. The loop contains a polyline (loop.IsPolyline == true, HatchLoopTypes.Polyline flag in on in its type) and associated entities. The loop's type is HatchLoopTypes.Derived | HatchLoopTypes.Polyline | HatchLoopTypes.External, two first of which only make sense in relation to the polyline and the last in relation to the db resident boundary entities.
The Hatch class contains overloads of AppendLoop to append either a polyline loop (Hatch.AppendLoop(HatchLoopTypes loopType,Point2dCollection vertexCollection,DoubleCollection bulgeCollection)) or a loop with db resident entities defining the boundary (Hatch.AppendLoop(HatchLoopTypes loopType,ObjectIdCollection dbObjIds)) but not both for the same loop. There does not seem to be methods for modifying an existing loop.
Having the polyline and the boundary entities in the same loop is not critical, I would be content with creating a hatch that looks and behaves the same as the original even if the number of loops and / or their loop types were different.
I have thus far failed. I already posted the code that just adds the boundary entities as separate loops (adding them together in a single loop gives eInvalidInput no matter whether I give HatchLoopTypes.Default or HatchLoopTypes.External as the type, other type values do not seem to make sense here). I also tried adding the polyline read from the original loop as a separate loop before or after the loops defined by the entities like so:

Code: [Select]
    var loop = originalHatch.GetLoopAt( i );

    var pline = loop.Polyline;
    if ( pline != null ) {
        Debug.Assert( loop.IsPolyline );
        // pline.
        var bvs = pline.Cast<BulgeVertex>();
        Point2dCollection vertexCollection = new Point2dCollection( bvs.Select( bv => bv.Vertex ).ToArray() );
        DoubleCollection bulgeCollection = new DoubleCollection( bvs.Select( bv => bv.Bulge ).ToArray() );
        h.AppendLoop( HatchLoopTypes.Outermost | HatchLoopTypes.Polyline | HatchLoopTypes.Derived, vertexCollection, bulgeCollection );
    }

This did not seem to make any difference in the end result. :(

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Duplicating an existing associative hatch in C#
« Reply #3 on: November 24, 2015, 04:34:56 AM »


Quote
I need to create an identical hatch to a given one (using C#). In the real case this is done in a different process on a different computer so I can't use clipboard, copy commands or such - I need to read the object's properties and recreate a new instance based on those.

Please clarify this process.

Different process on different computers ?   ... I imagine this could be cloud based.

I need to read the object's properties  ??      ... and do what with them ? all objects ?

and recreate a new instance based on those.  ? How? How is the date stored? How is the data transported between computers? How are you re-creating the instance.


Is your goal to create a pseudo multi user system ??

Would using xrefs smartly achieve the result you want ?
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Duplicating an existing associative hatch in C#
« Reply #4 on: November 24, 2015, 04:50:44 AM »

OK, I had a look at the site page.
According to the site you can already do this stuff :)
Good luck with the application.


kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

akaranta

  • Guest
Re: Duplicating an existing associative hatch in C#
« Reply #5 on: November 24, 2015, 04:56:18 AM »
Quote
Different process on different computers ?   ... I imagine this could be cloud based.

It can be thought that way.

Quote
I need to read the object's properties  ??      ... and do what with them ? all objects ?

Send them to the server which saves them to a database and broadcasts them to other clients. With all objects, yes, but the problem I am trying presently to solve is with associative hatches.

Quote
and recreate a new instance based on those.  ? How? How is the date stored? How is the data transported between computers? How are you re-creating the instance.

When a client autocad makes a change in the drawing a message about this is sent to the server. The server broadcasts the message to the interested clients (i.e. the ones having the said drawing open) and thus a client autocad receives a message about a change to the drawing (e.g. create, modify or delete an entity) and acts accordingly. The data is stored in a central database. The clients do not directly communicate with each other but with the server which relays the messages.
The messages contain the necessary information about the object's properties for the client to perform the change.
Creation, modification and deletion is done using the AutoCAD C# API.

Quote
Is your goal to create a pseudo multi user system ??

Not a pseudo but a real multi user system.

Quote
Would using xrefs smartly achieve the result you want ?

To an extent, yes, but not all the way.

Quote
According to the site you can already do this stuff

I have not looked in detail what the information there says but it should say we're not all the way there yet, i.e. are missing support for some object types. If it doesn't I'll have to discuss it with the person responsible for the web site content.


I would like to keep the discussion in this thread to things that are relevant to the presented problem, i.e. recreating an associative hatch using either AutoCAD C# or C++ API. If you are interested in the particulars of our application I will gladly answer your questions but would prefer to do so in private messages / email so as to not clutter this thread.

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Duplicating an existing associative hatch in C#
« Reply #6 on: November 24, 2015, 05:03:44 AM »

Quote
The messages contain the necessary information about the object's properties for the client to perform the change.

What form does the property data take ?
ie: Is it a DXF dump
if not, what ?
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Duplicating an existing associative hatch in C#
« Reply #7 on: November 24, 2015, 05:08:14 AM »

Quote
If you are interested in the particulars of our application I will gladly answer your questions but would prefer to do so in private messages / email so as to not clutter this thread.

I'm only interested in solving a technical problem.
To be able to do this, ALL the relevant criteria needs to be available. Anything else is a waste of time and effort.

kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

akaranta

  • Guest
Re: Duplicating an existing associative hatch in C#
« Reply #8 on: November 24, 2015, 05:29:20 AM »
Quote
What form does the property data take ?
ie: Is it a DXF dump
if not, what ?

The message is not a DXF dump - it contains the values of the object's relevant properties (as strings, booleans, doubles etc. and arrays of the same). To take a very simple example, for a line it contains the coordinates of the start point and the end point (+ properties common to all entities such as color). The points mentioned are not in any autocad specific format but just a set of doubles. The values for the properties are read from the objects using the AutoCAD C# API, e.g. the start point of a line is read using Line.StartPoint property (and then transformed into a double array to be transported as no AutoCAD specific data types are used in the messages themselves).
Thus, a message about creating a point could be thought to look as follows:

Code: [Select]
{
   :operation  :create
   :type          :point
   :drawing-id xxxx
   :object-id   yyyy // this is a GUID not AutoCAD ObjectId as that is not globally unique
   :start-point [0.0 1.0 0.0]
   :end-point   [10.0 20.0 0.0]
}

The data for a hatch is naturally much more complicated but the idea is the same.

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Duplicating an existing associative hatch in C#
« Reply #9 on: November 24, 2015, 05:53:43 AM »
Sounds to me as if you need to define the container ... or container options.


Personally, I'd put your own wrapper around the DXF data for the Hatch.

I think it would be reasonably fast.

dxf does stand for  Drawing eXchange Format.

It should also be relatively future proof.

kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

akaranta

  • Guest
Re: Duplicating an existing associative hatch in C#
« Reply #10 on: November 24, 2015, 07:06:52 AM »
Quote
Sounds to me as if you need to define the container ... or container options.

Sorry, I don't get your meaning here?


By "putting my own wrapper around the DXF data for the Hatch" do you mean to get the definition of that single entity as DXF (how does one do that?) and somehow import that into the target drawing? I see several problems to which I don't immediately see a solution to.

If I understand correctly DXF is a format for representing a whole drawing, not single entities. This has several implications, some of which are mentioned below.

The question is about associative hatches. The associated objects would need to be included in the same DXF? However, bundling several objects together like this (instead of storing them separately and just storing a link between them) sounds like it would make tracking changes to these objects much more complicated.

As a test, I created a simple drawing with two intersecting rectangles and an associative hatch in one of them (as in my attached drawing). The file size is 121kb, which is a huge amount of data compared to the number of bytes needed to represent the corresponding data as the property values for the corresponding objects. I imagine most of this is some overhead from dxf representing an entire drawing, not just single objects.
This may be irrelevant if there is a relatively straight forward way to get the dxf definition of a single object and to read the dxf definition of a single object to a drawing (also obtaining the ObjectId of the object thus created).

The hatch may be part of a block. It might be tricky to "extract" that hatch from that block to a separate dxf and when a change is received, taking out the one that is there and putting in the new one (from a separate dxf).


Sending single associative hatches as dxf files may be doable but at a quick glance it does not seem like an easy or otherwise attractive alternative. I would much prefer to find a way to do this using the API.