July 1, 2013

Lưu trữ đối tượng và tệp tin DWG và DXF (phần 2)

Thực thi hàm lưu trữ DWG

Khi thực thi hàm dwgOutFields()dwgInFields() cho một lớp mới, trước tiên bạn phải gọi phương thức assertReadEnabled() hoặc assertWriteEnabled() để đảm bảo rằng đối tượng đang được mở ở trạng thái phù hợp. 
Việc tiếp theo là lớp dẫn xuất phải gọi các hàm tương tự (ví dụ dwgOutFields()) trên lớp cơ sở liền kề. Quá trình này được gọi là siêu thông điệp (super messaging). Dưới đây là một ví dụ:
AcDbDerivedClass::dwgOutFields( ... );
{ 
   assertReadEnabled()
   myParent::dwgOutFields();
   // Perform class-specific operations after super-messaging.
}
Nếu quên gọi thông điệp phù hợp của lớp cơ sở hơn, bạn sẽ nhận được lỗi runtime.

Sau super-messaging (siêu thông điệp), bạn ghi hoặc đọc các trường field. Bạn có thể cải thiện quá trình bằng việc kiểm tra kiểu filer. Ví dụ, nếu kiểu filer là kIdXlateFiler và lớp không định nghĩa một kết nối tham chiếu, bạn có thể sửa lại đơn giản.
Với tệp tin DWG, bạn cần gọi thao tác ghi và đọc theo cùng trình tự. Nếu không, lớp dẫn xuất sẽ bị nhầm lẫn. Nếu có có liệu không xác định được kích thước, hãy kiểm tra kích thước trước tiên.

Ví dụ cho dwgOutFields()

Hầu hết filer đều gọi writeItem(), một hàm thành viên được quá tải (overload) cho tất cả các kiểu dữ liệu hỗ trợ. Ngoài ra còn có những hàm khác như writeInt32() được sử dụng trong ví dụ sau, mà có thể được sử dụng để hỗ trợ casting kiểu tự động. Các hàm như vậy bắt buộc tham số phải được xử lý như kiểu xác định bất chấp kiểu thực sự của nó trong bộ nhớ.
Chú ý Nếu lớp có dữ liệu integer, bạn cần sử dụng hàm đọc và ghi nào phù hợp nhất (ví dụ writeInt32)
Dưới đây là ví dụ từ AsdkPoly::dwgOutFields():
Acad::ErrorStatus
AsdkPoly::dwgOutFields(AcDbDwgFiler* filer) const
{
assertReadEnabled();
Acad::ErrorStatus es;
if ((es = AcDbCurve::dwgOutFields(filer))
!= Acad::eOk)
{
return es;
}

// Object Version - must always be the first item.
//
Adesk::Int16 version = VERSION;
filer->writeItem(version);

filer->writePoint2d(mCenter);
filer->writePoint2d(mStartPoint);
filer->writeInt32(mNumSides);
filer->writeVector3d(mPlaneNormal);
filer->writeString(mpName);
// mTextStyle is a hard pointer id, so filing it out to
// the purge filer (kPurgeFiler) prevents purging of
// this object.
//
filer->writeHardPointerId(mTextStyle);
filer->writeDouble(mElevation);
return filer->filerStatus();
}

Ví dụ cho dwgInFields()

