2 puan yazan GN⁺ 2024-12-19 | 1 yorum | WhatsApp'ta paylaş
  • Schemio’da şekilleri hiyerarşik hale getirme ve birbirine bağlama özellikleri arttıkça yerel koordinatlarla dünya koordinatları arasındaki dönüşüm editörün temel sorunu haline geldi
  • Üst öğe zinciri boyunca formülleri doğrudan uygulayan ilk yaklaşım, ölçekleme ve pivot noktası devreye girince bakımı zorlaştı
  • Taşıma, döndürme ve ölçeklemeyi 3×3 dönüşüm matrisi ile birleştirince birden çok dönüşüm tek bir dönüşümde bileştirilebilir ve hiyerarşik yapının birikimli dönüşümü de tutarlı biçimde hesaplanabilir
  • Dünya koordinatlarını nesneye göre koordinatlara geri çevirirken, tıklama konumu veya bağlayıcı bağlantı noktasını doğru bulmak için toplam dönüşüm matrisinin ters matrisi A⁻¹ kullanılır
  • Bir nesneyi başka bir üst öğeye mount ederken veya unmount ederken, ekrandaki konum ve dönüşü koruyacak şekilde yeni yerel değerler yeniden hesaplanmalıdır; böylece zıplama hareketleri önlenir

Schemio hiyerarşik editöre dönüşürken ortaya çıkan sorun

  • Schemio, şekil oluşturma, taşıma, yeniden boyutlandırma ve döndürmeyi destekleyen interaktif bir diyagram editörü olarak başladı
  • Her şeklin x, y, w, h, r değerlerinden oluşan bir area yapısı vardır
    • x, y: dünya koordinatlarına göre konum
    • w, h: genişlik ve yükseklik
    • r: dönüş açısı
  • Şekilleri birbirine bağlamak ve karmaşık etkileşimler oluşturmak için her nesneye childItems dizisi eklendi ve öğe hiyerarşisi getirildi
  • Yaygın vektör grafik editörlerindeki grup özelliğinde olduğu gibi, bir nesne hareket ettirildiğinde bağlı nesneler de birlikte hareket edebilir; ancak Schemio, diyagram editörü ile oyun motorunun karışımı gibi animasyonları ve kullanıcı tanımlı davranışları hedefler

SVG render’ı tek başına koordinat hesaplamasını çözmez

  • SVG’de öğeler iç içe yerleştirildiğinde tarayıcı, üst ve alt öğe dönüşümlerini render aşamasında işleyebilir
  • Schemio’nun render dışında bağlayıcı bağlantıları, nesne mount/unmount işlemleri ve kullanıcı tanımlı etkileşimleri de doğrudan hesaplaması gerekir
  • Bu özellikler için nesnenin yerel koordinatları ile tüm sahnenin dünya koordinatları arasında gidip gelen dönüşümlere ihtiyaç vardır
  • Başlangıçta üst öğe zinciri dolaşılarak basit formüllerle dönüşümler uygulanıyor, daha sonra üst öğe dönüşümleri önbelleğe alınarak optimize ediliyordu
  • Ölçekleme ve pivot noktası eklenince, yalnızca taşıma ve döndürmeyi varsayan formül kombinasyonları sınırlarına ulaştı

Ölçekleme ve pivot noktasının artırdığı karmaşıklık

  • Ölçekleme, nesne boyutunu dinamik olarak ayarlama özelliğidir ve Schemio’da harici diyagramları dinamik olarak yüklemede önemli bir rol oynar
  • Pivot noktası, nesnenin dönüş merkezini tanımlar
  • Nesnenin area yapısına dört özellik eklendi
    • px, py: genişlik ve yüksekliğe göreli pivot noktası
    • sx, sy: x ekseni ve y ekseni yönündeki ölçekleme katsayıları
  • Pivot noktasını göreli değer olarak tutmak, kullanıcı şeklin boyutunu değiştirdiğinde pivotun da birlikte ayarlanmasını sağlar
  • Taşıma, döndürme, ölçekleme ve pivot düzeltmesini doğrudan birleştirme yaklaşımı, gereksinimler arttıkça yönetmesi zor hale geldi

