/

28 tháng 12, 2013

Field và những con số biết nói

Khi làm việc với các cell trong Excel, bạn đã có khái niệm về số chết, và công thức Formula.

Số chết là một con số không được xây dựng từ công thức.

Ngược lại với số chết là số có liên kết (Formula) được xây dựng từ những biểu thức nhất định. Từ đó ta biết được nguồn gốc của con số, để có thể kiểm tra hay chỉnh sửa khi cần thiết.

/

26 tháng 12, 2013

Bổ sung thêm một số mẫu Hatch pattern

Bổ sung thêm một số mẫu Hatch (Tham khảo từ Cadviet.com)

Trong bộ sưu tập này có thêm một số mẫu Hatch về các loại gạch block, hatch mặt cắt sân, tường, mặt cắt các loại vật liệu xây dựng như kính, vân gỗ... rất cần thiết cho các bạn làm việc trong ngành kiến trúc, xây dựng, giao thông.

Hy vọng bạn sẽ tìm được một mẫu Hatch phù hợp yêu cầu!

 photo CVpat48.png
/

25 tháng 12, 2013

Liệt kê mẫu Hatch pattern có trong AutoCAD


Trong thư viện AutoCAD có rất nhiều mẫu Hatch mà không phải lúc nào người dùng cũng sử dụng hết. Bài viết này xin gửi đến các bạn một cái nhìn (theo đúng nghĩa đen) về các mẫu Hatch.


Album tổng hợp các Hatch Pattern của AutoCAD 2008


Dưới đây là các mẫu Hatch sẵn có trong AutoCAD phiên bản 2008:




/

21 tháng 12, 2013

Ứng dụng Field trong AutoCAD (Phần 3: Sử dụng AutoLISP)

Như đã biết, với khả năng lập công thức Formula, Field trong AutoCAD 2008 đã mang đến một cuộc "cách mạng" nho nhỏ giúp giải quyết các công việc định vị một cách đơn giản hơn bao giờ hết.

Thống kê thép giản đơn

Trong bài này, tôi không giới thiệu thêm các ứng dụng của Field nữa, mà chỉ đi giải quyết các bài toán đã nêu trong phần 1phần 2 bằng ngôn ngữ lập trình AutoLISP.

/

23 tháng 11, 2013

Nội suy cao độ trên bề mặt 3DFace

Nội suy độ cao trong công tác biên tập bản đồ là một công đoạn rất quan trọng trong việc chêm điểm địa hình. Nếu như trước kia mọi người vẫn thường dùng các lisp giản đơn để nội suy chủ yếu là nội suy đối với khu vực đồng bằng. Còn việc cấy chêm điểm ở vùng đồi núi là không đúng. Và việc cấy điểm thường dùng trên các phần mềm TOPO, HS……..cũng rất bất tiện vì cứ phải cài đặt và khuôn dạng điểm khó dùng.
Thấy việc thiết thực của vấn đề nên mình viết cho mọi người cách nội suy điểm trên bề mặt 3Dface (Nội suy trên mô hình TIN).

Lisp này bạn có thể apload và dùng được ngay trên Autocad.
Lisp nội suy độ cao trên bề mặt 3Dface

Tên Lệnh: 3DF

Cách sử dụng:


Để nội suy độ cao trên bề mặt 3Dface thì cần có một bề mặt 3Dface.

- Cách tạo bề mặt 3Dface: Từ tập điểm (Point hoặc Text) => Dùng lệnh TIN => Quét chọn tập điểm (Point hoặc Text) => Kết quả

- Dùng lệnh 3DF => Nhập cao chữ cần ghi độ cao lên màn hình => Quét chọn toàn bộ 3Dface vừa tạo =>
Kích chọn điểm cần nội suy.

Link: Mediafire

Tác giả: Nguyễn Thiên Đường
Nguồn: Trắc địa Pro
/

15 tháng 11, 2013

Lựa chọn các đối tượng khi làm việc với bản vẽ AutoCAD

Trong bài 1, tôi đã trình bày sơ qua cách sử dụng lệnh FILTER và 02 nhược điểm thường gặp của lệnh.

Sử dụng lệnh SSGET


Ở bài này, tôi sẽ giới thiệu cách sử dụng lệnh SSGET để khắc phục 2 nhược điểm đã nói ở trên.

Tên lệnh                     SSGET
Tên hàm AutoLISP    (defun lh_ssget)

/

Cách sử dụng lệnh filter trong AutoCAD (Phần 1)

Khi làm việc với AutoCAD, chắc hẳn đến một lúc nào đó các bạn sẽ cần phải lọc (Filter) ra một nhóm các đối tượng mang chung một vài thuộc tính nào đó.

Ví dụ: khi muốn thay đổi chiều cao Text cho một loạt các Text, hoặc thay đổi Layer, Màu sắc ...

Lúc đó bạn sẽ cần đến lệnh Filter (lệnh tắt FI).

Lệnh Filter và cách sử dụng
/

11 tháng 10, 2013

Hàm nội suy 2 chiều XSIP trong Excel

 Trong quá trình học tập, công tác, chắc hẳn không ít lần bạn đã phải dùng đến phương pháp nội suy.
 
Phương pháp nội suy một chiều đơn giản
 Để xây dựng công thức nội suy trên Excel, thường phải mất 1-2p để định hình các tham số, xây dựng hàm để tính Yns.

Trong bài này, tôi xin giới thiệu với các bạn 03 hàm nội suy trong Excel, sẽ giúp cho công việc tính toán nội suy của bạn được hiệu quả hơn.

/

8 tháng 10, 2013

Chỉnh sửa mã Field trong AutoCAD

Định dạng nâng cao cho Field trong AutoCAD 2005/2006/2007.

Mã điều khiển trong Field được giới thiệu trong AutoCAD 2005 (lệnh FIELD) cho phép lựa chọn chi tiết hơn khi sử dụng giao diện.

Chỉnh sửa FieldCode một cách trực quan
/

1 tháng 10, 2013

Đưa tọa độ điểm đo ra bản vẽ AutoCAD dưới dạng Text

Trong bài trước, tôi đã hướng dẫn các bạn cách đưa tọa độ điểm từ Excel ra bản vẽ AutoCAD bằng lệnh PLINE (hoặc lệnh 3DPOLYLINE).

Trong bài này, tôi sẽ hướng dẫn các bạn thực hiện công việc tương tự với lệnh TEXT.

Đưa tọa độ điểm đo ra bản vẽ chỉ với Excel và AutoCAD


Giả sử đã có một danh sách tọa độ XYZ của các điểm. Nhiệm vụ bây giờ là đưa các điểm này ra bản vẽ AutoCAD. Có rất nhiều ứng dụng hoặc mã AutoLISP khác nhau có thể thực hiện việc này. Nhưng ở đây, tôi sẽ chỉ dùng duy nhất Excel và AutoCAD - 2 phần mềm mà phổ biến với dân kỹ thuật!


/

30 tháng 9, 2013

Trong AutoCAD bạn chọn chế độ POLAR hay ORTHO?

Bạn hay sử dụng chế độ nào khi làm việc với AutoCAD?

Có rất nhiều chuyên gia Cad-er sử dụng chế độ ORTHO khi vẽ.

Kết quả một khảo sát nhỏ trên Facebook

/

29 tháng 9, 2013

Lấy tọa độ Polyline, Line trong bản vẽ AutoCAD vào Clipboard

Việc chuyển đổi dữ liệu qua lại giữa AutoCAD và Excel là vô cùng cần thiết. Dưới đây là một ứng dụng AutoLISP giúp copy dữ liệu tọa độ các đỉnh Polyline, 3dPolyline, Line vào clipbloard, qua đó có thể sử dụng để tùy chỉnh trên Excel.

Sau khi Appload LHID.VLX, sử dụng lệnh LHID từ dòng lệnh.

Video hướng dẫn:





Download LHID.VLX Mediafire (Direct link)

/

Vẽ Polyline trong bản vẽ AutoCAD từ danh sách toạ độ

Đã bao giờ bạn có một danh sách toạ độ XYZ của các điểm cần phải thể hiện trên bản vẽ AutoCAD.

List tọa độ trong Excel

Hoặc bạn xây dựng một hàm số, tính toạ độ XYZ các điểm trên Excel và muốn vẽ đồ thị hàm số.


/

28 tháng 9, 2013

Cài đặt nét in trong bản vẽ AutoCAD

Thông thường, để dễ quản lý bản vẽ, người làm việc với AutoCAD thường chia các loại đường nét thành các lớp có màu sắc khác nhau.

Cách cài đặt nét in trong bản vẽ AutoCAD

/

27 tháng 9, 2013

Thư viện AutoLISP mở rộng Doslib (Phần 2)

Các hàm thiết lập


--------------------------------------------------------------------------------

dos_getini
Trả về giá trị từ tệp tin INI Windows.

dos_regaddkey
Thêm một khóa key mới vào Registry Windows.

dos_regdel *
Loại bỏ một key hoặc giá trị từ Registry Windows.

dos_regdelkey
Loại bỏ một key từ Registry Windows

/

26 tháng 9, 2013

Thư viện AutoLISP mở rộng Doslib

Khoan nói đến VisualLISP (giống như một thư viện đồ sộ của AutoLISP) sẽ làm choáng ngợp bất cứ ai mới tiếp cận với AutoLISP. Chúng ta sẽ đi tìm hiểu những thư viện nhỏ hơn, hữu dụng hơn. Một trong số đó là DOSLIP mà tôi sẽ giới thiệu dưới đây.

Doslib - một sản phẩm miễn phí của McNeel

Doslib là gì?


DOSLib, là một thư viện các hàm AutoLISP cung cấp một loạt các tính năng giúp tương tác giữa AutoCAD với hệ điều hành Windows. Được viết bởi ứng dụng AutoCAD ObjectARX, DOSLib mở rộng AutoLISP với những hàm sau đây:


/

23 tháng 9, 2013

Chèn điểm point vào tâm hình tròn, Text, Line, block...

Chèn điểm point vào tâm hình tròn, Text, Line, block...

(defun c:vlisp ()
    (while
        (if (setq ent (car (entsel)))
            (progn
                (if (setq pt (cdr (assoc 10 (entget ent))))
                    (progn
                        (command "POINT" pt)
                        pt
                    )
                )
            )
        )
    )
    (princ)
)
/

22 tháng 9, 2013

Khởi động nhanh Nova Topo HS

Thông thường khi khởi động NOVA và TOPO, sẽ phải trải qua một số thao tác nhất định. Tuy nhiên vStartUp sẽ giúp bạn thực hiện một cách nhanh gọn nhất.



