July 5, 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

2 comments:

  1. tại sao mình đã chọn đường bao là polyline rồi mà vẫn xuất hiện lỗi eInvalidInput ở dòng hatchLoop là thế nào hả bạn?

    ReplyDelete
  2. Bạn post cả code lên để mình xem

    ReplyDelete

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