2D dönüşümleri matrislerle birleştirmek

  • 2D ve 3D grafiklerde taşıma, döndürme ve ölçekleme işlemlerinin tümü matris ile ifade edilebilir
  • 2D nokta 3×1 matris olarak, dönüşüm ise 3×3 matris olarak ele alınır
  • 3×3 dönüşüm matrisi ile 3×1 nokta matrisi çarpıldığında dönüştürülmüş 3×1 nokta elde edilir
  • Temel dönüşüm matrisleri şu şekilde ayrılır
    • Birim matris: Hiçbir dönüşüm yapmaz
    • Taşıma matrisi: Konumu taşır
    • Döndürme matrisi: Açıya göre döndürür
    • Ölçekleme matrisi: Boyutu ayarlar
  • Birden fazla dönüşüm birleştirilirken dönüşüm matrisleri çarpılarak tek bir dönüşümde birleştirilir

Hiyerarşik yapıda dönüşümleri biriktirme yöntemi

  • Bir nesnenin nihai dönüşümü yalnızca kendi dönüşümünü değil, üst nesnelerin dönüşümlerini de içerir
  • Hiyerarşi boyunca ilerleyip her nesnenin dönüşüm matrisini çarparak geçerli nesnenin toplam dönüşüm matrisi oluşturulabilir
  • Geçerli nesnenin dönüşüm matrisi Ai, üst nesnenin dönüşüm matrisi A(i-1) olarak alınırsa hiyerarşik dönüşüm, üst öğe dönüşümü ile geçerli nesne dönüşümünün çarpımı olarak birikir
  • Toplam formülde nesneyi pivot noktasına göre taşımak, döndürme ve ölçeklemeyi uygulamak, ardından tekrar geri taşımak sırası önemlidir
  • Pivot dikkate alınmazsa nesne seçilen pivotun değil, sol üst köşenin etrafında dönüyormuş gibi görünür
  • Pivot düzeltmesi, ölçekleme matrisi sonrasında uygulanmalıdır ki ölçekleme de pivot noktası temel alınarak gerçekleşiyormuş gibi görünsün

Dünya koordinatları ile yerel koordinatlar arasında hesaplama

  • Yerel koordinatlardan dünya koordinatlarına geçerken toplam dönüşüm matrisi noktayla çarpılır
  • Tersine, dünya koordinatlarını nesnenin yerel koordinatlarına çevirmek için toplam dönüşüm matrisinin ters matrisi kullanılır
  • Toplam dönüşüm A matrisi olarak paketlenirse dünya noktası, A ile yerel noktanın çarpımı olarak ifade edilir
  • Matris bölmesi yoktur; ancak A⁻¹ soldan çarpıldığında A⁻¹A birim matris olur ve yerel nokta elde edilir
  • Bu dönüşüm, kullanıcının dönüştürülmüş bir nesne üzerinde tıkladığı noktayı nesnenin sol üst köşesine göre koordinat olarak bulmak veya bağlayıcıyı doğru konuma tutturmak için gereklidir

Mount ve unmount sırasında konumu korumak

  • Hiyerarşi özelliğindeki zor problemlerden biri nesnenin mount ve unmount edilmesiydi
  • Bir nesneyi başka bir nesneye bağlamanın iki yolu vardır
    • Sahnede nesneyi sürükleyip başka bir nesnenin üzerine bırakmak
    • Item Selector panelinde hiyerarşiyi yeniden düzenlemek
  • Yalnızca hiyerarşi değiştirilirse nesnenin konumu yeni üst öğenin koordinatlarına göre yorumlanır ve ekranda yukarı-aşağı zıplama sorunu ortaya çıkar
  • Bunu önlemek için sürüklenen nesnenin yeni konumu ve dönüşü yeniden hesaplanmalıdır
  • 1. adım: Mevcut dünya konumunu kaydetme

    • Önce taşımadan önce nesnenin sol üst köşesinin dünya konumu kaydedilir
    • Örnek kodda nesnenin sol üst dünya koordinatı worldPointOnItem(0, 0, item) ile bulunur
    • worldPointOnItem, daha önce türetilen matris dönüşümü formülü kullanılarak uygulanır
  • 2. adım: Dönüş düzeltmesi

    • Nesnenin dönüşü üst öğeye göre tanımlandığından, üst öğe değiştiğinde sürüklenen nesnenin dönüşü de düzeltilmelidir
    • worldAngleOfItem fonksiyonu nesnenin sol üst ve sağ üst köşelerini dünya koordinatlarına dönüştürdükten sonra, nesnenin yerel x ekseninin dünya x ekseniyle yaptığı açıyı hesaplar
    • Önceki üst öğenin dünya dönüş açısı ile yeni üst öğenin dünya dönüş açısı karşılaştırılarak nesne dönüşü ayarlanır
    • item.area.r += previousParentWorldAngle - newParentWorldAngle
    • Bu hesaplama, üst öğe değişse bile nesnenin ekrandaki dönüşünün korunmasını sağlar
  • 3. adım: Konumu koruma

    • Nesne yeni üst öğenin altına taşındıktan sonra da ekranda aynı konumda kalacak şekilde yeni yerel koordinatlar hesaplanmalıdır
    • findTranslationMatchingWorldPoint fonksiyonu, belirli bir yerel noktanın istenen dünya noktasına denk gelmesi için gereken taşıma değerlerini hesaplar
    • Hesaplanan sonuç varsa nesnenin area.x, area.y değerleri yeni değerlerle güncellenir
    • Bu yöntemle nesne başka bir nesneye sürüklenerek hiyerarşi değiştirilse bile ekrandaki konumu korunur

