Cebirsel eğri çizici


14

Bir cebirsel eğri, {(x,y) in R^2 : f(x,y)=0 }bir polinomun sıfırları kümesi olarak tanımlanabilen "2D-düzlemi" nin belirli bir "1D altkümesidir" f. Burada 2D düzlemi gerçek düzlem olarak R^2görüyoruz, böylece böyle bir eğrinin neye benzeyebileceğini kolayca tahmin edebiliyoruz, temel olarak bir kalemle çizebileceğiniz bir şey.

Örnekler:

  • 0 = x^2 + y^2 -1 yarıçapı bir daire 1
  • 0 = x^2 + 2y^2 -1 bir elips
  • 0 = xy bir çapraz şekil, temel olarak x ekseni ve y ekseninin birleşimi
  • 0 = y^2 - x bir parabol
  • 0 = y^2 - (x^3 - x + 1)bir eliptik eğri
  • 0 = x^3 + y^3 - 3xy Descartes folium
  • 0 = x^4 - (x^2 - y^2) bir lemniskate
  • 0 = (x^2 + y^2)^2 - (x^3 - 3xy^2) üç yapraklı
  • 0 = (x^2 + y^2 - 1)^3 + 27x^2y^2 bir astroid

Görev

Bir polinom f(aşağıda tanımlandığı gibi) ve x / y aralıkları verildiğinde, eğriyi beyaz bir arka plan üzerinde siyah çizgi olarak gösteren en az 100x100 piksellik siyah beyaz bir görüntü elde edin.

ayrıntılar

Renk : Seçtiğiniz diğer iki rengi kullanabilirsiniz, bunları ayırmak kolay olmalıdır.

Çizim : Bir piksel görüntüsü yerine bu görüntüyü "ascii-art" olarak da çıktılandırabilirsiniz, burada "pikseller" arka planı boşluk / alt çizgi veya "boş görünen" başka bir karakter olmalıdır ve çizgi, " dolu "gibi Mveya Xveya #.

Takma ad konusunda endişelenmenize gerek yok.

Sadece polinomun işaretinin çizginin bir tarafından diğer tarafa değiştiği çizgileri çizmeniz yeterlidir (yani yürüyen kare algoritmasını kullanabileceğiniz anlamına gelir), 0 = x^2işaretin olduğu gibi patolojik vakaları doğru bir şekilde çizmeniz gerekmez. değil diğer hattın bir taraftan giderken değişir. Ama çizgi sürekli ve farklı işaretlerin bölgelerini ayıran olmalıdır f(x,y).

Polinom : Polinom(m+1) x (n+1) (gerçek) katsayıların bir matrisi / liste listesi olarak verilir , aşağıdaki örnekte katsayıların terimleri konumlarında verilmiştir:

[   1 * 1,   1 * x,   1 * x^2,   1 * x^3,  ... , 1 * x^n ]
[   y * 1,   y * x,   y * x^2,   y * x^4,  ... , y * x^n ]
[   ...  ,   ...   ,   ...   ,    ...   ,  ... ,   ...   ]
[ y^m * 1, y^m * x, y^m * x^2, y^m * x^3 , ..., y^m * x^n]

İsterseniz, matrisin kare olduğunu varsayabilirsiniz (bu her zaman gerekli sıfır dolgusu ile yapılabilir) ve isterseniz, matris boyutunun ek girdiler olarak verildiğini varsayabilirsiniz.

Aşağıda, yukarıdaki örnekler bu şekilde tanımlanan bir matris olarak temsil edilmektedir:

Circle:       Ellipse:      Parabola:  Cross:    Elliptic Curve: e.t.c
[-1, 0, 1]    [-1, 0, 1]    [ 0,-1]    [ 0, 0]   [-1, 1, 0,-1]
[ 0, 0, 0]    [ 0, 0, 0]    [ 0, 0]    [ 0, 1]   [ 0, 0, 0, 0]
[ 1, 0, 0]    [ 2, 0, 0]    [ 1, 0]              [ 1, 0, 0, 0]

X-aralığı / y-aralığı olan test senaryoları:

(Burada okunaklı olmayan ancak daha iyi kopyala yapıştırma özelliğine sahip bir formatta macunda mevcuttur .)

Circle:     
[-1, 0, 1]   [-2,2]   [-2,2]
[ 0, 0, 0]
[ 1, 0, 0]

