Uploaded by SPRV

Duong cong bspline

advertisement
TRƯỜNG ĐẠI HỌC BÁCH KHOA
KHOA CÔNG NGHỆ THÔNG TIN
ĐỒ ÁN LẬP TRÌNH TÍNH TOÁN
Xây dựng và biểu diễn đường cong B-spline
Người hướng dẫn : NGUYỄN TẤN KHÔI
Sinh viên thực hiện :
Trương Tấn Sang
Lớp 21T_DT2 Nhóm: Nh10
Lương Công Thịnh
Lớp 21T_DT2 Nhóm: Nh10
Đà Nẵng 27/05
MỤC LỤC
MỤC LỤC
1
DANH MỤC HÌNH VẼ
2
MỞ ĐẦU
3
1.TỔNG QUAN ĐỀ TÀI
4
2.CƠ SỞ LÝ THUYẾT
4
2.1.Ý tưởng
4
2.2.Cơ sở lý thuyết
4
3.TỔ CHỨC CẤU TRÚC DỮ LIỆU VÀ THUẬT TOÁN
9
3.1.Phát biểu bài toán
9
3.2.Cấu trúc dữ liệu
9
3.3.Thuật toán
9
3.3.1Thuật toán sử dụng phương trình
4.CHƯƠNG TRÌNH VÀ KẾT QUẢ
10
11
4.1.Tổ chức chương trình
11
4.2.Ngôn ngữ cài đặt
12
4.3.Kết quả
12
4.3.1.Giao diện chính của chương trình
12
4.3.2.Kết quả thực thi chương trình
14
4.3.3.Nhận xét, đánh giá
18
5.KẾT LUẬN VÀ HƯỚNG PHÁT TRIỂN
19
5.1.Kết luận
19
5.2.Hướng phát triển
19
6.Tài liệu tham khảo
19
Phụ lục
20
1
MỞ ĐẦU
Đường cong, hầu như có thể luôn luôn tìm được một đường cong rõ ràng ở khắp mọi
nơi, việc nghiên cứu cách biến đổi đường cong đó bằng cách thay đổi việc biểu diễn nó
theo tham số đi kèm biến nó trở thành đường cong tham số, hỗ trợ giúp đỡ trong các vấn
đề thiết kế đồ họa và kĩ thuật một cách triệt để. Đường cong tham số được biểu diễn thông
qua tham số, việc thay đổi tham số sẽ làm biến đổi đường cong theo từng mục đích của
người sử dụng, một trong số các kiểu đường cong là đường cong tham số bezier và đường
cong B-spline.
Đường cong tham số Bézier, được triển khai lần đầu tiên bởi Paul de Casteljau, sử dụng
thuật toán Casteljau để đánh giá đường cong, và chính thức trở nên nổi tiếng vào năm 1962
bởi kỹ sư Pierre Bézier cho mục đích thiết kế ô tô. Đường cong tham số Bézier được sử
dụng trong đồ họa máy tính và một số lĩnh vực khác. Tuy nhiên đường cong Bézier không
mang tính cục bộ. Ta có thể hiệu chỉnh các đỉnh điều khiển của đường cong Bézier để tạo
ra loại đường cong mong muốn. Tuy nhiên, khi thay đổi bất kỳ đỉnh điều khiển nào cũng
sẽ gây ra sự thay đổi trên toàn bộ đường cong.
Đường cong B-spline, tổng quát hơn và được xem là dạng tổng quát cùa đường cong
Bézier, mang nhiều điểm tương đồng với đường cong Bézier nhưng có nhiều đặc tính mong
muốn hơn. Số lượng thông tin mà đường cong B-spline yêu cầu nhiều hơn so với đường
cong bézier. Đường cong B-spline luôn có thể trở thành đường cong bezier bất cứ khi nào,
và cung cấp khả năng kiểm soát linh hoạt hơn nhờ vào đặc tính yêu cầu nhiều thông tin của
nó. Khác với đường cong bezier, việc tha đổi một đỉnh điều khiển sẽ dẫn đến sự thay đổi
trong toàn bộ được cong, việc thay đổi một đỉnh điều khiển trong đường cong B-spline
không yêu cầu việc thay đổi ở toàn bộ đường cong. Từ những thuộc tính đó, về thực tế, khi
muốn biểu diễn những đường cong và mặt cong tham số phức tạp, người ta sử dụng đường
cong B-spline. Việc tìm hiểu và nắm bắt được cách thức biến và biểu diễn đường cong Bspline dựa trên tham số sẽ là nội dung chính của đề tài này. Đề tài được thực hiện và kiểm
chứng kết quả dựa trên việc bổ sung các cơ sở lí thuyết, các ví dụ, bộ số mẫu và tham chiếu
với kết quả chuẩn từ các nguồn ngoài, kết hợp với nhận xét, đánh giá từ giảng viên hỗ trợ
hướng dẫn để đề tài được triển khai theo hướng đúng nhất và hiệu quả nhất.
2
1. TỔNG QUAN ĐỀ TÀI
Nghiên cứu tính chất, đặc điểm của đường cong tham số B-spline. Mối liên hệ giữa
các khái niệm, tính chất với nhau và triển khai, xây dựng công thức của đường cong Bspline phụ thuộc vào tham số. Triển khai bằng tay ví dụ, tham chiếu kết quả từ nguồn bên
ngoài được hỗ trợ. Thiết kế bộ số mẫu, tính toán kết quả dựa trên công thức được xây dựng
từ trước và đối chiếu với các nguồn ngoài để kiểm chứng độ chính xác và chỉnh sửa các
yếu tố liên quan khi xảy ra sai sót. Tham chiếu ví dụ, công thức, phương thức hoạt động
và cách làm từ các nguồn được hỗ trợ. Viết chương trình cho đầu vào là các bộ số mẫu và
đầu ra là kết quả từ tham số với công thức xây dựng, lưu trữ và đối chiếu với kết quả thực,
hiệu chỉnh chương trình, tăng hiệu suất và thử với nhiều bộ số khác nhau. Viết chương
trình vẽ hình từ kết quả từ mỗi sự thay đổi với tham số truyền vào.
2.CƠ SỞ LÝ THUYẾT
2.1.Ý tưởng
Tìm hiểu và nắm bắt các khái niệm liên quan đến đường cong tham số B-spline,
những khái niệm sẽ hỗ trợ và giúp đỡ cho các thao tác cơ bản trong việc nghiên cứu và
triển khai đường cong tham số B-spline, tìm hiểu và triển khai ra các mối liên hệ cố hữu
của những thuộc tính của đường cong tham số B-spline. Mối liên hệ cũng như sự phụ thuộc
lẫn nhau của các thuộc tính, ảnh hưởng đến hình dạng, tính chất và đặc điểm hình ảnh, số
liệu thực tế của đường cong.
2.2.Cơ sở lý thuyết
-
Các khái niệm
+ Bậc của đường cong B-spline
+ Các đỉnh điều khiển
+ Vector nút
Các loại vector nút :
+ Vector nút đồng nhất (uniform) : các vector nút liền kề cách nhau một khoảng là
hằng số. VD : [0,1,2,3,4,5,6,7,8]
-
+ Vector nút open uniform : {𝑡𝑖 = 𝑡1 , 𝑖 ≤ 𝑑 − 1 𝑡𝑖+1 − 𝑡𝑖 = 𝑐𝑜𝑛𝑠𝑡, 𝑑 − 1 ≤ 𝑖 ≤
𝑛 − 1 𝑡𝑖 = 𝑡𝑑+𝑛+1 , 𝑖 ≥ 𝑛 − 1
VD : [0,0,0,0,1,2,3,4,4,4,4]
(d = 3)
3
+ Vector nút không đồng nhất : vector nút sau không bé hơn vector nút trước
VD : [0,0,1,1.5,2,3,4,9]
-
Lý thuyết đường cong B-spline
+ Gọi bậc của đường cong là d (d ≥ 1)
+ Đường cong có n+1 đỉnh điều khiển P0 ,P1,...Pn (n+1 ≥d)
+ Đường cong có d+n+2 nút điều khiển { t0, t1, t2, ...,tn+d+1 }
+ Khi đó ta có phương trình cơ bản của đường cong B-spline:
𝑛
𝑃 (𝑡 ) = ∑
𝑁𝑖,𝑑 (𝑡 ). 𝑃𝑖 (𝑡𝑚𝑖𝑛 ≤ 𝑡 < 𝑡𝑚𝑎𝑥 )
𝑖=0
▪ Trong đó :
⮚ 𝑁𝑗,0 (𝑡) = {1 (𝑡𝑗 ≤ 𝑡 < 𝑡𝑗+1 ) 𝑛𝑔ượ𝑐 𝑙ạ𝑖 𝑏ằ𝑛𝑔 0 }
⮚ 𝑁𝑗,𝑘 (𝑡 ) =
𝑡−𝑡𝑗
𝑡𝑗+𝑘 −𝑡𝑗
𝑁𝑗,𝑘−1 (𝑡) +
𝑡𝑗+𝑘+1 −𝑡
𝑡𝑗+𝑘+1 −𝑡𝑗+1
𝑁𝑗+1,𝑘−1 (𝑡)
⮚ 𝑡𝑚𝑖𝑛 = 𝑡𝑑 , 𝑡𝑚𝑎𝑥 = 𝑡𝑛+1
▪ Với ti ≤ t ≤ ti+1 , xét Nj,k :
⮚ Nếu j ≥ i+1 thì Nj,k = 0
⮚ Nếu j+k < i thì Nj,k = 0
⮚ Vậy với [𝑗 ≥ 𝑖 + 1 𝑗 ≤ 𝑖 − 𝑘 − 1 thì Nj,k = 0
▪ Để tính P(t) với ti ≤ t < ti+1 , ta tính các giá trị từ Ni-d,d(t) cho đến Ni,d(t), khi
đó giá trị của P(t) sẽ là :
𝑖
∑
𝑁𝑗,𝑑 (𝑡 ). 𝑃𝑗
𝑗=𝑖−𝑑
Ví dụ minh họa :
Ví dụ 1 :
Cho B-spline bậc k = 3 có n+1 = 4 đỉnh điều khiển : 𝑃0 (10,0,0); 𝑃1 (20,30,0), 𝑃2 (50,40,0), 𝑃3 (80,0,0)
Các vector nút : U = 𝑢0 = 1, 𝑢1 = 2, 𝑢2 = 3, 𝑢3 = 4, 𝑢4 = 5, 𝑢5 = 6, 𝑢6 = 7, 𝑢7 = 8
Chọn u = 4.5 → 𝑢3 ≤ 𝑢 < 𝑢4
P(u) = 𝑁0,3 𝑃0 + 𝑁1,3 𝑃1 + 𝑁2,3 𝑃2 + 𝑁3,3 𝑃3
4
𝑁2,1 = 0 +
𝑁3,1 =
𝑁1,2 =
𝑁2,2 =
𝑁3,2 =
𝑁0,3 =
𝑁1,3 =
𝑁2,3 =
𝑁3,3 =
Vậy
𝑢4 −𝑢
𝑢4 −𝑢3
𝑢−𝑢3
𝑢4 −𝑢3
𝑢−𝑢1
𝑢3 −𝑢1
𝑢−𝑢2
𝑢4 −𝑢2
𝑢−𝑢3
𝑢5 −𝑢3
𝑢−𝑢0
𝑢3 −𝑢0
𝑢−𝑢1
𝑢4 −𝑢1
𝑢−𝑢2
𝑢5 −𝑢2
𝑢−𝑢3
𝑢6 −𝑢3
. 𝑁3,0 =
0.5
. 𝑁3,0 + 0 =
. 𝑁1,1 +
. 𝑁2,1 +
. 𝑁3,1 +
. 𝑁0,2 +
. 𝑁1,2 +
. 𝑁2,2 +
. 𝑁3,2 +
1
0.5
𝑢4 −𝑢
𝑢4 −𝑢2
𝑢5 −𝑢
𝑢5 −𝑢3
𝑢6 −𝑢
𝑢6 −𝑢4
𝑢4 −𝑢
𝑢4 −𝑢1
𝑢5 −𝑢
𝑢5 −𝑢1
𝑢6 −𝑢
𝑢6 −𝑢2
𝑢7 −𝑢
𝑢7 −𝑢3
1
=
=
1
2
1
2
0.5 1
. 𝑁2,1 = 0 +
. 𝑁3,1 =
. 𝑁4,1 =
2
. 𝑁3,2 =
. 𝑁4,2 =
2
1.5 1
2
. +
2
2
2
2
2
0.5 1
. =
2.5 1
3
. +
8
1.5 3
3
. +
4
0.5 1
3
8
3
3
4
1
8
1
48
1.5 3
. =
23
4
48
2.5 1
23
3
. =
8
. +0=
8
8
. =
. +0=
3
1
1.5 1
0.5 1
. 𝑁1,2 = 0 +
. 𝑁2,2 =
. =
48
1
48
𝑃(4.5) = 𝑁0,3 𝑃0 + 𝑁1,3 𝑃1 + 𝑁2,3 𝑃2 + 𝑁3,3 𝑃3
1
23
23
1
= 48 𝑃0 + 48 𝑃1 + 48 𝑃2 + 48 𝑃3 = (35.417, 33.542, 0)
Ví dụ 2 :
5
6
3.TỔ CHỨC CẤU TRÚC DỮ LIỆU VÀ THUẬT TOÁN
3.1.Phát biểu bài toán
Để thực hiện tính toán, cần dữ liệu của đường cong B-spline gồm :
-
Bậc của đường cong (gọi là d, với d ≥ 1)
Các đỉnh điều khiển : P0 ,P1,...Pn (n+1 ≥d)
-
Các nút điều khiển : t0, t1, t2, ...,tn+d+1
-
Một điểm trên đường cong B-spline (gọi là u, với u ∈ [td , tn ]
Với bộ dữ liệu đầu vào ( input ) trên, kết quả nhận được sau quá trình tính toán (
output ) là tọa độ của điểm với tham số được truyền vào ban đầu
𝑛
𝑃 (𝑡 ) = ∑
𝑁𝑖,𝑑 (𝑡 ). 𝑃𝑖 (𝑡𝑚𝑖𝑛 ≤ 𝑡 < 𝑡𝑚𝑎𝑥 )
𝑖=0
3.2.Cấu trúc dữ liệu
Chủ yếu sử dụng mảng động để lưu trữ và xử lý dữ liệu
3.3.Thuật toán
- Để tính các giá trị từ Ni-d,d(t) cho đến Ni,d(t), ta cần tính các giá trị từ Ni-d+1,d-1(t)
cho đến Ni,d-1(t). Tương tự, để tính các giá trị từ Ni-d+1,d-1(t) cho đến Ni,d-1(t), ta cần tính
được các giá trị từ từ Ni-d+2,d-2(t) cho đến Ni,d-2(t) và tiếp tục.
- Sơ đồ dưới đây giải thích cho phương pháp đã nêu, trong đó : ↓ đại diện cho biểu
thức
𝑡𝑗+𝑘+1 −𝑡
𝑡𝑗+𝑘+1 −𝑡𝑗+1
𝑁𝑗+1,𝑘−1 (𝑡) và ↙ đại diện cho biểu thức
𝑡−𝑡𝑗
𝑡𝑗+𝑘 −𝑡𝑗
𝑁𝑗,𝑘−1 (𝑡 )
7
- Thuật toán trên tính được các giá trị từ Ni-d,d(t) cho đến Ni,d(t). Bên cạnh đó, ta đã
có công thức : 𝑃(𝑡 ) = ∑𝑛𝑖=0 𝑁𝑖,𝑑 (𝑡 ). 𝑃𝑖 (𝑡𝑚𝑖𝑛 ≤ 𝑡 < 𝑡𝑚𝑎𝑥 ). Từ đó dễ dàng tính được kết
quả của P(t).
3.3.1Thuật toán sử dụng phương trình
- Để tính các giá trị từ Ni-d,d(t) cho đến Ni,d(t), ta sử dụng thuật toán quy hoạch động
để xây dựng mảng từ dưới lên, nghĩa là tính các giá trị bắt đầu từ Nj,0 ; Nj,1 ; ... Nj,k ; ... Nj,d1
; Nj,d ( 𝑗 ∈ [𝑖 − 𝑑, 𝑖] ). Với mỗi giá trị Nj,k , ta có thể tính được nhờ giá trị của Nj-1,k-1 và
Nj,k-1 đã tính được trước đó. Với cách làm này, ta cho giá trị của Ni,0 là 1
- Với k = 0, số bước tính là 1, với k = 1, số bước tính là 2. Vậy nên, với một giá trị
k, ta có k+1 bước tính.
- Do đó, để xây dựng mảng theo thứ tự từ dưới lên, ta có tổng cộng 1 + 2 + 3 + ... +
d + (d+1) =
(𝑑+1).(𝑑+2)
2
phép tính. Vậy độ phức tạp của thuật toán gần với O(d2).
- Để lưu các kết quả tính được, có thể tạo các mảng có độ dài lần lượt là 1,2,...,d+1.
Khi đó thuật toán sẽ tốn bộ nhớ O(d2).
- Một cách làm khác là tạo ra 2 mảng, mảng thứ nhất dùng để chứa các giá trị ở bậc
thấp hơn Nj,k-1, mảng thứ hai dùng để chứa các giá trị ở bậc Nj,k đang xét. Do đó có thể tính
được các giá trị ở mảng thứ hai nhờ giá trị ở mảng thứ nhất. Sau khi đã tính xong hết các
giá trị ở bậc k, ta gán các phần tử ở mảng thứ hai vào mảng thứ nhất, sau đó tiếp tục tính
toán ở bậc k+1. Cách làm này chỉ tốn bộ nhớ O(d)
8
4.CHƯƠNG TRÌNH VÀ KẾT QUẢ
4.1.Tổ chức chương trình
Chia chương trình thành các modules nhỏ, mang các chức năng, nhiệm vụ riêng biệt.
Các modules lần lượt chịu trách nhiệm cho: khai báo, định nghĩa và xây dựng công thức
cùng các tính chất liên quan đến đường cong tham số B-spline; khai triển và thực hiện việc
xây dựng ma trận tương xứng; nạp chồng các toán tử tính toán có sẵn cho mục đích sử
dụng với cấu trúc dữ liệu, các thư viện bên thứ ba; xây dựng, định nghĩa tính chất một điểm
với các thuộc tính về tọa độ trong không gian ba chiều. Trong đó:
- Module mang các chức năng liên quan đến định nghĩa và mô tả đường cong Bspline chứa class B-spline có các thuộc tính gồm độ của đường cong, vector nút, vector các
điểm làm đỉnh điều khiển và một số vector, các đối tượng phục vụ trong việc tính toán với
giải thuật De Boor. Class B-spline có các hàm thành phần gồm có các chức năng: lấy số
liệu về độ của đường cong, vector nút, vector các tọa độ các điểm làm đỉnh điều khiển từ
input. Hàm getMinAgentIndex dùng để lấy chỉ số của vector nút sao cho mọi tham số đầu
vào đều không được bé hơn vector nút đấy. Hàm getMaxAgentIndex dùng để lấy chỉ số
của vector nút sao cho mọi tham số đầu vào đều bé hơn vector nút đấy.
- Module mang chức năng tạo lập ma trận và các hàm thực hiện những việc liên quan
đến ma trận gồm có class Matrix với thuộc tính hàng, cột và vector dữ liệu ma trận. Có các
hàm thành phần lấy dữ liệu về hàng ,cột từ ma trận được tạo lập.
- Module nạp chồng toán tử, chức năng chính gồm có nạp chồng các toán tử toán
học có sẵn cho việc tính toán trực tiếp lên các đối tượng được tạo từ các kiểu dữ liệu tự
định nghĩa, các đối tượng từ các thư viện bên thứ 3 lẫn nạp chồng các toán tử nhập xuất
trực tiếp cho đối tượng mà không thông qua các thao tác từng phần.
- Module định nghĩa và mô tả một điểm trong không gian ba chiều, gồm các thuộc
tính về tọa độ và các hàm thành phần phục vụ lấy dữ liệu tọa độ từ đối tượng được tạo ra
- Module định nghĩa và mô tả tham số của đa thức bậc n. Có chức năng liên quan
đến việc tính toán giữa các đa thức với nhau và tính giá trị của đa thức theo tham số đầu
vào
Mỗi module được chia thành các file riêng cùng tên khác định dạng file gồm hai định
dạng là /.h/ và /.cpp/. Các file có định dạng /.h/ chứa các tiền khai báo cho thuộc tính và
hàm thành viên của kiểu dữ liệu tự tạo cùng với các lời tiền khai báo hàm liên quan và
được khai báo ngược lại ở đầu những file có sử dụng đến. Các file có định dạng /.cpp/ chứa
các đoạn mã thực thi, được liên kết với chính file cùng tên có định dạng /.h/ để đảm bảo độ
9
chính xác về tên định danh, các đoạn mã thực thi này là nội dung của các lời tiền khai báo
nằm ở file định dạng /.h/.
Sử dụng thư viện bên thứ 3 ( OPENGL và GLUT để thao tác với thư viện OPENGL)
để thực hiện các tác vụ vẽ hình và biểu diễn trong không gian ba chiều khi nhìn từ các góc
khác nhau thông qua thao tác xoay không gian tưởng tượng. Có chức năng kiểm tra kết quả
của việc tính toán đường cong B-spline một cách trực quan, sinh động.
4.2.Ngôn ngữ cài đặt
Sử dụng ngôn ngữ c++
4.3.Kết quả
4.3.1.Giao diện chính của chương trình
Giao diện console
Giao diện console, gồm các chức năng yêu cầu người dùng nhập vào các thuộc tính
của đường cong B-spline: bậc của đường cong, số đỉnh và tọa độ của mỗi đỉnh, vector nút
điều khiển, vector nút phụ thuộc vào tính chất không đồng nhất của đường cong B-spline
để phục vụ quá trình tính toán.
10
Giao diện đồ họa
Giao diện đồ họa, được vẽ bằng OPENGL, chứa đường cong B-spline được xây dựng
với các thuộc tính được người dùng cung cấp. Giao diện đồ họa cho phép người dùng thao
tác xoay để nhìn đường cong B-spline trong không gian ba chiều
4.3.2.Kết quả thực thi chương trình
- Test 1, input gồm:
+ Bậc của đường cong B-spline: 3
+ Bốn đỉnh điều khiển, lần lượt có các tọa độ:
P1( -4; -4; 0 ), P2( -2; 4; 0 ), P3( 2; -4; 0), P4( 4; 4; 0 )
+ Vector nút: V( 0.0; 0.0; 0.0; 0.0; 1.0; 1.0; 1.0; 1.0 )
Với các tham số u chạy từ 0 đến 1, có các tọa độ điểm tương ứng, được tính
toán từ phương trình đường cong tham số B-spline. Một số tọa độ mẫu đã được tính toán,
thành output của bài toán như:
p(0.0) = ( -4.00; -4.00; 0 )
p(0.1) = ( -3.34; -2.05; 0 )
p(0.2) = ( -2.59; -0.86; 0 )
p(0.3) = ( -1.77; -2.06; 0 )
p(0.4) = ( -0.90; -0.03; 0 )
p(0.5) = ( 0; 0; 0 )
p(0.6) = ( 0.90; 0.03; 0 )
p(0.7) = ( 1.77; 0.26; 0 )
11
p(0.8) = ( 2.59; 0.86; 0 )
p(0.9) = ( 3.34; 2.05; 0 )
- Test 2, input gồm:
+ Bậc của đường cong B-spline: 2
+ Bốn đỉnh điều khiển, lần lượt có các tọa độ:
P1( 0; -4; 0 ), P2( -5; 1; 0 ), P3( -2.5; 3.6; 0), P4( 0; 1.6; 0 ), P5( 2.5; 3.6; 0 ),
P5( 5; 1; 0 ), P6( 0; -4; 0 )
12
+ Vector nút: V( 0.0; 0.0; 0.0; 0.33; 0.44; 0.56; 0.67; 1.0; 1.0; 1.0 )
- Với các tham số u chạy từ 0 đến 1, có các tọa độ điểm tương ứng, được
tính toán từ phương trình đường cong tham số B-spline. Một số tọa độ mẫu đã
được tính toán, thành output của bài toán như sau:
p(0.00) = ( 0; -4; 0 )
p(0.65) = ( 2.92; 3.11; 0 )
p(0.05) = ( -1.35; -2.57; 0 )
p(0.70) = ( 3.43; 2.53; 0 )
p(0.10) = ( -2.38; -1.27; 0 )
p(0.75) = ( 3.63; 1.79; 0 )
p(0.15) = ( -3.11; -0.11; 0 )
p(0.80) = ( 3.53; 0.91; 0)
p(0.20) = ( -3.53; 0.91; 0 )
p(0.85) = ( 3.11; -0.11; 0 )
p(0.25) = ( -3.63; 1.79; 0 )
p(0.90) = ( 2.38; -1.27; 0)
p(0.30) = ( -3.43; 2.53; 0 )
p(0.95) = ( 1.35; -2.57; 0 )
p(0.35) = ( -2.92; 3.11; 0 )
p(0.40) = ( -2.14; 3.14; 0 )
p(0.45) = ( -1.12; 2.50; 0 )
p(0.50) = ( 0; 2.10; 0 )
p(0.55) = ( 1.12; 2.50; 0 )
p(0.60) = ( 2.14; 3.14; 0 )
13
- Test 3, với bậc d của đường cong là 1000, input quá lớn nên chỉ có thể hiển thị
bằng hình vẽ
14
4.3.3.Nhận xét, đánh giá
Về cơ bản, hoàn thành yêu cầu nhập thông tin về thuộc tính, các số liệu liên quan đến
đường cong B-spline để triển khai và tính toán cho ra được tọa độ các điểm trong không
gian, thuộc đường cong B-spline thông qua công thức và các phương pháp tính toán đã
được triển khai bên trong phần lệnh thực thi của chương trình với tham số được truyền vào,
bằng việc thay đổi tham số sẽ cho ra các tọa độ khác nhau theo mục đích của người dùng.
Hoàn thành được việc vẽ mô hình đường cong tham số B-spline dựa trên input, xoay được
trong không gian ba chiều để quan sát đường cong theo các hướng khác nhau, hình vẽ đủ
rõ ràng để làm tham khảo cho kết quả tính toán và đối chiếu với kết quả chuẩn khi cần.
Phần giao diện tương tác đầy đủ thông tin, rõ ràng mạch lạc dễ theo dõi quá trình tính toán.
Về thuật toán được sử dụng để tính toán trong chương trình, đánh giá các tiêu chí về
độ phức tạp về thời gian, độ phức tạp về bộ nhớ và độ khó của giải thuật thì thuật toán đang
sử dụng là đủ phù hợp để thực hiện được chương trình so với việc sử dụng các thuật toán
tối ưu hơn về riêng các yếu tố thời gian, độ phức tạp …
Về cấu trúc chương trình, việc chia chương trình thành các modules với chức năng
riêng biệt, mỗi module được chia thành các file cùng tên khác định dạng, trong đó chỉ rõ
chức năng của từng module thông qua định danh đủ rõ ràng để đánh giá được chương trình
mà không cần xem qua phần lệnh thực sự. Mặc dù sự thiếu kinh nghiệm và kiến thức có
thể khiến cho việc chia modules chưa hoàn toàn rõ ràng, nhưng chương trình cũng được
15
làm rõ ràng theo hết khả năng hiện tại, và đủ đáp ứng việc hiểu chương trình mà không cần
đọc hết phần thân chương trình.
5.KẾT LUẬN VÀ HƯỚNG PHÁT TRIỂN
5.1.Kết luận
- Đường cong tham số B-spline ứng dụng rất nhiều vào đời sống, trong việc phát
triển đồ họa và kỹ thuật. Trong những đường cong phức tạp, có sự tham gia của quá nhiều
thành phần và cần độ chính xác cao thì đường cong B-spline là một lựa chọn tốt để áp
dụng. Với các đặc tính của đường cong tham số B-spline không đồng nhất, trong đó đường
cong đồng nhất là một trường hợp con của đường cong không đồng nhất, người dùng có
thể dựa vào đó phát triển công thức xây dựng đường cong và áp dụng theo mục đích. Đề
án nghiên cứu được phát triển lấy đường cong B-spline làm chủ đạo để trước hết làm rõ
được chức năng của đường cong, và triển khai, xây dựng công thức, vẽ được hình minh
họa, thỏa mãn được những nhu cầu cơ bản trong việc sử dụng đường cong tham số dựa
trên những số liệu vào. Nhờ vào việc nghiên cứu đề án đã hiểu được nhiều hơn về đường
cong, cũng như cách xây dựng, và cách đường cong phụ thuộc vào tham số, phục vụ quá
trình phát triển trong tương lai.
5.2.Hướng phát triển
- Về cơ bản, cấu trúc dữ liệu cùng thuật toán được sử dụng trong chương trình là
vừa đủ để có thể minh họa chính xác cách hoạt động và mô tả được tọa độ điểm trên
đường cong dựa trên tham số đầu vào, cũng như vẽ hình minh họa trong giới hạn cho
phép. Vì thế, có thể xem chương trình hiện tại như một phần mềm tham khảo khi tìm hiểu
về đường cong B-spline, cách mô tả hình dạng và cách tọa độ thay đổi dựa trên tham số
nếu có có nhu cầu. Một phiên bản vừa đủ chức năng cơ bản của các trang web mô tả
đường cong tham số B-spline nổi tiếng như nurbscalculator.in.
- Khi cải tiến chương trình, xây dựng giao diện giao tiếp đồ họa, và hiển thị tất cả
thông tin trực quan hơn, cũng như tích hợp thêm cách khai triển các đường cong khác
như bezier thì có thể xem chương trình là một phần mềm hoàn chỉnh và đủ tính xác đáng
trong học thuật để làm nguồn tham chiếu chuẩn cho người dùng nếu cần.
- Các modules được tạo ra trong dự án này có thể tái sử dụng vào nhiều mục đích
khác nhau, bên cạnh đó việc thiết kế chương trình theo hướng này còn giúp cho việc
chỉnh sửa, mở rộng dễ dàng hơn.
6.Tài liệu tham khảo
●
http://www.cl.cam.ac.uk/teaching/1999/AGraphHCI/SMAG/node4.html
16
●
A general matrix representation for non-uniform B-spline subdivision with
boundary control by G. Casciola a, L. Romani
● Trang web http://nurbscalculator.in/
● Đường cong Bézier và B-spline - Khoa CNTT Đại học Bách Khoa Đà Nẵng
Phụ lục
Point3d.h
#ifndef POINT3D_H
#define POINT3D_H
class Point3D{
private:
double m_x{};
double m_y{};
double m_z{};
public:
Point3D (double x, double y, double z);
Point3D () = default;
double getPoint_x() const ;
double getPoint_y() const ;
double getPoint_z() const ;
};
#endif
Point3d.cpp
#include "Point3D.h"
Point3D::Point3D (double x, double y, double z) : m_x{x}, m_y{y}, m_z{z}
{}
double Point3D::getPoint_x() const {
return m_x;
}
double Point3D::getPoint_y() const{
return m_y;
}
double Point3D::getPoint_z() const{
return m_z;
}
17
Polynomial.h
#ifndef POLYNOMIAL_H_INCLUDED
#define POLYNOMIAL_H_INCLUDED
#include <vector>
class Polynomial{
private:
std::vector<float> _data{}; //coefficients of x^n + x^n-1 + ... + x + 1
public:
Polynomial() = default;
Polynomial(std::vector<float>);
const std::vector<float>& getData() const{return _data;};
int getDegree() const {return _data.size()-1;}
float calcPolynomial(float) const;
};
#endif // POLYNOMIAL_H_INCLUDED
Polynomial.cpp
#include "Polynomial.h"
#include <vector>
Polynomial::Polynomial(std::vector<float> inp) : _data{inp} {};
float Polynomial::calcPolynomial(float variable) const{
float res = _data[0];
for(int i = 1; i < _data.size(); i++) res = res*variable + _data[i];
return res;
}
Matrix.h
#ifndef MATRIX_H_INCLUDED
#define MATRIX_H_INCLUDED
#include <vector>
class Matrix
{
private:
int m_row{};
int m_collumn{};
std::vector< std::vector<float> > m_data{};
18
public:
Matrix(const std::vector< std::vector<float> > &);
Matrix() = default;
int getRow() const{return m_row;}
int getCollumn() const{return m_collumn;};
std::vector< std::vector<float> > const &getData() const{return m_data;}
};
#endif // MATRIX_H_INCLUDED
Matrix.cpp
#include "Matrix.h"
#include <vector>
#include <algorithm>
Matrix::Matrix(const std::vector< std::vector<float> > &inputData){
int row = inputData.size();
int col = 0;
for(int i = 0; i < row;i++)
col = std::max(col,(int)(inputData[i].size()));
m_data.resize(row);
for(int i = 0; i < row;i++){
m_data[i].resize(col,0.0f);
for(int j = 0; j < (int)(inputData[i].size());j++){
m_data[i][j] = inputData[i][j];
}
}
m_row = row;
m_collumn = col;
}
OperatorOverloading.h
#ifndef OVERLOADING_H
#define OVERLOADING_H
#include "Point3D.h"
#include "Matrix.h"
#include "Polynomial.h"
#include <iostream>
Point3D
operator+ (const Point3D& fstP, const Point3D& secP);
19
Point3D
operator* (const Point3D& point, double k);
Point3D
operator* (double k, const Point3D& point);
std::istream& operator>> (std::istream& in, Point3D& point);
std::ostream& operator<< (std::ostream& out,const Point3D& point);
Matrix operator+(const Matrix&,const Matrix&);
Matrix operator*(const Matrix&,const Matrix&);
Polynomial operator+(const Polynomial&,const Polynomial&);
Polynomial operator*(const Polynomial&,const Polynomial&);
#endif
OperatorOverloading.cpp
#include "OperatorOverloading.h"
#include <iomanip>
#include <iostream>
#include <algorithm>
Point3D operator+ (const Point3D& fstP, const Point3D& secP){
double x = fstP.getPoint_x() + secP.getPoint_x();
double y = fstP.getPoint_y() + secP.getPoint_y();
double z = fstP.getPoint_z() + secP.getPoint_z();
return Point3D{x,y,z};
}
Point3D operator* (const Point3D& point, double k){
double x = point.getPoint_x()*k;
double y = point.getPoint_y()*k;
double z = point.getPoint_z()*k;
return Point3D{x,y,z};
}
Point3D operator* (double k, const Point3D& point){
return Point3D(point*k);
}
std::istream& operator>> (std::istream& in, Point3D& point){
double x{}, y{}, z{};
in >> x;
in >> y;
in >> z;
point = Point3D{x,y,z};
20
return in;
}
std::ostream& operator<< (std::ostream& out,const Point3D& point){
out << std::fixed << std::setprecision(2);
out << '(' << point.getPoint_x() << ';' << point.getPoint_y() << ';' << point.getPoint_z()
<< ')' ;
return out;
}
/*
void getNumber(std::ifstream& inf, double& number){
inf >> number;
while ( inf.fail()){
inf.clear();
inf.ignore(1,'\n'); //
inf >> number;
}
}
std::ifstream& operator>> (std::ifstream& inf, Point3D& point){
double x{}, y{}, z{};
getNumber(inf, x);
getNumber(inf, y);
getNumber(inf, z);
point = Point3D(x,y,z);
return inf;
}
std::ofstream& operator<< (std::ofstream& outf, Point3D& point){
outf << '(' << point.getPoint_x() << ';' << point.getPoint_y() << ';' <<
point.getPoint_z() << ')' ;
}*/
Matrix operator* (const Matrix &fstM,const Matrix &secM) // fstM = firstMatrix, secM
= secondMatrix
{
if(fstM.getCollumn() != secM.getRow())
{
std::cerr<<"Khong the thuc hien phep nhan ma tran
"<<fstM.getRow()<<"x"<<fstM.getCollumn()
<<" va ma tran "<<secM.getRow()<<"x"<<secM.getCollumn()<<"\n";
return Matrix();
21
}
int newRow{fstM.getRow()};
int newCol{secM.getCollumn()};
const std::vector< std::vector<float> > &fstData = fstM.getData();
const std::vector< std::vector<float> > &secData = secM.getData();
std::vector< std::vector<float> > result(newRow, std::vector<float>(newCol));
for(int i = 0; i < newRow; i++) //loop through all row of the first matrix
{
for(int j = 0; j < newCol;j++){
float sum{0};
for(int k = 0; k < fstM.getCollumn();k++){
sum += fstData[i][k]*secData[k][j];
}
result[i][j] = sum;
}
}
return Matrix(result);
}
Matrix operator+ (const Matrix &fstM,const Matrix &secM)
{
if((fstM.getRow() != secM.getRow()) || (fstM.getCollumn() != secM.getCollumn())){
std::cerr<<"Khong the thuc hien phep cong ma
tran"<<fstM.getRow()<<"x"<<fstM.getCollumn()
<<" va ma tran "<<secM.getRow()<<"x"<<secM.getCollumn()<<"\n";
return Matrix();
}
int row = fstM.getRow();
int col = fstM.getCollumn();
std::vector< std::vector<float> > resData(row,std::vector<float>(col));
for(int i = 0; i < row;i++){
for(int j = 0; j < col;j++){
resData[i][j] = fstM.getData()[i][j] + secM.getData()[i][j];
}
}
return Matrix(resData);
}
Polynomial operator+(const Polynomial &fstP, const Polynomial &secP){
const std::vector<float> &fstData = fstP.getData();
const std::vector<float> &secData = secP.getData();
22
int resSize = std::max(fstData.size(),secData.size());
std::vector<float> res(resSize,0);
for(int i = 0; i < resSize; i++){
int a = fstData.size()-1-i;
int b = secData.size()-1-i;
res[resSize-1-i] = ((a >= 0)? fstData[a] : 0) + ((b >= 0)? secData[b] : 0);
}
return Polynomial(res);
}
Polynomial operator*(const Polynomial &fstP, const Polynomial &secP){
if(secP.getDegree() < 0) return fstP;
if(fstP.getDegree() < 0) return secP;
const std::vector<float> &fstData = fstP.getData();
const std::vector<float> &secData = secP.getData();
int resSize = fstP.getDegree() + secP.getDegree();
std::vector<float> res(resSize,0);
for(int i = 0; i < (int)fstData.size();i++){
for(int j = 0; j < (int)secData.size();j++){
res[i+j] += fstData[i]*secData[j];
}
}
return Polynomial(res);
}
23
Bspline.h
#ifndef BSPLINE_H_INCLUDED
#define BSPLINE_H_INCLUDED
#include "Point3D.h"
#include <vector>
class Bspline{
private:
int m_deg{};
std::vector<double> m_knots{};
std::vector<Point3D> m_ctrlPoints{};
// knots[minAgentIndex] <= agent < knots[maxAgentIndex]
int m_minAgentIndex{};
int m_maxAgentIndex{};
public:
Bspline(int,const std::vector<double> &,const std::vector<Point3D> &);
Bspline() = default;
int getDegree() const{return m_deg;}
int getMinAgentIndex() const {return m_minAgentIndex;}
int getMaxAgentIndex() const {return m_maxAgentIndex;}
std::vector<double> const &getKnots() const {return m_knots;}
std::vector<Point3D> const &getCtrlPoints() const {return m_ctrlPoints;}
};
// generate an array of value from N(i-d,d) to N(i,d)
std::vector<double> DeBoor(std::vector<double> const &,double,int,int);
// calculate the position of an agent
Point3D calcDeBoor(const Bspline &,double);
//divide given bspline into segments and return an array of each segment's position
std::vector<Point3D> calcBsplineSeg(const Bspline &,int);
#endif // BSPLINE_H_INCLUDED
Bspline.cpp
#include "Bspline.h"
#include "point3D.h"
#include "OperatorOverloading.h"
#include "Debugger.h"
24
#include "Polynomial.h"
#include <iostream>
#include <vector>
#include <algorithm>
//define bspline class
Bspline::Bspline(int degree,const std::vector<double>& knots,const
std::vector<Point3D>& controlPoints) :
m_deg {degree}, m_knots {knots}, m_ctrlPoints {controlPoints},
m_minAgentIndex {degree},
m_maxAgentIndex {(int)controlPoints.size()} //m_ prefix mean member
{}
// -----------------------------------bspline calculation-----------------------std::vector<double> DeBoor(std::vector<double> const &knots,double agent,int idx, int
deg){
// knots[idx] <= agent < knots[idx+1]
std::vector<double> res(deg+1,0),temp(deg+1,0); // used to build the triangle
temp[0] = 1;
for(int cDeg = 1; cDeg <= deg; cDeg++)//build bottom-up
{
for(int offset = 0; offset <= cDeg; offset++)// calculate from N(icDeg+1,cDeg) to N(i,cDeg)
{
double a{0}, b{0};
int j{idx-cDeg+offset};
int k{cDeg};
if(offset != 0 && knots[j+k] != knots[j])
{
a = ((agent - knots[j])/(knots[j+k]-knots[j]))*temp[offset-1];
}
if(offset < cDeg && knots[j+k+1] != knots[j+1])
{
b = ((knots[j+k+1] - agent)/(knots[j+k+1]-knots[j+1]))*temp[offset];
}
res[offset] = a+b;
}
temp = res;
}
return res;
}
25
std::vector<double> matrixMethod(std::vector<double> const &knots,double agent,int
idx, int deg){
// knots[idx] <= agent < knots[idx+1]
std::vector<Polynomial> res(deg+1),temp(deg+1); // used to build the triangle
temp[0] = Polynomial({0});
for(int cDeg = 1; cDeg <= deg; cDeg++)//build bottom-up
{
for(int offset = 0; offset <= cDeg; offset++)// calculate from N(icDeg+1,cDeg) to N(i,cDeg)
{
Polynomial a,b;
int j{idx-cDeg+offset};
int k{cDeg};
if(offset != 0 && knots[j+k] != knots[j])
{
std::vector<float> t{1/(knots[j+k]-knots[j]) , -knots[j]/(knots[j+k]knots[j])};
a = Polynomial(t)*temp[offset-1];
}
if(offset < cDeg && knots[j+k+1] != knots[j+1])
{
std::vector<float> t{-1/(knots[j+k+1]-knots[j+1]) ,
knots[j+k+1]/(knots[j+k+1]-knots[j+1])};
b = Polynomial(t)*temp[offset];
}
res[offset] = a+b;
}
temp = res;
}
std::vector<double> resVector(deg+1);
for(int i = 0; i <= deg;i++)
{
resVector[i] = res[i].calcPolynomial(agent);
}
return resVector;
}
Point3D calcDeBoor(const Bspline &bsplineData,double agent){
const std::vector<double> &knots = bsplineData.getKnots();
const std::vector<Point3D> &ctrlPoints = bsplineData.getCtrlPoints();
26
std::vector<double>::const_iterator it;
std::vector<double> resVector;
//calculate idx that knots[idx] <= agent < knots[idx+1] and idx < maxAgentIdx
it = std::upper_bound(knots.begin(),knots.end(),agent);
int idx = it - knots.begin()-1;
if(idx > bsplineData.getMaxAgentIndex()) idx = bsplineData.getMaxAgentIndex()-1;
int deg = bsplineData.getDegree();
Point3D res(0.0,0.0,0.0);
resVector = DeBoor(knots,agent,idx,deg);
for(int i = 0; i < deg+1;i++)
{
res = res + resVector[i]*ctrlPoints[i+(idx - deg)];
}
return res;
}
std::vector<Point3D> calcBsplineSeg(const Bspline &splineData,int segmentNum){
std::vector<Point3D> result;
double minAgent = splineData.getKnots()[splineData.getMinAgentIndex()];
double maxAgent = splineData.getKnots()[splineData.getMaxAgentIndex()];
float agentDist = (maxAgent - minAgent)/segmentNum;
//push all agent position from min to nearly max
for(double t = minAgent; t < maxAgent; t+= agentDist)
{
Point3D agentPoint = calcDeBoor(splineData,t);
result.push_back(agentPoint);
std::cout<<"P("<<t<<") = "<<agentPoint<<"\n";
}
//push maximum agent position
result.push_back(calcDeBoor(splineData,maxAgent));
return result;
}
Main.cpp
#include "Modules/Point3D.h"
#include "Modules/Bspline.h"
#include "Modules/OperatorOverloading.h"
27
#include <GL/glut.h>
#include <iostream>
#include <vector>
#include <math.h>
#include <windows.h>
#define DEFAULT_WIDTH 640
#define DEFAULT_HEIGHT 480
const int maxDegree = 1000;
const int segmentNum = 20;
const GLfloat minZoom = 0.01f;
const GLfloat maxZoom = 100.0f;
const GLfloat zoomSpeed = 0.1f;
const GLfloat rotateSpeed = 5.0f;
const GLdouble orthoNear = -50.0f;
const GLdouble orthoFar = 50.0f;
std::vector<Point3D> segPoints;
Bspline splineData;
GLfloat zoom = 1.0f;
GLfloat orthoWidth = 10.0f;
GLfloat orthoHeight = 10.0f;
GLfloat axisLength = 100.0f;
GLfloat curScreenWidth = DEFAULT_WIDTH;
GLfloat curScreenHeight = DEFAULT_HEIGHT;
Point3D bsplineCenter;
Point3D camPosition;
Point3D objectRotation;
template <typename T>
T getMin(T a, T b)
{
return (a > b)? b : a;
}
template <typename T>
T getMax(T a, T b){
return (a > b)? a : b;
}
Bspline initBsplineStdin(){
int deg,pointCount;
28
std::vector<Point3D> ctrlPoints;
std::vector<double> ctrlKnots;
//Nhap bac cua bspline
std::cout<<"Nhap bac cua bspline trong khoang gia tri [1,"<<maxDegree<<"] : ";
std::cin>>deg;
while(deg <= 0 || deg > maxDegree)
{
std::cout<<"Khong hop le, moi nhap lai bac cua bspline trong khoang gia tri
[1,"<<maxDegree<<"] : ";
std::cin>>deg;
}
//Nhap dinh dieu khien
std::cout<<"Moi nhap so dinh dieu khien : ";
std::cin>>pointCount;
while(pointCount < deg)
{
std::cout<<"So dinh dieu khien khong be hon bac cua bspline\n";
std::cout<<"Moi nhap so dinh dieu khien : ";
std::cin>>pointCount;
}
for(int i = 0; i < pointCount;i++)
{
float x,y,z;
std::cout<<"Nhap toa do cua dinh thu "<<i+1<<" : ";
std::cin>>x>>y>>z;
std::cout<<"Toa do cua dinh thu "<<i+1<<" :\t("<<x<<","<<y<<","<<z<<")\n";
ctrlPoints.push_back(Point3D(x,y,z));
}
ctrlPoints.shrink_to_fit();
//Nhap nut dieu khien
for(int i = 0; i < deg + pointCount + 1; i++)
{
double t;
std::cout<<"Moi nhap nut dieu khien thu "<<i+1<<" : ";
std::cin>>t;
ctrlKnots.push_back(t);
}
ctrlKnots.shrink_to_fit();
29
return Bspline(deg,ctrlKnots,ctrlPoints);
}
void init(){
//white background
glClearColor(1.0f,1.0f,1.0f,1.0f);
glClearDepth(1.0f);
glEnable(GL_DEPTH_TEST);
}
void initBspline(){
splineData = initBsplineStdin();
system("cls");
std::cout<<"Du lieu dau vao la B-spline bac "<<splineData.getDegree()<<" co :\n";
std::cout<<"Cac dinh dieu khien : \n";
for(Point3D p : splineData.getCtrlPoints()) std::cout<<p<<"\n";
std::cout<<"Cac vector nut : ";
for(double x : splineData.getKnots()) std::cout<<x<<" ";
std::cout<<"\n";
//using segPoints to draw bspline whenever reshape function called
segPoints = calcBsplineSeg(splineData,segmentNum);
//calculate center of bspline
Point3D firstPoint = splineData.getCtrlPoints()[0];
double minX,maxX,minY,maxY,minZ,maxZ;
minX = maxX = firstPoint.getPoint_x();
minY = maxY = firstPoint.getPoint_y();
minZ = maxZ = firstPoint.getPoint_z();
for(auto it = splineData.getCtrlPoints().begin(); it !=
splineData.getCtrlPoints().end();it++)
{
double thisX,thisY,thisZ;
thisX = (*it).getPoint_x();
thisY = (*it).getPoint_y();
thisZ = (*it).getPoint_z();
minX = getMin(thisX,minX);
minY = getMin(thisY,minY);
minZ = getMin(thisZ,minZ);
maxX = getMax(thisX,maxX);
30
maxY = getMax(thisY,maxY);
maxZ = getMax(thisZ,maxZ);
}
bsplineCenter = Point3D((minX+maxX)/2,(minY+maxY)/2,(minZ+maxZ)/2);
orthoWidth = orthoHeight = getMax(getMax(fabs(maxX-minX),fabs(maxYminY)),fabs(maxZ-minZ));
axisLength = orthoWidth/5;
//Set camera position to object center
camPosition =
Point3D(bsplineCenter.getPoint_x(),bsplineCenter.getPoint_y(),bsplineCenter.getPoint_z
()-0.1f);
//std::cout<<"Camera position :
"<<camPosition.getPoint_x()<<","<<camPosition.getPoint_y()<<","<<camPosition.getP
oint_z()<<"\n";
}
void drawBspline(){
//glMatrixMode(GL_MODELVIEW);
//glLoadIdentity();
glBegin(GL_LINE_STRIP);
glColor3f(1.0f,0.0f,0.0f);
for(auto it = segPoints.begin(); it!=segPoints.end(); it++)
{
Point3D thisPoint = *it;
glVertex3f(thisPoint.getPoint_x(),thisPoint.getPoint_y(),thisPoint.getPoint_z());
}
glEnd();
//draw line through all control points
glBegin(GL_LINE_STRIP);
glColor3f(0.8f,0.8f,0.8f); // grey
for(auto it = splineData.getCtrlPoints().begin(); it != splineData.getCtrlPoints().end();
it++)
{
Point3D point = *it;
glVertex3f(point.getPoint_x(),point.getPoint_y(),point.getPoint_z());
}
31
glEnd();
}
void drawAxis(){
//glMatrixMode(GL_MODELVIEW);
//glLoadIdentity();
glPushMatrix();
glTranslatef(bsplineCenter.getPoint_x(),bsplineCenter.getPoint_y(),bsplineCenter.getPoi
nt_z()); // draw axis at center of bspline
glBegin(GL_LINES);
//x axis
glColor3f(1.0f,0.0f,0.0f);
glVertex3f(0.0f,0.0f,0.0f);
glVertex3f(axisLength,0.0f,0.0f);
//y axis
glColor3f(0.0f,1.0f,0.0f);
glVertex3f(0.0f,0.0f,0.0f);
glVertex3f(0.0f,axisLength,0.0f);
//z axis
glColor3f(0.0f,0.0f,1.0f);
glVertex3f(0.0f,0.0f,0.0f);
glVertex3f(0.0f,0.0f,axisLength);
glEnd();
glPopMatrix();
}
void reshape(GLsizei width,GLsizei height){
if(height == 0) height = 1;
glViewport(50,50,width,height);
curScreenWidth = width;
curScreenHeight = height;
glutPostRedisplay();
//std::cerr<<"current width/height : "<<width<<","<<height<<"\n";
}
void displayOrtho(){
GLfloat aspect = curScreenWidth/curScreenHeight;
glMatrixMode(GL_PROJECTION);
32
glLoadIdentity();
GLfloat w = orthoWidth / zoom;
GLfloat h = orthoHeight / zoom;
if(curScreenWidth < curScreenHeight)
glOrtho(-w,w,-h/aspect,h/aspect,orthoNear/zoom,orthoFar/zoom);
else
glOrtho(-w*aspect,w*aspect,-h,h,orthoNear/zoom,orthoFar/zoom);
//look at bspline center
gluLookAt(camPosition.getPoint_x(),camPosition.getPoint_y(),camPosition.getPoint_z(),
bsplineCenter.getPoint_x(),bsplineCenter.getPoint_y(),bsplineCenter.getPoint_z(),0.0,1.0
,0.0);
}
void display(){
displayOrtho();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(bsplineCenter.getPoint_x(),bsplineCenter.getPoint_y(),bsplineCenter.getPoi
nt_z()); // draw axis at center of bspline
glRotatef(objectRotation.getPoint_x(),1.0f,0.0f,0.0f);
glRotatef(objectRotation.getPoint_y(),0.0f,1.0f,0.0f);
glRotatef(objectRotation.getPoint_z(),0.0f,0.0f,1.0f);
glTranslatef(-bsplineCenter.getPoint_x(),-bsplineCenter.getPoint_y(),bsplineCenter.getPoint_z()); // draw axis at center of bspline
drawAxis();
drawBspline();
glTranslatef(-bsplineCenter.getPoint_x(),-bsplineCenter.getPoint_y(),bsplineCenter.getPoint_z()); // draw axis at center of bspline
glutSwapBuffers();
}
void rotateObject(double x,double y, double z){
33
double rotX = objectRotation.getPoint_x()+x;
double rotY = objectRotation.getPoint_y()+y;
double rotZ = objectRotation.getPoint_z()+z;
if(fabs(rotX) > 360.0) rotX += (rotX < 0)? 360.0 : -360.0;
if(fabs(rotY) > 360.0) rotY += (rotY < 0)? 360.0 : -360.0;
if(fabs(rotZ) > 360.0) rotZ += (rotZ < 0)? 360.0 : -360.0;
objectRotation = Point3D(rotX,rotY,rotZ);
//std::cout<<"Current rotation : "<<objectRotation<<"\n";
}
void mouse(int button,int state,int x,int y){
if(button == 3)
{
zoom += zoomSpeed;
zoom = (zoom > maxZoom) ? maxZoom : zoom;
glutPostRedisplay();
}
else if(button == 4)
{
//std::cout<<"ZOOM OUT\n";
zoom -= zoomSpeed;
zoom = (zoom < minZoom) ? minZoom : zoom;
glutPostRedisplay();
}
//std::cerr<<"zoom factor :"<<zoom<<"\n";
}
void keyboard(unsigned char key,int x,int y){
switch(key)
{
case 'a' :
rotateObject(0.0,1.0*rotateSpeed,0.0);
break;
case 'd' :
rotateObject(0.0,-1.0*rotateSpeed,0.0);
break;
case 'w' :
rotateObject(1.0*rotateSpeed,0.0,0.0);
break;
case 's' :
rotateObject(-1.0*rotateSpeed,0.0,0.0);
34
break;
default :
break;
}
glutPostRedisplay();
}
void drawBsplineOpenGL(int argc, char *argv[]){
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowPosition(100,100);
glutInitWindowSize(DEFAULT_WIDTH,DEFAULT_HEIGHT);
glutCreateWindow("B-spline calculator");
glutReshapeFunc(reshape);
glutDisplayFunc(display);
glutMouseFunc(mouse);
glutKeyboardFunc(keyboard);
init();
glutMainLoop();
}
void calculatePoint(){
double minAgent = splineData.getKnots()[splineData.getMinAgentIndex()];
double maxAgent = splineData.getKnots()[splineData.getMaxAgentIndex()];
double t;
do
{
std::cout<<"Nhap t("<<minAgent<<"<=t<"<<maxAgent<<") : ";
std::cin>>t;
}while((t<minAgent) || (t>=maxAgent));
std::cout<<"P("<<t<<") = "<< calcDeBoor(splineData,t)<<"\n";
}
int choseAction()
{
int t = 0;
std::cout<<"\n";
std::cout<<"Chon cong viec can thuc hien :\n";
std::cout<<"1.Tinh gia tri cua B-spline tai mot diem\n";
std::cout<<"2.Ve duong cong B-spline\n";
std::cout<<"3.Thoat chuong trinh \n";
std::cin>>t;
if((t < 1) || (t > 3)) return -1;
return t;
35
}
int main(int argc, char *argv[]){
initBspline();
int t = 0;
do
{
t = choseAction();
switch(t)
{
case -1 :
std::cout<<"Khong hop le, moi nhap lai";
break;
case 1 :
calculatePoint();
break;
case 2 :
drawBsplineOpenGL(argc,argv);
break;
default :
break;
}
}while(t != 3);
return 0;
}
36
Download