Szívgörbét ábrázolunk Java programmal. A Valentin-nap inspirálta ezt a feladatot. Számos matematikai görbe ismert, amelyek szívformához (kardioid) hasonlítanak. Szükséges egy megfelelő paraméteres görbe. A függvény szív formájú ábrája/grafikonja és egyenletrendszere alapján is nagy a választék.
Ábrázoljuk ezt a paraméteres szívgörbét Java swing GUI felületen!
A szívgörbe ábrázolásához felhasználom az StdDraw osztályt, amely ennek a tankönyvnek a példatárából származik: Robert Sedgewick, Kevin Wayne: Computer Science: An Interdisciplinary Approach, 1st edition, Princeton University, Addison-Wesley Professional, 2016, ISBN 978-0134076423. Az osztály metódusaival könnyen beállítható a nézőpont, a vízszintes/függőleges skála, a rajzoláshoz használt toll mérete/színe és a grafikai primitívek közül csak a pont ábrázolása szükséges.
Négy megoldást mutatok. Mindegyik azonos szívgörbét rajzol a fenti egyenletrendszer alapján. Mindegyik metódus átveszi az N paramétert, amely az összetartozó x és y koordinátapárok számát jelenti. Az N db pont meghatározása/kiszámolása szükséges a szívgörbe ábrázolásához. A szívgörbe ábrázolása önálló ablakban – grafikus felhasználói felületen – jelenik meg. A feladat matematikai jellegéből adódik, hogy tipikus a t nevű ciklusváltozó használata. A metódusokat a vezérlés az 512 paraméterrel hívja meg.
1. megoldás
1 2 3 4 5 6 7 8 9 10 11 |
static void heartCurveDraw1(final int N) { double[] x=new double[N]; double[] y=new double[N]; for(int t=0; t<N; t++) { x[t]=Math.sqrt(2)*Math.pow(Math.sin(t), 3); y[t]=-Math.pow(Math.cos(t), 3)-Math.pow(Math.cos(t), 2)+ 2*Math.cos(t); } for(int t=0; t<N; t++) StdDraw.point(x[t], y[t]); } |
A heartCurveDraw1() metódus a kiszámolt x és y koordinátákat két párhuzamos, double típusú tömb adatszerkezetben tárolja. A két tömbbe összesen 2*N db double típusú szám kerül. Azonos index jelöli az összetartozó koordinátapárokat. Az egymást követő két ciklus közül az első előállítja az adatszerkezetet és a második megjeleníti a pontokat.
2. megoldás
1 2 3 4 5 6 7 8 9 10 |
static void heartCurveDraw2(final int N) { Point2D[] point=new Point2D[N]; for(int t=0; t<N; t++) point[t]=new Point2D.Double( Math.sqrt(2)*Math.pow(Math.sin(t), 3), -Math.pow(Math.cos(t), 3)-Math.pow(Math.cos(t), 2)+ 2*Math.cos(t)); for(int i=0; i<N; i++) StdDraw.point(point[i].getX(), point[i].getY()); } |
A heartCurveDraw2() metódus a párhuzamos tömbök helyett adatszerkezetként egyetlen tömböt használ. A java.awt.geom csomag Point2D osztályú objektumai kerülnek a tömbbe. Mivel a Point2D absztrakt osztály, így a Double() osztálymetódusával (factory method) példányosítható úgy, hogy a szükséges koordinátapárokat megfelelően tudja tárolni. A tömbbe N db objektum kerül.
3. megoldás
1 2 3 4 5 6 7 8 9 |
static void heartCurveDraw3(final int N) { for(int t=0; t<N; t++) { Point2D p=new Point2D.Double( Math.sqrt(2)*Math.pow(Math.sin(t), 3), -Math.pow(Math.cos(t), 3)-Math.pow(Math.cos(t), 2)+ 2*Math.cos(t)); StdDraw.point(p.getX(), p.getY()); } } |
A heartCurveDraw3() metódus nem használ tömb adatszerkezetet. Tehát nem emlékszik az összes pont koordinátájára. Ehelyett a ciklus röptében, egyesével létrehozza a pontobjektumokat és azonnal ki is rajzolja azokat (átmeneti az emlékezet).
4. megoldás
1 2 3 4 5 6 7 8 |
static void heartCurveDraw4(final int N) { IntStream.range(0, N). mapToObj(t -> new Point2D.Double( Math.sqrt(2)*Math.pow(Math.sin(t), 3), -Math.pow(Math.cos(t), 3)-Math.pow(Math.cos(t), 2)+ 2*Math.cos(t))). forEach(p -> StdDraw.point(p.getX(), p.getY())); } |
A heartCurveDraw4() metódus Stream API-t és lambda kifejezéseket használ. Az első N természetes számból készül egy sorozat, amihez röptében hozzákötődik a t-edik Point2D típusú objektum. Ezzel létrejön egy folyam adatszerkezet. Tehát van egy pillanat, amíg a program emlékszik az összes folyambeli pontobjektumra. Végül a folyam feldolgozása, bejárása során egyesével megszólítva a folyam objektumait, a pontok kirajzolódnak a vászonra.
A vezérlés
1 2 3 4 5 6 7 8 9 10 |
public static void main(String[] args) { StdDraw.setPenRadius(0.01); StdDraw.setPenColor(Color.RED); StdDraw.setXscale(-Math.PI, Math.PI); StdDraw.setYscale(-5.0/4*Math.PI, 3.0/4*Math.PI); //heartCurveDraw1(512); //heartCurveDraw2(512); //heartCurveDraw3(512); heartCurveDraw4(512); } |
Az eredmény
A szívgörbe önálló – swing, grafikus felhasználói felület, GUI – ablakban így jelenik meg:
A bejegyzéshez tartozó teljes forráskódot ILIAS e-learning tananyagban tesszük elérhetővé tanfolyamaink résztvevői számára.
A feladat – a matematikai háttértől eltekintve – a Java SE szoftverfejlesztő tanfolyam szakmai moduljának 21-24. óra: Objektumorientált programozás 2. rész, valamint a 29-36. Grafikus felhasználói felület alkalmaihoz kötődik.
A 2D szívforma egyenletrendszerét erről a weboldalról választottam: Heart Curve – from Wolfram MathWorld. Egy merész továbbfejlesztési ötlet: a haladóknak megtalálható a 3D szívforma ábrázolása is: Heart Surface – from Wolfram MathWorld.
Sándor is blogolt már a Valentin-nap témában: Rómeó és Júlia. Ebből kiderül, hogy vajon ki szereti jobban a másikat: Rómeó vagy Júlia.
Nézegettem Balázs a hivatkozott weboldalakat. Meglepődtem az egyenleteken, egyenletrendszereken. Ez nálam mindig egy korlát.
Az a tapasztalatom Ádám, hogy érdemes többféle szinten közelíteni az elvárásokhoz. Például többféle tantárgypedagógia megfogalmazza a problémamegoldás szintjeit és modelljeit. Ha szeretnéd, akkor beszélgethetünk erről valamelyik óránk előtt vagy után.