Ters matrisle yeni taşıma değerini bulmak

  • Yeni taşıma değerini bulma problemi, dünya noktası Pw ve yerel nokta PL verildiğinde nesnenin taşıma matrisi At değerini bulma problemidir
  • Zaten bilinen üst öğe dönüşümü, pivot, döndürme ve ölçekleme matrisleri tek bir A matrisi altında toplanabilir
  • Üst öğe dönüşüm matrisinin tersi kullanılarak denklem düzenlenir; ancak 3×1 matris kare matris olmadığından aynı şekilde ters matris uygulanamaz
  • Bunun yerine determinant açılarak gerekli x, y taşıma bileşenleri ayrıştırılır
  • Bu hesaplama uygulandığında, sürüklenen nesne yeni üst öğeye taşınırken konumu ve dönüşü doğal şekilde korunur; tuhaf zıplamalar veya bozulmalar önlenebilir

Kod ve demo

  • Schemio uygulaması GitHub deposu ishubin/schemio üzerinden incelenebilir
  • Doğrudan kullanmak için schem.io üzerinde interaktif diyagramlar veya uygulama prototipleri oluşturabilirsiniz
  • Schemio’da matris dönüşümlerinin yanı sıra Bézier eğrileri, diferansiyel hesap ve performans optimizasyonu için quadtrees gibi başka matematiksel konular da vardır