Download ngay và luôn

Dung lượng vStartUp chỉ ~100kb, không hề nặng máy một chút nào. Khi chạy lần đầu, chương trình sẽ ẩn về Tray để bạn có thể khởi động Nova và Topo bất cứ lúc nào.
/

12 tháng 9, 2013

Ứng dụng Field trong AutoCad (Phần 2 Lập công thức Formula)

Sau khi lập được Block cao độ, hay block lý trình như hướng dẫn ở phần 01, bạn sẽ nhận ra ngay hạn chế của AutoCAD 2005.

Nâng cấp đáng kể nhất của Field trong AutoCAD 2008 là Formula

Đó là:

- Block cao độ thường sử dụng đơn vị mét (m). Trong khi các bản vẽ cầu cống lại sử dụng đơn vị 1cm=1unit hoặc 1mm=1unit (gọi chung là unit). Nghĩa là khi dịch chuyển Block cao độ 10unit, thì Field cao độ cũng nhảy 10unit trong khi đúng ra nó chỉ được phép nhảy 10/100 (m) hoặc 10/1000 (m) mà thôi.

- Block lý trình trên trắc dọc và Block cọc GPMB lại thường được vẽ với đơn vị mét = 1unit, do vậy không cần thay đổi tỉ lệ cho Field.

- Khi sử dụng Block cao độ và Block lý trình, thường xuất hiện khái niệm kèm theo là Mức so sánhLý trình gốc. Hai khái niệm này tương đồng với nhau cho phép xác định được gốc tương đối.

Hãy tưởng tượng có 2 ngôi nhà có cùng một thiết kế kích thước khung giàn, cấu tạo... giống y hệt nhau. Nhưng lại được xây tại 02 vị trí có chênh cao là 15.0m. Đây là lúc người kỹ sư thiết kế cần dùng đến Mức so sánh để chỉ việc chỉnh sửa nó duy nhất một lần một khoảng 15.0 đơn vị và tất cả các cao độ còn lại sẽ "nhảy" theo. Vậy là được 1 ngôi nhà mới mà chẳng tốn công sức!


Xem thêm Phần 1 ở đây

Download ví dụ



/

11 tháng 9, 2013

Ứng dụng Field trong AutoCAD (Phần 1: AutoCAD2005)


Có một câu hỏi khá thú vị mà chắc hẳn ai cũng trả lời được. Đó là Có máy tính bỏ túi rồi thì cần gì phải có Excel?

Calculator hay Excel
Câu trả lời là Dữ liệu liên kết (một trong những đặc điểm nổi bật của Excel) . Với Excel, bạn có thể xây dựng công thức, quản lý và chỉnh sửa cho phù hợp nhất.

Vậy bạn có biết trong AutoCAD cũng có tính năng tương tự?!

/

31 tháng 8, 2013

AutoCAD bị treo khi copy từ bản vẽ này sang bản vẽ khác

Với AutoCAD từ phiên bản 2008, khi copy giữa các bản vẽ với nhau có thể gây ra tình trạng treo máy tính.

Một trong những nguyên nhân thường gặp là do bản vẽ có nhiều tỉ lệ Scale khác nhau?!


/

29 tháng 8, 2013

Tips: Bật/tắt nền màu xám của một trường dữ liệu (FIELD) trong AutoCAD

Sự hiển thị khác nhau giữa một trường dữ liệu (FIELD) với MTEXT hoặc DTEXT là khung nền màu xám tự động xuất hiện xung quanh text. Khung nền này không được in ra trong bản vẽ. Nó chỉ dùng để chỉ cho người sử dụng nhận biết đâu là trường dữ liệu.



Khung viền màu xám bao quanh FIELD trong bản vẽ AutoCAD

/

8 tháng 8, 2013

Đo nhanh diện tích và chiều dài trong AutoCAD

Có thể nói, việc đo diện tích và chiều dài là một phần không thể thiếu trong các bản vẽ kỹ thuật.


Command: 1 Tính diện tích nhanh của một vùng hay nhiều vùng bao khép kín.

Command: 2 Tính chiều dài nhanh của một hay nhiều đoạn thẳng liên tiếp.

Kết quả của các lệnh 1, 2 được copy trực tiếp vào clipboard, qua đó người dùng có thể paste ra excel, word hoặc các chương trình khác.

/

14 tháng 7, 2013

Quản lý giao dịch Transaction (Phần 3) - Ví dụ

Ví dụ về giao dịch lồng nhau

Ví dụ dưới đây bao gồm 3 giao dịch lồng nhau. Chuỗi sự kiện như sau:
 
Để tạo một giao dịch lồng mới
  1. Tạo một đa giác mới và đưa nó vào trong Cơ sở dữ liệu.
  1. Bắt đầu giao dịch 1:
  • Lựa chọn đa giác và lấy con trỏ tới nó. Mở để đọc.
  • Tạo một khối đặc (extruded solid) từ đa giác.
  • Tạo một khối trụ ở giữa đa giác mở rộng.
  1. Bắt đầu giao dịch 2: Trừ khối trụ từ khối đặc (Tạo một lỗ hổng ở giữa khối đặc).

  2. Bắt đầu giao dịch 3:
  • Cắt một nửa khuôn mẫu dọc theo mặt phẳng X/Z và di chuyển nó quanh trục X để bạn có thể nhìn thấy hai mảnh.
  • Hủy bỏ giao dịch được không nhỉ? Câu trả lời là có.
  1. Bắt đầu giao dịch 3 (bắt đầu lai): Cắt khuôn mẫu dọc theo mặt phẳng Y/Z và di chuyển nó quanh trục Y.
  2. Kết thúc giao dịch 3.
  3. Kết thúc giao dịch 2.

Chú ý: Nếu bạn muốn hủy bỏ tại điểm này, Giao dịch 2 và 3 cũng bị hủy đồng thời. Nếu bạn hủy bỏ một giao dịch vòng ngoài, mọi giao dịch lồng bên trong cũng bị hủy theo, thậm chí nếu chúng đã kết thúc thành công trước đó.
  1. Kết thúc giao dịch 1.
Dưới đây là mã nguồn của ví dụ:

void
transactCommand()
{
Adesk::Boolean interrupted;
Acad::ErrorStatus es = Acad::eOk;
AcDbObjectId savedCylinderId,savedExtrusionId;

// Create a poly and post it to the database.
//
acutPrintf("\nCreating a poly...Please supply the"
" required input.");
if ((es = createAndPostPoly()) != Acad::eOk)
return;

// Start a transaction.
//
AcTransaction *pTrans
= actrTransactionManager->startTransaction();
assert(pTrans != NULL);
acutPrintf("\n\n###### Started transaction one."
" ######\n");

// Select the poly and extrude it.
//
AcDbObject *pObj = NULL;
AsdkPoly *pPoly = NULL;
AcDb3dSolid *pSolid = NULL;
AcDbObjectId objId;
ads_name ename;
ads_point pickpt;

for (;;) {
switch (acedEntSel("\nSelect a polygon: ",
ename, pickpt))
{
case RTNORM:
acdbGetObjectId(objId, ename);

if ((es = pTrans->getObject(pObj, objId,
AcDb::kForRead)) != Acad::eOk)
{
acutPrintf("\nFailed to obtain an object"
" through transaction.");
actrTransactionManager->abortTransaction();
return;
}

assert(pObj != NULL);
pPoly = AsdkPoly::cast(pObj);

if (pPoly == NULL) {
acutPrintf("\nNot a polygon. Try again");
continue;
}
break;
case RTNONE:
case RTCAN:
actrTransactionManager->abortTransaction();
return;
default:
continue;
}
break;
}

// Now that a poly is created, convert it to a region
// and extrude it.
//
acutPrintf("\nWe will be extruding the poly.");
AcGePoint2d c2d = pPoly->center();
ads_point pt;
pt[0] = c2d[0]; pt[1] = c2d[1]; pt[2] = pPoly->elevation();
acdbEcs2Ucs(pt,pt,asDblArray(pPoly->normal()),Adesk::kFalse);
double height;

if (acedGetDist(pt, "\nEnter Extrusion height: ",
&height) != RTNORM)
{
actrTransactionManager->abortTransaction();
return;
}

if ((es = extrudePoly(pPoly, height,savedExtrusionId)) !=
Acad::eOk) {
actrTransactionManager->abortTransaction();
return;
}

// Create a cylinder at the center of the polygon of
// the same height as the extruded poly.
//
double radius = (pPoly->startPoint()
- pPoly->center()).length() * 0.5;
pSolid = new AcDb3dSolid;
assert(pSolid != NULL);

pSolid->createFrustum(height, radius, radius, radius);
AcGeMatrix3d mat(AcGeMatrix3d::translation(
pPoly->elevation()*pPoly->normal())*
AcGeMatrix3d::planeToWorld(pPoly->normal()));
pSolid->transformBy(mat);

// Move it up again by half the height along
// the normal.
//
AcGeVector3d x(1, 0, 0), y(0, 1, 0), z(0, 0, 1);
AcGePoint3d moveBy(pPoly->normal()[0] * height * 0.5,
pPoly->normal()[1] * height * 0.5,
pPoly->normal()[2] * height * 0.5);
mat.setCoordSystem(moveBy, x, y, z);
pSolid->transformBy(mat);
addToDb(pSolid, savedCylinderId);
actrTransactionManager
->addNewlyCreatedDBRObject(pSolid);
pSolid->draw();
acutPrintf("\nCreated a cylinder at the center of"
" the poly.");

// Start another transaction. Ask the user to select
// the extruded solid followed by selecting the
// cylinder. Make a hole in the extruded solid by
// subtracting the cylinder from it.
//
pTrans = actrTransactionManager->startTransaction();
assert(pTrans != NULL);
acutPrintf("\n\n###### Started transaction two."
" ######\n");
AcDb3dSolid *pExtrusion, *pCylinder;

if ((es = getASolid("\nSelect the extrusion: ", pTrans,
AcDb::kForWrite, savedExtrusionId, pExtrusion))
!= Acad::eOk)
{
actrTransactionManager->abortTransaction();
actrTransactionManager->abortTransaction();
return;
}

assert(pExtrusion != NULL);

if ((es = getASolid("\nSelect the cylinder: ", pTrans,
AcDb::kForWrite, savedCylinderId, pCylinder))
!= Acad::eOk)
{
actrTransactionManager->abortTransaction();
actrTransactionManager->abortTransaction();
return;
}

assert(pCylinder != NULL);
pExtrusion->booleanOper(AcDb::kBoolSubtract, pCylinder);
pExtrusion->draw();
acutPrintf("\nSubtracted the cylinder from the"
" extrusion.");

// At this point, the cylinder is a NULL solid. Erase it.
//
assert(pCylinder->isNull());
pCylinder->erase();

// Start another transaction and slice the resulting
// solid into two halves.
//
pTrans = actrTransactionManager->startTransaction();
assert(pTrans != NULL);
acutPrintf("\n\n##### Started transaction three."
" ######\n");

AcGeVector3d vec, normal;
AcGePoint3d sp,center;
pPoly->getStartPoint(sp);
pPoly->getCenter(center);
vec = sp - center;
normal = pPoly->normal().crossProduct(vec);
normal.normalize();
AcGePlane sectionPlane(center, normal);
AcDb3dSolid *pOtherHalf = NULL;
pExtrusion->getSlice(sectionPlane, Adesk::kTrue,
pOtherHalf);
assert(pOtherHalf != NULL);

// Move the other half three times the vector length
// along the vector.
//
moveBy.set(vec[0] * 3.0, vec[1] * 3.0, vec[2] * 3.0);
mat.setCoordSystem(moveBy, x, y, z);
pOtherHalf->transformBy(mat);
AcDbObjectId otherHalfId;
addToDb(pOtherHalf, otherHalfId);

actrTransactionManager
->addNewlyCreatedDBRObject(pOtherHalf);
pOtherHalf->draw();
pExtrusion->draw();
acutPrintf("\nSliced the resulting solid into half"
" and moved one piece.");

// Now abort transaction three, to return to the hole in
// the extrusion.
//
Adesk::Boolean yes = Adesk::kTrue;
if (getYOrN("\nLet's abort transaction three, yes?"
" [Y] : ", Adesk::kTrue, yes,interrupted) == Acad::eOk
&& yes == Adesk::kTrue)
{
acutPrintf("\n\n$$$$$$ Aborting transaction"
" three. $$$$$$\n");
actrTransactionManager->abortTransaction();
acutPrintf("\nBack to the un-sliced solid.");
pExtrusion->draw();
char option[256];
acedGetKword("\nHit any key to continue.", option);
} else {
acutPrintf("\n\n>>>>>> Ending transaction three."
" <<<<<<\n");
actrTransactionManager->endTransaction();
}

// Start another transaction (three again). This time,
// slice the solid along a plane that is perpendicular
// to the plane we used last time: that is the slice
// we really wanted.
//
pTrans = actrTransactionManager->startTransaction();
assert(pTrans != NULL);
acutPrintf("\n\n##### Started transaction three."
" ######\n");
moveBy.set(normal[0] * 3.0, normal[1] * 3.0,
normal[2] * 3.0);
normal = vec;
normal.normalize();
sectionPlane.set(center, normal);
pOtherHalf = NULL;

pExtrusion->getSlice(sectionPlane, Adesk::kTrue,
pOtherHalf);
assert(pOtherHalf != NULL);
mat.setCoordSystem(moveBy, x, y, z);
pOtherHalf->transformBy(mat);
addToDb(pOtherHalf, otherHalfId);
actrTransactionManager
->addNewlyCreatedDBRObject(pOtherHalf);
pOtherHalf->draw();
pExtrusion->draw();

acutPrintf("\nSliced the resulting solid into half"
" along a plane");
acutPrintf("\nperpendicular to the old one and moved"
" one piece.");

// Now, give the user the option to end all the transactions.
//
yes = Adesk::kFalse;

if (getYOrN("\nAbort transaction three? : ",
Adesk::kFalse, yes,interrupted) == Acad::eOk
&& yes == Adesk::kTrue)
{
acutPrintf("\n\n$$$$$$ Aborting transaction"
" three. $$$$$$\n");
actrTransactionManager->abortTransaction();
acutPrintf("\nBack to the un-sliced solid.");
} else {
acutPrintf("\n\n>>>>>> Ending transaction three."
" <<<<<<\n");
actrTransactionManager->endTransaction();
}

yes = Adesk::kFalse;
if (getYOrN("\nAbort transaction two? : ",
Adesk::kFalse, yes,interrupted) == Acad::eOk
&& yes == Adesk::kTrue)
{
acutPrintf("\n\n$$$$$$ Aborting transaction two."
" $$$$$$\n");
actrTransactionManager->abortTransaction();
acutPrintf("\nBack to separate extrusion and"
" cylinder.");
} else {
acutPrintf("\n\n>>>>>> Ending transaction two."
" <<<<<<\n");
actrTransactionManager->endTransaction();
}

yes = Adesk::kFalse;
if (getYOrN("\nAbort transaction one? : ",
Adesk::kFalse, yes,interrupted) == Acad::eOk
&& yes == Adesk::kTrue)
{
acutPrintf("\n\n$$$$$$ Aborting transaction one."
" $$$$$$\n");
actrTransactionManager->abortTransaction();
acutPrintf("\nBack to just the Poly.");
} else {
actrTransactionManager->endTransaction();
acutPrintf("\n\n>>>>>> Ending transaction one."
" <<<<<<\n");
}
}

static Acad::ErrorStatus
createAndPostPoly()
{
int nSides = 0;
while (nSides < 3) {
acedInitGet(INP_NNEG, "");
switch (acedGetInt("\nEnter number of sides: ",
&nSides))
{
case RTNORM:
if (nSides < 3)
acutPrintf("\nNeed at least 3 sides.");
break;
default:
return Acad::eInvalidInput;
}
}

ads_point center, startPt, normal;
if (acedGetPoint(NULL, "\nLocate center of polygon: ",
center) != RTNORM)
{
return Acad::eInvalidInput;
}

startPt[0] = center[0];
startPt[1] = center[1];
startPt[2] = center[2];

while (asPnt3d(startPt) == asPnt3d(center)) {
switch (acedGetPoint(center,
"\nLocate start point of polygon: ", startPt)) {
case RTNORM:
if (asPnt3d(center) == asPnt3d(startPt))
acutPrintf("\nPick a point different"
" from the center.");
break;
default:
return Acad::eInvalidInput;
}
}

// Set the normal to the plane of the polygon to be
// the same as the Z direction of the current UCS,
// (0, 0, 1) since we also got the center and
// start point in the current UCS. (acedGetPoint()
// returns in the current UCS.)
normal[X] = 0.0;
normal[Y] = 0.0;
normal[Z] = 1.0;
acdbUcs2Wcs(normal, normal, Adesk::kTrue);
acdbUcs2Ecs(center, center, normal, Adesk::kFalse);
acdbUcs2Ecs(startPt, startPt, normal, Adesk::kFalse);
double elev = center[2];

AcGePoint2d cen = asPnt2d(center),
start = asPnt2d(startPt);
AcGeVector3d norm = asVec3d(normal);
AsdkPoly *pPoly = new AsdkPoly;
if (pPoly==NULL)
return Acad::eOutOfMemory;
Acad::ErrorStatus es;

if ((es=pPoly->set(cen, start, nSides, norm,
"transactPoly",elev))!=Acad::eOk)
return es;

pPoly->setDatabaseDefaults(
acdbHostApplicationServices()->workingDatabase());
postToDb(pPoly);
return Acad::eOk;
}
// Extrudes the poly to a given height.
//
static Acad::ErrorStatus
extrudePoly(AsdkPoly* pPoly, double height, AcDbObjectId& savedExtrusionId)
{
Acad::ErrorStatus es = Acad::eOk;

// Explode to a set of lines.
//
AcDbVoidPtrArray lines;
pPoly->explode(lines);

// Create a region from the set of lines.
//
AcDbVoidPtrArray regions;
AcDbRegion::createFromCurves(lines, regions);
assert(regions.length() == 1);
AcDbRegion *pRegion
= AcDbRegion::cast((AcRxObject*)regions[0]);
assert(pRegion != NULL);

// Extrude the region to create a solid.
//
AcDb3dSolid *pSolid = new AcDb3dSolid;
assert(pSolid != NULL);
pSolid->extrude(pRegion, height, 0.0);

for (int i = 0; i < lines.length(); i++) {
delete (AcRxObject*)lines[i];
}

for (i = 0; i < regions.length(); i++) {
delete (AcRxObject*)regions[i];
}

// Now we have a solid. Add it to database, then
// associate the solid with a transaction. After
// this, transaction management is in charge of
// maintaining it.
//
pSolid->setPropertiesFrom(pPoly);
addToDb(pSolid, savedExtrusionId);
actrTransactionManager
->addNewlyCreatedDBRObject(pSolid);
pSolid->draw();
return Acad::eOk;
}

static Acad::ErrorStatus
getASolid(char* prompt,
AcTransaction* pTransaction,
AcDb::OpenMode mode,
AcDbObjectId checkWithThisId,
AcDb3dSolid*& pSolid)
{
AcDbObject *pObj = NULL;
AcDbObjectId objId;
ads_name ename;
ads_point pickpt;

for (;;) {
switch (acedEntSel(prompt, ename, pickpt)) {
case RTNORM:
AOK(acdbGetObjectId(objId, ename));
if (objId != checkWithThisId) {
acutPrintf("\n Select the proper"
" solid.");
continue;
}
AOK(pTransaction->getObject(pObj, objId, mode));
assert(pObj != NULL);
pSolid = AcDb3dSolid::cast(pObj);
if (pSolid == NULL) {
acutPrintf("\nNot a solid. Try again");
AOK(pObj->close());
continue;
}
break;
case RTNONE:
case RTCAN:
return Acad::eInvalidInput;
default:
continue;
}
break;
}
return Acad::eOk;
}
/

Quản lý giao dịch Transcation (Phần 2)

Giao dịch lồng nhau


Các giao dịch có thể lồng vào nhau, bạn có thể bắt đầu một giao dịch bên trong một giao dịch khác và kết thúc hoặc hủy bỏ giao dịch gần đây.

Trình quản lý giao dịch duy trì các giao dịch trong một khối, trong đó những giao dịch gần nhất nằm trên đỉnh của khối. Khi bắt đầu một giao dịch mới sử dụng AcTransactionManager::startTransaction(), thì giao dịch đó được thêm vào tại đỉnh của khối và con trỏ đến nó được trả về (một thể hiện của AcTransaction). Khi một ai đó gọi AcTransactionManager::endTransaction() hoặc AcTransactionManager::abortTransaction(), thì giao dịch trên cùng của khối sẽ kết thúc hoặc bị hủy bỏ. 


