[Drawkit] DKShapeGroups and DXF blocks

Allan Daly allandaly at me.com
Tue Apr 14 07:58:42 PDT 2009


Wow, Graham. This is a great start. Thanks for all the useful info.

One quick follow up question then I'm going to dig in --> can groups  
be nested? Can a group contain another group? DXF blocks allow this so  
if DK can do this then great -- but if not then I'll need to "flatten"  
or otherwise deal with that situation.

-Allan


On Apr 13, 2009, at 7:51 PM, Graham Cox wrote:

>
> On 14/04/2009, at 7:47 AM, Allan Daly wrote:
>
>> I'm getting ready to tackle drawing DXF "blocks" in DK and I wonder  
>> if I could ask you for some conceptual help.
>>
>> A "block" is a collection of DXF entities with a unique name that  
>> can be placed in a drawing multiple times. Inside the block all of  
>> the entities are positioned with respect to a base point. The  
>> entire block can then be placed in a drawing by "inserting" it at a  
>> location. The base point of the block is placed at the "insertion"  
>> point. Block translations and rotations then are referenced to the  
>> insertion point.
>>
>> The DKShapeGroup clearly is a close match to much of this behavior.
>>
>> If I have a list of entities that need to go into the DKShapeGroup,  
>> what is the best way to create the group? Do I need to add them to  
>> a drawing on a layer, then group them all together? Or is there a  
>> way to add a new DKShape (or whatever) into an existing group one  
>> at a time? How do I get the DKShapes into the right position  
>> relative to the "base point?" How does DK handle the base point?  
>> The documentation of the DKShapeGroup methods suggests that the  
>> base point becomes the center of the bounding rectangle -- but I  
>> need to be able to set the basepoint to match the block definition  
>> (could be anywhere) so when I insert it into the drawing later it  
>> will be in the right place.
>>
>> Also -- can I create a DKShapeGroup and not draw it? A block is  
>> really just a definition of a group of entities. It is not drawn  
>> until it is inserted into the drawing. Can I create a non-drawn  
>> DKShapeGroup then copy it when I need to insert it? is there an  
>> easy way to copy DKShapeGroups? Or even better, is there a way to  
>> reference the DKShapeGroup so that if I change the DKShapeGroup  
>> definition then all instances where that group is placed in the  
>> drawing would be automatically updated?
>>
>> I'm sure I can dive into this and get something working -- but if  
>> you wouldn't mind giving me some high level advice as to how you  
>> think it might be best to proceed I think that would save me a lot  
>> of time.
>>
>> Thanks for any help you can send my way.
>
>
> This may need a bit of back-and-forth to get fully worked out,  
> because I'm not familiar with DXF. But yes, it sounds like  
> DKShapeGroup is what you want here.
>
> You can create a DKShapeGroup (a.k.a "group") from a bunch of  
> objects in advance, then add the group to the layer. In fact I would  
> recommend this approach, rather than adding the objects to the layer  
> then grouping them. DKShapeGroup has a convenience method  
> +groupWithObjects: which is intended for this.
>
> Currently it's not so easy to add objects one at a time to a group,  
> though if you end up needing to do that, it can probably be worked  
> out.
>
> Where things get slightly tricky is with managing the coordinate  
> systems within the groups. When an object is in a group, its  
> location is modified so that it's relative to the group. Other  
> attributes such as angle and size are unaffected, but special  
> transforms that apply group attributes are constructed for  
> rendering. The location is automatically adjusted when the object is  
> grouped, so for example when using +groupWithObjects:, the objects  
> you pass here would have their original locations, and be modified  
> automatically. The group itself would be initially located according  
> to the locations of the original objects. This reflects the typical  
> usage of groups where you select a bunch of existing objects and  
> group them.
>
> As long as the original object's locations are all set correctly  
> relative to each other, things will work out fine. Even if they are  
> stored in the DXF file such that the location is group-relative, it  
> should work because it's only the relative positions of the objects  
> that matters. The group needs to figure out the bounding rect of the  
> objects it contains, and that is used to set the initial bounds and  
> location of the group as a whole. You can then position the entire  
> group where you need it overall.
>
> A group inherits from a shape, mostly to get the same interactive  
> behaviour. As a result, its location is initially set as the centre  
> of the bounding rect, but as with any shape, you can displace this  
> elsewhere using the -setOffset: method. This would be the way to set  
> your "basepoint" to anywhere within the bounding rect of the group.  
> Somehow there will be a way to determine the position of the  
> basepoint relative to the bounding rect of the group from the DXF  
> data. For example each object's position might be relative to the  
> basepoint, so after determining the union of the bounds of each  
> individual object, the basepoint will be relative to this bounding  
> rect. Remember that setOffset: requires a value that is proportional  
> to the unit rect, so a little further calculation will be needed.  
> Note that if the basepoint is outside of the bounding rect (not sure  
> from your description if this is possible), then that might work,  
> but this is currently untested since in DrawKit you can't  
> interactively move the location outside the bounds. If it turns out  
> to be necessary it shouldn't be a problem to modify the code as  
> needed to allow you to do this.
>
> Once you've created the group you can add it to the layer as with  
> any object. If you simply retain it somewhere it won't be drawn if  
> it's not added to a layer, and it can be copied as with any object.  
> The group's contents are "deep copied" so you get a completely  
> unique copy including all of the content each time. Each copy can be  
> positioned and added to a layer as a separate object - once copied  
> it retains no connection to the original.
>
> One further thing to mention about groups. When a group is drawn,  
> there are two ways that can be handled. One way is to build a  
> transform that is used to transform each contained object's path,  
> then draw the path using its style as normal. The other way is to  
> build a transform that affects the overall graphics context, then  
> draw the path as normal. The outcome is geometrically identical, but  
> may differ in appearance. In the first case, a stroke width for  
> example isn't scaled - 2 points is always 2 points, even if the  
> object being stroked is inside a group that has been scaled to some  
> other size. In the second case, the stroke width would scale  
> according to any group scaling, and so on. Which to use depends on  
> your requirements. The first case is often the one to go with for  
> CAD-type apps and is the default. The second might apply to more  
> artistic type apps, and would match what is usually done for SVG  
> graphics. To use the second approach, the group must be set to  
> transform its contents visually by setting the ivar  
> m_transformVisually to YES. (Note that in the current beta there's  
> no accessor for this - there should be one, and I've added it for  
> the next update).
>
> Hope this helps, but of course if you need more info or  
> clarification, just ask.
>
> --Graham
>
>
>
>
> _______________________________________________
> Drawkit mailing list
> Drawkit at lists.apptree.net
> http://lists.apptree.net/listinfo.cgi/drawkit-apptree.net



More information about the Drawkit mailing list