Author Topic: Conceptual thinking: selections per layer  (Read 3111 times)

0 Members and 1 Guest are viewing this topic.

huiz

  • Swamp Rat
  • Posts: 919
  • Certified Prof C3D
Conceptual thinking: selections per layer
« on: October 06, 2011, 03:42:33 AM »
For a tool I need to know how many texts, lines, hatches and blocks are placed on each layer.

I can do a selectionset of texts and layername to find out how many that are. Then I can do a selectionset of lines and layername to find that count. And so on.

After getting the amount of blocks I also need the blockname that is most used on that particular layer. Do I need a loop through all blocks and count per blockname how many there are?


Is there a much easier way to do this?
The conclusion is justified that the initialization of the development of critical subsystem optimizes the probability of success to the development of the technical behavior over a given period.

bargool

  • Guest
Re: Conceptual thinking: selections per layer
« Reply #1 on: October 06, 2011, 08:11:24 AM »
For example, you can make a Dictionary<string, int> (string is for layername and int for number) for each type of needed entity.
Then You can iterate entities in current space (for example), detect type of entity and work with its Layer property filling the Dictionary.
One iteration for all information.
Then you can work just with dictionaries.

Bryco

  • Water Moccasin
  • Posts: 1883
Re: Conceptual thinking: selections per layer
« Reply #2 on: October 06, 2011, 10:00:44 AM »
It depends on how you treat nested blocks. If there is a hatch in a nested block and you want the layer that the hatch is actually on then you may be better off cycling threw the blocks, modelspace being one of them

huiz

  • Swamp Rat
  • Posts: 919
  • Certified Prof C3D
Re: Conceptual thinking: selections per layer
« Reply #3 on: October 06, 2011, 01:09:54 PM »
No nested blocks, just kind of blockcount per layer. @bargool: why using a dictionary instead of a class, or an array?

The goal of this new tool is to create a legend in the drawing based on layer information. Loop through each layer (if it is on and it contains objects), count if there are texts and mtexts, count how many lines, arcs, polylines, count how many blocks. Based on the counts I can predict the row in the legend which says: That layer contains (mostly) lines so this row in the legend shows a line and a description (layer desc or layer name).
But in case there are mostly (or only) blocks on that layer, I want to know which block is most used.

If I just start looping each layer and each object I think I use too many resources. So I thought there must be a better way to collect this information.
The conclusion is justified that the initialization of the development of critical subsystem optimizes the probability of success to the development of the technical behavior over a given period.

Draftek

  • Guest
Re: Conceptual thinking: selections per layer
« Reply #4 on: October 06, 2011, 03:20:12 PM »
I'd stay away from selection sets if possible.

bargool's idea is good and fast.

bargool

  • Guest
Re: Conceptual thinking: selections per layer
« Reply #5 on: October 06, 2011, 04:28:38 PM »
the topic is "Conceptual thinking"  :-)
I just mean that you need only one iteration, because all entity types (or nearly all?) have field "layer". How do you organize information is your decision.
You can use class. For example, "LayerInformation" with fields int blockCount, lineCount and so on, and some methods.. And information about file is other class, which contains List<LayerInformation>..

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Conceptual thinking: selections per layer
« Reply #6 on: October 06, 2011, 04:31:39 PM »

LINQ may be worth looking at.
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.

bargool

  • Guest
Re: Conceptual thinking: selections per layer
« Reply #7 on: October 06, 2011, 04:40:50 PM »
LINQ may be worth looking at.
Yep! LINQ is very good!
For example, we will have all mtexts in BlockTableRecord btr with this query
Code: [Select]
var foundedTexts = from ObjectId id in btr
where transaction.GetObject(id, OpenMode.ForRead) is MText
select (MText)transaction.GetObject(id, OpenMode.ForRead);

kaefer

  • Guest
Re: Conceptual thinking: selections per layer
« Reply #8 on: October 06, 2011, 08:10:09 PM »
LINQ may be worth looking at.

Definitely. GroupBy and ToDictionary could be especially worthy:
Code: [Select]
    static class Extensions
    {
        public static IDictionary<string, int> GroupByNCount(this IEnumerable<EntInfo> eis, Func<EntInfo, string> keySelector)
        {
            return eis.GroupBy(keySelector).ToDictionary(grp => grp.Key, grp => grp.Count());
        }
    }
grp would be IGrouping<string, EntInfo> here.

Regarding the design of a class to represent data to query against, the problem description suggest something holding the object type and layer name, and a block name if appropriate.
Something like:
Code: [Select]
    class EntInfo
    {
        public string Type;
        public string Layer;
        public string Blockname;
        public EntInfo(Entity e)
        {
            Type = e.GetType().Name;
            Layer = e.Layer;
            Blockname = null;
        }
        public EntInfo(BlockReference b)
        {
            Type = "BlockReference";
            Layer = b.Layer;
            Blockname = b.Name;
        }
        public static EntInfo Create(Entity ent)
        {
            return ent is BlockReference ?
                new EntInfo((BlockReference)ent) :
                    ent is DBText ||
                    ent is MText ||
                    ent is Line ||
                    ent is Hatch ? new EntInfo(ent) : null;
        }
    }

