Uygulamalı Geometriye Giriş

Modern geometrik modelleme ve eğri tasarımının matematiksel temelleri

P(t) = Σ B_{i,n}(t) · P_i

Afin Uzay ve Temel Kavramlar

Afin uzay, geometrik modellemenin temelini oluşturan matematiksel yapıdır. Vektör uzayından farklı olarak, afin uzayda belirli bir orijin nokta yoktur ve noktalar arasındaki ilişkiler vektörler vasıtasıyla tanımlanır.

Afin Uzayın Temel Özellikleri:
  • Nokta kümesi: A (afin uzay)
  • Vektör uzayı: V (ilişkili vektör uzayı)
  • Etki fonksiyonu: A × V → A
  • Boyut: dim(A) = dim(V)
  • Translasyon değişmezliği: Koordinat sisteminden bağımsızlık
P = O + \vec{v}

Bu formülde P bir nokta, O referans noktası ve v⃗ konum vektörüdür. Afin uzayda iki nokta arasındaki fark her zaman bir vektör verir.

Geometrik Anlam
Afin uzay, "paralel çizgilerin sonsuza kadar uzandığı" Öklid geometrisinin genelleştirilmiş halidir. Açılar ve uzunluklar korunmayabilir, ancak parallellik ve oranlar korunur.
1. Referans nokta O seç
2. Koordinat eksenleri {e₁, e₂, ..., eₙ} tanımla
3. Herhangi bir P noktası için: P = O + x₁e₁ + x₂e₂ + ... + xₙeₙ
4. Koordinat dönüşümlerini afin transformasyonlarla gerçekleştir
Önemli Not: Afin uzayda vektör toplamı doğrudan tanımlanmaz. Noktalar toplanamaz, sadece bir noktaya vektör eklenebilir veya iki nokta arasındaki fark alınabilir.

Nokta-Vektör İlişkileri ve Barisantrik Koordinatlar

Barisantrik koordinatlar, n+1 nokta tarafından tanımlanan n-boyutlu simpleks içindeki herhangi bir noktayı ifade etmenin güçlü bir yoludur. Bu koordinat sistemi, interpolasyon ve geometrik modelleme için kritik öneme sahiptir.

P = λ_0 P_0 + λ_1 P_1 + ... + λ_n P_n

Bu formülde λᵢ barisantrik koordinatlardır ve şu koşulu sağlarlar:

\sum_{i=0}^{n} λ_i = 1
Barisantrik Koordinatların Özellikleri:
  • Afin değişmezlik: Koordinat sisteminden bağımsız
  • Doğal interpolasyon: Ağırlıklı ortalama
  • Simpleks içi konum: 0 ≤ λᵢ ≤ 1 ise P simpleks içinde
  • Kenar ve köşe tanımları: λᵢ = 0 ise P, i'inci köşenin karşı yüzünde
  • Merkez noktası: λᵢ = 1/(n+1) ise P simpleksin merkezinde
2D Üçgen Örneği
Üçgen ABC için herhangi bir P noktası: P = λₐA + λᵦB + λᶜC
λₐ + λᵦ + λᶜ = 1
λₐ = Alan(PBC)/Alan(ABC), λᵦ = Alan(APC)/Alan(ABC), λᶜ = Alan(ABP)/Alan(ABC)
Barisantrik Koordinat Hesaplama:
1. Simpleksi tanımlayan noktaları {P₀, P₁, ..., Pₙ} belirle
2. Hedef nokta P için lineer sistem kur: P - P₀ = Σλᵢ(Pᵢ - P₀)
3. Sistem çöz ve λ₀ = 1 - Σλᵢ hesapla
4. Doğrulama: Σλᵢ = 1 kontrol et
Koordinat Türü Avantajlar Dezavantajlar Kullanım Alanı Kartezyen Basit hesaplamalar Koordinat sistemine bağımlı Genel amaçlı Barisantrik Afin değişmez, doğal interpolasyon Daha karmaşık hesaplamalar Interpolasyon, mesh işlemleri Homojen Projektif dönüşümler Ekstra boyut 3D grafiklerde dönüşümler
Pratik İpucu: Barisantrik koordinatlar, finite element analizinde şekil fonksiyonları olarak kullanılır ve mesh tabanlı simülasyonlarda kritik rol oynar.

Düzlemde ve Uzayda Eğriler

Parametrik eğriler, geometrik modelleme ve bilgisayar grafiklerinin temel yapı taşlarıdır. Bir eğri, parametrik fonksiyon olarak r(t) = (x(t), y(t), z(t)) şeklinde tanımlanır.

\vec{r}(t) = (x(t), y(t), z(t)), \quad t \in [a,b]
Eğri Türleri ve Özellikleri:
  • Düzlem eğrileri: 2D uzayda tanımlı, z(t) = 0
  • Uzay eğrileri: 3D uzayda serbestçe konumlanmış
  • Kapalı eğriler: r(a) = r(b)
  • Açık eğriler: Başlangıç ve bitiş noktaları farklı
  • Düzgün eğriler: r'(t) ≠ 0 her noktada
Eğri Geometrisi Temel Kavramlar:
Teğet vektör: T(t) = r'(t)/|r'(t)|
Normal vektör: N(t) = T'(t)/|T'(t)|
Binormal vektör: B(t) = T(t) × N(t)
Eğrilik: κ(t) = |r'(t) × r''(t)|/|r'(t)|³
Yaygın Eğri Örnekleri
Doğru: r(t) = P₀ + t·d⃗
Çember: r(t) = (R cos t, R sin t)
Helix: r(t) = (R cos t, R sin t, ht)
Elips: r(t) = (a cos t, b sin t)
Eğri Analizi Süreci:
1. Parametrik denklemi tanımla: r(t)
2. Birinci türevi hesapla: r'(t) (hız vektörü)
3. İkinci türevi hesapla: r''(t) (ivme vektörü)
4. Eğrilik ve burulma hesapla
5. Frenet çerçevesini {T, N, B} oluştur
s = \int_a^b |\vec{r}'(t)| dt = \int_a^b \sqrt{x'(t)^2 + y'(t)^2 + z'(t)^2} dt

Bu formül eğri uzunluğunu (yay uzunluğu) verir ve parametrik eğrilerin en önemli özelliklerinden biridir.

Parametrizasyon Dikkat: Aynı eğri farklı parametrizasyonlara sahip olabilir. Geometrik özellikler parametrizasyondan bağımsız, ancak hesaplamalar parametrizasyona bağlı olabilir.

Eğrilerde Lineer İnterpolasyon Yöntemi

Lineer interpolasyon, iki nokta arasında düz bir çizgi oluşturan en basit interpolasyon yöntemidir. Parçalı lineer eğriler oluşturmak için kullanılır ve karmaşık interpolasyon yöntemlerinin temelini oluşturur.

P(t) = (1-t)P_0 + tP_1, \quad t \in [0,1]

Bu formülde t parametresi 0'dan 1'e değişirken, P(t) noktası P₀'dan P₁'e doğru düz bir çizgi boyunca hareket eder.

Lineer İnterpolasyonun Özellikleri:
  • Afin değişmezlik: Koordinat sisteminden bağımsız
  • Sınır değerleri: P(0) = P₀, P(1) = P₁
  • Lineerlik: Birinci dereceden polinom
  • Konveks kombinasyon: P(t) her zaman P₀ ve P₁ arasında
  • Simetri: P(t) = P(1-s) formunda yazılabilir
Parçalı Lineer Eğri Oluşturma:
1. Kontrol noktaları {P₀, P₁, ..., Pₙ} tanımla
2. Her segment için: Pᵢ(t) = (1-t)Pᵢ + tPᵢ₊₁
3. Global parametrizasyon: t ∈ [i, i+1] için segment i
4. Süreklilik kontrolü: Pᵢ(1) = Pᵢ₊₁(0)
Çok Boyutlu Genelleme
3D uzayda: P(t) = (1-t)(x₀, y₀, z₀) + t(x₁, y₁, z₁)
Her koordinat bağımsız olarak interpolasyon yapılır:
x(t) = (1-t)x₀ + tx₁
y(t) = (1-t)y₀ + ty₁
z(t) = (1-t)z₀ + tz₁
function linearInterpolation(P0, P1, t) { return { x: (1-t) * P0.x + t * P1.x, y: (1-t) * P0.y + t * P1.y, z: (1-t) * P0.z + t * P1.z }; } // Parçalı lineer eğri function piecewiseLinear(points, globalT) { let segment = Math.floor(globalT); let localT = globalT - segment; if (segment >= points.length - 1) { segment = points.length - 2; localT = 1.0; } return linearInterpolation(points[segment], points[segment + 1], localT); }
Özellik Lineer İnterpolasyon Avantaj/Dezavantaj Hesaplama karmaşıklığı O(1) ✅ Çok hızlı Süreklilik C⁰ ❌ Köşeli geçişler Hafıza gereksinimi Minimal ✅ Çok düşük Esneklik Sınırlı ❌ Sadece düz çizgiler Stabil Mükemmel ✅ Hiçbir zaman salınım yapmaz
Uygulama Alanları: Lineer interpolasyon, oyun motorlarında hareket animasyonları, 3D modellemede mesh basitleştirme ve gerçek zamanlı grafik uygulamalarında yaygın olarak kullanılır.