Khi các con trỏ đối tượng được lấy nhờ vào mã ID, chúng luôn luôn liên hệ với giao dịch gần nhất. Bạn có thể lấy được giao dịch gần đây bằng cách sử dụng AcTransactionManager::topTransaction(), sau đó là AcTransaction::getObject() hoặc AcTransactionManager::getObject() để lấy được con trỏ đến một đối tượng. Trình quản lý giao dịch tự động liên kết với con trỏ đối tượng được lấy với giao dịch gần đây. Bạn có thể dùng AcTransaction::getObject() chỉ với giao dịch gần đây nhất

Khi các giao dịch bắt đầu lồng vào nhau, con trỏ đối tượng được lấy trong giao dịch ngoài cùng cũng dùng được cho các thao tác ở giao dịch trong nhất. Nếu giao dịch gần đây bị hủy bỏ, mọi quá trình hoàn thành trên tất cả các đối tượng (kết hợp với hoặc giao dịch này, hoặc giao dịch bên ngoài) từ lúc bắt đầu của giao dịch gần đây, được hủy bỏ và đối tượng quay trở lại trạng thái ban đầu trước khi giao dịch. Con trỏ đối tượng lấy được trong giao dịch gần đây sẽ mất hiệu lực khi nó bị hủy bỏ.

Nếu giao dịch trong cùng kết thúc thành công bằng cách gọi hàm AcTransactionManager::endTransaction(), các đối tượng có con trỏ lấy được trong giao dịch này sẽ liên kết với giao dịch bên ngoài và sử dụng được cho các quá trình tiếp theo. Quá trình như thế cứ tiếp diễn cho đến khi giao dịch ngoài cùng (đầu tiên) kết thúc, cùng lúc là mọi thay đổi trên các đối tượng sẽ được thực hiện đồng thời. Nếu giao dịch ngoài cùng bị hủy bỏ, mọi thao tác trên tất cả các giao dịch bên trong và chính nó cũng bị hủy bỏ theo.

Tránh giao dịch đệ quy (Recursive Transactions)


Cơ chế quản lý giao dịch trong AutoCAD dựa trên thực tế là các giao dịch không đệ quy. Khi một giao dịch kết thúc (hoặc hủy bỏ), bạn không cần cố gắng để khởi động và kết thúc (hoặc hủy bỏ) một giao dịch khác. Nếu làm như thế, có thể dẫn đến kết quả không lường trước và thiết ổn định. 

Để tránh gây ra vấn đề này, trước khi thực hiện một giao dịch, kiểm tra xem có an toàn để thực hiện hay không. Để làm điều này, thực thi một reactor giao dịch và đặt cờ flag để quyết định khi nào AutoCAD đang ở lưng chừng một quá trình kết thúc (hoặc hủy bỏ) giao dịch. Các phần khác của mã nguồn làm việc với giao dịch nên kiểm tra flag này trước khi tiến hành một giao dịch mới.

Bởi rất nhiều quá trình trong AutoCAD sử dụng quản lý giao dịch, và các quá trình này kích hoạt rất nhiều thông báo khác nhau, cho nên việc sử dụng mã thông báo để kiểm tra xem có an toàn khi thực thiện một giao dịch hay không là thật sự quan trọng.


Biên Giao dịch


Bởi vì chính bạn (không phải hệ thống) chịu trách nhiệm bắt đầu, kết thúc hoặc hủy bỏ giao dịch, nên việc ý thức về biên giao dịch là rất quan trọng. Một biên giao dịch là khoảng thời gian giữa lúc bắt đầu và kết thúc (hoặc hủy bỏ) một giao dịch. Nếu được, bạn hãy giới hạn biên giao dịch trong khoảng nhỏ nhất có thể. Ví dụ như, nếu bạn bắt đầu một giao dịch trong một hàm, hãy thử kết thúc giao dịch trước khi trả về từ hàm đó, bởi bạn có thể không có kiến thức về giao dịch bên ngoài hàm. Bạn không cần thực hiện quy tắc này nếu muốn duy trì một vài kiểu của trình quản lý toàn cầu cho các hoạt động giao dịch, nhưng bạn vẫn cần phải chịu trách nhiệm đối với việc hủy bỏ hay kết thúc giao dịch mà bạn đã khởi động trước đó.

Nhiều ứng dụng có thể sử dụng quản lý giao dịch cho công việc của chúng, và các thao tác trên các đối tượng  sẽ được thực hiện khi kết thúc giao dịch ngoài cùng. Vì thế, hãy kéo dài biên các giao dịch của bạn tối đa có thể trong biên của lệnh AutoCAD®. Khi một lệnh kết thúc, không nên có bất cứ một giao dịch đang hoạt động. Nếu còn giao dịch hoạt động (khối giao dịch không rỗng) khi một  lệnh kết thúc, AutoCAD sẽ hủy bỏ chúng. Có một ngoại lệ, giao dịch vẫn có thể hoạt động khi kết thúc lệnh và AutoCAD trả về dòng lệnh nhắc Command. Nói chung, ý tưởng tốt hơn cả là bắt đầu một giao dịch khi một trong số các hàm của bạn được khởi động như là một phần của lệnh đã đăng ký và kết thúc giao dịch khi bạn trả về từ hàm này. Bạn có thể khái quát nó vào tất cả các lệnh trong AutoCAD bằng cách sử dụng thông báo AcEditorReactor::commandWillStart()AcEditorReactor::commandEnded(), nhưng vẫn có những lệnh nhất định không nên sử dụng trong giao dịch. Các lệnh sau đây không nên thực hiện trong giao dịch:
  • ARX
  • DXFIN
  • INSERT
  • NEW
  • OPEN
  • PURGE
  • QUIT
  • RECOVER
  • REDO
  • SAVE
  • SCRIPT
  • U
  • UNDO
  • XREF

Lấy con trỏ đến đối tượng trong một giao dịch


Cả AcTransactionManager::getObject() lẫn AcTransaction::getObject() đều có thể được dùng để lấy con trỏ đối tượng từ ID của nó. Con trỏ lấy được sẽ làm việc với giao dịch gần nhất. Việc thử lấy con trỏ sử dụng các kết quả giao dịch khác sẽ gây ra lỗi. Ngoài ra, con trỏ lấy được cũng chỉ hợp lệ cho đến khi giao dịch mà chúng làm việc, hoặc một giao dịch bên ngoài, bị hủy bỏ. Khi giao dịch ngoài cùng kết thúc, các thay đổi trên các con trỏ hợp lệ sẽ được thực hiện.

Cả hai hàm getObject() đều lấy một tham số là AcDb::OpenMode và bạn có thể lấy con trỏ đối tượng để đọc, ghi, hoặc notify (thông báo). Mọi yêu cầu đều thành công, ngoài trừ trường hợp: nếu đối tượng đang thông báo và yêu cầu lấy con trỏ là để ghi (nhằm mục đích chỉnh sửa), lỗi (eWasNotifying) sẽ trả về. Không nên chỉnh sửa một đối tượng khi nó đang ở trong trạng thái thông báo đến các đối tượng khác.

Nếu bạn sử dụng getObject() để lấy con trỏ đối tượng, bạn không bao giờ được gọi phương thức close() trên con trỏ đó. Việc gọi close() chỉ hợp lệ nếu bạn lấy con trỏ bằng phương thức acdbOpenObject() hoặc đối tượng mới được tạo ra. Để có thêm thông tin về việc sử dụng phương thức close(), xem thêm các chuyên mục nhỏ dưới đây, Đối tượng mới tạo và giao dịch và Hoà trộn giữa mô hình giao dịch với cơ chế Mở và Đóng.

Đối tượng mới tạo và Giao dịch


Có hai cách để làm thực hiện việc tạo mới đối tượng trong một công việc quản lý giao dịch.

Phương pháp được khuyến nghị là sử dụng close(), đóng đối tượng sau khi thêm nó vào trong Cơ sở dữ liệu hoặc khoang chứa container thích hợp và lưu lại ID được trả về. Ngay sau khi đóng đối tượng, bạn đã có thể sử dụng hàm getObject() để lấy một con trỏ mới để thao tác tiếp theo. Thậm chí nếu bạn gọi phương thức close() trên đối tượng sau khi thêm nó vào trong CSDL, việc tạo ra nó sẽ bị hoàn tác nếu giao dịch bên ngoài bị hủy bỏ. Xem thêm Hoà trộn giữa mô hình giao dịch với cơ chế Mở và Đóng.

Phương pháp thứ hai là thêm đối tượng mới được tạo ra trong bộ nhớ vào CSDL hoặc khoang chứa thích hợp. Sau đó đưa nó vào trong giao dịch gần nhất bằng phương thức AcTransactionManager::addNewlyCreatedDBRObject() hoặc AcTransaction::addNewlyCreatedDBRObject. Bây giờ thì nó đã có thể làm việc với giao dịch. Mọi thay đổi trên đối tượng, thậm chí là việc tạo ra nó cũng sẽ được quyết định bởi giao dịch thành công hay hủy bỏ.

Nguyên tắc thời gian hẹn trước (Commit-Time) 


Khi giao dịch ngoài cùng kết thúc, trình quản lý giao dịch sẽ gọi hàm thông báo endCalledOnOutermostTransaction() (Xem trong Reactor giao dịch) và bắt đầu quá trình thực hiện các thay đổi hẹn trước. Mỗi đối tượng được thực hiện một cách riêng lẻ, cái này sau cái khác, cho đến khi tất cả các thay đổi hẹn trước được thực hiện. Trong suốt quá trình này, bạn không nên thay đổi bất cứ đối tượng nào đang tham gia quá trình, và cũng không nên bắt đầu một giao dịch mới. Nếu không, AutoCAD sẽ hủy bỏ với thông báo lỗi eInProcessOfCommitting

Bạn có thể chỉnh sửa từng đối tượng riêng lẻ sau khi quá trình hẹn trước được thực hiện xong, nhưng không nên lưu lại ID của đối tượng bạn muốn chỉnh sửa và đợi cho đến khi nhận được thông báo transactionEnded() báo hiệu kết thúc giao dịch, rồi mới thực hiện các chỉnh sửa. 

Undo và giao dịch


Mô hình giao dịch sử dụng cơ chế undo của AutoCAD và phương thức AcDbObject::cancel() khi thực thi AcTransactionManager::abortTransaction(). Nó yêu cầu bạn không được gộp bất kì quá trình có sử dụng cơ chế undo dưới lệnh của AutoCAD trong giao dịch. Nó sẽ gây nhầm lẫn cho  AcDbTransactionManager::abortTransaction() và tạo ra kết quả không mong muốn. Ví dụ của quá trình sử dụng cơ chế undo dưới lệnh là các lệnh PEDIT và SPLINEDIT.