Since IEnumerable is lazy, the data collected needs to be persisted before the transaction ends, perhaps with ToArray, and could be queried at leisure afterwards.

Code: [Select]
                EntInfo[] eis =
                    ((BlockTableRecord)tr.GetObject(
                        SymbolUtilityServices.GetBlockModelSpaceId(db),
                        OpenMode.ForRead))
                    .Cast<ObjectId>()
                    .Select(id => tr.GetObject(id, OpenMode.ForRead))
                    .OfType<Entity>()
                    .Select(EntInfo.Create)
                    .Where(ei => ei != null)
                    .ToArray();
                tr.Commit();
                printResults(eis);
Dunno if this constitutes uneconomical use of resources.

huiz

  • Swamp Rat
  • Posts: 919
  • Certified Prof C3D
Re: Conceptual thinking: selections per layer
« Reply #9 on: October 07, 2011, 02:57:30 AM »
Wow thanks for all this information! @bargool: it is indeed conceptual thinking, I was not looking for a complete solution in code but the best idea how to solve this. Though the code samples do make things more clear!

So I understand using selection sets are slower and more resource spilling. I'll have a look at the other solutions mentioned here.

The conclusion is justified that the initialization of the development of critical subsystem optimizes the probability of success to the development of the technical behavior over a given period.

Draftek

  • Guest
Re: Conceptual thinking: selections per layer
« Reply #10 on: October 07, 2011, 08:49:42 AM »
If your going to be iterating through each database object of the drawing, you might want to think about not using transactions. They can cause performance issues also.

Jeff H

  • Needs a day job
  • Posts: 6150
Re: Conceptual thinking: selections per layer
« Reply #11 on: October 07, 2011, 05:22:00 PM »
One school of thought is to do what ever is easiest then test and if performance is a issue then try a different approach.
If selectionsets keeps the code less complex, easy to maintain, and does not cause a performance issue then I would use them.

Another point for performance is to use a ObjectId's ObjectClass property
That way  you could only open objects that you need and not take performance hits of object's that got paged to disk, transaction's growing large, closing ,disposing etc...... of objects that are not of a type you need.
 

huiz

  • Swamp Rat
  • Posts: 919
  • Certified Prof C3D
Re: Conceptual thinking: selections per layer
« Reply #12 on: October 08, 2011, 01:45:23 AM »
You are right Jeff H. But my experience with first simple coding till it works and after that finetuning, unfortunately the finetuning part will be skipped. Time, costs, that kind of things :-)

But with the information which is provided here by all these smart guys here, I am able to get new and better ideas to get to a solution. It is still not easy what is the best way. If I iterate each object and put it in a dictionary I have an overload because I don't need objects on layers that are off or frozen, I also don't need objects like dimensions, objects on layouts, and all objects with an objectid but no visible presentation.
But if I work with selection sets per layer and check each selected object to see what type it is and if it is a block, which block it is, I have the feeling I can do things much easier. But after trying all the ideas here in this topic I might conclude that selection sets are the best way for me.
Using LinQ might be a solution but I have to read more about that and do some tests to see how it works.

At least I got some new and interesting ideas and if I can't use it now, I will use it somewhere in the future :-)
The conclusion is justified that the initialization of the development of critical subsystem optimizes the probability of success to the development of the technical behavior over a given period.

huiz

  • Swamp Rat
  • Posts: 919
  • Certified Prof C3D
Re: Conceptual thinking: selections per layer
« Reply #13 on: October 13, 2011, 06:11:49 AM »
Well, I'm finished with the tool and thanks to all your help I made some decisions.

At the moment I started using selection sets. The tool needs certain objects per layer. Because I don't need to iterate every object and also I don't need every layer, I have chosen for selection sets. They are quite slow, also the iterating of every object on that layer but I don't think all the other solutions will be much faster, or I need looping through a lot of unnecessary objects. I put a progress bar on the form so slowness is not a real problem. Drawings with 20000 objects need about 20 seconds to be examined.

The tool, which will create a Legend in the drawing, is checking the amount of certain elements on a particular layer. If there are mostly blocks, it also checks which block is most used. I use a dictionary for this but I'm not sure if there are better ways. Dictionaries are also a bit slow.

Code: [Select]
If dcBlockDict.ContainsKey(objCurBlock.Name) Then
   dcBlockDict(objCurBlock.Name) += 1
Else
   dcBlockDict.Add(objCurBlock.Name, 1)
End If

Code above is used to calculate the most used block.

At the moment I think it is finished and if slowness is a problem for our clients I can see if there can be some optimalisation. Who's interested in seeing the tool in progress, you can see a video here:

http://www.youtube.com/embed/DsUlcODnoHE?rel=0&amp;hd=1
The conclusion is justified that the initialization of the development of critical subsystem optimizes the probability of success to the development of the technical behavior over a given period.