Полностью согласен, скажу больше, вещь вредная и ненужная.
Есть способ, который и должен реализовываться в таких случаях:
(взято из недр autodesk.autocad.objectarx)
мне помогло :)
You could try embedding an AcDbBlockReference entity in your custom entity.
This is not a trivial operation, but it would give you essentially what you
want. I'm not sure how well this will work with an AcDbBlockReference
because AcDbBlockReference is a complex entity (i.e. it can have
subentities - AcDbAttributes), but if you don't add any attributes to your
embedded blockReference it might work ok.
Here's a document I wrote about this back during AutoCAD2000 development
when I put in the dxf support for this mechanism (this was supposed to go
into the ARX documenation, but I don't see it in there):
There are essentially two ways to embed an object in another object, either
the encapsulating object has a data member that is an actual embedded
object, or the encapsulating object has a pointer to an object (that object
is then considered to be embedded). In either case the encapsulating object
is responsible for the allocation/deallocation of the embedded object and
the encapsulating object must also forward all calls to the embedded
object's methods since AutoCAD will know nothing about the embedded object.
So, to display the embedded object, the encapsulating object's worldDraw
must make a call to the embedded object's worldDraw.
For getGripPoints()/getStretchPoints() you will need to call the embedded
object's method last so that it's points will end up with indices higher
than those of the encapsulating entity. Then, in
moveGripPointsAt()/moveStretchPointsAt() if any of the indices passed in are
above the range of those of the encapsulating entity, you should subtract
off the highest index value of the encapsulating entity and pass the result
into the embedded object's moveGripPointsAt()/moveStretchPointsAt(). For
example here's the pertinent code from a version of the ARXLAB's jblob
sample updated to have an embedded AcDbCircle entity:
Acad::ErrorStatus
Jblob::getGripPoints(
AcGePoint3dArray& gripPoints,
AcDbIntArray& osnapMasks,
AcDbIntArray& geomIds) const
{
assertReadEnabled();
gripPoints.append(mp);
gripPoints.append(mp + 0.5 * (mpblob - mp));
gripPoints.append(mpblob);
AcGeVector3d xoff(mrblob, 0, 0);
AcGeVector3d yoff(0, mrblob, 0);
gripPoints.append(mpblob + xoff);
gripPoints.append(mpblob + yoff);
gripPoints.append(mpblob - xoff);
gripPoints.append(mpblob - yoff);
return circle.getGripPoints(gripPoints, osnapMasks, geomIds);
}
Acad::ErrorStatus
Jblob::moveGripPointsAt(
const AcDbIntArray& indices,
const AcGeVector3d& offset)
{
AcGePoint3d oldquad, newquad;
assertWriteEnabled();
AcDbIntArray circleIndices;
for (int i = 0; i < indices.length(); i++) {
int idx = indices[i];
switch(idx) {
case 0:
mp += offset;
continue; // stretch begin point
case 1:
mp += offset;
mpblob += offset;
continue; // move
case 2:
mpblob += offset;
continue; // stretch blob center
// stretch blob radius:
//
case 3:
oldquad = mpblob + AcGeVector3d(mrblob, 0, 0);
break;
case 4:
oldquad = mpblob + AcGeVector3d(0, mrblob, 0);
break;
case 5:
oldquad = mpblob - AcGeVector3d(mrblob, 0, 0);
break;
case 6:
oldquad = mpblob - AcGeVector3d(0, mrblob, 0);
break;
default:
if (idx > 6)
circleIndices.append(idx - 7);
continue;
}
newquad = oldquad + offset;
mrblob = newquad.distanceTo(mpblob);
}
if (circleIndices.length() > 0)
return circle.moveGripPointsAt(circleIndices, offset);
else
return Acad::eOk;
}
For filing purposes, the encapsulating object must call the embedded
object's dwgOutFields/dwgInFields/dxfOutFields/dxfInFields methods from
within the its own such methds.
For dwg filing, the call to the embedded object's dwgOutFields/dwgInFields
methods may occur at any point in the encapsulating object's dwgOutFields
(after the call to the base class's method of course), just make sure that
the call occurs in the same place in both dwgOutFields() and dwgInFields().
For example, here's the pertinent code from the updated jblob sample
program:
Acad::ErrorStatus
Jblob::dwgInFields(AcDbDwgFiler* filer)
{
assertWriteEnabled();
AcDbEntity::dwgInFields(filer);
filer->readItem(&mp);
filer->readItem(&mpblob);
filer->readItem(&mrblob);
filer->readItem(&mnormal);
return circle.dwgInFields(filer);
}
Acad::ErrorStatus
Jblob::dwgOutFields(AcDbDwgFiler* filer) const
{
assertReadEnabled();
AcDbEntity::dwgOutFields(filer);
filer->writeItem(mp);
filer->writeItem(mpblob);
filer->writeItem(mrblob);
filer->writeItem(mnormal);
return circle.dwgOutFields(filer);
}
For DXF filing, the embedded object must be filed out/in after all the data
of the encapsulating object has been filed out/in so the call to the
embedded object's dxfOutFields/dxfInFields method should come last in the
encapsulating object's dxfOutFields/dxfInFields methods code. There is also
a need for some sort of separator between the encapsulating object's data
and the subsequent embedded object's data. This separator must be similar
in function to the groups 0 or 100 in that it must cause the filer to stop
reading data. The normal DXF group code 0 cannot be used because DXF
proxies use the group code 0 to tell when to stop reading data. The group
code 100 could have been used, but that might have caused unnecessary
confusion when manually reading a DXF file and there was a need to
distinguish when an embedded object was about to be written out in order to
do some internal bookkeeping. So, a new DXF group code 101 has been
introduced.
The new AcDb::DxfCode enum value for DXF group code 101 is:
AcDb::kDxfEmbeddedObjectStart.
The data string "Embedded Object" will be automatically written out by the
filer for this DXF group code.
There are also two new methods on the AcDbDxfFiler class:
virtual Acad::ErrorStatus
AcDbDxfFiler::writeEmbeddedObjectStart();
The implementation of this function should be (and is in the ARX internal
filers) to write out the AcDb::DxfCode of AcDb::kDxfEmbeddedObjectStart (DXF
group code 101) and suppress the writing out of the AcDb::DxfCode of
AcDb::kDxfStart (DXF group code 0) for the embedded object that follows. A
string data value of "Embedded Object" should always be (and is in the ARX
internal filers) written out for the AcDb::kDxfEmbeddedObjectStart group
code.
This method must be called in the encapsulating object's dxfOutFields()
method just before calling the dxfOutFields() method of the embedded object.
If multiple embedded objects are involved, then this method must be called
just before each embedded object's dxfOutFields() method is called. This
method should only be called in the dxfOutFields() of the encapsulating
object.
The base class implementation of this method is to abort the program, so it
must be overridden in derived classes on which the method is expected to be
called.
Returns Acad::eOk.
virtual Adesk::Boolean
AcDbDxfFiler::atEmbeddedObjectStart();
The implementation of this function should be (and is in the ARX internal
filers) to test to see if the filer is currently pointing to an item with an
AcDb::DxfCode of AcDb::kDxfEmbeddedObjectStart. If this is the case, then
the filer moves the file pointer to the next item and returns Adesk::kTrue.
Otherwise the file pointer is left alone and Adesk::kFalse is returned.
The base class implementation of this method is to abort the program, so it
must be overridden in derived classes on which the method is expected to be
called.
To demonstrate how these new methods are used, here's the pertinent code
from an updated jblob sample program:
Acad::ErrorStatus
Jblob::dxfInFields(AcDbDxfFiler* filer)
{
assertWriteEnabled();
struct resbuf rb;
Acad::ErrorStatus es = AcDbEntity::dxfInFields(filer);
if (es != Acad::eOk) {
return es;
}
if (!filer->atSubclassData(kClassName)) {
return Acad::eBadDxfSequence;
}
mnormal = AcGeVector3d(0, 0, 1); // set default value:
while (es == Acad::eOk) {
if ((es = filer->readItem(&rb)) == Acad::eOk) {
switch(rb.restype) {
case AcDb::kDxfXCoord:
mp.set(rb.resval.rpoint[X], rb.resval.rpoint[Y],
rb.resval.rpoint[Z]);
break;
case AcDb::kDxfXCoord+1:
mpblob.set(rb.resval.rpoint[X], rb.resval.rpoint[Y],
rb.resval.rpoint[Z]);
break;
case AcDb::kDxfReal:
mrblob = rb.resval.rreal;
break;
case AcDb::kDxfNormalX:
mnormal.set(rb.resval.rpoint[X], rb.resval.rpoint[Y],
rb.resval.rpoint[Z]);
}
}
}
if (filer->atEmbeddedObjectStart())
return circle.dxfInFields(filer);
else {
filer->setError(Acad::eMissingDxfField,
"missing expected embeddedObject marker");
return filer->filerStatus();
}
}
Acad::ErrorStatus
Jblob::dxfOutFields(AcDbDxfFiler* filer) const
{
assertReadEnabled();
AcDbEntity::dxfOutFields(filer);
filer->writeItem(AcDb::kDxfSubclass, kClassName);
filer->writeItem(AcDb::kDxfXCoord, mp);
filer->writeItem(AcDb::kDxfXCoord + 1, mpblob);
filer->writeItem(AcDb::kDxfReal, mrblob);
if (filer->includesDefaultValues()
|| mnormal != AcGeVector3d(0,0,1))
{
filer->writeItem(AcDb::kDxfNormalX, mnormal);
}
filer->writeEmbeddedObjectStart();
return circle.dxfOutFields(filer);
}
Here's what the output will look like in a DXF file (the 310 group data
strings were shortened for readability):
0
JBLOB
5
52
330
19
100
AcDbEntity
8
0
92
256
310
00010000040000003C0000000600000002000000...
310
000000000000000000000000000000F03F700000...
310
0000
100
Jblob
10
4.026791
20
3.172968
30
0.0
11
5.916743
21
5.299622
31
0.0
40
1.458724
101
Embedded Object
100
AcDbEntity
100
AcDbCircle
10
5.916743
20
5.299622
30
0.0
40
0.729362
"lado" <lado@cospec.co.kr> wrote in message
news:9882F084408928ED5A3875EAA53672BA@in.WebX.maYIadrTaRb...
> ...Thank you for your reply again...
>
> > because it's used by our internal code to add entities. But, you still
> > should not try to use it to add an entity to a database.
>
> Ahh... the expression 'internally used' in the ARX reference that I hate
too
> much...
>
> > In other words, you cannot do what you are trying to do.
>
> Yes... I understand... It's so sad to me...
> 'MyDoor' custom class derives other class 'MyEntity'(should do..)... so,
> deriving AcDbBlockReference is impossible... (as you see, Multiple
> Inheritance also impossible..)
> I'd better give it up...
>
>