Dưới đây là ví dụ cho AsdkPoly::dwgInFields()
Acad::ErrorStatus
AsdkPoly::dwgInFields(AcDbDwgFiler* filer)
{
assertWriteEnabled();
Acad::ErrorStatus es;
if ((es = AcDbCurve::dwgInFields(filer)) != Acad::eOk)
{
return es;
}

// Object Version - must always be the first item.
//
Adesk::Int16 version;
filer->readItem(&version);
if (version > VERSION)
return Acad::eMakeMeProxy;
switch (version)
{
case 1:
{
AcGePoint3d center;
filer->readPoint3d(&center);
AcGePoint3d startPoint;
filer->readPoint3d(&startPoint);
filer->readInt32(&mNumSides);
filer->readVector3d(&mPlaneNormal);
acutDelString(mpName);
filer->readString(&mpName);
filer->readHardPointerId(&mTextStyle);

//convert data from old format
acdbWcs2Ecs(asDblArray(center),asDblArray(center),
asDblArray(mPlaneNormal),Adesk::kFalse);
mCenter.set(center.x,center.y);
mElevation = center.z;

acdbWcs2Ecs(asDblArray(startPoint),asDblArray(startPoint),
asDblArray(mPlaneNormal),Adesk::kFalse);
mStartPoint.set(startPoint.x,startPoint.y);
assert(mElevation == startPoint.z);
break;
}
case 2:
filer->readPoint2d(&mCenter);
filer->readPoint2d(&mStartPoint);
filer->readInt32(&mNumSides);
filer->readVector3d(&mPlaneNormal);
acutDelString(mpName);
filer->readString(&mpName);
filer->readHardPointerId(&mTextStyle);
filer->readDouble(&mElevation);
break;
default:
assert(false);
}
return filer->filerStatus();
}

Thực thi hàm lưu trữ DXF

Nếu thực thi hàm dxfOutFields()dxfInFields() cho một lớp mới, lớp dẫn xuất của bạn phải gọi hàm assertReadEnabled() hoặc assertWriteEnabled() trước tiên. Sau đó là gọi các hàm tương trự trên lớp cơ sở liền kề (siêu thông điệp). 

DXF Group Code Ranges 

Thể hiện DXF của đối tượng là tổ hợp của các cặp mã nhóm và dữ liệu, với từng mã nhóm xác định kiểu dữ liệu. Khi định nghĩa thể hiện DXF của riêng mình, nhóm dữ liệu đầu tiên bạn ghi chép và read in phải là đánh dấu dữ liệu dưới lớp. Đánh dấu bao gồm mã nhóm 100 theo sau bởi sâu kí tự là tên lớp hiện hành. Sau đó, bạn chọn mã nhóm từ bảng sau tương ứng với các kiểu dữ liệu của mỗi trường dữ liệu bạn định sao chép.
Bảng mã nhóm DXF cho thể hiện đối tượng
Từ
Đến
Kiểu dữ liệu
1
4
Text
6
9
Text
10
17
Điểm hoặc vector (3 chiều)
38
59
Số thực Real
60
79
Số nguyên 16-bit integer
90
99
Số nguyên 32-bit integer
100
100
Đánh dấu dữ liệu Subclass
102
102
Text
140
149
Real
170
179
16-bit integer
210
219
3 reals
270
279
16-bit integer
280
289
8-bit integer
300
309
Text
310
319
Binary chunk
320
329
Handle
330
339
Soft pointer ID
340
349
Hard pointer ID
350
359
Soft owner ID
360
369
Hard owner ID

Một mã ID được dịch sang rlname. Ví dụ, AcDbObjectId tương ứng với một ads_name, được đại diện trong resval union là rlname.

Phụ thuộc thứ tự Order Dependence