Ellipse:
[-1, 0, 1]   [-2,2]   [-1,1]
[ 0, 0, 0]
[ 2, 0, 0]

Cross:
[ 0, 0]      [-1,2]   [-2,1]
[ 0, 1]

Parabola:
[ 0,-1]      [-1,3]   [-2,2]
[ 0, 0]
[ 1, 0]

Elliptic Curve:
[-1, 1, 0,-1]    [-2,2]   [-3,3]
[ 0, 0, 0, 0]  
[ 1, 0, 0, 0]  

Folium of Descartes:
[  0,  0,  0,  1]    [-3,3]   [-3,3]
[  0, -3,  0,  0]
[  0,  0,  0,  0]
[  1,  0,  0,  0]

Lemniscate:
[  0,  0, -1,  0,  1]    [-2,2]   [-1,1]
[  0,  0,  0,  0,  0]
[  1,  0,  0,  0,  0]

Trifolium:
[ 0, 0, 0,-1, 1]    [-1,1]   [-1,1]
[ 0, 0, 0, 0, 0]
[ 0, 3, 2, 0, 0]
[ 0, 0, 0, 0, 0]
[ 1, 0, 0, 0, 0]

Astroid:
[ -1,  0,  3,  0, -3,  0,  1]    [-1,1]   [-1,1]
[  0,  0,  0,  0,  0,  0,  0]
[  3,  0, 21,  0,  3,  0,  0]
[  0,  0,  0,  0,  0,  0,  0]
[ -3,  0,  3,  0,  0,  0,  0]
[  0,  0,  0,  0,  0,  0,  0]
[  1,  0,  0,  0,  0,  0,  0]

Bu pdf'den bazı eğriler için ilham aldım .


" Takma ad konusunda endişelenmenize gerek yok " demek, her pikseli, merkezinin çizginin üzerinde olup olmadığına göre renklendirebileceğimiz anlamına mı geliyor?
Peter Taylor

Takma adla bağlantıyı görmüyorum. Ancak hayır, farklı işaretlerin bölgelerini ayıran sürekli bir çizgi olmalıdır.
flawr

Matris mx ndeğil (m+1)x'dir (n+1). Girdi olarak ne alıyoruz:, m, nveya m+1,n+1? Yoksa seçebilir miyiz?
Luis Mendo

Grafik fonksiyonunu yeni bir pencerede gösterebilir miyiz?
R. Kap

1
@LuisMendo Evet, eksen istediğiniz herhangi bir yönde olabilir. (Dikey oldukları sürece =)
Kusur

Yanıtlar:


10

Haskell, 283275 bayt

Fonksiyon gmatris ve iki aralık ile argüman olarak çağrılmalıdır. Matris sadece bir liste listesidir, aralıklar her biri iki elemanlı bir listedir.