1 yorum

 
GN⁺ 2024-12-19
Hacker News yorumları
  • Schemio’yu ilk kez duyuyorum, harika görünüyor: https://schem.io/
    Görünümü ve kullanımı oldukça pürüzsüz; çok öne çıkarmıyorlar ama açık kaynak: https://github.com/ishubin/schemio

    • Schemio, https://schem.io sitesinin backend kısmı hariç açık kaynak olarak yayımlanmış
      Frontend kodu tamamen açık ve kendi sunucunuzu da barındırabiliyorsunuz. Ancak bu durumda depolama olarak yalnızca dosya sistemi kullanıldığı için veritabanı ya da kullanıcı yönetimi yok
    • Daha ayrıntılı diyagramlara yakınlaşıp sonra kolayca tekrar uzaklaşabilme biçimini sevdim
      Obsidian’da istediğim özellik buydu, ama Schemio kadar pürüzsüz değildi
  • Dönüşüm matrisleri 1980’lerde Adobe PostScript tarafından popülerleştirildi; SVG de PostScript’in görüntüleme modelinden çok şey ödünç aldı
    PostScript’te 2D matris kullanımına aşağıdaki kaynaklardan bakılabilir
    https://personal.math.ubc.ca/~cass/graphics/text/old.pdf/las...
    https://scientificgems.wordpress.com/2014/11/28/mathematics-...

    • Adobe’nin popülerleştirdiğini söylemek zor; dönüşüm matrisleri zaten cebirde öğrenilen bir konu değil mi diye düşünüyorum
  • Homojen koordinatlara da bakmak iyi olabilir: https://en.wikipedia.org/wiki/Homogeneous_coordinates

    • Yazının yazarı olarak öneri için teşekkürler
      Vakit bulunca mutlaka okuyacağım; hızlıca göz attığımda, kullandığım dönüşüm matrisleriyle ilgili bir bölüm de var gibi görünüyor
  • Editörü oluşturma sürecini iyi özetlemiş; lineer cebir özeti olarak da güzel
    Ama zaten tüm editörler lineer cebir kullanmıyor mu?

    • Teknik olarak tüm grafik editörlerinin çeşitli amaçlar için lineer cebire dayandığı söylenebilir
      Ancak bunu ilk kez geliştiren biri için tüm sorunlar apaçık görünmeyebiliyor; bu yüzden matematik açısından yaşadığım zorlukları paylaşmak istedim. Zaten lineer cebir kullanıyordum, ama matrislerin hesaplamayı ne kadar basitleştirdiği asıl noktaydı
      Ayrıca SVG rendering’e dayanırsanız ilgili matematiği derinlemesine düşünmeden yalnızca kodla da ilerleyebilirsiniz. Örneğin nesne hiyerarşisi getirmemiş olsaydım matematiği neredeyse hiç dert etmem gerekmezdi. SVG tüm dönüşümleri hallederdi; matrislerin var olduğunu ya da SVG nesnelerine 1:1 uygulanabildiğini bilmeniz bile gerekmezdi. Hiyerarşisiz nesne sürüklemek de çok daha kolay olurdu; SVG transform özniteliğindeki translate(x,y) değerini değiştirmeniz yeterdi
  • QGraphicsView framework’üne bakmaya değer: https://doc.qt.io/qt-6/graphicsview.html
    Kullandığım grafik framework’leri arasında en güçlülerden biri. Nesne hiyerarşisini de içeren sahne-nesne dönüşümlerinin yanı sıra, karmaşık ve etkileşimli sahneleri render etmek için birçok güçlü araç sunuyor
    Ne yazık ki web’de QGVF kadar iyi çalışan bir alternatif bulamadım

  • Schemio iyi görünüyor
    Claude ile çok sayıda akış diyagramı oluşturuyorum; Claude çıktıyı Mermaidjs olarak veriyor ve tarayıcıda render ediyorum. Akıştan sekansa yakınlaşıp uzaklaşma özelliği daha iyi göründüğü için Schemio ile de benzer bir şey denemek istiyorum

  • 2D öteleme için 3x3 homojen matris kullanınca, 2D ötelemenin aslında z = 1 düzlemi boyunca ilerleyen bir 3D kesme olması çok hoş
    https://youtu.be/AheaTd_l5Is?t=263

  • Bununla ilgili olarak https://webglfundamentals.org/webgl/lessons/webgl-scene-grap... ve genel olarak https://webglfundamentals.org okunmaya değer; dönüşüm hiyerarşisi için de sağlam bir giriş niteliğinde

  • Hem yazı hem yazılım çok ilginç
    Kişisel olarak diyagramlar için sağlam bir açık kaynak yazılım arıyordum; nedense Schemio daha önce radarımda hiç belirmemişti
    Dönüşümler ve animasyonlar için lineer cebir yerine geometrik cebir kullanmanın daha sezgisel olabileceğini de hissediyorum
    [1] Projective Geometric Algebra:
    https://projectivegeometricalgebra.org/

  • Çok sayıda çocuğu olan bir nesneyi hareket ettirince, her kare arasında tüm çocukların A(i-1) terimini güncellemek ve bunu torunlara doğru yinelemeli olarak indirmek gerekecek; maliyeti artmaz mı diye merak ediyorum
    Yoksa makul boyuttaki şekillerde pek kötü değil mi?

    • Herhangi bir üst nesnenin hareketinde, altındaki tüm çocukların dönüşüm matrisleri her seferinde güncellenmek zorunda
      Yine de şimdiye kadar belirgin bir performans düşüşü yok. Şu anda yalnızca gerekirse diye hesaplama yapılıyor; gerçek SVG öğelerini etkilemediği için SVG öğelerini güncellemek gerekmiyor. Bu dönüşüm matrislerini yeniden hesaplamamızın nedeni, bağlı konektörleri yeniden ayarlarken ya da konum tabanlı mantığı işlerken belirli bir nesnenin yerel-dünya koordinatlarını bilmeye ihtiyaç duyulabilmesi