Với DXF, trong miêu tả của tác giả lớp (lớp author's discretion), nhóm dữ liệu có thể thể hiện theo thứ tự tùy ý, hoặc bỏ qua tùy chọn. Một số lớp hỗ trợ hỗ trợ thứ tự độc lập của nhóm dữ liệu trong khi một số khác lại không. Nếu bạn cho phép độc lập thứ tự, khi đó hàm dxfInFields() phải sử dụng câu lệnh switch để lựa chọn hành động dựa trên giá trị mã nhóm. Độc lập thứ tự thường phù hợp với đối tượng có số lượng trường biết trước và không thay đổi. Đối tượng có chiều dài mảng thay đổi hoặc cấu trúc hướng tới order-dependent khi chúng được lưu và đọc.

Ví dụ cho dxfOutFields()  

Đoạn mã từ AsdkPoly::dxfOutFields()
Acad::ErrorStatus
AsdkPoly::dxfOutFields(AcDbDxfFiler* filer) const
{
assertReadEnabled();
Acad::ErrorStatus es;
if ((es = AcDbCurve::dxfOutFields(filer))
!= Acad::eOk)
{
return es;
}
filer->writeItem(AcDb::kDxfSubclass, "AsdkPoly");
// Object Version
//
Adesk::Int16 version = VERSION;
filer->writeInt16(AcDb::kDxfInt16, version);
filer->writePoint2d(AcDb::kDxfXCoord, mCenter);
filer->writePoint2d(AcDb::kDxfXCoord + 1, mStartPoint);
filer->writeInt32(AcDb::kDxfInt32, mNumSides);

// Always use max precision when writing out the normal.
filer->writeVector3d(AcDb::kDxfNormalX, mPlaneNormal,16);
filer->writeString(AcDb::kDxfText, mpName);
filer->writeItem(AcDb::kDxfHardPointerId, mTextStyle);
filer->writeDouble(AcDb::kDxfReal, mElevation);
return filer->filerStatus();
}

Ví dụ cho dxfInFields() với độc lập thứ tự Order Independence  

Ví dụ cho AsdkPoly::dxfInFields()
Acad::ErrorStatus
AsdkPoly::dxfInFields(AcDbDxfFiler* filer)
{
assertWriteEnabled();
Acad::ErrorStatus es = Acad::eOk;
resbuf rb;
if ((AcDbCurve::dxfInFields(filer) != Acad::eOk)
|| !filer->atSubclassData("AsdkPoly"))
{
return filer->filerStatus();
}
// Object Version
Adesk::Int16 version;
filer->readItem(&rb);
if (rb.restype != AcDb::kDxfInt16)
{
filer->pushBackItem();
filer->setError(Acad::eInvalidDxfCode,
"\nError: expected group code %d (version)",
AcDb::kDxfInt16);
return filer->filerStatus();
}

version = rb.resval.rint;
if (version > VERSION)
return Acad::eMakeMeProxy;

AcGePoint3d cen3d,sp3d;
AcGePoint2d cen2d,sp2d;
long numSides;
AcDbObjectId textStyle;
double elevation;
Adesk::UInt32 fieldsFlags = 0;
char * pName = NULL;
AcGeVector3d planeNormal;

while ((es == Acad::eOk)
&& ((es = filer->readResBuf(&rb)) == Acad::eOk))
{
switch (rb.restype) {
case AcDb::kDxfXCoord:
if (version == 1)
cen3d = asPnt3d(rb.resval.rpoint);
else
cen2d = asPnt2d(rb.resval.rpoint);
fieldsFlags |= 0x1;
break;
case AcDb::kDxfXCoord + 1:
if (version == 1)
sp3d = asPnt3d(rb.resval.rpoint);
else
sp2d = asPnt2d(rb.resval.rpoint);
fieldsFlags |= 0x2;
break;
case AcDb::kDxfInt32:
numSides = rb.resval.rlong;
fieldsFlags |= 0x4;
break;
case AcDb::kDxfNormalX:
planeNormal = asVec3d(rb.resval.rpoint);
fieldsFlags |= 0x8;
break;
case AcDb::kDxfText:
acutUpdString(rb.resval.rstring,pName);
fieldsFlags |= 0x11;
break;
case AcDb::kDxfHardPointerId:
acdbGetObjectId(textStyle, rb.resval.rlname);
fieldsFlags |= 0x12;
break;
case AcDb::kDxfReal:
if (version == 2)
{
fieldsFlags |= 0x10;
elevation = rb.resval.rreal;
break;
}
//fall through intentional
default:
// An unrecognized group. Push it back so that
// the subclass can read it again.
filer->pushBackItem();
es = Acad::eEndOfFile;
break;
}
}

// At this point, the es variable must contain eEndOfFile,
// either from readResBuf() or from pushbackBackItem(). If
// not, it indicates that an error happened and we should
// return immediately.
//
if (es != Acad::eEndOfFile)
return Acad::eInvalidResBuf;
// Now check to be sure all necessary group codes were
// present.
//
// Mandatory fields:
// - center
// - start point
// - normal
// - number of sides
// - elevation (if version > 1)
short required[] =
{AcDb::kDxfXCoord, AcDb::kDxfXCoord+1, AcDb::kDxfInt32,
AcDb::kDxfNormalX, AcDb::kDxfReal};

for (short i = 0; i < (version>1?4:3); i++) {
if (!fieldsFlags & 0x1) {
filer->setError(Acad::eMissingDxfField,
"\nMissing DXF group code: %d", 2, required[i]);
return Acad::eMissingDxfField;
} else
fieldsFlags >>= 1;
}
mPlaneNormal = planeNormal;
mNumSides = numSides;
mTextStyle = textStyle;
setName(pName);
acutDelString(pName);
if (version==1)
{
//convert data from old format
acdbWcs2Ecs(asDblArray(cen3d),asDblArray(cen3d),
asDblArray(planeNormal),Adesk::kFalse);
mCenter.set(cen3d.x,cen3d.y);
mElevation = cen3d.z;

acdbWcs2Ecs(asDblArray(sp3d),asDblArray(sp3d),
asDblArray(planeNormal),Adesk::kFalse);
mStartPoint.set(sp3d.x,sp3d.y);
assert(mElevation == sp3d.z);
} else {
mCenter = cen2d;
mStartPoint = sp2d;
mElevation = elevation;
}
return es;
}

Ví dụ cho dxfInFields() với phụ thuộc thứ tự

Đoạn code dưới đây trình bày cách bạn có thể ghi hàm dxfInFields() là một order-dependent. 
Acad::ErrorStatus
AsdkPoly::dxfInFields(AcDbDxfFiler* filer)
{
assertWriteEnabled();

if ((AcDbCurve::dxfInFields(filer) != Acad::eOk) ||
!filer->atSubclassData("AsdkPoly") )
{
return filer->filerStatus();
}

try
{
struct resbuf rb;

// Object Version
Adesk::Int16 version;
filer->readItem(&rb);
if (rb.restype != AcDb::kDxfInt16)
throw AcDb::kDxfInt16;

version = rb.resval.rint;
if (version > VERSION)
return Acad::eMakeMeProxy;

if (version == 1)
{
AcGePoint3d cent,sp;

filer->readItem(&rb);
if (rb.restype != AcDb::kDxfXCoord)
throw AcDb::kDxfXCoord
cent = asPnt3d(rb.resval.rpoint);

filer->readItem(&rb);
if (rb.restype != AcDb::kDxfXCoord + 1)
throw AcDb::kDxfXCoord + 1;
sp = asPnt3d(rb.resval.rpoint);

filer->readItem(&rb);
if (rb.restype != AcDb::kDxfInt32)
throw AcDb::kDxfInt32;
mNumSides = rb.resval.rlong;

filer->readItem(&rb);
if (rb.restype != AcDb::kDxfNormalX)
throw AcDb::kDxfNormalX
mPlaneNormal = asVec3d(rb.resval.rpoint);

filer->readItem(&rb);
if (rb.restype != AcDb::kDxfText)
throw AcDb::kDxfText;
setName(rb.resval.rstring);

filer->readItem(&rb);
if (rb.restype != kDxfHardPointerId)
throw AcDb::kDxfHardPointerId;
acdbGetObjectId(mTextStyle, rb.resval.rlname);

// Convert data from old format.
acdbWcs2Ecs(asDblArray(cent),asDblArray(cent),
asDblArray(mPlaneNormal),Adesk::kFalse);
mCenter.set(cent.x,cent.y);
mElevation = cent.z;

acdbWcs2Ecs(asDblArray(sp),asDblArray(sp),
asDblArray(mPlaneNormal),Adesk::kFalse);
mStartPoint.set(sp.x,sp.y);
assert(mElevation == sp.z);
}
else if (version == 2)
{
filer->readItem(&rb);
if (rb.restype != AcDb::kDxfXCoord)
throw AcDb::kDxfXCoord;
mCenter = asPnt2d(rb.resval.rpoint);

filer->readItem(&rb);
if (rb.restype != AcDb::kDxfXCoord + 1)
throw AcDb::kDxfXCoord + 1;
mStartPoint = asPnt2d(rb.resval.rpoint);

filer->readItem(&rb);
if (rb.restype != AcDb::kDxfInt32)
throw AcDb::kDxfInt32
mNumSides = rb.resval.rlong;

filer->readItem(&rb);
if (rb.restype != AcDb::kDxfNormalX)
throw AcDb::kDxfNormalX;
mPlaneNormal = asVec3d(rb.resval.rpoint);

filer->readItem(&rb);
if (rb.restype != AcDb::kDxfText)
throw AcDb::kDxfText
setName(rb.resval.rstring);

filer->readItem(&rb);
if (rb.restype != AcDb::kDxfHardPointerId)
throw AcDb::kDxfHardPointerId;
acdbGetObjectId(mTextStyle, rb.resval.rlname);

filer->readItem(&rb);
if (rb.restype != AcDb::kDxfReal)
throw AcDb::kDxfReal;
mElevation = rb.resval.rreal;
}
else assert(false);
}
catch (AcDb::DxfCode code)
{
filer->pushBackItem();
filer->setError(Acad::eInvalidDxfCode,
"\nError: expected group code %d", code);
return filer->filerStatus();
}
}

Tham chiếu đối tượng

Một tham chiếu đối tượng có thể là cứng hoặc mềm và nó có thể là tham chiếu sở hữu hay là một con trỏ tham chiếu. Sự phân biệt cứng và mềm chỉ ra liệu đối tượng được tham chiếu có cần thiết với sự tồn tại của đối tượng tham chiếu đến nó hay không. Một tham chiếu cứng chỉ ra một đối tượng phụ thuộc vào đối tượng tham chiếu để tồn tại. Một tham chiếu mềm có nghĩa là đối tượng có một số kiểu quan hệ với đối tượng đượng tham chiếu, nhưng không nhất thiết. Tham chiếu sở hữu dictate có bao nhiêu đối tượng được lưu. Nếu một đối tượng sở hữu một đối tượng khác, sau đó bất cứ khi nào đối tượng đầu tiên được file out, nó kéo theo đối tượng được sở hữu với nó. Bởi một đối tượng chỉ có duy nhất một chủ sở hữu, tham chiếu sở hữu được dùng cho phép ghi không thừa (nonredundant) của CSDL. Ngược lại, tham chiếu con trỏ được dùng để biệu thị một tham chiếu tuy fý giữa các đối tượng CSDL (AcDbObject). Tham chiếu con trỏ được dùng để hoàn thành (dư thừa) ghi ra CSDL.
Ví dụ, trong hình vẽ, đoạn thẳng kép chỉ ra tham chiếu sở hữu. Nếu theo sau đoạn thẳng kép này, bạn tiếp xúc vào mọi đối tượng trong CSDL nhỏ này chỉ một lần. Nếu bạn theo sau đoạn thẳng đơn, thể hiện tham chiếu con trỏ, bạn tiếp xúc vào đối tượng hơn một lần, bởi vì đa đối tượng có thể trỏ về cùng một đối tượng. Để có được "định nghĩa" đầy đủ về đối tượng AcDbLine, bạn cần thực hiện các tham chiếu cứng, tham chiếu cả sở hữu và con trỏ (nghĩa là: cả đoạn thẳng đơn và kép solid liền).

No comments:

Post a Comment

Featured Post

Khóa học AutoLISP cơ bản | Tự học lập trình | AutoLISP that la don gian

Khóa học được cung cấp bởi  Thanh Trí AutoCAD       Thông tin thêm: 👉👉👉

Popular Posts