II.1. Xây dựng ERD.
Luận văn tốt nghiệp GVHH: Nguyễn Hữu Hải. TINOBJECT VERTEX TRIANGLE FILLSTYLE TIN x, y, z Color Color objID name TINATTRIBUTRE ATTRIBUTEVALUE UserData Hình 2-1. Lược đồ các thực thể cơ bản của Tin. Chú giải:
• Thực thể VERTEX: lưu trữ thông tin về đỉnh trong không gian. Ngoài các giá trị tọa độ không gian, ta còn lưu trữ màu của đỉnh.
• Thực thể TRIANGLE: lưu trữ thông tin về các tam giác. Thuộc tính kèm theo mỗi tam giác là: màu tô, màu cạnh, độ rộng cạnh và mẫu cạnh.
• Thực thể FILLSTYLE: chứa thông tin về các mẫu tô (fill pattern).
• Thực thể TIN: lưu trữ thông tin về một TIN. Thuộc tính kèm theo là tên của TIN, không gian bao phủ nhỏ nhất (Minimum Bounding Region), độ dài cạnh dài nhất nối giữa hai đỉnh trong TIN.
• Thực thể TINATTRIBUTE: thuộc tính do người dùng định nghĩa.
• Thực thể ATTRIBUTEVALUE: là các giác trị của một TINATTRIBUTE. Hai thực thể này chủ yếu dùng trong quá trình hiển thị Tin sẽđược trình bày cụ thể
hơn ở tầng Presentaion.
• Thực thể TINOBJECT: là lớp tổng quát hóa của các lớp trên. Mỗi instance của lớp này có thuộc objID là một số nguyên duy nhất, tăng dần được dùng như một
định danh đối tượng khi cần kết nối các đối tượng TIN sang các CSDL khác.
II.2. Hiện thực các lớp C++.
II.2.1. Lược đồ lớp.
Từ các thực thể của ERD, ta xây dựng lược đồ lớp dựa trên chuNn UML như sau:
+getMBR() : float* +objID : int CDBTinObject +x : float +y : float +z : float +color : int CDBTinVertex +color : int CDBTinTriangle +VertexCount() : int +TriangleCount() : int +AddVertex() : CDBTinVertex +RemoveVertex() +AddTriangle() : CDBTinTriangle +RemoveTriangle() +name : char* CDBTin PVirtual PObject -pattern : int[] CDBFillStyle +NextObjID : int CDBTinInfo +FillSylte 1 -VVList<> m_Triangles 0..* 1 -VVList<> m_Vertex 0..* -m_Triangle 0..* -m_Vertices 3 -m_Tin Hình 2-2. Lược đồ lớp. Chú giải:
- CDBTinObject: dẫn xuất từ thực thể TINOBJECT trong lược đồ ERD.
Ngoài thuộc tính objID, mỗi đối tượng CDBTinObject có phương thức
getMBR() để trả về vùng bao phủ nhỏ nhất (Minimum Bounding Region), nếu có, của mỗi đối tượng Tin.
- CDBTinVertex: dẫn xuất từ thực thể VERTEX. Mỗi đỉnh có thể thuộc vào một TIN.
- CDBTinTriangle: dẫn xuất từ thực thể TRIANGLE
- CDBTin: dẫn xuất từ thực thể TIN. Lớp CDBTin có hai bốn phương thức quan trọng AddVertex(), RemoveVertex(), AddTriangle(), RemoveTriangle()
nhằm bảo đảm tính nhất quán của dữ liệu. - CDBFillStyle: dẫn xuất từ thực thể FILLSTYLE.
Ta thấy các lớp CDBTinVertex, CDBTinTriangle, CDBTin đều kế thừa từ lớp PVirtual. Nhưđã trình bày ở trên, do các các đối tượng thuộc các lớp này so sánh bằng thông qua nội dung. của chúng. Hai đỉnh bằng nhau khi có tọa độ không gian bằng nhau. Hai tam giác bằng nhau khi các đỉnh của chúng bằng nhau từng đôi một. Hai TIN bằng nhau khi chúng có cùng tên.
Trong lược đồ lớp xuất hiện thêm lớp CDBTinInfo. Đây là một lớp đặc biệt. Nó chỉ có duy nhất một instance trong một CSDL. Instance của lớp này chứa một số thông tin giúp cho việc sinh ra giá trịobjID cho các đối tượng TIN.
II.2.2. Tính toàn vẹn dữ liệu trong CSDL của TIN.
Một yêu cầu cơ bản CSDL là tính toàn vẹn và nhất quán dữ liệu. Yêu cầu toàn vẹn và nhất quán dữ liệu được thể hiện ở mối liên kết giữa đỉnh và tam giác. Khi xóa một tam
Luận văn tốt nghiệp GVHH: Nguyễn Hữu Hải.
giác ra khỏi TIN, ta cần xóa các tham khảo đến tam giác này từ các đỉnh của nó. Và khi xóa một đỉnh, ta cần xóa tất cả các tam giác đi qua đỉnh này. Ngoài ra, trong một TIN không có hai đối tượng bằng nhau. Phép so sánh bằng giữahai đối tượng được trình bày như phần trên
Để bảo toàn tính toàn vẹn và nhất quán dữ liệu, việc thêm và xóa cách đỉnh, tam giác vào/ra khỏi TIN không thể thực hiện một cách trực tiếp mà phải thông qua hai phương thức AddVertex() và AddTriangle() của lớp CDBTin.
II.2.3. Interface của các lớp persistent.
a.CDBTinObject.
class CDBTinObject: public PVirtual {
public:
CDBTinObject(); ~CDBTinObject() {}; CDBTin* Tin();
void setTin(Link<CDBTin> tin); void setObjId(int new_id);
virtual int getObjType() const; // TIN_ROOT virtual real* get_mbr() const;
// overriden methods
virtual o_4b compare(const PVirtual& key) const; virtual o_u4b hash() const;
// static methods
static CDBTinObject* findTinObj(o_u4b objID); // getter & seter
o_u4b getObjID() { return m_objID; } // property & public fields
__declspec(property(get=getObjID)) o_u4b objID;
int tag;
int UserData; // 32-bit transient user data };
b.CDBTinVertex.
class CDBTinVertex : public CDBTinObject {
public:
CDBTinVertex(real x, real y, real z); virtual ~CDBTinVertex();
void getCoordinate(real* xyz); void setCoordinate(real* xyz) ;
CDBTinTriangle* triangles(int index) const;
int triangle_cnt() const { return RefTriangles.size(); } bool isRefTriangle(CDBTinTriangle& T);
public: // static methods
static real* UnMap(real* _xyz); static real* Map(real* xyz); static void MapReset();
static void MapRestore(void* pMap); static void* MapSave();
static bool MapEnabled();
static void MapEnable(bool enabled);
static void MapCoordinate(int* AxisOrder, real* Origin, int*
AxisDir, int abs_map=0);
static void MapAxisDirection(int dirX, int dirY,int dirZ, int abs_map=0);
static void MapOrigin(real orgX, real orgY, real orgZ, int abs_map=0);
static void MapAxisOrder(int newX, int newY, int newZ, int abs_map=0);
public: // overriden methods
virtual o_4b compare(const PVirtual& key) const; virtual int getObjType() const;
virtual real* get_mbr() const; };
c.CDBTinTriangle.
class CDBTinTriangle : public CDBTinObject {
public:
CDBTinTriangle() ; virtual ~CDBTinTriangle() ;
CDBTinVertex* vertex(int index) const; real* getNormVector();
void getNormVector(real* xyz); public: // overriden methods
virtual int getObjType() const;
virtual o_4b compare(const PVirtual& key) const; virtual real* get_mbr() const;
public: // property & public field
Link<CDBTinFillStyle> FillStyle; linestyle lineStyle[3];
};
d.CDBTin.
class CDBTin : public CDBTinObject {
public:
CDBTin(LPTSTR name); virtual ~CDBTin();
int IndexOf(CDBTinObject& obj);
CDBTinVertex* Vertices(unsigned int index); CDBTinVertex* findVertex(real x, real y, real z); CDBTinVertex* findVertex(CDBTinVertex& p);
CDBTinVertex* addVertex(real x, real y, real z); int VertexCount() const;
CDBTinTriangle* Triangles(unsigned int index);
CDBTinTriangle* findTriangle(CDBTinVertex* a, CDBTinVertex* b,
CDBTinVertex* c);
CDBTinTriangle* findTriangle(CDBTinTriangle& t);
CDBTinTriangle* addTriangle(CDBTinVertex& a, CDBTinVertex& b,
CDBTinVertex& c);
int TriangleCount() const;
void removeTriangle(CDBTinTriangle& t); void removeVertex(CDBTinVertex& p); void Empty();
void* SelectVertex(real* XRange,real* YRange,real* ZRange,int tag); void* SelectVertex(real* xyz1, real* xyz2, int tag);
void* SelectTriangle(real* xyz1, real* xyz2, int tag); void* SelectTriangle(void* vertices, int tag);
void ClearTag(int what); public: // overriden methods
virtual int getObjType() const; virtual real* get_mbr() const; public: // static methods
static CDBTin* newTin(LPTSTR name, int persistent=1); static CDBTin* findTin(LPTSTR name);
static int TinCount(); static CDBTin* Tin(int index); };
Luận văn tốt nghiệp GVHH: Nguyễn Hữu Hải.
II.3. Tạo và nạp lược đồ CSDL.
Lược đồ CSDL Versant được tạo ra bằng trình biên dịch lược đồ (schema compiler)
schcomp.exe. Đầu vào của schcomp.exe là tập tin .imp chứa các khai báo về các lớp persistent của CSDL. Sau đây là nội dung đầy đủ của tập tin TincoreSchema.imp khai báo các lớp persistent của thư viện GTIN.
#include <cxxcls/pobject.h> #include <cxxcls/vlist.h> #include <cxxcls/vset.h> #include "RootClasses.h" #include "tin.h" #include "tinvertex.h" #include "tintriangle.h" O_CAPTURE_SCHEMA(CDBTinInfo) O_CAPTURE_SCHEMA(CDBTinObject) O_CAPTURE_SCHEMA(CDBTin) O_CAPTURE_SCHEMA(CDBTinVertex) O_CAPTURE_SCHEMA(CDBTinTriangle) O_CAPTURE_SCHEMA(CDBTinFillStyle) O_CAPTURE_SCHEMA(VVList(CDBTinVertex)) O_CAPTURE_SCHEMA(VVList(CDBTinTriangle)) O_CAPTURE_SCHEMA(VVList(CDBTinObject)) O_CAPTURE_SCHEMA(VVSet(CDBTinTriangle)) O_CAPTURE_SCHEMA(VVSet(CDBTinVertex)) O_CAPTURE_SCHEMA(VVSet(CDBTinObject)) O_TRANSIENT(CDBTinObject, "objID","UserData") O_TRANSIENT(CDBTinVertex,"x","y","z","Color","mapX","mapY","mapZ") O_TRANSIENT(CDBTinTriangle,"FillColor") O_TRANSIENT(CDBTinFillStyle,"Style","Name","m_Active","Active","IsDefault Style") O_TRANSIENT(CDBTin,"BottomLeft","TopRight","Name","MaxEdgeLen","DefaultFi llStyle") O_TRANSIENT(CDBTinInfo,"DefaultFillStyle","NextObjID","ActiveStyle") III. HỆ TỌA ĐỘ ÁNH XẠ. III.1. Tại sao có hệ tọa độ ánh xạ?
Trong một số bài toán, để giải thuật trở nên đơn giản, trong sáng hơn, ta cần dùng đến hệ tọa độ ánh xạ. Các giá trị tọa độ không gian của các đối tượng TIN là giá trịđo đạc từ thế giới thực. Các giá trị này thông qua qua một số phép ánh xạ sẽ trở thành giá trị
tọa độ của đối tượng đó trong một hệ tọa độ khác, đó là hệ tọa độ ánh xạ. Như vậy phép ánh xạởđây thực chất là các phép biến đổi hệ trục tọa độ. Để dảm bảo tính hiệu quả của chương trình, lớp DML chỉ cung cấp các phép biến đổi đơn giản cho phép người dùng tịnh tiến hệ trục và thực hiện các phép xoay trục theo những góc 900. Một ví dụ dùng hệ tọa độ ánh xạ sẽ được trình bày ở phần giải thuật: “giao TIN với mặt phẳng”.
III.2. Các phép ánh xạ.
DML hỗ trợ ba phép ánh xạ cơ bản: thay đổi vị trí trục, đảo hướng trục và tịnh tiến gốc tọa độ. Các phép ánh xạ này lưu trữ trong cấu trúc MAPSTATUS.
typedef struct {
int AxisOrder[3]; real Origin[3]; int AxisDir[3]; } MAPSTATUS, *PMAPSTATUS;
Các phép ánh xạ là hai chiều và có mang tính tương đối. Ánh xạ thuận chuyển tọa độ
thế giới thực sang tọa độ ánh xạ; ánh xạ nghịch chuyển tọa độ ánh xạ sang tọa độ thế
giới thực. Phép ánh xạ tương đối tác động lên bảng ánh xạ dựa vào hệ trục tọa độ hiện tại. Phép ánh xạ tuyệt đối tác động lên bảng ánh xạ theo hệ trục chuNn ban đầu.
Objects/ Search Query Mapping is enabled. Mapping is disabled. World coordinate World coordinate Mapped coordinate
APPLICATION coordinateObject
Hình 2-3. Sơđồ Mapped Coordinate System.
III.2.1.Các phép ánh xạ.
a.Thay đổi trật tự trục tọa độ.
Phép thay đổi trục tọa độ cho phép giả lập việc xoay các trục tọa độ.
Ví dụ: đối với hệ tọa độ thế giới thực, trục z hướng lên, trục y nằm hướng ngang sang phải và x hướng ra. Trong khi hệ tọa độ dùng trong OpenGL là: trục y hướng lện, x ngang sang phải và z hướng ra. Như vậy ta thấy, để vẽ một đối tượng từ thế giới thực bằng OpenGL ta phải hoán đổi vị trí các trục như sau: xw Æ zv, yw Æ xv, zw Æ zv. Phép đổi trật tự trục tọa độ tác động đến trường AxisOrder của cấu trúc MAPSTATUS. Các trục tọa độđược mã hóa như sau: 0 – x, 1 – y, 2 – z.
Phép ánh xạ thuận tác động lên trường AxisOrder của bảng ánh xạ như sau:
OldOrder = AxisOrder;
AxisOrder[OldOrder[X_AXIS]]=newX; AxisOrder[OldOrder[Y_AXIS]]=newY; AxisOrder[OldOrder[Z_AXIS]]=newZ;
b.Tịnh tiến hệ trục tọa độ.
Phép tịnh tiến hệ trục tọa dộ tác động đến trường Origin theo công thức sau:
Origin[X_AXIS]+=orgX; Origin[Y_AXIS]+=orgY; Origin[Z_AXIS]+=orgZ;
c. Đảo trục tọa dộ.
Đảo trục tọa độ giống như xoay trục tọa độ một góc 1800. Phép ánh xạ này tác động lên trường AxisDir như sau:
AxisDir[X_AXIS]*=dirX; AxisDir[Y_AXIS]*=dirY; AxisDir[Y_AXIS]*=dirZ;
III.2.2.Công thức đổi tọa độ thực sang tọa độ ánh xạ và ngược lại.
Từ thông tin trong bảng ánh xạ, ta có thể chuyển tọa độ thế giới thực sang tọa độ ánh xạ thuận theo phương trình sau:
xmap = (xyz[AxisOrder[X_AXIS]]-Origin[X_AXIS])*AxisDir[X_AXIS]; ymap = (xyz[AxisOrder[Y_AXIS]]-Origin[Y_AXIS])*AxisDir[Y_AXIS]; zmap = (xyz[AxisOrder[Z_AXIS]]-Origin[Z_AXIS])*AxisDir[Z_AXIS];
Luận văn tốt nghiệp GVHH: Nguyễn Hữu Hải.
Để thực hiện phép ánh xạ ngược, ta dùng công thức sau:
xyz[AxisOrder[X_AXIS]]=xmap*AxisDir[X_AXIS]+Origin[X_AXIS]; xyz[AxisOrder[Y_AXIS]]=ymap*AxisDir[Y_AXIS]+Origin[Y_AXIS]; xyz[AxisOrder[Z_AXIS]]=zmap*AxisDir[Z_AXIS]+Origin[Z_AXIS];
III.3. Sử dụng các phép ánh xạ.
Các phép ánh xạ trên được hiện thực ở tầng DML. Khi người dùng cho bật chếđộ ánh xạ thì tất cả những tọa độ không gian truy cập từ các đối tượng TIN trả vềđều đã được thông qua phép ánh xạ thuận. Và khi thay đổi tọa độ ánh xạ, thì giá trị này sẽ thông qua phép ánh xạ nghịch chuyển thành tọa độ thực rồi mới được gán vào CSDL. Các câu lệnh truy vấn cũng hỗ trợ phép ánh xạ này.
Người dùng sử dụng hệ tọa độ ánh xạ thông qua nhóm hàm API về ánh xạ tọa độ. Ta sẽđề cập đến các hàm API này ở phần sau. Sau đây là đoạn khung mã để sử dụng hệ
tọa độ ánh xạ.
void* pMap = tinMapSave(); // lưu lại tình trạng ánh xạ. tinMapEnable(true); // bật hệ tọa độ ánh xạ.
tinMapXXXX(…); // các hàm thực hiện 3 phép ánh xạ. /* các thao tác trên các đối tượng không gian */
tinMapRestore(pMap); // phục hồi lại tình trạng ánh xạ trước đó.
IV. TRUY VẤN CÁC ĐỐI TƯỢNG KHÔNG GIAN.
IV.1. Các loại câu truy vấn thường dùng trong dữ liệu không gian.
Đối với dữ liệu không gian nói chung, TIN nói riêng, ta thường thực hiện hai loại truy vấn phỗ biến : truy vấn theo vùng – region query, và truy vấn các đối tượng lân cận – neighbour query.
• Truy vấn theo vùng trả về các đối tượng không gian có vùng bao nhỏ nhất giao với vùng do người dùng đưa vào.
• Truy vấn lân cận trả về các đối tượng lân cận với một đối tượng xác định một khoảng cách cho trước.
Việc truy vấn dữ liệu là một chức năng cơ bản của một DBMS, do đó, ta hãy xem xét cách thức thực hiện truy vấn của Versant và mức độ hỗ trợ của nó đối với các yêu cầu truy vấn trên dữ liệu không gian.
IV.2. Truy vấn trong Versant.
Do cơ sở lý thuyết của truy vấn trên ODB là còn khá mới so với RDB, nên các câu truy vấn được hỗ trợ bởi Versant là còn hạn chế. Chỉ những câu truy vấn tìm kiếm – Search query – là được hỗ trợ trực tiếp từ DBMS.
a.Search query.
Truy vấn tìm kiếm, search query, là xem xét một nhóm đối tượng và trả về những đối tượng thỏa điều kiện dò tìm.
Trong Versant, điều kiện dò tìm được gọi là perdicate, mỗi predicate là kết hợp bởi một hay nhiều predicate term. Mỗi predicate term bao gồm ba thành phần: thuộc tính cần kiểm tra, phép toán so sánh và giá trị khóa. Các predicate term kết hợp với các phép logic toán and, or, not tạo thành predicate.
Predicate ::= PredicateTerm [ AND|OR PredicateTerm ]*
PerdicateTerm ::=[NOT] AttributeName COMPARISION_OPERATOR KeyValue
Trong đó:
• AttributeName: tên thuộc tính cần so sánh của đối tượng. Tên thuộc tính phải
được đặt theo đúng quy cách. Thuộc tính phải thuộc một trong các kiểu sau: kiểu vô hướng; kiểu mảng tĩnh các phần tử 1 byte; Vstr của kiểu 1 bytes; các
Link, LinkVstr và mảng các Link; chuỗi kiểu PString hoặc VString; các kiểu lưu trữ thời gian: VDate, VTime, o_date, o_time, o_timestamp, o_interval.
• COMPARISION_OPERATOR: là các phép toán so sánh. Có 4 loại phép toán so sánh: quan hệ (=,>=,…), so sánh chuỗi (O_MATCH, O_NOT_MATCH), kiểm tra đối tượng có thuộc lớp hay không (O_ISA_EXACT, O_NOT_ISA_ EXACT) và các phép toán tập hợp.
• KeyValue: là giá trị cho trước dùng để so sánh với thuộc tính của các đối tượng.
Như vậy, ta có thể hiện thực câu truy vấn theo vùng bằng predicate như sau:
(xmin<= x)and(x <= xmax)and(ymin<= y)and(y <= ymax)and(zmin<= z)and(z <= zmax). Do hạn chế của mệnh đề truy vấn chỉ lượng giá giá trị thuộc tính với một giá trị khác, nên ta không thể thiết lập biểu thức truy vấn lân cận theo cơ chế trên. Vì vậy, để có thể
truy vấn các đối tượng lân cận một đối tượng, ta phải viết giải thuật hiện thực ở cấp chương trình.
b.Chỉ mục cho Search query.
Việc truy tìm các đối tượng thỏa mệnh đề truy vấn theo vùng sẽ trở nên rất nặng nề do, DBMS phải tiến hành lượng giá sáu mệnh đề logic, sau đó phải giao các kết quả trung gian với nhau mới đưa ra được kết quả cuối cùng. Do đó, để tăng hiệu suất tìm kiếm ta phải giảm bớt số lượng đối tượng lượng giá mà không ảnh hưởng đến kết quả. Để làm
được điều này, Versant cung cấp khả năng tạo chỉ mục trên các thuộc tính.
Chỉ mục chỉ áp dụng trên một thuộc tính đơn của một lớp và ảnh hưởng đến tất cả các
đối tượng của lớp này. Nó là một danh sách của các cặp gồm giá trị khóa và định danh của đối tượng. Chỉ mục không có tên và được quản lý tựđộng, nó có thể là duy nhất hoặc không duy nhất. Tuy nhiên, một chỉ mục chỉ có tác dụng đến một lớp duy nhất, nó không có tính kế thừa. Vì vậy, để chỉ mục cho một thuộc tính của lớp cha có tác dụng trên các lớp con, ta phải thiết lập chỉ mục tường minh cho các lớp con này. Mỗi thuộc tính có thể có hai loại chỉ mục: chỉ mục B-Tree và chỉ mục bảng băm – hash table. Tùy vào các câu truy vấn dựđịnh trên thuộc tính đế có thểđặt các loại chỉ
mục phù hợp.
• Chỉ mục B-Tree: thường phù hợp cho các câu query theo đoạn. Như vậy, trong câu truy vấn theo vùng, các thuộc tính tọa độ của đối tượng nên được đặt chỉ
mục B-Tree.
• Chỉ mục bảng băm: thường phù hợp với phép so sách trùng các chuỗi.
c.Chỉ mục cho dữ liệu đa chiều.
Ta thấy, đối với các đối tượng không gian dựa vào cơ chế truy vấn của Versant chỉ
giải quyết được một phần nhỏ các yêu cầu truy vấn do cơ chế chỉ mục của Versant là chỉ mục của thuộc tính đơn. Vì vậy, ta cần xây dựng một cấu trúc chỉ mục khác phù