Hoà trộn giữa mô hình giao dịch với cơ chế Mở và Đóng 

 
Mô hình giao dịch tồn tại song song với cơ chế đóng và mở đối tượng như đã nói ở chương 5, Đối tượng Cơ sở dữ liệu. Tuy nhiên nếu sử dụng mô hình giao dịch, khuyến cáo bạn không nên sử dụng lẫn lộn nó với cơ chế đóng mở. Ví dụ, nếu bạn lấy con trỏ tới đối tượng sử dụng AcTransaction::getObject(), bạn không nên gọi phương thức close() trên con trỏ của đối tượng nếu không muốn gặp phải những lỗi không mong đợi làm AutoCAD "chết bất đắc kỳ tử". Tuy nhiên, bạn vẫn có thể mở và đóng các đối tượng riêng rẽ khi các giao dịch vẫn đang hoạt động. Bạn cũng có thể khởi tạo đối tượng mới, thêm chúng vào CSDL và đóng chúng lại khi giao dịch chưa kết thúc. Mục đích cơ bản của việc pha trộn là cho phép thực hiện đa tác của nhiều ứng dụng mà một số sử dụng giao dịch, một số thì không.

 Giao dịch và phát sinh đồ hoạ 



Bạn có thể dùng AcTransactionManager::queueForGraphicsFlush()AcTransactionManager::flushGraphics() để vẽ các thực thể theo yêu cầu ngay cả khi chúng liên kết với giao dịch và một số giao dịch vẫn đang hoạt động, có nghĩa là các thay đổi trên thực thể không được hẹn trước. Phương thức AcTransactionManager::queueForGraphicsFlush() sắp xếp tất cả các thực thể eligible liên kết với các giao dịch để cập nhật đồ họa và phương thức AcTransactionManager::flushGraphics() vẽ lại chúng. Bạn có thể dùng AcDbEntity::draw() để vẽ từng thực thể riêng lẻ. Điều này giúp bạn nhìn thấy thực thể trên màn hình mà không phải đợi đến lúc kết thúc quá trình giao dịch ngoài cùng, khi mà mọi thay đổi đều được vẽ lại. Sử dụng AcTransactionManager::enableGraphicsFlush() để bật hoặc tắt chức năng vẽ thực thể. Khi một lệnh kết thúc, bạn sẽ mất quyền kiểm soát đồ họa và nó sẽ tự động kích hoạt lại.

Reactor giao dịch


Trình quản lý giao dịch có một danh sách các phản ứng reactor mà trình thông báo của nó liên quan đến kiểu giao dịch. Dưới đây là các sự kiện gửi thông báo:
  • AcTransactionReactor::transactionStarted()
  • AcTransactionReactor::transactionEnded()
  • AcTransactionReactor::transactionAborted()
  • AcTransactionReactor::endCalledOnOutermostTransaction()
  • AcTransactionReactor::transactionAboutToStart()
  • AcTransactionReactor::transactionAboutToEnd()
  • AcTransactionReactor::transactionAboutToAbort()
  • AcTransactionReactor::objectIdSwapped()
3 thông báo đầu tiên được gửi đi khi một giao dịch, bao giồm cả các giao dịch lồng được khởi động, kết thúc hoặc hủy bỏ. Bạn có thể dùng những thông báo này kết hợp với AcTransactionManager::numActiveTransactions() để xác định các giao dịch có liên quan đến thông báo. Ví dụ, nếu gọi hàm AcTransactionManager::numActiveTransactions() trả về 0 trong hàm chồng AcTransactionReactor::transactionEnded() hoặc AcTransactionReactor::transactionAborted(), bạn có thể biết được giao dịch ngoài cùng đang kết thúc hay bị hủy.
Thông báo endCalledOnOutermostTransaction() báo hiệu kết thúc quá trình thay đổi hẹn trước được thực hiện của tất cả các giao dịch. Bạn có thể sử dụng để sử dụng nó để thực hiện các dọn dẹp cần thiết trước khi quá trình hẹn trước bắt đầu.

Tham số đầu tiên trong tất cả các thông báo thể hiện số lượng các giao dịch đang hoạt động cộng với những giao dịch đã kết thúc thành công. Nó không bao gồm giao dịch vừa bắt đầu hoặc đã bị hủy bỏ.
/

13 tháng 7, 2013

Quản lý giao dịch Transaction

Chuyên mục này miêu tả mô hình Giao dịch (transaction), được sử dụng để thao tác trên các đối tượng AcDb. Trong mô hình này, nhiều thao tác trên nhiều đối tượng khác nhau được nhóm lại cùng với nhau trong một quá trình nguyên tử (atomic) gọi là một giao dịch (transaction).

Các giao dịch có thể được lồng và có thể kết thúc hay huỷ bỏ tuỳ theo quyết định của khách hàng (client). Mô hình này có thể được sử dụng kết hợp với cơ chế mở đóng trong từng đối tượng riêng lẻ như đã nói đến trong chuyên mục Đối tượng Cơ sở dữ liệu.



  • Tổng quan về quản lý giao dịch
  • Trình quản lý giao dịch
  • Các giao dịch lồng nhau
  • Giao dịch biên ngoài
  • Lấy con trỏ đến đối tượng trong một giao dịch
  • Đối tượng mới tạo và Giao dịch
  • Nguyên tắc thời gian hẹn trước (Commit-Time)
  • Undo và Giao dịch
  • Hoà trộn giữa mô hình giao dịch với cơ chế Mở và Đóng
  • Giao dịch và phát sinh đồ hoạ
  • Reactor giao dịch
  • Ví dụ về giao dịch lồng nhau
 

Tổng quan về quản lý giao dịch

 


Mô hình giao dịch đóng gói nhiều quá trình trên nhiều đối tượng bởi một số client (máy khách) thành một quá trình nguyên tử gọi là giao dịch. Bên trong ranh giới của một giao dịch, các client có thể mang các con trỏ từ ID của các đối tượng. Các con trỏ này sẽ hợp lệ cho đến khi giao dịch kết thúc, hoặc bị huỷ bỏ bởi client. Nếu giao dịch kết thúc thành công, các quá trình trên đối tượng sẽ được thực hiện theo đúng yêu cầu. Nếu huỷ bỏ giao dịch, các thao tác trên đối tượng cũng bị huỷ bỏ theo.

Quá trình trên các đối tượng sử dụng dạng thức (paradigm) này có một số lợi thế so với cơ chế mở và đóng đơn thuần đã nói đến trong chuyên mục Đối tượng Cơ sở dữ liệu. Cơ chế mở và đóng thích hợp hơn với các quá trình đơn giản trên một đối tượng riêng lẻ hoặc một nhóm đối tượng nhỏ. Tuy nhiên, sẽ có những hạn chế nhất định trong việc mở đối tượng theo cách này. Ví dụ, nếu đối tượng được mở để đọc, bạn không thể mở nó để Ghi tại cùng thời điểm. Nếu đối tượng được mở để ghi, bạn cũng không thể mở nó để ghi một lần nữa. Danh sách các lỗi xung đột của cơ chế mở và đóng, xem bài Đối tượng Cơ sở dữ liệu. Mô hình giao dịch khoan dung (lenient) hơn, có thể lấy được con trỏ đối tượng từ mã ID cho một phương thức đặc biệt thường thành công nếu như đối tượng có liên hệ với giao dịch.

Tuỳ thuộc vào ứng dụng của bạn, có thể sẽ gặp phải những khó khăn khác khi sử dụng cơ chế đóng mở. Nếu ứng dụng mở và đóng cùng một đối tượng một số lần nhất định chỉ trong một quá trình - ví dụ trong 1 lệnh - bạn sẽ gánh chịu (incur) sự thiếu hiệu quả nghiêm trọng do sử dụng đóng mở nhiều lần. Một số lượng các quá trình thời gian tiêu dùng (time-consuming) có liên kết với quá trình đóng đối tượng. Nếu bạn mở một đối tượng để Ghi, chỉnh sửa, và đóng đối tượng lại, thì bản ghi Undo của sự thay đổi được giao phó vào quá trình undo tệp tin, đồ hoạ đối tượng được phát sinh, và các thông báo được kích hoạt. Tất cả các quá trình được thực hiện mỗi lần đối tượng được đóng lại. Nếu bạn giao dịch hoá các quá trình và sử dụng con trỏ đối tượng sử dụng giao dịch, mọi hoạt động đề cập trước đó sẽ xảy ra một lần duy nhất khi kết thúc giao dịch. Kết quả được cải thiện hiệu quả đáng kể và một quá trình undo tệp tin nhỏ hơn, bởi vì số lượng các bản ghi undo giảm xuống.

Ngoài ra, nếu bạn có một mạng lưới phức tạp nơi các đối tượng tham chiếu đến các đối tượng khác bằng mã ID, bạn mỗ lấy con trỏ tới một đối tượng trong bất kỳ module nào của chương trình mà không phải lo lắng xem đã có module hay chương trình nào khác đã mở đối tượng hay chưa. Các hoạt động này chỉ có thể sử dụng mô hình giao dịch bởi vì giao dịch nhóm các quá trình và cho phép lấy con trỏ từ mã ID vượt qua cả ranh giới của một module.

Trình quản lý giao dịch


Trình quản lý giao dịch là một đối tượng quản lý toàn cục, giống như trình soạn thảo editor,  nó có trách nhiệm duy trì các giao dịch. Nó là một đại diện của AcTransactionManager và được duy trì trong hệ thống registry. Bạn có thể lấy được nó từ hệ thống registry bằng macro actrTransactionManager, có mở rộng là:

#define actrTransactionManager  \
AcTransactionManager::cast(
acrxSysRegistry()->at(AC_TRANSACTION_MANAGER_OBJ))

Trình quản lý giao dịch cần được dụng để mở đầu, kết thúc hoặc huỷ bỏ một giao dịch. Nó có thể cung cấp thông tin như số lượng các giao dịch hiện hành tại một thời điểm bất kỳ (xem thêm chuyên mục, Giao dịch lồng nhau) và một danh sách tất cả các đối tượng có con trỏ đang được sử dụng trong mọi giao dịch. Trình quản lý giao dịch duy trì một danh sách các reactor để nhắc nhở các máy trạm về sự kiện bắt đầu, kết thúc hay huỷ bỏ một giao dịch. 