import Data.List
t=transpose
u=tail
z=zipWith
l%x=sum$z(*)l$iterate(*x)1                                   --generate powers and multiply with coefficients
e m y x=[l%x|l<-m]%y                                         --evaluate the encoded polynomial
a#b=[a,a+(b-a)/102..b]                                       --create a range
g m[u,w][i,j]=unlines$v[map((0<).e m y)$u#w|y<-i#j]          --evaluate the function on the grid, get the sign
f g=u[u$u$map fst$scanl(\(r,l)c->(c==l,c))(1<0,1<0) l|l<-g]  --find +- or -+ transitions within lines
a&b|a&&b=' '|0<1='#'                                         --helper function for creating the string
v g=z(z(&))(f g)(t$f$t g)                                    --create the string

Burada daha ilginç durumlar için çıktılar: 100x100'den 40x40'a kadar sonucu küçültmek zorunda olduğumu unutmayın, böylece eşik konsola sığacak (sadece sabit kodlu 102'yi daha küçük bir sayıya değiştirin). Ayrıca y ekseninin aşağıya baktığını unutmayın.


Burada yapabileceğiniz birkaç küçük golf var. Son satır, $bayt kaydetmek için kullanabileceği zaman parenleri kullanır . Kullandığınız her iki yer de mapolabilir (<$>)ve sadece bir ekez kullandığınız için (0<)içerisini tanımlayabilirsiniz. Ayrıca eadlandırılabilir (!)3 bayt kaydedin.
Post Rock Garf Hunter

Ve ztanımında viçeri girmek 4 parantezden ( z(&)ve çevresinde f g) kurtulmanızı sağlar .
Rock Garf Hunter Post

Ayrıca #tek bir karakteri yeniden adlandırabilir (örneğin s) ve bunun yerine desenlerin desenlerde eşleşmesini sağlayabilirsiniz g. (Örneğin s[a,b]=[a,a+(b-a)/102..b];g m u i=unlines$v[m!y<$>s u|y<-s i])
Post Rock Garf Hunter

6

Matlab, 114 , 100 92 bayt

İş için doğru araç? Matlab'ın printfbir dize olarak bir polinom üretmek için yaptığı ilginç yolu kullanıyorum . ezplotBelirtilen alanda örtük eğriyi çizen bu polinom sağlanabilir . Okunabilirlik için kod; bu gerekli değildir ve büyüklüğe sayılmaz.

function P(A,W,H,h,w)
t=0:h*w-1;
ezplot(sprintf('+%d*x^%.0f*y^%d',[A(:)';t/h;rem(t,h)]),[W,H])

Genişletilebilir snippet olarak golf ilerleme.


Test senaryolarının çıktısı (tam görünüm için tıklayın): Test senaryoları


2
Gerçekten güzel bir çözüm kullanarak sprintf/ezplot!
flawr

fixBunun yerine kullanmak floor, iki basamaklı bayt sayısına ulaşmanıza yardımcı olabilir :-)
Luis Mendo

Ayrıca [h,w]=size(A);t=0:h*w-1;üç bayt daha kaydetmek için kullanabilirsiniz !
flawr

@LuisMendo Aslında daha iyisini yapabilirim. Matlab'ın printf'inin tamsayı yer tutucusu olmadığı için üzüldüm, ancak yine de böyle şeyleri destekliyor %.0f. Bu, döşemeyi tamamen bırakabileceğim ve printfdüzeltebileceğim anlamına geliyor!
algmyr

@flawr Daha sonraki yinelemelerde bunun ikinci bölümünü kullanıyorum. Biçimlendirmenin en iyi sürümle son olarak son derece açık olmadığını fark ettim. Bu kristalin anlaşılır olması için biçimlendirme düzenlendi.
algmyr

6

Python 2, 261 bayt

E=enumerate
M,[a,c],[b,d]=input()
e=(c-a)/199.
I=200
J=-int((b-d)/e-1)
print'P2',I,J,255
i=I*J
while i:i-=1;x,y=c-i%I*e,b+i/I*e;u,v,w=map(sum,zip(*((z*p/x,z*q/y,z)for q,R in E(M)for p,t in E(R)for z in[t*x**p*y**q])));print int(255*min(1,(w*w/(u*u+v*v))**.5/e))

Girdi biçimi: matrix,xbounds,ybounds(örn. [[-1,0,1],[0,0,0],[1,0,0]],[-2,2],[-2,2]). Çıktı biçimi: düz PGM .

Bu, birinci mertebeden yaklaşımı kullanarak her piksel merkezinden eğriye kadar olan mesafeyi tahmin eder d ( x , y ) = | p ( x , y ) | / | ∇ p ( x , y ) |; burada ∇ p , polinom p'nin gradyanıdır . (Bu, ( x , y ) ile ( x , y , p ( x , y )) ' deki teğet düzlemin xy düzlemiyle kesiştiği mesafedir.) Sonra d (x , y ), d ( x , y ) ile orantılı olarak eğrinin bir piksel genişliğinden daha azdır , bu da hoş kenar yumuşatılmış çizgilerle sonuçlanır (bu bir gereksinim olmamasına rağmen).

çıktı

İşte 16 bölü uzaklık fonksiyonu ile aynı grafikler görünür hale getirmek için.


Bekle, peki kodda gerçek grafik çizimi nerede oluyor?
R. Kap

@ R.Kap Kod stdout'a düz PGM formatında bir görüntü yazar. Bir tane var printgörüntü başlığında için deyim ve bir printde deyim whileher piksel değeri için döngü.
Anders Kaseorg

Vay canına, bu gerçekten harika! Çizim algoritmanız hakkında biraz daha derinlemesine düşünür müsünüz?
flawr

@flawr Açıklamayı biraz genişlettim; bu sorularınızı cevaplıyor mu?
Anders Kaseorg

@AndersKaseorg Evet, çok teşekkür ederim!
flawr

5

Python 3.5 + MatPlotLib + Numpy, 352 bayt:

from matplotlib.pyplot import*;from numpy import*
def R(M,S,U,r=range):N=linspace;E='+'.join([str(y)+'*'+m for y,m in[q for i,g in zip(M,[[i+'*'+p for p in['1']+['x^%d'%p for p in r(1,len(M[0]))]]for i in['1']+['y^%d'%i for i in r(1,len(M))]])for q in zip(i,g)if q[0]]]);x,y=meshgrid(N(*S,200),N(*U,200));contour(x,y,eval(E.replace('^','**')),0);show()

Adlandırılmış bir işlev. Oldukça uzun, ama hey, sadece görevi yerine getirebildiğim için mutluyum. Tümü dizilerde olması gereken -range ve -range m by nmatrisi olan 3 girdi alır (örneğin, ). Tamamlanan grafiği yeni, grafik, etkileşimli bir pencerede çıktılar. Bunu yapabildiğim zaman daha fazla golf oynayacak, ama şimdilik bundan memnunum.xy[[-1,0,1],[0,0,0],[1,0,0]],[-2,2],[-2,2]

Test Durumları için Nihai Çıktılar:

Nihai Çıktı


5

MATL , 67 61 bayt

8Wt:qwq/t2:"wid*2M1)+i:q!^]!2&!w[1IK2]&!**ss&eZS5Y62&Y+|4=0YG

Bu kod, dilden önce gelen dilin 18.5.0 sürümünde çalışır. Giriş İsteğe bağlı kullanır m, nparametreleri. Matris, satır ayırıcılar olarak noktalı virgül içerir. Kesin giriş formatı (örnek olarak parabol kullanılarak)

[-1,3]
3  
[-2,2]
2
[0,-1; 0, 0; 1, 0]

Kod, 255 × 255 boyutunda bir resim oluşturur. Bu kullanılarak test edilebilir @Suever bireyin Matl Çevrimiçi diğer ilginç özellikler arasında, grafik çıkışını içerir, derleyici,. Örneğin bakınız

Bu derleyici hala deney aşamasındadır. Lütfen sorunları MATL sohbet odasında @Suever'a bildirin . "Çalıştır" düğmesi çalışmazsa sayfayı yenilemeyi ve tekrar tıklamayı deneyin.

ASCII çıktısını tercih ederseniz , kodun biraz değiştirilmesi gerekir (değişiklikler sadece yukarıdaki kodun sadece ilk iki ve son dört karakterini etkiler):

101t:qwq/t2:"wid*2M1)+i:q!^]!2&!w[1IK2]&!**ss&eZS5Y62&Y+|4<42*c

Bu *, eğriyi temsil etmek için karakter kullanan 100 × 100 ASCII ızgarasını üretir . Bunu @Dennis ' ile de test edebilirsiniz. Çevrimiçi deneyin! platformu:

Karakterler genişlikten biraz daha yüksek olduğu için ASCII çıkışının en boy oranının değiştirildiğine dikkat edin.

açıklama

Kod önce bir x - y ızgarasındaki iki değişkenli polinomu hesaplar . Bu, her boyutun sırasıyla x değerlerini, y değerlerini, x üslerini, y üslerini temsil ettiği bir ara 4D dizisini hesaplayarak yayıncılığı yoğun şekilde kullanır .

Bu fonksiyondan sıfır seviye çizgisi hesaplanır. Zorluk, yalnızca işaret değişikliklerinin algılanması gerektiğini belirttiğinden, kod, 2 × 2 blok içeren 2D konvolüsyon uygular ve bloğun dört değeri aynı işarete sahip değilse, bir pikseli çizgiye ait olarak işaretler.

8W      % Push 2^8, that is, 256. (The ASCII-output version pushes 101 instead)
t:q     % Duplicate. Push range [0 1 ... 255]
wq      % Swap. Subtract 1 to obtain 255
/       % Divide. Gives normalized range [0 1/255 2/255... 1]
t       % Duplicate
2:"     % For loop: do this twice
  w     %   Swap top two elements in the stack
  i     %   Input two-number array defining x range (resp. y in second iteration)
  d     %   Difference of the two entries
  *     %   Multiply by normalized range
  2M1)  %   Push the array again and get its first entry
  +     %   Add. This gives the range for x values (resp. y)
  i     %   Input m (n in second iteration)
  :q    %   Range [0 1 ...m-1] (resp. [0 1 ...n-1])
  !     %   Convert to column array
  ^     %   Power, element-wise with broadcast. This gives a matrix of size m×256
        %   (resp. n×256) of powers of x (resp. y) for the range of values computed
        %   previously
]       % End for loop
!       % Transpose. This transforms the n×256 matrix of powers of y into 256×n
2       % Push 2
&!      % Permute dimensions 1 and 3: transforms the 256×n matrix into a 4D array
        % of size 1×n×256×1
w       % Swap top two elements in the stack: bring 256×m matrix to top
[1IK2]  % Push vector [1 3 4 2]
&!      % Permute dimensions as indicated by the vector: transforms the m×256 matrix
        % into a 4D array of size m×1×1×256
*       % Multiply element-wise with broadcast: gives 4D array of size m×n×256×256
        % with mixed powers of x and y for at the grid of x, y values
*       % Implicitly input m×n matrix. Multiply element-wise with broadcast: gives
        % 4D array of size m×n×256×256
ss      % Sum along first two dimensions: gives 4D array of size 1×1×256×256
&e      % Squeeze singleton dimensions: gives matrix of size 256×256. This is the
        % two-variable polynomial evaluated at the x, y grid.
        % Now we need to find the zero level curve of this function. We do this by 
        % detecting when the sign of the function changes along any of the two axes
ZS      % Matrix of sign values (1, 0 or -1)
5Y6     % Predefined literal: matrix [1 1; 1 1]
2&Y+    % Compute 2D convolution, keeping only the valid (central) part
|4=     % True if absolute value of result is 4, which indicates no sign changes.
        % (The ASCII version computes a negated version of this, for better display)
0YG     % Display as image. (The ASCII-output version does the following instead:
        % multiply by 42 and convert to char. 42 is ASCII for '*', and character 0 
        % is shown as space. The 2D char array is then implicitly displayed)

Tüm test örnekleri

Denemek istemeniz durumunda, tüm girdiler uygun biçimde:

Circle:
[-2,2]
3
[-2,2]
3
[-1, 0, 1; 0, 0, 0; 1, 0, 0]

Ellipse:
[-2,2]
3
[-1,1]
3
[-1, 0, 1; 0, 0, 0; 2, 0, 0]

Cross:
[-1,2]
2
[-2,1]
2
[0, 0; 0, 1]

Parabola:
[-1,3]
3  
[-2,2]
2
[0,-1; 0, 0; 1, 0]

Elliptic Curve:
[-2,2]
3
[-3,3]
4
[-1, 1, 0,-1; 0, 0, 0, 0; 1, 0, 0, 0]

Folium of Descartes:
[-3,3]
4
[-3,3]
4
[0,  0,  0,  1; 0, -3,  0,  0; 0,  0,  0,  0; 1,  0,  0,  0]


Lemniscate:
[-2,2]
3
[-1,1]
5
[0,  0, -1,  0,  1; 0,  0,  0,  0,  0; 1,  0,  0,  0,  0]

Trifolium:
[-1,1]
5
[-1,1]
5
[0, 0, 0,-1, 1; 0, 0, 0, 0, 0; 0, 3, 2, 0, 0; 0, 0, 0, 0, 0; 1, 0, 0, 0, 0]

Astroid
[-1,1]
7
[-1,1]
7
[-1,  0,  3,  0, -3,  0,  1; 0,  0,  0,  0,  0,  0,  0; 3,  0, 21,  0,  3,  0,  0; 0,  0,  0,  0,  0,  0,  0; -3,  0,  3,  0,  0,  0,  0; 0,  0,  0,  0,  0,  0,  0; 1,  0,  0,  0,  0,  0,  0]

2
Perl'den daha okunabilir. İyi iş, ayrıca güzel bir çevrimiçi derleyici!
flawr

@flawr Perl LOL'den daha okunabilir . Çevrimiçi derleyiciye gelince, hepsi Suever'in işi!
Luis Mendo

1
@flawr Şimdi evrişim ile!
Luis Mendo

1
<3 evrişim!
flawr
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.