Eğrilerde Polinom İnterpolasyonu ve 4-Nokta Yöntemi

Polinom interpolasyonu, verilen noktalardan geçen en düşük dereceli polinomun bulunması işlemidir. n+1 nokta için n dereceli tek bir polinom vardır ve bu polinom Weierstrass yaklaşım teoremi gereği sürekli fonksiyonları keyfi hassasiyetle yaklaşabilir.

P_n(t) = a_0 + a_1 t + a_2 t^2 + ... + a_n t^n
Polinom İnterpolasyonun Temel Teoremi:
n+1 farklı nokta (t₀, P₀), (t₁, P₁), ..., (tₙ, Pₙ) verildiğinde, bu noktalardan geçen tek bir n dereceli polinom vardır.
4-Nokta Polinom İnterpolasyon Süreci:
1. Dört kontrol noktası seç: P₀, P₁, P₂, P₃
2. Parametre değerleri ata: t₀ = 0, t₁ = 1/3, t₂ = 2/3, t₃ = 1
3. Vandermonde matrisi oluştur: V·a = P
4. Katsayıları çöz: a = V⁻¹·P
5. Kübik polinom: P(t) = a₀ + a₁t + a₂t² + a₃t³
\begin{bmatrix} 1 & 0 & 0 & 0 \\ 1 & 1/3 & 1/9 & 1/27 \\ 1 & 2/3 & 4/9 & 8/27 \\ 1 & 1 & 1 & 1 \end{bmatrix} \begin{bmatrix} a_0 \\ a_1 \\ a_2 \\ a_3 \end{bmatrix} = \begin{bmatrix} P_0 \\ P_1 \\ P_2 \\ P_3 \end{bmatrix}
Runge Fenomeni
Yüksek dereceli polinomlarda, özellikle eşit aralıklı noktalarda interpolasyon yapılırken kenar bölgelerde büyük salınımlar oluşabilir. Bu problemi çözmek için Chebyshev noktaları kullanılabilir.
// 4-nokta kübik polinom interpolasyonu function cubicPolynomialInterpolation(P0, P1, P2, P3, t) { // Vandermonde matrisinin tersini kullanarak katsayıları hesapla const a0 = P0; const a1 = -11/6 * P0 + 3 * P1 - 3/2 * P2 + 1/3 * P3; const a2 = 3 * P0 - 9/2 * P1 + 3 * P2 - 1/2 * P3; const a3 = -1 * P0 + 3/2 * P1 - 3/2 * P2 + 1/2 * P3; // P(t) = a0 + a1*t + a2*t^2 + a3*t^3 return { x: a0.x + a1.x*t + a2.x*t*t + a3.x*t*t*t, y: a0.y + a1.y*t + a2.y*t*t + a3.y*t*t*t, z: a0.z + a1.z*t + a2.z*t*t + a3.z*t*t*t }; } // Alternatif: Matris formunda function matrixBasedCubic(points, t) { const M = [ [1, 0, 0, 0], [-11/6, 3, -3/2, 1/3], [3, -9/2, 3, -1/2], [-1, 3/2, -3/2, 1/2] ]; const tVector = [1, t, t*t, t*t*t]; // Sonuç = tVector * M * points }
Polinom Derecesi Nokta Sayısı Süreklilik Uygulama Alanı Lineer (1) 2 C⁰ Basit interpolasyon Kuadratik (2) 3 C¹ (türev sürekli) Parabol fit etme Kübik (3) 4 C² (eğrilik sürekli) Düzgün eğriler Yüksek derece (n>3) n+1 C^(n-1) Özel durumlar (dikkatli kullanım)
Sayısal Kararlılık: Yüksek dereceli polinom interpolasyonu sayısal hatalar açısından risklidir. Genellikle 3-4 derece üzerinde spline interpolasyonu tercih edilir.
Optimizasyon İpucu: Eşit aralıklı noktalarda Runge fenomenini önlemek için Chebyshev noktaları kullanın: tₖ = cos((2k-1)π/(2n)) formülü ile.

Lagrange ve Newton Polinom Yöntemleri

Lagrange ve Newton interpolasyon yöntemleri, polinom interpolasyonunu gerçekleştirmek için iki farklı yaklaşım sunar. Her ikisi de aynı polinomu üretir ancak hesaplama yöntemleri ve avantajları farklıdır.

Lagrange İnterpolasyonu

P(t) = \sum_{i=0}^{n} P_i \cdot L_i(t)

Burada Lᵢ(t) Lagrange baz polinomlarıdır:

L_i(t) = \prod_{\substack{j=0 \\ j \neq i}}^{n} \frac{t - t_j}{t_i - t_j}
Lagrange Baz Polinomlarının Özellikleri:
  • Kronecker delta: Lᵢ(tⱼ) = δᵢⱼ (i=j ise 1, değilse 0)
  • Bölüm birliği: ∑Lᵢ(t) = 1
  • Polinom derecesi: Her Lᵢ(t) n dereceli polinom
  • Lokal destek yok: Bir nokta değişimi tüm baz fonksiyonlarını etkiler