Ngoài khả năng quản lý, trình quản lý giao dịch còn có thể được dùng để lấy con trỏ từ mã ID. Khi điều đó được thực hiện, đối tượng có liên hệ với giao dịch trên đỉnh (gần nhất). Trình quản lý giao dịch còn có thể được sử dụng để sắp xếp mọi đối tượng theo thứ tự trong tất cả giao dịch cho quá trình câp nhật đồ hoạ và dồn dịch sắp xếp (flush the queue).

Đối tượng trình quản lý giao dịch được tạo ra và quản lý bởi hệ thống. Bạn không nên xoá nó.

    /

    12 tháng 7, 2013

    Tạo mới UCS và đặt làm UCS hiện hành

    By Gopinath Taget

    Đoạn mã nguồn sau đây trình bày cách tạo một UCS đặt tên và thiết lập nó thành UCS hiện hành. Có hai hàm cần phải nhớ là:

    1. acedVports2VportTableRecords() - Hàm này cần được gọi trước khi truy cập đến bảng các viewport.
    2. acedVportTableRecords2Vports() - Hàm này cần được gọi khi kết thúc chương trình để áp dụng các thay đổi lên bảng viewport.
    Hai hàm trên rất cần thiết để AutoCAD có thể cập nhật viewport với các thiết lập hiện hành.

    // - asdkucsarx._test command (do not rename)
    static void asdkucsarx_test(void)
    {
    Acad::ErrorStatus es;
    AcDbUCSTableRecord *myUCS = new AcDbUCSTableRecord;

    //define your own ucs

    AcGePoint3d origin_point(0,0,0);
    AcGeVector3d UCSXaxis(0,1,0);
    AcGeVector3d UCSYaxis(1,0,0);

    myUCS->setOrigin(origin_point);
    myUCS->setXAxis(UCSXaxis);
    myUCS->setYAxis(UCSYaxis);

    es=myUCS->setName( _T("MyUCS"));

    if (es != Acad::eOk)
    {
    acutPrintf(_T("\nFailed to set name"));
    return;
    }

    AcDbObjectId UCSId;
    AcDbSymbolTable *pUCSTable;

    if (acdbHostApplicationServices()->workingDatabase()->
    getUCSTable(pUCSTable,AcDb::kForWrite)==Acad::eOk)
    {
    es=pUCSTable->add(UCSId,myUCS);
    es=pUCSTable->close();
    es= myUCS->close();
    }
    else
    {
    acutPrintf(_T("\nFailed to get UCS table"));
    return;
    }

    //To set the current UCS, I accessed
    // the active AcDbViewportTableRecord
    // and used setUCS to set the UCS I created as current.

    AcDbViewportTable *pVT;
    es = acedVports2VportTableRecords();
    if (es != Acad::eOk)
    {
    acutPrintf(
    _T("\nFailed to load vport info into vport table records"));
    return;
    }

    es=acdbHostApplicationServices()->
    workingDatabase()->getViewportTable(pVT,AcDb::kForRead);
    if (es != Acad::eOk)
    {
    acutPrintf(_T("\nFailed to get vport table"));
    pVT->close();
    return;
    }

    AcDbViewportTableIterator* pIter = NULL;

    es=pVT->newIterator(pIter);

    if (es != Acad::eOk)
    {
    acutPrintf(_T("\nFailed to get vport table"));
    pVT->close();
    delete pIter;
    return;
    }

    for (pIter->start();!pIter->done();pIter->step())
    {

    AcDbViewportTableRecord* pRec;
    //it should be open for write mode
    es=pIter->getRecord(pRec,AcDb::kForWrite);

    if (es != Acad::eOk)
    {
    acutPrintf(
    _T("\nFailed to get vport table record"));
    pVT->close();
    pRec->close();
    delete pIter;
    return;
    }

    TCHAR* name=NULL;
    es=pRec->getName(name);
    if (es != Acad::eOk)
    {
    acutPrintf(
    _T("\nFailed to get name from vport table"));
    pVT->close();
    pRec->close();
    delete pIter;
    return;
    }

    if (_tcsicmp(name,_T("*ACTIVE"))==0)
    {
    es=pRec->setUcs(UCSId);
    }
    es=pRec->close();
    }
    es=acedVportTableRecords2Vports(); //force update
    es=pVT->close();
    delete pIter;
    return ;
    }
    /

    Tạo Viewports mới trong không gian PaperSpace

    By Augusto Goncalves

    Để tạo mới một viewport trong không gian PaperSpace, giống như lệnh MVIEW, thực hiện theo các bước sau:
    1. Tạo một đối tượng mới có kiểu AcDbViewport.
    2. Thiết lập tọa độ view (với các hàm setWidth(), setHeight()setCenterPoint()).
    3. Thêm viewport vào không gian paper.
    4. Lấy các thiết lập view từ người dùng (AcDbViewTableRecord).
    5. Thiết lập view có được trong viewport mới tạo ra bằng hàm acdbSetCurrentView().
    6. Kích hoạt viewport với hàm AcDbViewport::setOn().

    CHÚ Ý: Hàm AcDbViewport::setOn() chỉ làm việc nếu lệnh của bạn được đăng ký mà không có flag ACRX_CMD_TRANSPARENT. Nếu không, AcDbViewport::setOn() sẽ trả về eCommandWasInProgress và bạn không thể kích hoạt viewport cho đến khi đặt biến TILEMODE bằng 1 rồi trở về 0.  avnd you cannot activate the viewport until you set tilemode to 1 and back to 0.

    Dưới đây là mã nguồn thực hiện:

    // Only works in paperspace
    AcDbObjectId mCurViewportId = acedGetCurViewportObjectId();
    if (mCurViewportId == AcDbObjectId::kNull)
    {
    acutPrintf(_T("\nCommand only works in paperspace."));
    return;
    }

    AcDbViewport *pCurViewport;
    if (Acad::eOk != acdbOpenObject(pCurViewport,mCurViewportId,
    AcDb::kForRead))
    {
    acutPrintf(_T("\nCannot get active viewport."));
    return;
    }

    if (pCurViewport->number() != 1)
    {
    acutPrintf(_T("\nCommand only works in paperspace."));
    pCurViewport->close();
    return;
    }
    pCurViewport->close();

    // Ask for the position
    ads_point pt1,pt2;

    if (RTNORM != acedGetPoint(NULL,
    _T("\nSelect first corner: "), pt1))
    return;

    if (RTNORM != acedGetCorner(pt1,
    _T("\nSelect second corner: "), pt2))
    return;

    // Ask for the view to use
    ACHAR mViewName[133];

    if (RTNORM != acedGetString(0,
    _T("\nEnter name of view to use: "), mViewName))
    return;

    // Create new viewport
    AcDbViewport *pViewport = new AcDbViewport;

    pViewport->setWidth(fabs(pt2[X] - pt1[X]));
    pViewport->setHeight(fabs(pt2[Y] - pt1[Y]));
    pViewport->setCenterPoint(AcGePoint3d(
    pt1[X] + (pt2[X] - pt1[X]) / 2,
    pt1[Y] + (pt2[Y] - pt1[Y]) / 2,
    pt1[Z]));

    // Append new viewport to paper space
    AcDbBlockTable *pTable;
    AcDbBlockTableRecord *pPsBTR;

    if (Acad::eOk != acdbHostApplicationServices()->
    workingDatabase()->getBlockTable(pTable, AcDb::kForRead))
    {
    acutPrintf(_T("\nCannot get block table."));
    delete pViewport;
    return;
    }

    if (Acad::eOk != pTable->getAt(ACDB_PAPER_SPACE, pPsBTR,
    AcDb::kForWrite))
    {
    acutPrintf(_T("\nCannot access paper space."));
    pTable->close();
    delete pViewport;
    return;
    }
    pTable->close();

    AcDbObjectId mViewPortId;
    if (Acad::eOk != pPsBTR->appendAcDbEntity(mViewPortId, pViewport))
    {
    acutPrintf(_T("\nCannot append viewport to paper space."));
    pPsBTR->close();
    delete pViewport;
    return;
    }
    pPsBTR->close();
    pViewport->setOn();

    // Set the view
    AcDbViewTable *pViewTable;
    AcDbViewTableRecord *pViewTR;

    if (Acad::eOk != acdbHostApplicationServices()->
    workingDatabase()->getViewTable(pViewTable, AcDb::kForRead))
    {
    acutPrintf(_T("\nCannot get view table."));
    pViewport->close();
    return;
    }

    if (Acad::eOk != pViewTable->getAt(mViewName,
    pViewTR, AcDb::kForRead))
    {
    acutPrintf(_T("\nCannot access view '%s'."), mViewName);
    pViewport->close();
    pViewTable->close();
    return;
    }

    pViewTable->close();

    if (acedSetCurrentView(pViewTR, pViewport)!=Acad::eOk)
    acutPrintf(_T("\nFailed to set view"));

    // Close the objects
    pViewTR->close();
    pViewport->close();
    /

    5 tháng 7, 2013

    Lớp AcDbHatch class - ObjectARX SDK

    AcDbHatch là một thực thể đồng phẳng được tạo ra và đặt trong một mặt phẳng tùy ý trong không gian 3D. 

    Mặt phẳng HATCH có thể là đơn nhất tùy thuộc vào vector chỉ phương trong WCS (World Coordinate System) và cao độ cho biết khoảng cách từ trục WCS tới mặt phẳng HATCH. Mặt phẳng HATCH chấp nhận hệ tọa độ đối tượng của AutoCAD (OCS - object coordinate system). Gốc của nó trùng với gốc của WCS, trục X và Y được tính toán dựa trên thuật toán trục tọa độ riêng.



    Đường bao hatch thể hiện diện tích và được lấp đầy với mẫu hatch cho trước. Thể hiện bên trong của đường bao là tập hợp của các vòng loop đồng phẳng. Mỗi vòng lại được tạo bởi các đường 2D từ line, cung tròn arc, ellip và spline. Nếu đường bao chứa hơn 2 vòng loop, diện tích xác định bởi từng vòng nhỏ phải được phân tách hoàn toàn hoặc vòng này sẽ nằm trọn vẹn trong vòng khác.

    Một vòng phải là vòng đơn, khép kín và liên tục, tự giao cắt chỉ xảy ra tại điểm kết thúc endpoint. Hơn nữa, điểm bắt đầu và kết thúc phải trùng nhau. Khi xác định một đường bao hatch, ứng dụng phải đảm bảo rằng các vòng và đường bao đã được xác định và có cấu trúc. Nếu đường bao chứa nhiều hơn hai vòng, chúng phải được tổ chức trong một cấu trúc lồng, nghĩa là vòng bên ngoài sẽ được xây dựng trước, sau đó là tất cả các vòng trong lần lượt theo thứ tự. Nếu có nhiều hơn một vòng ngoài, hãy lặp lại quá trình đó. AutoCAD chỉ cho phép giới hạn số đường bao hợp lệ nhằm duy trì tính hiệu quả thực thi của API

    Thể hiện nội hàm của đường bao hatch là GELIB 2D geometry, bao gồm AcGeLineSeg2d, AcGeCircArc2d, AcGeEllipArc2dAcGeNurbCurve2d. Nếu đường bao chứa một polyline, một phương thức đặc biệt sẽ được tiến hành để xây dựng các vòng loop

    Chú ý: AutoCAD luôn giả thiết trục X cho một đường bao AcGeCircArc2d là vector 2D AcGeVector2d of (1.0, 0.0).

    Hatch liên kết (associative) cho phép ứng dụng tạo ra các thực thể hatch có thể liên kết với đường bao của các thực thể AutoCAD trong CSDL như LINE, ARC, CIRCLE, CIRCLE, ELLIPSE, SPLINE, POLYLINE, TEXT, MTEXT, ATTRIBUTE DEFINITION, ATTRIBUTE, SHAPE, SOLID, TRACE, TOLERANCE, REGION, VIEWPORT, 3D FACE, BLOCK INSERT, XREF, LWPOLYLINE, RASTER v.v.  Khi chỉnh sửa các thực thể hình học nguồn, hatch sẽ thay đổi một cách tự động.

    Khi sử dụng thực thể riêng (custom entity), bạn phải định nghĩa một phương thức explode để hatch có thể làm việc. Phương thức này cần phải bẻ gãy thực thể của bạn  thành các thực thể giản đơn. Nếu không xây dựng từ các thực thể nguyên bản, phương thức của bạn nên trả về giá trị eExplodeAgain. Nó khiến cho AcDbHatch tự gọi phương thức explode trên thực thể bạn trả về, cho đến khi mọi thực thể được bẻ gãy thành các thực thể nguyên bản (native).

    Khi định nghĩa một đường bao hatch sử dụng các đối tượng CSDL, ứng dụng phải chắc chắn rằng các đối tượng được chọn có đường bao hợp lệ và  đồng phẳng với mặt phẳng hatch. Đối tượng được chọn còn phải cấu thành được các vòng loop. Bạn cũng cần xác định flag liên kết (associativity flag) trước khi thiết lập đường bao. Phương thức insertLoopAt()appendLoop() sẽ xuất ra các yếu tố hình học từ đối tượng CSDL và bảo quản mã ID của đối tượng đó với cấu trúc vòng cho hatch liên kết.

    Nếu đường bao chứa nhiều hơn 2 vòng loop cho một hatch đặc, diện tích  xác định bởi từng vòng loop phải được chia cắt hoặc cái này sẽ nằm trọn vẹn trong cái khác. Ngoài ra, mỗi vòng cũng phải là đơn giản, đóng và liên tục, nghĩa là các giao cắt của chính nó chỉ xảy ra tại các điểm endpoint. Nếu đường bao hatch không thỏa mãn yêu cầu này, kết quả trả về có thể không lường trước và mâu thuẫn giữa phần hatch và phần không được hatch.

    Các Mline  là các thực thể phức hợp có thể tạo ra nhiều hơn một vòng loop, nghĩa là chúng sẽ bị trả về như là các đường bao. Nếu sử dụng API AcDbHatch và lựa chọn đối tượng AcDbMline, hatch sẽ không được hiển thị và phương thức appendloop() sẽ trả về eInvalidInput. Để khắc phục vấn đề này, bạn có thể tạo ra 1 vùng region bằng cách sử dụng đường biên để xây dựng một đối tượng AcDbRegion. Bạn có thể phá region để lấy vòng loop giản đơn, và đưa thành loop của đối tượng AcDbHatch. Ứng dụng của bạn cần phải kiểm tra trạng thái trả về của mỗi hàm API và xóa thực thể hatch nếu trạng thái là eInvalidInput.

    Hiện tại, AutoCAD hỗ trợ 3 kiểu mẫu hatch là User-defined,  Predefined, và Custom. Xem enum HatchPatternType để biết thêm thông tin.

    Phương thức sau đây kích hoạt ứng dụng để thiết lập và lấy dữ liệu mẫu hatch. Nếu gọi AcDbHatch::setPatternScale() (hoặc bất cứ phương thức nào khác), giá trị scale thay đổi, tuy nhiên mẫu vẫn không thay đổi trên màn hình. Đây là do thiết kế. Bạn cần phải gọi AcDbHatch::setPattern() sau khi thay đổi tỉ lệ scale patterne, góc quay, tên mẫu, ... Chỉ cần gọi một lần là đủ cho tất cả các kết hợp của mẫu thay đổi. 

    AutoCAD đang hỗ trợ 3 kiểu hatch, là Normal, Outer, và Ignore. Xem thê enum HatchStyle.

    Phương thức sau đâu cho phép ứng dụng thiết lập và lấy về kiểu hatch. Các phương thức này được cung cấp nhằm mục đích tương thích , tốt nhất là luôn sử dụng kiểu Normal.

    AcDbHatch::HatchStyle style() const;
    Acad::ErrorStatus setStyle(AcDbHatch::HatchStyle hstyle);
     
    Sau khi định nghĩa đường bao và xác định mẫu, kiểu hatch, ứng dụng phải dựng lên các đoạn thẳng hatch hoặc diện tích hatch để hiển thị. Lớp AcDbHatch duy trì việc tính toán các đoạn thẳng hatch và diện tích hatch để hỗ trợ phương thức worldDraw()viewportDraw() trong việc thể hiện thực thể. Tuy nhiên, việc tính toán này không được ghi lại trong bản vẽ hoặc tệp tin DXF nhằm đảm bảo dung lượng tệp tin. Thay vào đó, AutoCAD sẽ tính toán lại các đoạn thẳng và khối hatch khi các bản vẽ này được mở ra trong lần kế tiếp.

    Nếu đường bao hoặc các vòng loop thay đổi, ứng dụng phải xây dựng lại đoạn thẳng hatch và diện tích hatch phù hợp.

    Đường bao không hiển thị.  Đây không phải là vấn đề hiện tại bởi vì thực thể hatch luôn luôn liên kết với các đối tượng hình học trong CSDL trong mọi trường hợp. 

    Chú ý: Gọi hàm explode với một mẫu hatch solid sẽ trả về giá trị eNotApplicable.

    Ví dụ


    Chú ý: ví dụ dưới đây chưa được dịch hoặc gỡ lỗi (debugged) và có thể chứa các lỗi cú pháp. Nó chỉ trình bày thủ tục tạo ra các thực thể AcDbHatch trong môi trường API.

    Ví dụ dưới đây trình bày cách để tạo ra thực thể HATCH trên mặt phẳng WCS XY. Biên ngoài là một hình chữ nhật còn biên trong là một đường tròn. Mẫu hatch là SOLID với màu sắc mặc định của AutoCAD. HATCH tạo ra không có liên kết (associative - có thể kéo dãn theo các đường biên).

    Acad::ErrorStatus acqHatch1() 
    {
    AcDbHatch* pHatch = new AcDbHatch();

    // Set hatch plane
    //
    AcGeVector3d normal(0.0, 0.0, 1.0);
    pHatch->setNormal(normal);
    pHatch->setElevation(0.0);

    // Set non associative hatch
    //
    pHatch->setAssociative(Adesk::kFalse);

    // Set hatch pattern to SolidFill type
    //
    pHatch->setPattern(AcDbHatch::kPreDefined, "SOLID");

    // Set hatch style to kNormal
    //
    pHatch->setHatchStyle(AcDbHatch::kNormal);

    // Construct hatch external boundary
    //
    AcGePoint2dArray vertexPts;
    AcGeDoubleArray vertexBulges;
    vertexPts.setPhysicalLength(0).setLogicalLength(5);
    vertexPts[0].set(2.0, 2.0);
    vertexPts[1].set(8.0, 2.0);
    vertexPts[2].set(8.0, 8.0);
    vertexPts[3].set(2.0, 8.0);
    vertexPts[4].set(2.0, 2.0);
    vertexBulges.setPhysicalLength(0).setLogicalLength(5);
    for (int i = 0; i < 5; i++)
    vertexBulges[i] = 0.0;

    // Append an external loop (rectangle) to hatch boundary

    pHatch->appendLoop(AcDbHatch::kExternal, vertexPts, vertexBulges);

    // Construct a circle
    //
    AcGePoint2d cenPt(5.0, 5.0);
    double TWOPI = 2.0 * 3.1415926535897932;
    AcGeCircArc2d *cirArc = new AcGeCircArc2d();
    cirArc->setCenter(cenPt);
    cirArc->setRadius(1.0);
    cirArc->setAngles(0.0, TWOPI);

    // Append an internal circular loop to hatch boundary
    //
    AcGeIntArray edgeTypes;
    AcGeVoidPointerArray edgePtrs;
    edgeTypes.append(AcDbHatch::kCirArc);
    edgePtrs.append((void*)cirArc);
    pHatch->appendLoop(AcDbHatch::kDefault, edgePtrs, edgeTypes);

    // Elaborate solid fill
    //
    pHatch->evaluateHatch();

    // Post hatch entity to database
    //
    AcDbObjectId newId;
    postToModelSpace(pHatch, newId);

    return eOk;
    }

    Ví dụ dưới đây trình bày cách tạo một thực thể HATCH có liên kết (associative) trong mặt phẳng WCS XY. Đường biên ngoài là hình chữ nhật còn biên trong là một đường tròn. Mẫu HATCH là ANSI31, màu sắc mặc định. HATCH mới tạo ra có liên kết, có thể kéo dãn hoặc co lại theo các đường biên.

    Acad::ErrorStatus acqHatch2() 
    {
    AcDbHatch* pHatch = new AcDbHatch();

    // Set hatch plane
    //
    AcGeVector3d normal(0.0, 0.0, 1.0);
    pHatch->setNormal(normal);
    pHatch->setElevation(0.0);

    // Set hatch pattern to ANSI31 predefined type
    //
    pHatch->setHatchPattern(AcDbHatch::kPreDefined, "ANSI31");

    // Set Associativity
    //
    pHatch->setAssociative(Adesk::kTrue);

    // Construct database AcDbLines
    //
    AcGePoint2d vertexPts[4];
    AcDbObjectId lineId, cirId, hatchId;
    AcDbObjectIdArray dbObjIds;
    AcDbLine *line;

    vertexPts[0].set(2.0, 2.0, 0.0);
    vertexPts[1].set(8.0, 2.0, 0.0);
    vertexPts[2].set(8.0, 8.0, 0.0);
    vertexPts[3].set(2.0, 8.0, 0.0);

    for (int i = 0; i < 4; i++) {
    line = new AcDbLine();
    line->setStartPoint(vertexPts[i])
    line->setEndPoint(vertexPts[(i == 3) ? 0 : i+1])
    line->postToDb(line, lineId);
    dbObjIds.append(lineId);
    }

    // Append an external rectangular loop to hatch boundary
    //
    pHatch->appendLoop(AcDbHatch::kExternal, dbObjIds);

    // Create a AcDbCircle and post it to database
    //
    AcGePoint2d cenPt(5.0, 5.0, 0.0);
    AcGeVector3d normal(0.0, 0.0, 1.0);
    AcDbCircle *circle = new AcDbCircle();
    circle->setNormal(normal);
    circle->setCenter(cenPt);
    circle->setRadius(1.0);
    circle->postToDb(circle, cirId);
    dbObjIds.setLogicalLength(0);
    dbObjIds.append(cirId);

    // Append an internal loop (circle) to hatch boundary
    //
    pHatch->appendLoop(AcDbHatch::kDefault, dbObjIds);

    // Elaborate hatch lines
    //
    pHatch->evaluateHatch();

    // Get all associative source boundary object Ids for later use.
    //
    dbObjIds.setLogicalLength(0);
    pHatch->getAssocObjIds(dbObjIds);

    // Post hatch entity to database
    //
    pHatch->postToDb(pHatch, hatchId);

    // Attach hatchId to all source boundary objects for notification.
    //
    AcDbEntity *pEnt;
    int numObjs = dbObjIds.length();
    Acad::ErrorStatus es;
    for (i = 0; i < numObjs; i++) {
    es = acdbOpenAcDbEntity(pEnt, dbObjIds[i], AcDb::kForWrite);
    if (es == Acad::eOk) {
    pEnt->addPersistentReactor(hatchId);
    pEnt->close();
    }
    }
    return eOk;
    }

    Dẫn xuất từ

      AcRxObject
        |-AcGiDrawable
          |-AcDbObject
            |-AcDbEntity
              |-AcDbHatch
    /

    Tính chiều dài đường cong Curve trong ObjectARX


    Dưới đây là đoạn mã dùng để tính toán chiều dài một đường cong Curve.

    Curve ở đây được hiểu theo nghĩa rộng hơn, bao gồm cả đoạn thẳng LINE, các đa tuyến POLYLINE, các cung tròn ARC, đường tròn CIRCLE.


    Acad::ErrorStatus GetLength(AcDbObjectId id, double& length)
    {
    Acad::ErrorStatus es;

    AcDbCurve* pEnt;
    es = acdbOpenObject(pEnt, id, AcDb::kForRead);
    if( es == Acad::eOk && pEnt)
    {
    double startParam, endParam, startDist, endDist;

    es = pEnt->getStartParam(startParam);
    if( es!=Acad::eOk ) { pEnt->close(); return es; }

    es = pEnt->getEndParam(endParam);
    if( es!=Acad::eOk ) { pEnt->close(); return es; }

    es = pEnt->getDistAtParam(startParam, startDist);
    if( es!=Acad::eOk ) { pEnt->close(); return es; }

    es = pEnt->getDistAtParam(endParam, endDist);
    if( es!=Acad::eOk ) { pEnt->close(); return es; }

    es = pEnt->close();
    length = endDist - startDist;
    }

    return es;
    }
    /

    4 tháng 7, 2013

    37.6 Lưới tam giác đơn giản Regular Triangulations

    37.6   Regular Triangulations


    37.6.1   Description

    Let PW = {(pi, wi) | i = 1, , n } be a set of weighted points where each pi is a point and each wiis a scalar called the weight of point pi. Alternatively, each weighted point (pi, wi) can be regarded as a sphere (or a circle, depending on the dimensionality of pi) with center pi and radius ri=√wi. The power diagram of the set PW is a space partition in which each cell corresponds to a sphere (pi, wi) of PWand is the locus of points p whose power with respect to (pi, wi)is less than its power with respect to any other sphere in PW. In the two-dimensional space, the dual of this diagram is a triangulation whose domain covers the convex hull of the set P= { pi | i = 1, , n } of center points and whose vertices form a subset of P. Such a triangulation is called a regular triangulation. Three points pi, pj and pk of Pform a triangle in the regular triangulation of PWiff there is a point p of the plane with equal powers with respect to (pi, wi), (pj, wj)and (pk, wk) and such that this power is less than the power of pwith respect to any other sphere in PW.
    Let us defined the power product of two weighted points (pi, wi) and (pj, wj) as:
    Π(pi, wi, pj, wj) = pipj 2 - wi - wj .
    Π(pi, wi, pj, 0) is simply the power of point pjwith respect to the sphere (pi, wi), and two weighted points are said to be orthogonal if their power product is null. The power circle of three weighted points (pi, wi), (pj, wj)and (pk, wk) is defined as the unique circle (π, ω) orthogonal to (pi, wi), (pj, wj)and (pk, wk). The regular triangulation of the sets PWsatisfies the following regular property (which just reduces to the Delaunay property when all the weights are null): a triangle pipjpk is a face of the regular triangulation of PW iff the power product of any weighted point (pl, wl) of PW with the power circle of (pi, wi), (pj, wj) and (pk, wk) is positive or null. We call power test of (pi, wi), (pj, wj), (pk, wk), and (pl, wl), the predicates which amount to compute the sign of the power product of (pl, wl) with respect to the power circle of (pi, wi), (pj, wj) and (pk, wk). This predicate amounts to computing the sign of the following determinant
    |
    1 xi yi xi 2 + yi 2 - wi
    1 xj yj xj 2 + yj 2 - wj
    1 xk yk xk 2 + yk 2 - wk
    1 xl yl xl 2 + yl 2 - wl
    |
    A pair of neighboring faces pipjpkand pipjpl is said to be locally regular (with respect to the weights in PW) if the power test of (pi, wi), (pj, wj), (pk, wk), and (pl, wl) is positive. A classical result of computational geometry establishes that a triangulation of the convex hull of Psuch that any pair of neighboring faces is regular with respect to PW, is a regular triangulation of PW.
    Alternatively, the regular triangulation of the weighted points set PWcan be obtained as the projection on the two dimensional plane of the convex hull of the set of three dimensional points P'= { (pi,pi 2 - wi ) | i = 1, , n }.
    The class Regular_triangulation_2<Traits, Tds> is designed to maintain the regular triangulation of a set of 2d weighted points. It derives from the class Triangulation_2<Traits, Tds>. The functions insert and remove are overwritten to handle weighted points and maintain the regular property. The function move is not overwritten and thus does not preserve the regular property. The vertices of the regular triangulation of a set of weighted points PW correspond only to a subset of PW. Some of the input weighted points have no cell in the dual power diagrams and therefore do not correspond to a vertex of the regular triangulation. Such a point is called a hidden point. Because hidden points can reappear later on as vertices when some other point is removed, they have to be stored somewhere. The regular triangulation store those points in special vertices, called hidden vertices. A hidden point can reappear as vertex of the triangulation only when the two dimensional face that hides it is removed from the triangulation. To deal with this feature, each face of a regular triangulation stores a list of hidden vertices. The points in those vertices are reinserted in the triangulation when the face is removed.
    Regular triangulation have member functions to construct the vertices and edges of the dual power diagrams.

    The Geometric Traits

    The geometric traits of a regular triangulation must provide a weighted point type and a power test on these weighted points. The concept RegularTriangulationTraits_2, is a refinement of the concept TriangulationTraits_2. Cgal provides the class Regular_triangulation_euclidean_traits_2<Rep,Weight>which is a model for the traits concept RegularTriangulationTraits_2. The class Regular_triangulation_euclidean_traits_2<Rep,Weight>derives from the class Triangulation_euclidean_traits_2<Rep>and uses a Weighted_point type derived from the type Point_2 of Triangulation_euclidean_traits_2<Rep>. Note that, since the type Weighted_point is not defined in Cgal kernels, plugging a filtered kernel such as Exact_predicates_exact_constructions_kernel in Regular_triangulation_euclidean_traits_2<K,Weight> will in fact not provide exact predicates on weighted points.To solve this, there is also another model of the traits concept, Regular_triangulation_filtered_traits_2<FK>, which is providing filtered predicates (exact and efficient). The argument FK must be a model of the Kernel concept, and it is also restricted to be a instance of the Filtered_kernel template.

    The Vertex Type and Face Type of a Regular Triangulation

    The base vertex type of a regular triangulation includes a Boolean data member to mark the hidden state of the vertex. Therefore Cgal defines the concept RegularTriangulationVertexBase_2 which refine the concept TriangulationVertexBase_2and provides a default model for this concept.
    The base face type of a regular triangulation is required to provide a list of hidden vertices, designed to store the points hidden by the face. It has to be a model of the concept RegularTriangulationFaceBase_2. Cgal provides the templated class Regular_triangulation_face_base_2<Traits>as a default base class for faces of regular triangulations.

    37.6.2   Example: a Regular Triangulation

    The following code creates a regular triangulation of a set of weighted points and output the number of vertices and the number of hidden vertices.

    File: examples/Triangulation_2/regular.cpp

    #include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
    #include <CGAL/Regular_triangulation_euclidean_traits_2.h>
    #include <CGAL/Regular_triangulation_filtered_traits_2.h>
    #include <CGAL/Regular_triangulation_2.h>

    #include <fstream>

    typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
    typedef CGAL::Regular_triangulation_filtered_traits_2<K> Traits;
    typedef CGAL::Regular_triangulation_2<Traits> Regular_triangulation;

    int main()
    {
    std::ifstream in("data/regular.cin");

    Regular_triangulation::Weighted_point wp;
    int count = 0;
    std::vector<Regular_triangulation::Weighted_point> wpoints;
    while(in >> wp){
    count++;
    wpoints.push_back(wp);
    }
    Regular_triangulation rt(wpoints.begin(), wpoints.end());
    rt.is_valid();
    std::cout << "number of inserted points : " << count << std::endl;
    std::cout << "number of vertices : " ;
    std::cout << rt.number_of_vertices() << std::endl;
    std::cout << "number of hidden vertices : " ;
    std::cout << rt.number_of_hidden_vertices() << std::endl;
    return 0;
    }