Preview:Option Explicit ' Public Type P_Type X As Double ' Coordinate x dei punti. Y As Double ' Coordinate y dei punti. 'z As Double ' Coordinate z dei punti. End Type Public Sub Bezier_C(Pi() As P_Type, Pc() As P_Type) ' ' Ritorna, nel vettore Pc(), i valori della curva di Bezier calcolata ' al valore u (0 <= u <= 1). La curva e' calcolata in modo ' parametrico con il valore 0 di u corrispondente a Pc(0) ' ed il valore 1 corrispondente a Pc(NPC_1). ' Questo algoritmo ricalca la forma classica del polinomio ' di Bernstein. ' Dim I&, K&, NPI_1&, NPC_1&, NF&, u#, BF# ' NPI_1 = UBound(Pi) NPC_1 = UBound(Pc) 'NF = Prodotto(NPI_1) ' For I = 0 To NPC_1 u = CDbl(I) / CDbl(NPC_1) Pc(I).X = 0# Pc(I).Y = 0# 'Pc(I).z = 0# For K = 0 To NPI_1 'BF = NF * (u ^ K) * ((1 - u) ^ (NPI_1 - K)) _ / (Prodotto(K) * Prodotto(NPI_1 - K)) BF = Prodotto(NPI_1, K + 1) * (u ^ K) * ((1# - u) ^ (NPI_1 - K)) _ / Prodotto(NPI_1 - K) Pc(I).X = Pc(I).X + Pi(K).X * BF Pc(I).Y = Pc(I).Y + Pi(K).Y * BF 'Pc(I).z = Pc(I).z + Pi(K).z * BF Next K Next I ' ' ' End Sub Public Sub Bezier_1(Pi() As P_Type, Pc() As P_Type) ' ' Ritorna, nel vettore Pc(), i valori della curva di Bezier. ' La curva e' calcolata in modo parametrico (0 <= u < 1) ' con il valore 0 di u corrispondente a Pc(0); ' Attenzione: il punto Pc(NPC_1), corrispondente al valore u = 1, ' non puo' essere calcolato. ' ' Parametri: ' Pi(0 to NPI - 1): Vettore dei punti, dati, da ' approssimare. ' Pc(0 to NPC - 1): Vettore dei punti, calcolati, ' della curva approssimante. ' Dim I&, K&, NPI_1&, NPC_1& Dim u#, u_1#, ue#, u_1e#, BF# ' NPI_1 = UBound(Pi) ' N. di punti da approssimare - 1. NPC_1 = UBound(Pc) ' N. di punti sulla curva - 1. ' ' La curva inizia sempre da Pi(0) -> u = 0: Pc(0).X = Pi(0).X Pc(0).Y = Pi(0).Y 'Pc(0).z = Pi(0).z ' For I = 1 To NPC_1 - 1 u = CDbl(I) / CDbl(NPC_1) ue = 1# u_1 = 1# - u u_1e = u_1 ^ NPI_1 ' Pc(I).X = 0# Pc(I).Y = 0# 'Pc(I).z = 0# For K = 0 To NPI_1 BF = Prodotto(NPI_1, K + 1) * ue * u_1e / Prodotto(NPI_1 - K) Pc(I).X = Pc(I).X + Pi(K).X * BF Pc(I).Y = Pc(I).Y + Pi(K).Y * BF 'Pc(I).z = Pc(I).z + Pi(K).z * BF ' ue = ue * u u_1e = u_1e / u_1 Next K Next I ' ' La curva finisce sempre su Pi(NPI_1) -> u = 1: Pc(NPC_1).X = Pi(NPI_1).X Pc(NPC_1).Y = Pi(NPI_1).Y 'Pc(NPC_1).z = Pi(NPI_1).z ' ' ' End Sub Public Sub Bezier(Pi() As P_Type, Pc() As P_Type) ' ' Ritorna, nel vettore Pc(), i valori della curva di Bezier. ' La curva e' calcolata in modo parametrico (0 <= u < 1) ' con il valore 0 di u corrispondente a Pc(0); ' ' Questa versione elimina alcuni problemi di "underflow" ' e di "overflow" presentati dalla Bezier_1 e dalla Bezier_C. ' ' Parametri: ' Pi(0 to NPI - 1): Vettore dei punti, dati, da ' approssimare. ' Pc(0 to NPC - 1): Vettore dei punti, calcolati, ' della curva approssimante. ' Dim I&, K&, NPI_1&, NPC_1& Dim u#, u_1#, ue#, BF# Static NPI_1_O&, CB_Tav#() ' NPI_1 = UBound(Pi) ' N. di punti da approssimare - 1 (deve essere 2 <= NPI_1 <= 1029). NPC_1 = UBound(Pc) ' N. di punti sulla curva - 1. ' If NPI_1_O <> NPI_1 Then ' Prepara la tavola dei coefficienti binomiali: ReDim CB_Tav#(0 To NPI_1) For K = 0 To NPI_1 CB_Tav(K) = rncr(NPI_1, K) Next K ' NPI_1_O = NPI_1 End If ' ' La curva inizia sempre da Pi(0) -> u = 0: Pc(0).X = Pi(0).X Pc(0).Y = Pi(0).Y 'Pc(0).z = Pi(0).z ' For I = 1 To NPC_1 - 1 u = CDbl(I) / CDbl(NPC_1) ue = 1# u_1 = 1# - u ' Pc(I).X = 0# Pc(I).Y = 0# 'Pc(I).z = 0# For K = 0 To NPI_1 BF = CB_Tav(K) * ue * u_1 ^ (NPI_1 - K) ' Pc(I).X = Pc(I).X + Pi(K).X * BF Pc(I).Y = Pc(I).Y + Pi(K).Y * BF 'Pc(I).z = Pc(I).z + Pi(K).z * BF ' ue = ue * u Next K Next I ' ' La curva finisce sempre su Pi(NPI_1) -> u = 1: Pc(NPC_1).X = Pi(NPI_1).X Pc(NPC_1).Y = Pi(NPI_1).Y 'Pc(NPC_1).z = Pi(NPI_1).z ' ' ' End Sub Public Sub Bezier_P(Pi() As P_Type, Pc() As P_Type) ' ' Ritorna, nel vettore Pc(), i valori della curva di Bezier calcolata ' al valore u (0 <= u < 1). La curva e' calcolata in modo ' parametrico con il valore 0 di u corrispondente a Pc(0); ' Attenzione: il punto Pc(NPC_1), corrispondente al valore u = 1, ' non puo' essere calcolato. ' ' Questo algoritmo (tratto da una pubblicazione di P. Bourke ' e tradotto dal C) e' particolarmente interessante, in quanto ' evita l' uso dei fattoriali della forma normale. ' Dim K&, I&, KN&, NPI_1&, NPC_1&, NN&, NKN& Dim u#, uk#, unk#, Blend# ' NPI_1 = UBound(Pi) NPC_1 = UBound(Pc) ' For I = 0 To NPC_1 - 1 u = CDbl(I) / CDbl(NPC_1) uk = 1# unk = (1# - u) ^ NPI_1 ' Pc(I).X = 0# Pc(I).Y = 0# 'Pc(I).z = 0# ' For K = 0 To NPI_1 NN = NPI_1 KN = K NKN = NPI_1 - K Blend = uk * unk uk = uk * u unk = unk / (1# - u) Do While NN >= 1 Blend = Blend * CDbl(NN) NN = NN - 1 If KN > 1 Then Blend = Blend / CDbl(KN) KN = KN - 1 End If If NKN > 1 Then Blend = Blend / CDbl(NKN) NKN = NKN - 1 End If Loop ' Pc(I).X = Pc(I).X + Pi(K).X * Blend Pc(I).Y = Pc(I).Y + Pi(K).Y * Blend 'Pc(I).z = Pc(I).z + Pi(K).z * Blend Next K Next I ' ' La curva finisce sempre su Pi(NPI_1) -> u = 1: Pc(NPC_1).X = Pi(NPI_1).X Pc(NPC_1).Y = Pi(NPI_1).Y 'Pc(NPC_1).z = Pi(NPI_1).z ' ' ' End Sub Private Function Prodotto(ByVal N2&, Optional ByVal N1& = 2) As Double ' ' Ritorna il prodotto dei numeri, consecutivi, interi e positivi, ' da N1 a N2 (0 < N1 <= N2). Se N1 > N2 ritorna 1. ' Se N1 manca, ritorna il Fattoriale di N2; in questo caso puo' ' anche essere N2 = 0 perche', per definizione, e' 0! = 1: ' Dim Pr#, I& ' Pr = 1# For I = N1 To N2 Pr = Pr * CDbl(I) Next I ' Prodotto = Pr ' ' ' End Function Public Sub B_Spline(Pi() As P_Type, ByVal NK&, Pc() As P_Type) ' ' Ritorna, nel vettore Pc(), i valori della curva B-Spline. ' La curva e' calcolata in modo parametrico (0 <= u <= 1) ' con il valore 0 di u corrispondente a Pc(0) ed il valore ' 1 corrispondente a Pc(NPC_1). ' ' Parametri: ' Pi(0 to NPI - 1): Vettore dei punti, dati, da ' approssimare. ' Pc(0 to NPC - 1): Vettore dei punti, calcolati, ' della curva approssimante. ' NK: Numero di nodi della curva ' approssimante: ' NK = 2 -> segmenti di retta. ' NK = 3 -> curve quadratiche. ' .. . .................. ' NK = NPI -> splines di Bezier. Dim NPI_1&, NPC_1&, I&, J&, tmax#, u#, ut#, bn#() Const Eps = 0.0000001 ' NPI_1 = UBound(Pi) ' N. di punti da approssimare - 1. NPC_1 = UBound(Pc) ' N. di punti sulla curva - 1. tmax = NPI_1 - NK + 2 ' ' La curva inizia sempre da Pi(0) -> u = 0: Pc(0).X = Pi(0).X Pc(0).Y = Pi(0).Y ' For I = 1 To NPC_1 - 1 u = CDbl(I) / CDbl(NPC_1) ut = u * tmax If Abs(ut - CDbl(NPI_1 + NK - 2)) <= Eps Then Pc(I).X = Pi(NPI_1).X Pc(I).Y = Pi(NPI_1).Y Else Call B_Basis(NPI_1, ut, NK, bn()) Pc(I).X = 0# Pc(I).Y = 0# For J = 0 To NPI_1 Pc(I).X = Pc(I).X + bn(J) * Pi(J).X Pc(I).Y = Pc(I).Y + bn(J) * Pi(J).Y Next J End If Next I ' ' La curva finisce sempre su Pi(NPI_1) -> u = 1: Pc(NPC_1).X = Pi(NPI_1).X Pc(NPC_1).Y = Pi(NPI_1).Y ' ' ' End Sub Private Sub B_Basis(ByVal NPI_1&, ByVal ut#, ByVal K&, bn#()) ' ' Compute the basis function (also called weight) ' for the B-Spline approximation curve: ' Dim NT&, I&, J& Dim b0#, b1#, bl0#, bl1#, bu0#, bu1# ReDim bn#(0 To NPI_1 + 1), bn0#(0 To NPI_1 + 1), t#(0 To NPI_1 + K + 1) ' NT = NPI_1 + K + 1 For I = 0 To NT If (I < K) Then t(I) = 0# If ((I >= K) And (I <= NPI_1)) Then t(I) = CDbl(I - K + 1) If (I > NPI_1) Then t(I) = CDbl(NPI_1 - K + 2) Next I For I = 0 To NPI_1 bn0(I) = 0# If ((ut >= t(I)) And (ut < t(I + 1))) Then bn0(I) = 1# If ((t(I) = 0#) And (t(I + 1) = 0#)) Then bn0(I) = 0# Next I ' For J = 2 To K For I = 0 To NPI_1 bu0 = (ut - t(I)) * bn0(I) bl0 = t(I + J - 1) - t(I) If (bl0 = 0#) Then b0 = 0# Else b0 = bu0 / bl0 End If bu1 = (t(I + J) - ut) * bn0(I + 1) bl1 = t(I + J) - t(I + 1) If (bl1 = 0#) Then b1 = 0# Else b1 = bu1 / bl1 End If bn(I) = b0 + b1 Next I For I = 0 To NPI_1 bn0(I) = bn(I) Next I Next J ' ' ' End Sub Public Sub C_Spline(Pi() As P_Type, Pc() As P_Type) ' ' Ritorna, nel vettore Pc(), i valori della curva C-Spline. ' La curva e' calcolata in modo parametrico (0 <= u <= 1) ' con il valore 0 di u corrispondente a Pc(0) ed il valore ' 1 corrispondente a Pc(NPC_1). ' ' Parametri: ' Pi(0 to NPI - 1): Vettore dei punti, dati, da ' interpolare. ' Pc(0 to NPC - 1): Vettore dei punti, calcolati, ' della curva interpolante. ' Dim NPI_1&, NPC_1&, I&, J& Dim u#, ui#, uui# Dim cof() As P_Type ' NPI_1 = UBound(Pi) ' N. di punti da interpolare - 1. NPC_1 = UBound(Pc) ' N. di punti sulla curva - 1. ' Call Find_CCof(Pi(), NPI_1 + 1, cof()) ' ' La curva inizia sempre da Pi(0) -> u = 0: Pc(0).X = Pi(0).X Pc(0).Y = Pi(0).Y ' For I = 1 To NPC_1 - 1 u = CDbl(I) / CDbl(NPC_1) J = Int(u * CDbl(NPI_1)) + 1 If (J > (NPI_1)) Then J = NPI_1 ' ui = CDbl(J - 1) / CDbl(NPI_1) uui = u - ui ' Pc(I).X = cof(4, J).X * uui ^ 3 + cof(3, J).X * uui ^ 2 + cof(2, J).X * uui + cof(1, J).X Pc(I).Y = cof(4, J).Y * uui ^ 3 + cof(3, J).Y * uui ^ 2 + cof(2, J).Y * uui + cof(1, J).Y Next I ' ' La curva finisce sempre su Pi(NPI_1) -> u = 1: Pc(NPC_1).X = Pi(NPI_1).X Pc(NPC_1).Y = Pi(NPI_1).Y ' ' ' End Sub Private Function rncr(ByVal N&, ByVal K&) As Double ' ' Calcola i coefficienti binomiali Cn,k come: ' rncr = N! / (K! * (N - K)!) ' ' Nota: La funzione ha senso solo per 0 < N, K <= N ' e 0 <= K. Nessun errore viene segnalato. ' Dim I&, rncr_T# ' If ((N < 1) Or (K < 1) Or (N = K)) Then rncr = 1# ' Else rncr_T = 1# For I = 1 To N - K rncr_T = rncr_T * (1# + CDbl(K) / CDbl(I)) Next I ' rncr = rncr_T End If ' ' ' End Function Public Sub T_Spline(Pi() As P_Type, ByVal VZ&, Pc() As P_Type) ' ' Ritorna, nel vettore Pc(), i valori della curva T-Spline. ' La curva e' calcolata in modo parametrico (0 <= u <= 1) ' con il valore 0 di u corrispondente a Pc(0) ed il valore ' 1 corrispondente a Pc(NPC_1). ' ' Parametri: ' Pi(0 to NPI - 1): Vettore dei punti, dati, da ' interpolare. ' Pc(0 to NPC - 1): Vettore dei punti, calcolati, ' della curva interpolante. ' VZ: Valore di tensione della curva ' (1 <= VZ <= 100): valori grandi ' di VZ appiattiscono la curva. ' Dim NPI_1&, NPC_1&, I&, J& Dim H#, z#, z2i#, szh#, u#, u0#, u1#, du1#, du0# Dim s() As P_Type ' NPI_1 = UBound(Pi) ' N. di punti da interpolare - 1. NPC_1 = UBound(Pc) ' N. di punti sulla curva - 1. z = CDbl(VZ) ' Call Find_TCof(Pi(), NPI_1 + 1, s(), z) ' ' La curva inizia sempre da Pi(0) -> u = 0: Pc(0).X = Pi(0).X Pc(0).Y = Pi(0).Y ' H = 1# / CDbl(NPI_1) szh = Sinh(z * H) z2i = 1# / z / z For I = 1 To NPC_1 - 1 u = CDbl(I) / CDbl(NPC_1) J = Int(u * CDbl(NPI_1)) + 1 If (J > (NPI_1)) Then J = NPI_1 ' u0 = CDbl(J - 1) / CDbl(NPI_1) u1 = CDbl(J) / CDbl(NPI_1) du1 = u1 - u du0 = u - u0 ' Pc(I).X = s(J).X * z2i * Sinh(z * du1) / szh + (Pi(J - 1).X - s(J).X * z2i) * du1 / H Pc(I).X = Pc(I).X + s(J + 1).X * z2i * Sinh(z * du0) / szh + (Pi(J).X - s(J + 1).X * z2i) * du0 / H Pc(I).Y = s(J).Y * z2i * Sinh(z * du1) / szh + (Pi(J - 1).Y - s(J).Y * z2i) * du1 / H Pc(I).Y = Pc(I).Y + s(J + 1).Y * z2i * Sinh(z * du0) / szh + (Pi(J).Y - s(J + 1).Y * z2i) * du0 / H Next I ' ' La curva finisce sempre su Pi(NPI_1) -> u = 1: Pc(NPC_1).X = Pi(NPI_1).X Pc(NPC_1).Y = Pi(NPI_1).Y ' ' ' End Sub Private Sub Find_TCof(Pi() As P_Type, ByVal NPI&, s() As P_Type, ByVal z#) ' ' Find the coefficients of the T-Spline ' using constant interval: ' Dim I&, H#, a0#, b0#, zh#, z2# ' ReDim s(1 To NPI) As P_Type, f(1 To NPI) As P_Type ReDim a(1 To NPI) As Double, B(1 To NPI) As Double, C(1 To NPI) As Double ' H = 1# / CDbl(NPI - 1) zh = z * H a0 = 1# / H - z / Sinh(zh) b0 = z * 2# * Cosh(zh) / Sinh(zh) - 2# / H For I = 1 To NPI - 2 a(I) = a0 B(I) = b0 C(I) = a0 Next I ' z2 = z * z / H For I = 1 To NPI - 2 f(I).X = (Pi(I + 1).X - 2# * Pi(I).X + Pi(I - 1).X) * z2 f(I).Y = (Pi(I + 1).Y - 2# * Pi(I).Y + Pi(I - 1).Y) * z2 Next I ' Call TRIDAG(a(), B(), C(), f(), s(), NPI - 2) For I = 1 To NPI - 2 s(NPI - I).X = s(NPI - 1 - I).X s(NPI - I).Y = s(NPI - 1 - I).Y Next I ' s(1).X = 0# s(NPI).X = 0# s(1).Y = 0# s(NPI).Y = 0# ' ' ' End Sub Private Sub Find_CCof(Pi() As P_Type, ByVal NPI&, cof() As P_Type) ' ' Find the coefficients of the cubic spline ' using constant interval parameterization: ' Dim I&, H# ' ReDim s(1 To NPI) As P_Type, f(1 To NPI) As P_Type, cof(1 To 4, 1 To NPI) As P_Type ReDim a(1 To NPI) As Double, B(1 To NPI) As Double, C(1 To NPI) As Double ' H = 1# / CDbl(NPI - 1) For I = 1 To NPI - 2 a(I) = 1# B(I) = 4# C(I) = 1# Next I ' For I = 1 To NPI - 2 f(I).X = 6# * (Pi(I + 1).X - 2# * Pi(I).X + Pi(I - 1).X) / H / H f(I).Y = 6# * (Pi(I + 1).Y - 2# * Pi(I).Y + Pi(I - 1).Y) / H / H Next I ' Call TRIDAG(a(), B(), C(), f(), s(), NPI - 2) For I = 1 To NPI - 2 s(NPI - I).X = s(NPI - 1 - I).X s(NPI - I).Y = s(NPI - 1 - I).Y Next I ' s(1).X = 0# s(NPI).X = 0# s(1).Y = 0# s(NPI).Y = 0# For I = 1 To NPI - 1 cof(4, I).X = (s(I + 1).X - s(I).X) / 6# / H cof(4, I).Y = (s(I + 1).Y - s(I).Y) / 6# / H cof(3, I).X = s(I).X / 2# cof(3, I).Y = s(I).Y / 2# cof(2, I).X = (Pi(I).X - Pi(I - 1).X) / H - (2# * s(I).X + s(I + 1).X) * H / 6# cof(2, I).Y = (Pi(I).Y - Pi(I - 1).Y) / H - (2# * s(I).Y + s(I + 1).Y) * H / 6# cof(1, I).X = Pi(I - 1).X cof(1, I).Y = Pi(I - 1).Y Next I ' ' ' End Sub Private Sub TRIDAG(a#(), B#(), C#(), f() As P_Type, s() As P_Type, ByVal NPI_2&) ' ' Solves the tridiagonal linear system of equations: ' Dim J&, bet# ReDim gam#(1 To NPI_2) ' If B(1) = 0 Then Exit Sub ' bet = B(1) s(1).X = f(1).X / bet s(1).Y = f(1).Y / bet For J = 2 To NPI_2 gam(J) = C(J - 1) / bet bet = B(J) - a(J) * gam(J) If (bet = 0) Then Exit Sub s(J).X = (f(J).X - a(J) * s(J - 1).X) / bet s(J).Y = (f(J).Y - a(J) * s(J - 1).Y) / bet Next J ' For J = NPI_2 - 1 To 1 Step -1 s(J).X = s(J).X - gam(J + 1) * s(J + 1).X s(J).Y = s(J).Y - gam(J + 1) * s(J + 1).Y Next J ' ' ' End Sub Private Function Cosh(ByVal z As Double) As Double ' ' Ritorna il coseno iperbolico di z#: ' Cosh = (Exp(z) + Exp(-z)) / 2# ' ' ' End Function Private Function Sinh(ByVal z As Double) As Double ' ' Ritorna il seno iperbolico di z#: ' Sinh = (Exp(z) - Exp(-z)) / 2# ' ' ' End Function
Thursday, December 21, 2017
Splines in VB6
Subscribe to:
Posts (Atom)