Lagrange İnterpolasyon Algoritması:
1. Her i için baz polinomunu hesapla: Lᵢ(t)
2. Ağırlıklı toplamı hesapla: P(t) = ∑PᵢLᵢ(t)
3. t değeri için sonucu değerlendir
function lagrangeInterpolation(points, t) { let result = { x: 0, y: 0, z: 0 }; const n = points.length; for (let i = 0; i < n; i++) { let Li = 1.0; // Lagrange baz polinomunu hesapla for (let j = 0; j < n; j++) { if (i !== j) { Li *= (t - points[j].t) / (points[i].t - points[j].t); } } // Ağırlıklı katkıyı ekle result.x += points[i].x * Li; result.y += points[i].y * Li; result.z += points[i].z * Li; } return result; }

Newton İnterpolasyonu

P(t) = f[t_0] + f[t_0,t_1](t-t_0) + f[t_0,t_1,t_2](t-t_0)(t-t_1) + ...

Bu formülde f[t₀,t₁,...,tₖ] k'inci derece bölünmüş farkları (divided differences) temsil eder.

f[t_i, t_{i+1}, ..., t_{i+k}] = \frac{f[t_{i+1}, ..., t_{i+k}] - f[t_i, ..., t_{i+k-1}]}{t_{i+k} - t_i}
Newton İnterpolasyon Tablosu:
1. 0. derece farklar: f[tᵢ] = P(tᵢ)
2. 1. derece farklar: f[tᵢ,tᵢ₊₁] = (f[tᵢ₊₁] - f[tᵢ])/(tᵢ₊₁ - tᵢ)
3. Yüksek derece farkları rekürsif hesapla
4. Diagonal elemanları Newton formülünde kullan
Özellik Lagrange Newton Hesaplama karmaşıklığı O(n²) O(n²) önceden hesaplama + O(n) değerlendirme Yeni nokta ekleme Tüm hesaplamayı tekrarla Sadece yeni katsayıları hesapla Sayısal kararlılık Orta Daha iyi (nested form) Bellek kullanımı Nokta listesi Bölünmüş farklar tablosu Kod basitliği Basit Orta karmaşıklık
function newtonInterpolation(points, t) { const n = points.length; let dividedDiffs = new Array(n).fill(0).map(() => new Array(n).fill(0)); // 0. derece farkları for (let i = 0; i < n; i++) { dividedDiffs[i][0] = points[i].y; } // Bölünmüş farklar tablosunu doldur for (let j = 1; j < n; j++) { for (let i = 0; i < n - j; i++) { dividedDiffs[i][j] = (dividedDiffs[i+1][j-1] - dividedDiffs[i][j-1]) / (points[i+j].t - points[i].t); } } // Newton polinomunu değerlendir (Horner şeması) let result = dividedDiffs[0][n-1]; for (let i = n-2; i >= 0; i--) { result = dividedDiffs[0][i] + (t - points[i].t) * result; } return result; } // 3D nokta interpolasyonu için genişletilmiş versiyon function newton3D(points, t) { return { x: newtonInterpolation(points.map(p => ({t: p.t, y: p.x})), t), y: newtonInterpolation(points.map(p => ({t: p.t, y: p.y})), t), z: newtonInterpolation(points.map(p => ({t: p.t, y: p.z})), t) }; }
Hangisini Seçmeli?
Lagrange tercih edin: Tek seferlik hesaplamalar için, basit implementasyon gereken durumlar
Newton tercih edin: Adaptif nokta ekleme gerektiğinde, sayısal kararlılık önemli olduğunda
Ortak Problem: Her iki yöntem de yüksek dereceli polinomlarda Runge fenomenine maruz kalır. Çözüm için parçalı interpolasyon veya spline yöntemleri kullanın.

Eğrilerde Hermite İnterpolasyon Yöntemi

Hermite interpolasyonu, sadece nokta değerlerini değil, aynı zamanda türev bilgilerini de kullanarak daha düzgün ve kontrol edilebilir eğriler oluşturan gelişmiş bir interpolasyon yöntemidir. Bu yöntem, C¹ sürekliliği garanti eder.

P(t) = P_0 H_0(t) + P_1 H_1(t) + T_0 H_2(t) + T_1 H_3(t)

Burada Hᵢ(t) Hermite baz fonksiyonları, P₀, P₁ uç noktalar, T₀, T₁ bu noktalardaki teğet vektörlerdir.

Kübik Hermite Baz Fonksiyonları:
  • H₀(t) = 2t³ - 3t² + 1: Başlangıç noktası ağırlığı
  • H₁(t) = -2t³ + 3t²: Bitiş noktası ağırlığı
  • H₂(t) = t³ - 2t² + t: Başlangıç teğet ağırlığı
  • H₃(t) = t³ - t²: Bitiş teğet ağırlığı
\begin{bmatrix} P(0) \\ P(1) \\ P'(0) \\ P'(1) \end{bmatrix} = \begin{bmatrix} 2 & -2 & 1 & 1 \\ 3 & -3 & 2 & 1 \\ 0 & 0 & 1 & 0 \\ 1 & 0 & 0 & 0 \end{bmatrix} \begin{bmatrix} t³ \\ t² \\ t \\ 1 \end{bmatrix}
Hermite İnterpolasyon Süreci:
1. Uç noktaları belirle: P₀, P₁
2. Teğet vektörlerini hesapla/tahmin et: T₀, T₁
3. Hermite baz fonksiyonlarını hesapla: H₀, H₁, H₂, H₃
4. Ağırlıklı kombinasyonu oluştur
5. C¹ sürekliliği kontrol et
function hermiteBasisFunctions(t) { const t2 = t * t; const t3 = t2 * t; return { H0: 2*t3 - 3*t2 + 1, // Başlangıç nokta ağırlığı H1: -2*t3 + 3*t2, // Bitiş nokta ağırlığı H2: t3 - 2*t2 + t, // Başlangıç teğet ağırlığı H3: t3 - t2 // Bitiş teğet ağırlığı }; } function hermiteInterpolation(P0, P1, T0, T1, t) { const basis = hermiteBasisFunctions(t); return { x: basis.H0 * P0.x + basis.H1 * P1.x + basis.H2 * T0.x + basis.H3 * T1.x, y: basis.H0 * P0.y + basis.H1 * P1.y + basis.H2 * T0.y + basis.H3 * T1.y, z: basis.H0 * P0.z + basis.H1 * P1.z + basis.H2 * T0.z + basis.H3 * T1.z }; } // Teğet vektör tahmini (sınırlı farklar kullanarak) function estimateTangent(P_prev, P_next, scale = 1.0) { return { x: scale * (P_next.x - P_prev.x) / 2, y: scale * (P_next.y - P_prev.y) / 2, z: scale * (P_next.z - P_prev.z) / 2 }; }
Teğet Vektör Kontrolü
Hermite interpolasyonunun gücü, teğet vektörlerin manuel kontrolünde yatar. Bu, eğrinin yerel şeklini hassas biçimde ayarlamaya olanak tanır:
• Büyük teğet: Eğriyi o yönde uzatır
• Küçük teğet: Eğriyi o noktada düzleştirir
• Zıt yönlü teğetler: S-şekli oluşturur
Özellik Standart Polinom Hermite Gerekli veri Sadece noktalar Noktalar + türevler Kontrol seviyesi Sınırlı Yüksek (teğet kontrolü) Süreklilik C⁰ C¹ garanti Hesaplama maliyeti Orta Orta-yüksek Uygulama kolaylığı Kolay Orta (teğet tahmin gerekir)
Adaptif Teğet Hesabı: Catmull-Rom spline yöntemi kullanarak teğet vektörleri otomatik hesaplayabilirsiniz: T₀ = k(P₁ - P₋₁), k ∈ [0.5, 1.0]
Dikkat: Çok büyük teğet vektörleri aşırı salınımlara (overshoot) neden olabilir. Teğet büyüklüğü genellikle komşu noktalar arası mesafenin %50-%100'ü kadar tutulmalıdır.

Spline İnterpolasyon Yöntemi ve Kübik Spline Eğrileri

Spline interpolasyonu, yüksek dereceli polinomların neden olduğu Runge fenomenini önlemek için parçalı polinom kullanır. Kübik spline'lar, C² süreklilik sağlayarak çok düzgün eğriler oluşturur.

Kübik Spline Özellikleri:
• Her segment kübik polinom: Sᵢ(x) = aᵢ + bᵢx + cᵢx² + dᵢx³
• İç noktalarda C² sürekli: S'(xᵢ) ve S''(xᵢ) sürekli
• n+1 nokta için n segment
• 4n katsayı, 4n-2 kısıt → 2 serbestlik derecesi
S_i(x) = a_i(x-x_i)^3 + b_i(x-x_i)^2 + c_i(x-x_i) + d_i
Spline İnterpolasyon Kısıtları:
  • Interpolasyon: Sᵢ(xᵢ) = yᵢ ve Sᵢ(xᵢ₊₁) = yᵢ₊₁
  • C¹ süreklilik: Sᵢ'(xᵢ₊₁) = Sᵢ₊₁'(xᵢ₊₁)
  • C² süreklilik: Sᵢ''(xᵢ₊₁) = Sᵢ₊₁''(xᵢ₊₁)
  • Sınır koşulları: Doğal, clamped, periodic
Thomas Algoritması ile Kübik Spline Çözümü:
1. İkinci türevleri mᵢ = S''(xᵢ) olarak tanımla
2. Tridiagonal sistem oluştur: [h]m = r
3. Thomas algoritması ile sistemi çöz
4. Spline katsayılarını hesapla: aᵢ, bᵢ, cᵢ, dᵢ
5. Her segment için spline fonksiyonunu oluştur
\begin{bmatrix} h_0 & 2(h_0+h_1) & h_1 \\ & h_1 & 2(h_1+h_2) & h_2 \\ & & \ddots & \ddots & \ddots \end{bmatrix} \begin{bmatrix} m_0 \\ m_1 \\ m_2 \\ \vdots \end{bmatrix} = \begin{bmatrix} r_0 \\ r_1 \\ r_2 \\ \vdots \end{bmatrix}
class CubicSpline { constructor(points, boundaryType = 'natural') { this.points = points.sort((a, b) => a.x - b.x); this.n = points.length - 1; this.boundaryType = boundaryType; this.computeCoefficients(); } computeCoefficients() { const n = this.n; const h = new Array(n); const y = this.points.map(p => p.y); const x = this.points.map(p => p.x); // Segment uzunlukları for (let i = 0; i < n; i++) { h[i] = x[i + 1] - x[i]; } // Tridiagonal sistem kurulumu const alpha = new Array(n - 1); for (let i = 1; i < n; i++) { alpha[i - 1] = 3 / h[i] * (y[i + 1] - y[i]) - 3 / h[i - 1] * (y[i] - y[i - 1]); } // Thomas algoritması const l = new Array(n + 1); const mu = new Array(n); const z = new Array(n + 1); l[0] = 1; mu[0] = z[0] = 0; for (let i = 1; i < n; i++) { l[i] = 2 * (x[i + 1] - x[i - 1]) - h[i - 1] * mu[i - 1]; mu[i] = h[i] / l[i]; z[i] = (alpha[i - 1] - h[i - 1] * z[i - 1]) / l[i]; } l[n] = 1; z[n] = 0; // Geri yerine koyma const c = new Array(n + 1); const b = new Array(n); const d = new Array(n); c[n] = 0; for (let j = n - 1; j >= 0; j--) { c[j] = z[j] - mu[j] * c[j + 1]; b[j] = (y[j + 1] - y[j]) / h[j] - h[j] * (c[j + 1] + 2 * c[j]) / 3; d[j] = (c[j + 1] - c[j]) / (3 * h[j]); } this.coefficients = { a: y, b, c, d }; } evaluate(x) { const { points } = this; const n = this.n; // Hangi segmentte olduğunu bul let i = 0; while (i < n && x > points[i + 1].x) i++; i = Math.min(i, n - 1); const { a, b, c, d } = this.coefficients; const dx = x - points[i].x; return a[i] + b[i] * dx + c[i] * dx * dx + d[i] * dx * dx * dx; } // 3D spline için genişletme static create3D(points, boundaryType = 'natural') { const splineX = new CubicSpline(points.map((p, i) => ({x: i, y: p.x})), boundaryType); const splineY = new CubicSpline(points.map((p, i) => ({x: i, y: p.y})), boundaryType); const splineZ = new CubicSpline(points.map((p, i) => ({x: i, y: p.z})), boundaryType); return { evaluate: (t) => ({ x: splineX.evaluate(t), y: splineY.evaluate(t), z: splineZ.evaluate(t) }) }; } }
Sınır Koşulu Matematiksel Tanım Avantaj Kullanım Alanı Natural (Doğal) S''(x₀) = S''(xₙ) = 0 Basit, minimum eğrilik Genel amaçlı interpolasyon Clamped S'(x₀) = f'₀, S'(xₙ) = f'ₙ Türev kontrolü Belirli eğim gereken durumlar Periodic S(x₀) = S(xₙ), S'(x₀) = S'(xₙ) Kapalı eğriler Döngüsel veriler
Spline'ın Matematiksel Temeli
Spline kelimesi gemicilik terminolojinden gelir - ince ahşap şeritler (spline) çivilerle sabitlenerek gemi gövdelerinin düzgün eğrilerini oluştururdu. Matematiksel spline de aynı şekilde "minimum enerji" prensibini takip eder.
Performans Optimizasyonu: Büyük veri setleri için B-spline representasyonu kullanın. Bu, O(n³) çözüm yerine O(n) değerlendirme sağlar ve yerel kontrol imkanı sunar.
Extrapolation Uyarısı: Spline'lar, veri aralığı dışında kübik polinomun doğal davranışını sergiler ve beklenmedik sonuçlar verebilir. Extrapolation için dikkatli olun.

Bézier Eğrileri ve Temel Kavramlar

Bézier eğrileri, Pierre Bézier tarafından 1960'larda otomotiv endüstrisi için geliştirilen parametrik eğrilerdir. CAD sistemleri, bilgisayar grafikleri ve vektör çizim programlarının temelini oluştururlar.

Bézier Eğrilerinin Temel Özellikleri:
• Kontrol poligonu ile tanımlanır
• Bernstein polinomları kullanır
• Konveks gövde özelliği
• Afin değişmezlik
• Uç nokta interpolasyonu (ilk ve son kontrol noktası)
B(t) = \sum_{i=0}^{n} P_i \cdot B_{i,n}(t), \quad t \in [0,1]

Burada Pᵢ kontrol noktaları, B_{i,n}(t) n-dereceli Bernstein baz polinomlarıdır.

Yaygın Bézier Eğri Türleri:
  • Lineer (n=1): B(t) = (1-t)P₀ + tP₁
  • Kuadratik (n=2): B(t) = (1-t)²P₀ + 2(1-t)tP₁ + t²P₂
  • Kübik (n=3): En yaygın kullanılan, 4 kontrol noktası
  • Yüksek derece: Özel tasarım gereksinimleri için
De Casteljau Algoritması (Geometrik Yaklaşım):
1. Kontrol noktalarını P₀, P₁, ..., Pₙ olarak sırala
2. İlk seviye: Qᵢ⁰ = Pᵢ
3. Rekürsif hesaplama: Qᵢʳ = (1-t)Qᵢʳ⁻¹ + tQᵢ₊₁ʳ⁻¹
4. Final sonuç: B(t) = Q₀ⁿ
class BezierCurve { constructor(controlPoints) { this.controlPoints = controlPoints; this.degree = controlPoints.length - 1; } // De Casteljau algoritması ile değerlendirme evaluate(t) { let points = [...this.controlPoints]; for (let level = 1; level <= this.degree; level++) { for (let i = 0; i <= this.degree - level; i++) { points[i] = { x: (1 - t) * points[i].x + t * points[i + 1].x, y: (1 - t) * points[i].y + t * points[i + 1].y, z: (1 - t) * points[i].z + t * points[i + 1].z }; } } return points[0]; } // Bernstein yaklaşımı ile değerlendirme evaluateBernstein(t) { let result = { x: 0, y: 0, z: 0 }; const n = this.degree; for (let i = 0; i <= n; i++) { const bernstein = this.bernsteinPolynomial(n, i, t); result.x += this.controlPoints[i].x * bernstein; result.y += this.controlPoints[i].y * bernstein; result.z += this.controlPoints[i].z * bernstein; } return result; } // Bernstein polinom hesaplama bernsteinPolynomial(n, i, t) { return this.binomialCoefficient(n, i) * Math.pow(1 - t, n - i) * Math.pow(t, i); } // Binom katsayısı hesaplama binomialCoefficient(n, k) { if (k > n) return 0; if (k === 0 || k === n) return 1; let result = 1; for (let i = 1; i <= k; i++) { result = result * (n - i + 1) / i; } return result; } // Türev hesaplama derivative() { if (this.degree === 0) return null; const derivativePoints = []; for (let i = 0; i < this.degree; i++) { derivativePoints[i] = { x: this.degree * (this.controlPoints[i + 1].x - this.controlPoints[i].x), y: this.degree * (this.controlPoints[i + 1].y - this.controlPoints[i].y), z: this.degree * (this.controlPoints[i + 1].z - this.controlPoints[i].z) }; } return new BezierCurve(derivativePoints); } } // Kübik Bézier örneği const cubicBezier = new BezierCurve([ { x: 0, y: 0, z: 0 }, // P0: Başlangıç noktası { x: 1, y: 2, z: 0 }, // P1: Başlangıç teğet kontrol noktası { x: 3, y: 2, z: 1 }, // P2: Bitiş teğet kontrol noktası { x: 4, y: 0, z: 0 } // P3: Bitiş noktası ]); // Eğriyi değerlendirme const point = cubicBezier.evaluate(0.5); console.log("t=0.5'teki nokta:", point);
Endüstriyel Kullanım
Otomotiv: Renault ve Citroën'de araç gövde tasarımı
Grafik Tasarım: Adobe Illustrator, Photoshop vektör araçları
3D Modelleme: Blender, Maya, 3ds Max NURBS yüzeyleri
Animasyon: Hareket yolları ve keyframe interpolasyonu
Derece Kontrol Noktası Matematiksel Form Kullanım Alanı 1 (Lineer) 2 (1-t)P₀ + tP₁ Basit çizgiler 2 (Kuadratik) 3 (1-t)²P₀ + 2(1-t)tP₁ + t²P₂ TrueType fontlar 3 (Kübik) 4 Σ P_i C(3,i)(1-t)^(3-i) t^i PostScript, SVG n (Genel) n+1 Σ P_i C(n,i)(1-t)^(n-i) t^i Özel tasarım
Tasarım İpucu: Kübik Bézier eğriler, çoğu uygulama için ideal dereceyi sağlar. Daha yüksek dereceler kontrol edilmesi zor eğriler oluşturabilir.

Bézier Eğrilerinin Bernstein Gösterimi

Bernstein polinomları, Sergei Bernstein tarafından 1912'de Weierstrass yaklaşım teoreminin yapıcı bir kanıtı için geliştirilmiştir. Bézier eğrilerinin matematiksel temelini oluşturur ve birçok güzel özelliğe sahiptir.

B_{i,n}(t) = \binom{n}{i} t^i (1-t)^{n-i}

Bu formülde i = 0, 1, ..., n ve t ∈ [0,1] değerlerini alır.

Bernstein Polinomlarının Temel Özellikleri:
  • Pozitiflik: B_{i,n}(t) ≥ 0 for t ∈ [0,1]
  • Bölüm birliği: Σᵢ B_{i,n}(t) = 1
  • Simetri: B_{i,n}(t) = B_{n-i,n}(1-t)
  • Uç değerler: B_{i,n}(0) = δ_{i,0}, B_{i,n}(1) = δ_{i,n}
  • Maksimum: B_{i,n}(i/n) maksimum değerde
Bernstein Polinomlarının Hesaplanması:
1. Binom katsayısını hesapla: C(n,i) = n!/(i!(n-i)!)
2. t^i terimini hesapla
3. (1-t)^(n-i) terimini hesapla
4. Tüm terimleri çarp: B_{i,n}(t)
5. Optimizasyon: Rekürsif ilişki kullan
class BernsteinBasis { constructor(degree) { this.degree = degree; this.precomputeBinomials(); } // Binom katsayılarını önceden hesapla precomputeBinomials() { this.binomials = new Array(this.degree + 1); for (let i = 0; i <= this.degree; i++) { this.binomials[i] = this.factorial(this.degree) / (this.factorial(i) * this.factorial(this.degree - i)); } } factorial(n) { if (n <= 1) return 1; let result = 1; for (let i = 2; i <= n; i++) { result *= i; } return result; } // Tek bir Bernstein baz fonksiyonu evaluate(i, t) { return this.binomials[i] * Math.pow(t, i) * Math.pow(1 - t, this.degree - i); } // Tüm baz fonksiyonlarını hesapla evaluateAll(t) { const basis = new Array(this.degree + 1); for (let i = 0; i <= this.degree; i++) { basis[i] = this.evaluate(i, t); } return basis; } // De Casteljau tabanlı verimli hesaplama evaluateAllDeCasteljau(t) { const basis = new Array(this.degree + 1); const temp = new Array(this.degree + 1); // Initialize temp[0] = 1; for (let i = 1; i <= this.degree; i++) { temp[i] = 0; } // Compute using Pascal's triangle approach for (let level = 0; level <= this.degree; level++) { for (let i = level; i >= 0; i--) { if (i < level) { temp[i] = (1 - t) * temp[i] + t * temp[i + 1]; } else if (i === level) { temp[i] = t * temp[i]; } } basis[level] = temp[0]; // Shift for next level for (let i = this.degree; i >= 1; i--) { temp[i] = temp[i - 1]; } temp[0] = 0; } return basis; } // Türev hesaplama derivative() { if (this.degree === 0) return null; return new BernsteinBasis(this.degree - 1); } } // Kübik Bernstein baz fonksiyonları örneği const cubicBasis = new BernsteinBasis(3); // Çeşitli t değerleri için değerlendirme for (let t = 0; t <= 1; t += 0.25) { const basis = cubicBasis.evaluateAll(t); console.log(`t=${t}: B0=${basis[0].toFixed(3)}, B1=${basis[1].toFixed(3)}, B2=${basis[2].toFixed(3)}, B3=${basis[3].toFixed(3)}`); console.log(`Toplam: ${basis.reduce((sum, b) => sum + b, 0).toFixed(3)}`); // Her zaman 1.000 }
Bernstein Polinomlarının Geometrik Anlamı
Her Bernstein polinomu B_{i,n}(t), i'inci kontrol noktasının t parametresi için "ağırlığını" temsil eder. Bu ağırlıklar pozitif ve toplamları 1 olduğundan, Bézier eğrisi kontrol noktalarının konveks kombinasyonudur.
Derece Bernstein Polinomları Özel Durum 0 B₀,₀(t) = 1 Sabit fonksiyon 1 B₀,₁(t) = 1-t, B₁,₁(t) = t Lineer interpolasyon 2 B₀,₂=(1-t)², B₁,₂=2t(1-t), B₂,₂=t² Kuadratik form 3 B₀,₃=(1-t)³, B₁,₃=3t(1-t)², ... Kübik Bézier (en yaygın)
B_{i,n}(t) = (1-t)B_{i,n-1}(t) + tB_{i-1,n-1}(t)

Bu rekürsif ilişki, Bernstein polinomlarının verimli hesaplanmasını sağlar ve De Casteljau algoritmasının temelini oluşturur.

Sayısal Hassasiyet: Yüksek dereceli Bernstein polinomlarında, t≈0 veya t≈1 yakınlarında sayısal hassasiyet sorunları ortaya çıkabilir. Bu durumlar için özel algoritmalar gerekebilir.
Performans İpucu: Gerçek zamanlı uygulamalarda, binom katsayılarını önceden hesaplayıp saklayın. Ayrıca De Casteljau algoritması genellikle doğrudan Bernstein hesaplamalarından daha kararlıdır.

Bézier Eğrilerinin Özellikleri ve İnterpolasyon Yöntemleriyle İlişkileri

Bézier eğrileri, benzersiz matematiksel ve geometrik özellikleri sayesinde bilgisayar grafiklerinde ve CAD sistemlerinde yaygın kullanım alanı bulmuştur. Bu özellikler, tasarımcılara sezgisel kontrol ve öngörülebilir davranış sağlar.

Temel Geometrik Özellikler:
  • Afin değişmezlik: Koordinat dönüşümleri altında korunur
  • Konveks gövde özelliği: Eğri kontrol poligonunun dışına çıkmaz
  • Uç nokta interpolasyonu: B(0) = P₀, B(1) = Pₙ
  • Teğet özelliği: Uç noktalarda teğet kontrol kenarlarına paralel
  • Simetri: B(t) kontrol noktaları ters çevrildiğinde B(1-t) olur
Konveks Gövde Teoremi:
Bézier eğrisi B(t) her zaman kontrol noktalarının konveks gövdesi (convex hull) içinde kalır. Bu, eğrinin "şaşırmayacağı" ve kontrol poligonunun sınırları içinde davranacağı anlamına gelir.
Bézier Eğrilerinin Analizi:
1. Uç Nokta Analizi: B(0) = P₀, B(1) = Pₙ
2. Teğet Analizi: B'(0) = n(P₁ - P₀), B'(1) = n(Pₙ - Pₙ₋₁)
3. Eğrilik Analizi: İkinci türev B''(t) hesaplama
4. İnfleksiyon Noktaları: B''(t) = 0 çözümü
5. Konveks Hull Kontrolü: Tüm noktaların sınırlar içinde olması
class BezierAnalysis { constructor(controlPoints) { this.curve = new BezierCurve(controlPoints); this.controlPoints = controlPoints; this.degree = controlPoints.length - 1; } // Uç noktalar ve teğetler getEndpointProperties() { const startPoint = this.curve.evaluate(0); const endPoint = this.curve.evaluate(1); // Teğet vektörler (türev) const derivative = this.curve.derivative(); const startTangent = derivative.evaluate(0); const endTangent = derivative.evaluate(1); return { start: { point: startPoint, tangent: startTangent }, end: { point: endPoint, tangent: endTangent } }; } // Konveks gövde hesaplama computeConvexHull() { // Graham scan algoritması const points = [...this.controlPoints]; // En alt-sol noktayı bul let start = 0; for (let i = 1; i < points.length; i++) { if (points[i].y < points[start].y || (points[i].y === points[start].y && points[i].x < points[start].x)) { start = i; } } // Açısal sıralama [points[0], points[start]] = [points[start], points[0]]; points.slice(1).sort((a, b) => { const angleA = Math.atan2(a.y - points[0].y, a.x - points[0].x); const angleB = Math.atan2(b.y - points[0].y, b.x - points[0].x); return angleA - angleB; }); // Konveks gövde oluştur const hull = [points[0], points[1]]; for (let i = 2; i < points.length; i++) { while (hull.length > 1 && this.crossProduct(hull[hull.length-2], hull[hull.length-1], points[i]) <= 0) { hull.pop(); } hull.push(points[i]); } return hull; } crossProduct(O, A, B) { return (A.x - O.x) * (B.y - O.y) - (A.y - O.y) * (B.x - O.x); } // Eğri uzunluğu tahmin (adaptive quadrature) estimateArcLength(tolerance = 1e-6) { return this.adaptiveQuadrature(0, 1, tolerance); } adaptiveQuadrature(a, b, tolerance) { const c = (a + b) / 2; const fa = this.arcLengthIntegrand(a); const fb = this.arcLengthIntegrand(b); const fc = this.arcLengthIntegrand(c); const simpson1 = (b - a) * (fa + 4 * fc + fb) / 6; const fac = this.arcLengthIntegrand((a + c) / 2); const fcb = this.arcLengthIntegrand((c + b) / 2); const simpson2 = (c - a) * (fa + 4 * fac + fc) / 6 + (b - c) * (fc + 4 * fcb + fb) / 6; if (Math.abs(simpson2 - simpson1) < tolerance) { return simpson2; } else { return this.adaptiveQuadrature(a, c, tolerance / 2) + this.adaptiveQuadrature(c, b, tolerance / 2); } } arcLengthIntegrand(t) { const derivative = this.curve.derivative(); const tangent = derivative.evaluate(t); return Math.sqrt(tangent.x * tangent.x + tangent.y * tangent.y + tangent.z * tangent.z); } // Interpolasyon yöntemleriyle karşılaştırma compareWithInterpolation(points, method = 'lagrange') { let interpolatedCurve; switch(method) { case 'lagrange': interpolatedCurve = new LagrangeInterpolation(points); break; case 'hermite': interpolatedCurve = new HermiteInterpolation(points); break; case 'spline': interpolatedCurve = new CubicSpline(points); break; } // Comparison metrics const metrics = { bezier: { smoothness: 0, oscillation: 0, complexity: 'O(n)' }, interpolation: { smoothness: 0, oscillation: 0, complexity: 'O(n²)' } }; // Test points for comparison const testPoints = 100; for (let i = 0; i <= testPoints; i++) { const t = i / testPoints; const bezierPoint = this.curve.evaluate(t); const interpPoint = interpolatedCurve.evaluate(t); // Calculate curvature and oscillation metrics // ... detailed analysis implementation } return metrics; } }
Özellik Bézier Lagrange Hermite Spline Interpolasyon Sadece uç noktalar Tüm noktalar Noktalar + türevler Tüm noktalar Kontrol Sezgisel (poligon) Sınırlı Teğet kontrolü Lokal kontrol Süreklilik C∞ (tek segment) C∞ C¹ C² Kararlılık Mükemmel Runge problemi İyi Çok iyi Hesaplama O(n) O(n²) O(1) O(n³) kurulum + O(1)
Variation Diminishing Özelliği
Bézier eğrisi, herhangi bir düzlem ile kontrol poligonundan daha az veya eşit sayıda kesişim yapar. Bu özellik, eğrinin "salınım yapmayacağını" garanti eder ve tasarımda öngörülebilirlik sağlar.
Hibrit Yaklaşımlar: Karmaşık şekiller için Bézier segmentlerini spline'larla birleştiren hibrit yöntemler kullanılabilir. Bu, her yöntemin avantajlarını maksimize eder.
Yüksek Derece Uyarısı: 4. dereceden yüksek Bézier eğriler kontrol edilmesi zor olabilir. Çoğu pratik uygulamada kübik Bézier segmentleri zincirleme bağlanır.

Bézier Eğrilerinde Bölme Algoritması

De Casteljau bölme algoritması, bir Bézier eğrisini belirli bir parametrik değerde iki alt-eğriye bölen güçlü bir yöntemdir. Bu algoritma, eğri editing, collision detection ve adaptif rendering uygulamalarında kritik rol oynar.

De Casteljau Bölme Süreci:
1. t parametresinde bölme noktasını belirle
2. De Casteljau piramidini oluştur
3. Sol alt-eğri: Piramit sol kenarı kontrol noktaları
4. Sağ alt-eğri: Piramit sağ kenarı kontrol noktaları
5. Her iki alt-eğri aynı dereceyi korur
class BezierSubdivision { constructor(curve) { this.curve = curve; this.controlPoints = curve.controlPoints; this.degree = curve.degree; } // Ana bölme fonksiyonu subdivide(t) { const leftPoints = []; const rightPoints = []; // De Casteljau piramidi let currentLevel = [...this.controlPoints]; leftPoints.push(currentLevel[0]); // Sol kenar rightPoints.unshift(currentLevel[currentLevel.length - 1]); // Sağ kenar for (let level = 1; level <= this.degree; level++) { const nextLevel = []; for (let i = 0; i < currentLevel.length - 1; i++) { const interpolated = { x: (1 - t) * currentLevel[i].x + t * currentLevel[i + 1].x, y: (1 - t) * currentLevel[i].y + t * currentLevel[i + 1].y, z: (1 - t) * currentLevel[i].z + t * currentLevel[i + 1].z }; nextLevel.push(interpolated); } leftPoints.push(nextLevel[0]); rightPoints.unshift(nextLevel[nextLevel.length - 1]); currentLevel = nextLevel; } return { left: new BezierCurve(leftPoints), right: new BezierCurve(rightPoints), splitPoint: currentLevel[0] // Bölme noktası }; } // Çoklu bölme - parametrik değerler listesi multipleSubdivision(tValues) { // t değerlerini sırala const sortedT = [...tValues].sort((a, b) => a - b); let segments = [this.curve]; let currentOffset = 0; for (let i = 0; i < sortedT.length; i++) { const t = sortedT[i]; const adjustedT = (t - currentOffset) / (1 - currentOffset); // Son segmenti böl const lastSegment = segments[segments.length - 1]; const subdivision = new BezierSubdivision(lastSegment); const result = subdivision.subdivide(adjustedT); // Son segmenti değiştir ve yeni segmenti ekle segments[segments.length - 1] = result.left; segments.push(result.right); currentOffset = t; } return segments; } // Adaptif bölme - eğrilik tabanlı adaptiveSubdivision(maxCurvature = 0.1, minLength = 0.01) { return this.adaptiveSubdivisionRecursive(this.curve, maxCurvature, minLength); } adaptiveSubdivisionRecursive(curve, maxCurvature, minLength) { const segments = []; // Eğri uzunluğunu tahmin et const estimatedLength = this.estimateLength(curve); if (estimatedLength < minLength) { return [curve]; } // Maksimum eğrilik hesapla const maxCurv = this.calculateMaxCurvature(curve); if (maxCurv <= maxCurvature) { return [curve]; } // Orta noktada böl const subdivision = new BezierSubdivision(curve); const result = subdivision.subdivide(0.5); // Rekürsif alt-bölme const leftSegments = this.adaptiveSubdivisionRecursive( result.left, maxCurvature, minLength ); const rightSegments = this.adaptiveSubdivisionRecursive( result.right, maxCurvature, minLength ); return [...leftSegments, ...rightSegments]; } calculateMaxCurvature(curve) { let maxCurvature = 0; const samples = 20; const secondDerivative = curve.derivative().derivative(); if (!secondDerivative) return 0; for (let i = 0; i <= samples; i++) { const t = i / samples; const firstDeriv = curve.derivative().evaluate(t); const secondDeriv = secondDerivative.evaluate(t); // 2D eğrilik formülü: κ = |x'y'' - y'x''| / (x'² + y'²)^(3/2) const numerator = Math.abs( firstDeriv.x * secondDeriv.y - firstDeriv.y * secondDeriv.x ); const denominator = Math.pow( firstDeriv.x * firstDeriv.x + firstDeriv.y * firstDeriv.y, 1.5 ); if (denominator > 1e-10) { const curvature = numerator / denominator; maxCurvature = Math.max(maxCurvature, curvature); } } return maxCurvature; } estimateLength(curve) { // Basit kontrol poligon uzunluğu tahmini let length = 0; for (let i = 0; i < curve.controlPoints.length - 1; i++) { const p1 = curve.controlPoints[i]; const p2 = curve.controlPoints[i + 1]; length += Math.sqrt( (p2.x - p1.x) ** 2 + (p2.y - p1.y) ** 2 + (p2.z - p1.z) ** 2 ); } return length; } // Tolerans tabanlı düzleştirme flattenWithTolerance(tolerance = 0.1) { const points = []; this.flattenRecursive(this.curve, 0, 1, points, tolerance); return points; } flattenRecursive(curve, tStart, tEnd, points, tolerance) { const startPoint = curve.evaluate(0); const endPoint = curve.evaluate(1); const midPoint = curve.evaluate(0.5); // Lineer interpolasyon orta noktası const linearMid = { x: 0.5 * (startPoint.x + endPoint.x), y: 0.5 * (startPoint.y + endPoint.y), z: 0.5 * (startPoint.z + endPoint.z) }; // Sapma mesafesi const deviation = Math.sqrt( (midPoint.x - linearMid.x) ** 2 + (midPoint.y - linearMid.y) ** 2 + (midPoint.z - linearMid.z) ** 2 ); if (deviation <= tolerance) { // Yeterince düz - nokta ekle if (points.length === 0) { points.push({ ...startPoint, t: tStart }); } points.push({ ...endPoint, t: tEnd }); } else { // Böl ve rekürsif devam et const subdivision = new BezierSubdivision(curve); const result = subdivision.subdivide(0.5); const tMid = (tStart + tEnd) / 2; this.flattenRecursive(result.left, tStart, tMid, points, tolerance); this.flattenRecursive(result.right, tMid, tEnd, points, tolerance); } } } // Örnek kullanım const originalCurve = new BezierCurve([ { x: 0, y: 0, z: 0 }, { x: 1, y: 3, z: 0 }, { x: 3, y: 3, z: 1 }, { x: 4, y: 0, z: 0 } ]); const subdivider = new BezierSubdivision(originalCurve); // t=0.3'te böl const split = subdivider.subdivide(0.3); console.log("Sol eğri:", split.left.controlPoints); console.log("Sağ eğri:", split.right.controlPoints); // Çoklu bölme const multiSplit = subdivider.multipleSubdivision([0.25, 0.5, 0.75]); console.log("4 segmente bölündü:", multiSplit.length); // Adaptif bölme const adaptiveSegments = subdivider.adaptiveSubdivision(0.1, 0.1); console.log("Adaptif segmentler:", adaptiveSegments.length);
Bölme Algoritmasının Uygulama Alanları:
  • Collision Detection: Eğrilerin kesişim analizi
  • Adaptive Rendering: Eğrilik tabanlı tessellation
  • Curve Editing: Lokal değişiklikler için segmentasyon
  • Path Planning: Robotik ve animasyon yolları
  • Font Rendering: Karakter gliflerinin rasterizasyonu
Matematik Güzelliği
De Casteljau algoritması sadece sayısal bir yöntem değil, aynı zamanda geometrik bir yapıdır. Her bölme işlemi, orijinal eğrinin "fractal" yapısını korur ve alt-eğriler aynı matematiksel özellikleri sergiler.
Bölme Stratejisi Avantaj Dezavantaj Kullanım Uniform (Eşit) Basit implementasyon Gereksiz bölmeler Animasyon keyframes Adaptive (Adaptif) Optimal segment sayısı Karmaşık hesaplama Rendering, CAD Curvature-based Görsel kalite odaklı Eğrilik hesaplama maliyeti Grafik tasarım User-defined Tam kontrol Manuel müdahale gerekir İnteraktif editing
Performans İpucu: Gerçek zamanlı uygulamalarda, eğrilik tabanlı adaptif bölme yerine önceden hesaplanmış lookup tablolarını kullanmayı düşünün.
Sayısal Kararlılık: Çok küçük t değerlerinde (t < 1e-10) bölme işlemi sayısal hassasiyet sorunlarına yol açabilir. Bu durumlar için özel kontroller ekleyin.

Bézier Eğrilerinin Derece Yükseltilmesi

Derece yükseltme (degree elevation), bir Bézier eğrisinin aynı şeklini korurken daha yüksek dereceli bir eğriye dönüştürülmesi işlemidir. Bu process, eğri operations, boolean işlemleri ve format dönüşümleri için kritiktir.

P_i^{(n+1)} = \frac{i}{n+1} P_{i-1}^{(n)} + \frac{n+1-i}{n+1} P_i^{(n)}

Bu formülde P_i^{(n)} n-dereceli eğrinin i'inci kontrol noktası, P_i^{(n+1)} ise (n+1)-dereceli eğrinin yeni kontrol noktalarıdır.

Derece Yükseltme Algoritması:
1. Mevcut derece n'yi belirle
2. Yeni kontrol noktası sayısı: n+2
3. İlk nokta: P₀^(n+1) = P₀^(n)
4. Son nokta: P_{n+1}^(n+1) = P_n^(n)
5. Ara noktalar: Konveks kombinasyon formülü
class BezierDegreeElevation { constructor(curve) { this.originalCurve = curve; this.originalDegree = curve.degree; this.originalPoints = curve.controlPoints; } // Tek seviye derece yükseltme elevateByOne() { const n = this.originalDegree; const oldPoints = this.originalPoints; const newPoints = new Array(n + 2); // İlk nokta aynı kalır newPoints[0] = { ...oldPoints[0] }; // Ara noktalar - konveks kombinasyon for (let i = 1; i <= n; i++) { const alpha = i / (n + 1); const beta = (n + 1 - i) / (n + 1); newPoints[i] = { x: alpha * oldPoints[i - 1].x + beta * oldPoints[i].x, y: alpha * oldPoints[i - 1].y + beta * oldPoints[i].y, z: alpha * oldPoints[i - 1].z + beta * oldPoints[i].z }; } // Son nokta aynı kalır newPoints[n + 1] = { ...oldPoints[n] }; return new BezierCurve(newPoints); } // Çoklu derece yükseltme elevateByK(k) { let currentCurve = this.originalCurve; for (let step = 0; step < k; step++) { const elevator = new BezierDegreeElevation(currentCurve); currentCurve = elevator.elevateByOne(); } return currentCurve; } // Matris formunda derece yükseltme elevateByMatrix() { const n = this.originalDegree; const elevationMatrix = this.buildElevationMatrix(n); const newPoints = []; for (let i = 0; i <= n + 1; i++) { let newPoint = { x: 0, y: 0, z: 0 }; for (let j = 0; j <= n; j++) { const weight = elevationMatrix[i][j]; newPoint.x += weight * this.originalPoints[j].x; newPoint.y += weight * this.originalPoints[j].y; newPoint.z += weight * this.originalPoints[j].z; } newPoints.push(newPoint); } return new BezierCurve(newPoints); } buildElevationMatrix(n) { const matrix = []; for (let i = 0; i <= n + 1; i++) { const row = new Array(n + 1).fill(0); if (i === 0) { row[0] = 1; // İlk nokta } else if (i === n + 1) { row[n] = 1; // Son nokta } else { // Ara noktalar if (i - 1 >= 0) row[i - 1] = i / (n + 1); if (i < n + 1) row[i] = (n + 1 - i) / (n + 1); } matrix.push(row); } return matrix; } // Optimum derece bulma findOptimalDegree(targetPoints, tolerance = 1e-6) { let bestDegree = this.originalDegree; let bestError = Infinity; // Maksimum makul derece const maxDegree = Math.min(targetPoints.length - 1, this.originalDegree + 10); for (let degree = this.originalDegree; degree <= maxDegree; degree++) { const elevatedCurve = this.elevateByK(degree - this.originalDegree); const error = this.calculateFittingError(elevatedCurve, targetPoints); if (error < bestError) { bestError = error; bestDegree = degree; } if (error < tolerance) break; } return { degree: bestDegree, error: bestError }; } calculateFittingError(curve, targetPoints) { let totalError = 0; for (const target of targetPoints) { const curvePoint = curve.evaluate(target.t); const distance = Math.sqrt( (curvePoint.x - target.x) ** 2 + (curvePoint.y - target.y) ** 2 + (curvePoint.z - target.z) ** 2 ); totalError += distance * distance; } return Math.sqrt(totalError / targetPoints.length); } // Derece düşürme (yaklaşık) reduceDegree(targetDegree) { if (targetDegree >= this.originalDegree) { return this.originalCurve; // Derece zaten düşük } // Least squares yaklaşımı const sampleCount = 100; const samples = []; for (let i = 0; i <= sampleCount; i++) { const t = i / sampleCount; const point = this.originalCurve.evaluate(t); samples.push({ ...point, t }); } // Düşük dereceli eğri fit et return this.fitCurveToSamples(samples, targetDegree); } fitCurveToSamples(samples, degree) { // Simplified curve fitting - gerçek implementasyon daha karmaşık // Bu örnek temel yaklaşımı gösterir const n = degree; const controlPoints = new Array(n + 1); // Uç noktalar controlPoints[0] = { ...samples[0] }; controlPoints[n] = { ...samples[samples.length - 1] }; // Ara noktaları basit interpolasyonla tahmin et for (let i = 1; i < n; i++) { const ratio = i / n; const sampleIndex = Math.floor(ratio * (samples.length - 1)); controlPoints[i] = { ...samples[sampleIndex] }; } return new BezierCurve(controlPoints); } } // Örnek kullanım const originalCurve = new BezierCurve([ { x: 0, y: 0, z: 0 }, { x: 1, y: 2, z: 0 }, { x: 3, y: 1, z: 1 }, { x: 4, y: 0, z: 0 } ]); const elevator = new BezierDegreeElevation(originalCurve); // Kübik'ten kuartik'e yükselt const quarticCurve = elevator.elevateByOne(); console.log("Orijinal derece:", originalCurve.degree); // 3 console.log("Yeni derece:", quarticCurve.degree); // 4 // 2 derece birden yükselt const quinticCurve = elevator.elevateByK(2); console.log("2 seviye yükseltilmiş derece:", quinticCurve.degree); // 5 // Eğriler aynı şekle sahip olduğunu doğrula const t = 0.5; console.log("Orijinal t=0.5:", originalCurve.evaluate(t)); console.log("Yükseltilmiş t=0.5:", quarticCurve.evaluate(t));
Derece Yükseltmenin Matematiksel Temeli:
  • Shape Preservation: Eğrinin şekli tamamen korunur
  • Bernstein İlişkisi: B_{i,n}(t) = (1-t)B_{i,n+1}(t) + tB_{i-1,n+1}(t)
  • Control Point Convexity: Yeni noktalar mevcut noktaların konveks kombinasyonu
  • Invariant Properties: Afin değişmezlik ve konveks gövde özellikleri korunur
  • Reversibility: Teorik olarak (ama pratikte zor) geri çevrilebilir
Aspect Derece Yükseltme Derece Düşürme Hassasiyet Tam (kayıpsız) Yaklaşık (kayıplı) Hesaplama Basit, doğrudan Karmaşık, optimizasyon Kontrol noktası sayısı Artar Azalır Kullanım sebebi Format uyumu, işlemler Basitleştirme, optimizasyon Kararlılık Mükemmel Parametreye bağlı
Endüstriyel Uygulamalar
CAD Sistemleri: Farklı formatlarda curve exchange (IGES, STEP)
Font Teknolojisi: TrueType ↔ PostScript dönüşümleri
Animation Software: Keyframe interpolasyonu ve easing functions
3D Printing: Slice kalınlığına göre eğri basitleştirme
Performans Optimizasyonu: Çok yüksek dereceli eğrilerle çalışırken, rendering sırasında adaptif derece düşürme kullanarak performans artışı sağlayabilirsiniz.
Dikkat: Sürekli derece yükseltme kontrol noktası sayısını exponential artırır. Pratik uygulamalarda makul bir üst limit belirleyin.

B-Spline ve NURBS Eğrileri

B-Spline (Basis Spline) ve NURBS (Non-Uniform Rational B-Spline) eğrileri, modern CAD ve 3D modelleme sistemlerinin temel yapı taşlarıdır. Bézier eğrilerinin genelleştirilmiş halleri olarak, yerel kontrol ve esneklik avantajları sunarlar.

B-Spline Avantajları:
  • Yerel kontrol: Bir kontrol noktası sadece yakın bölgeyi etkiler
  • Uniform süreklilik: C^(k-1) süreklilik (k: derece)
  • Variation diminishing: Salınım azaltıcı özellik
  • Knot vector esnekliği: Parametrik kontrol
  • Efficient evaluation: De Boor algoritması
S(t) = \sum_{i=0}^{n} P_i \cdot N_{i,k}(t)

Burada N_{i,k}(t) k-dereceli B-spline baz fonksiyonları, P_i kontrol noktalarıdır.

De Boor Algoritması (B-Spline Evaluation):
1. Knot span belirle: t ∈ [u_j, u_{j+1}]
2. İlgili kontrol noktalarını seç: P_{j-k+1}, ..., P_j
3. Rekürsif hesaplama: k seviye
4. Her seviyede lineer interpolasyon
5. Final sonuç: S(t)
class BSplineCurve { constructor(controlPoints, degree, knotVector = null) { this.controlPoints = controlPoints; this.degree = degree; this.n = controlPoints.length - 1; // Son kontrol noktası indeksi // Knot vector otomatik oluştur (uniform/clamped) if (knotVector === null) { this.knotVector = this.createClampedKnotVector(); } else { this.knotVector = knotVector; } this.m = this.knotVector.length - 1; // Son knot indeksi } createClampedKnotVector() { const knots = []; const k = this.degree; const n = this.n; // Başlangıç: k+1 tane 0 for (let i = 0; i <= k; i++) { knots.push(0); } // Orta kısım: uniform spacing for (let i = 1; i < n - k + 1; i++) { knots.push(i / (n - k + 1)); } // Son: k+1 tane 1 for (let i = 0; i <= k; i++) { knots.push(1); } return knots; } // De Boor algoritması ile değerlendirme evaluate(t) { // Knot span bulma const span = this.findSpan(t); // De Boor algoritması const points = []; for (let i = 0; i <= this.degree; i++) { points.push({ ...this.controlPoints[span - this.degree + i] }); } for (let r = 1; r <= this.degree; r++) { for (let i = this.degree; i >= r; i--) { const alpha = this.calculateAlpha(span, i, r, t); points[i] = { x: (1 - alpha) * points[i-1].x + alpha * points[i].x, y: (1 - alpha) * points[i-1].y + alpha * points[i].y, z: (1 - alpha) * points[i-1].z + alpha * points[i].z }; } } return points[this.degree]; } findSpan(t) { const n = this.n; const k = this.degree; // Edge cases if (t >= this.knotVector[n + 1]) return n; if (t <= this.knotVector[k]) return k; // Binary search let low = k; let high = n + 1; let mid = Math.floor((low + high) / 2); while (t < this.knotVector[mid] || t >= this.knotVector[mid + 1]) { if (t < this.knotVector[mid]) { high = mid; } else { low = mid; } mid = Math.floor((low + high) / 2); } return mid; } calculateAlpha(span, i, r, t) { const u = this.knotVector; const denominator = u[span + i - r + 1] - u[span + i - this.degree]; if (Math.abs(denominator) < 1e-10) return 0; return (t - u[span + i - this.degree]) / denominator; } // B-spline baz fonksiyonu hesaplama (Cox-de Boor formula) basisFunction(i, k, t) { const u = this.knotVector; if (k === 0) { return (u[i] <= t && t < u[i + 1]) ? 1 : 0; } let left = 0, right = 0; if (u[i + k] !== u[i]) { left = (t - u[i]) / (u[i + k] - u[i]) * this.basisFunction(i, k - 1, t); } if (u[i + k + 1] !== u[i + 1]) { right = (u[i + k + 1] - t) / (u[i + k + 1] - u[i + 1]) * this.basisFunction(i + 1, k - 1, t); } return left + right; } // Türev hesaplama derivative(order = 1) { if (order <= 0) return this; if (order > this.degree) return null; const newDegree = this.degree - order; const newControlPoints = []; // Recursive türev hesaplama let currentPoints = [...this.controlPoints]; let currentKnots = [...this.knotVector]; let currentDegree = this.degree; for (let derivOrder = 1; derivOrder <= order; derivOrder++) { const tempPoints = []; for (let i = 0; i <= this.n - derivOrder; i++) { const denominator = currentKnots[i + currentDegree + 1] - currentKnots[i + derivOrder]; if (Math.abs(denominator) > 1e-10) { const factor = currentDegree / denominator; tempPoints.push({ x: factor * (currentPoints[i + 1].x - currentPoints[i].x), y: factor * (currentPoints[i + 1].y - currentPoints[i].y), z: factor * (currentPoints[i + 1].z - currentPoints[i].z) }); } else { tempPoints.push({ x: 0, y: 0, z: 0 }); } } currentPoints = tempPoints; currentDegree -= 1; } return new BSplineCurve(currentPoints, newDegree, this.knotVector.slice(order, -order)); } } // NURBS Curve (Rational B-Spline) class NURBSCurve extends BSplineCurve { constructor(controlPoints, degree, weights, knotVector = null) { super(controlPoints, degree, knotVector); this.weights = weights || new Array(controlPoints.length).fill(1); } evaluate(t) { // Homojen koordinatlar const homogeneousPoints = this.controlPoints.map((point, i) => ({ x: point.x * this.weights[i], y: point.y * this.weights[i], z: point.z * this.weights[i], w: this.weights[i] })); // B-spline evaluation with homogeneous coordinates const tempCurve = new BSplineCurve(homogeneousPoints, this.degree, this.knotVector); const homogeneousResult = tempCurve.evaluate(t); // Perspective division if (Math.abs(homogeneousResult.w) < 1e-10) { throw new Error("Division by zero in NURBS evaluation"); } return { x: homogeneousResult.x / homogeneousResult.w, y: homogeneousResult.y / homogeneousResult.w, z: homogeneousResult.z / homogeneousResult.w }; } // Ağırlık değiştirme setWeight(index, weight) { if (index >= 0 && index < this.weights.length) { this.weights[index] = weight; } } // Rasyonel eğri özellikleri isRational() { return !this.weights.every(w => Math.abs(w - 1) < 1e-10); } // Perspektif projektif dönüşümler applyProjectiveTransform(matrix4x4) { // 4x4 homojen transformation matrix const newPoints = []; const newWeights = []; for (let i = 0; i < this.controlPoints.length; i++) { const p = this.controlPoints[i]; const w = this.weights[i]; // Homojen koordinatlara çevir const homogeneous = [p.x * w, p.y * w, p.z * w, w]; // Matrix çarpımı const transformed = [0, 0, 0, 0]; for (let row = 0; row < 4; row++) { for (let col = 0; col < 4; col++) { transformed[row] += matrix4x4[row][col] * homogeneous[col]; } } // Geri dönüştür newWeights.push(transformed[3]); if (Math.abs(transformed[3]) > 1e-10) { newPoints.push({ x: transformed[0] / transformed[3], y: transformed[1] / transformed[3], z: transformed[2] / transformed[3] }); } else { newPoints.push({ x: 0, y: 0, z: 0 }); } } return new NURBSCurve(newPoints, this.degree, newWeights, this.knotVector); } } // Örnek kullanım const bsplinePoints = [ { x: 0, y: 0, z: 0 }, { x: 1, y: 2, z: 0 }, { x: 3, y: 3, z: 1 }, { x: 5, y: 1, z: 1 }, { x: 6, y: 0, z: 0 } ]; // Kübik B-spline const bspline = new BSplineCurve(bsplinePoints, 3); console.log("B-spline t=0.5:", bspline.evaluate(0.5)); // NURBS eğri (ağırlıklı) const weights = [1, 2, 1, 2, 1]; // Orta noktalar daha ağırlıklı const nurbs = new NURBSCurve(bsplinePoints, 3, weights); console.log("NURBS t=0.5:", nurbs.evaluate(0.5)); // Türev hesaplama const derivative = bspline.derivative(1); console.log("B-spline türev t=0.5:", derivative.evaluate(0.5));
Özellik Bézier B-Spline NURBS Kontrol türü Global Yerel Yerel + ağırlıklı Interpolasyon Sadece uç noktalar Hiçbiri (genel) Hiçbiri (genel) Geometrik dönüşümler Afin Afin Projektif Konik kesitler Yaklaşık Yaklaşık Tam Endüstriyel kullanım Grafik tasarım CAD/CAM Havacılık, otomotiv
NURBS'ün Gücü
NURBS, çember, elips, hiperbol ve parabeller gibi konik kesitleri tam olarak temsil edebilen tek eğri türüdür. Bu özellik, havacılık ve otomotiv endüstrilerinde kritik öneme sahiptir.
Knot Vector Stratejileri:
• Uniform: Eşit aralıklı knot'lar
• Non-uniform: Değişken aralıklı knot'lar
• Clamped: Uç noktalarda çokluk
• Periodic: Döngüsel eğriler için
• Adaptive: Eğrilik tabanlı knot yerleştirme
Performans İpucu: Gerçek zamanlı uygulamalarda knot span bulma işlemini optimize etmek için binary search yerine lookup table kullanabilirsiniz.
NURBS Dikkat: Ağırlık değerleri sıfıra yaklaştığında sayısal kararsızlık oluşabilir. Minimum ağırlık threshold'u belirleyin.

Geometrik Modelleme Yolculuğunuzun Başlangıcı

Bu kapsamlı rehberde uygulamalı geometrinin temel yapı taşlarını keşfettiniz. Afin uzaylardan NURBS eğrilerine kadar uzanan bu yolculuk, modern bilgisayar grafiklerinin ve CAD sistemlerinin matematiksel temellerini ortaya koymuştur.

Yöntem Karmaşıklık Esneklik Uygulama Alanı Lineer İnterpolasyon ⭐ ⭐ Basit animasyonlar Polinom İnterpolasyon ⭐⭐ ⭐⭐ Bilimsel modelleme Hermite Eğrileri ⭐⭐⭐ ⭐⭐⭐ Animasyon yolları Spline Eğrileri ⭐⭐⭐⭐ ⭐⭐⭐⭐ CAD tasarım Bézier Eğrileri ⭐⭐⭐ ⭐⭐⭐⭐ Grafik tasarım NURBS ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ Endüstriyel tasarım
Sonraki Adımlar
Yüzey Modelleme: Bézier yüzeyleri, B-spline yüzeyleri, NURBS yüzeyleri
Solid Modelleme: Boolean işlemler, CSG, boundary representation
Mesh İşleme: Subdivision surfaces, mesh smoothing, remeshing
Diferansiyel Geometri: Eğrilik analizi, geodezikler, minimal yüzeyler
Hesaplamalı Geometri: Voronoi diyagramları, Delaunay triangulation

"Geometri = Sanat + Matematik + Mühendislik"

- Modern tasarımın evrensel dili