gitweb on Svarog

projekti pod git sistemom za održavanje verzija -- projects under the git version control system
Lavirint, objedinjeno resenje, doterana inicijalizacija sistema za prikaz
[spa2-materijali.git] / PretrazivanjeSaVracanjem / Lavirint / SuperKomplikovanoResenje / Prikaz.java
1 import java.util.ArrayList;
2 import java.util.HashMap;
3 import java.util.LinkedHashMap;
4 import java.util.List;
5 import java.util.Map;
6 import java.util.concurrent.CountDownLatch;
7 import java.util.function.Function;
9 import javafx.application.Application;
10 import javafx.application.Platform;
11 import javafx.collections.FXCollections;
12 import javafx.collections.ObservableList;
13 import javafx.geometry.Insets;
14 import javafx.geometry.VPos;
15 import javafx.scene.Scene;
16 import javafx.scene.canvas.Canvas;
17 import javafx.scene.canvas.GraphicsContext;
18 import javafx.scene.control.Button;
19 import javafx.scene.control.Label;
20 import javafx.scene.control.ListCell;
21 import javafx.scene.control.ListView;
22 import javafx.scene.control.Slider;
23 import javafx.scene.layout.BorderPane;
24 import javafx.scene.layout.ColumnConstraints;
25 import javafx.scene.layout.GridPane;
26 import javafx.scene.layout.Priority;
27 import javafx.scene.layout.StackPane;
28 import javafx.scene.layout.VBox;
29 import javafx.scene.paint.Color;
30 import javafx.scene.paint.Paint;
31 import javafx.scene.shape.Circle;
32 import javafx.scene.shape.StrokeLineCap;
33 import javafx.scene.shape.StrokeLineJoin;
34 import javafx.scene.text.Font;
35 import javafx.scene.text.FontWeight;
36 import javafx.scene.text.TextAlignment;
37 import javafx.stage.Stage;
39 public class Prikaz extends Application {
41 public static final Color STVARNO_BELA = Color.hsb(0, 0, 1.0);
42 public static final Color BELA = Color.hsb(0, 0, 0.95);
43 public static final Color SVETLO_SIVA = Color.hsb(0, 0, 0.8);
44 public static final Color SIVA = Color.hsb(0, 0, 0.6);
45 public static final Color TAMNO_SIVA = Color.hsb(0, 0, 0.4);
46 public static final Color CRNA = Color.hsb(0, 0, 0.2);
47 public static final Color STVARNO_CRNA = Color.hsb(0, 0, 0.0);
49 public static final Color SVETLO_CRVENA = Color.hsb( 0, 0.2, 1.0);
50 public static final Color SVETLO_NARANDZASTA = Color.hsb( 30, 0.2, 1.0);
51 public static final Color SVETLO_ZUTA = Color.hsb( 60, 0.2, 1.0);
52 public static final Color SVETLO_ZELENA = Color.hsb(120, 0.2, 1.0);
53 public static final Color SVETLO_TIRKIZNA = Color.hsb(180, 0.2, 1.0);
54 public static final Color SVETLO_AZURNA = Color.hsb(210, 0.2, 1.0);
55 public static final Color SVETLO_PLAVA = Color.hsb(240, 0.2, 1.0);
56 public static final Color SVETLO_PURPURNA = Color.hsb(270, 0.2, 1.0);
57 public static final Color SVETLO_LJUBICASTA = Color.hsb(300, 0.2, 1.0);
58 public static final Color SVETLO_RUZICASTA = Color.hsb(330, 0.2, 1.0);
60 public static final Color CRVENA = Color.hsb( 0, 0.9, 0.8);
61 public static final Color NARANDZASTA = Color.hsb( 30, 0.9, 0.8);
62 public static final Color ZUTA = Color.hsb( 60, 0.9, 0.8);
63 public static final Color ZELENA = Color.hsb(120, 0.9, 0.8);
64 public static final Color TIRKIZNA = Color.hsb(180, 0.9, 0.8);
65 public static final Color AZURNA = Color.hsb(210, 0.9, 0.8);
66 public static final Color PLAVA = Color.hsb(240, 0.9, 0.8);
67 public static final Color PURPURNA = Color.hsb(270, 0.9, 0.8);
68 public static final Color LJUBICASTA = Color.hsb(300, 0.9, 0.8);
69 public static final Color RUZICASTA = Color.hsb(330, 0.9, 0.8);
71 public static final Color TAMNO_CRVENA = Color.hsb( 0, 0.8, 0.4);
72 public static final Color TAMNO_NARANDZASTA = Color.hsb( 30, 0.8, 0.4);
73 public static final Color TAMNO_ZUTA = Color.hsb( 60, 0.8, 0.4);
74 public static final Color TAMNO_ZELENA = Color.hsb(120, 0.8, 0.4);
75 public static final Color TAMNO_TIRKIZNA = Color.hsb(180, 0.8, 0.4);
76 public static final Color TAMNO_AZURNA = Color.hsb(210, 0.8, 0.4);
77 public static final Color TAMNO_PLAVA = Color.hsb(240, 0.8, 0.4);
78 public static final Color TAMNO_PURPURNA = Color.hsb(270, 0.8, 0.4);
79 public static final Color TAMNO_LJUBICASTA = Color.hsb(300, 0.8, 0.4);
80 public static final Color TAMNO_RUZICASTA = Color.hsb(330, 0.8, 0.4);
82 ////////////////////
83 // Boje i stilovi //
84 ////////////////////
86 protected static Paint bojaPozadine = BELA;
87 protected static Paint bojaOkvira = CRNA;
88 protected static Map<Integer, Paint> bojaPoljaPozadina = new HashMap<>();
89 protected static Map<Integer, Paint> bojaPoljaTekst = new HashMap<>();
90 protected static Font font = Font.font("Arial", FontWeight.BOLD, 12);
92 public static void boja(Paint pozadina, Paint okvir) {
93 bojaPozadine = pozadina;
94 bojaOkvira = okvir;
95 }
97 public static void boja(int vrednost, Paint bojaPozadine, Paint bojaTeksta) {
98 if (bojaPozadine == null) {
99 bojaPoljaPozadina.remove(vrednost);
101 bojaPoljaPozadina.put(vrednost, bojaPozadine);
102 if (bojaTeksta == null) {
103 bojaPoljaTekst.remove(vrednost);
105 bojaPoljaTekst.put(vrednost, bojaTeksta);
108 public static void boja(int vrednostMin, int vrednostMax, Color bojaMin, Color bojaMax, Paint bojaTeksta) {
109 if (bojaMin == null || bojaMax == null) {
110 throw new IllegalArgumentException();
112 int n = vrednostMax - vrednostMin;
113 for (int i = 0; i <= n; i++) {
114 int vrednost = vrednostMin + i;
115 bojaPoljaPozadina.put(vrednost, bojaMin.interpolate(bojaMax, (double) (i) / n));
116 if (bojaTeksta == null) {
117 bojaPoljaTekst.remove(vrednost);
119 bojaPoljaTekst.put(vrednost, bojaTeksta);
123 ////////////////
124 // Geometrija //
125 ////////////////
127 private static double velicinaPolja = 32;
128 private static double velicinaRazmaka = 4;
129 private static int debljinaOkvira = 0;
130 private static double debljinaPuta = velicinaPolja / 2;
132 public static void velicina(double polje, double razmak, int okvir) {
133 velicinaPolja = polje;
134 velicinaRazmaka = razmak;
135 debljinaOkvira = okvir;
136 debljinaPuta = velicinaPolja / 2;
139 protected static double ukupnaDuzina(int brojPolja) {
140 return x(brojPolja + debljinaOkvira, 0.0);
143 protected static double x(int indeks, double delta) {
144 indeks = indeks + debljinaOkvira;
145 return indeks * (velicinaPolja + velicinaRazmaka) + velicinaRazmaka + velicinaPolja * delta;
148 protected static double x(int indeks) {
149 return x(indeks, 0.0);
152 protected static double k(int indeks) {
153 return x(indeks, 0.5);
156 protected static double w(int count, double delta) {
157 return (velicinaPolja + velicinaRazmaka) * count + velicinaRazmaka * (delta - 1);
160 protected static double w(int count) {
161 return w(count, 0);
164 protected static double r() {
165 return 2 * velicinaRazmaka;
168 /////////////
169 // Sadrzaj //
170 /////////////
172 protected static String naslovProzora;
173 protected static int sirinaMape;
174 protected static int visinaMape;
175 protected static FunkcijaZaMapu funkcijaZaMapu;
177 @FunctionalInterface
178 public static interface FunkcijaZaMapu {
179 public int vrednostNa(int x, int y);
182 public static void mapa(String naslov, int sirina, int visina, FunkcijaZaMapu funkcijaZaMapu) {
183 naslovProzora = naslov;
184 sirinaMape = sirina;
185 visinaMape = visina;
186 Prikaz.funkcijaZaMapu = funkcijaZaMapu;
187 pokreni();
190 protected static Map<String, FunkcijaZaPut> funkcijeZaPuteve = new LinkedHashMap<>();
191 protected static Map<String, FunkcijaZaVrednostPuta> funkcijeZaVrednostiPuteva = new LinkedHashMap<>();
192 protected static Map<String, Paint> bojeZaPuteve = new HashMap<>();
194 @FunctionalInterface
195 public static interface FunkcijaZaPut {
196 public KorakPuta korak(int indeks);
199 @FunctionalInterface
200 public static interface FunkcijaZaVrednostPuta {
201 public String vrednost();
204 public static class KorakPuta {
205 public int x, y;
208 public static KorakPuta korak(int x, int y) {
209 KorakPuta korak = new KorakPuta();
210 korak.x = x; korak.y = y;
211 return korak;
214 public static void put(String naziv, FunkcijaZaPut funkcijaZaPut, FunkcijaZaVrednostPuta funkcijaZaVrednostPuta, Paint boja) {
215 odradiKasnije(() -> {
216 funkcijeZaPuteve.remove(naziv);
217 funkcijeZaVrednostiPuteva.remove(naziv);
218 bojeZaPuteve.remove(naziv);
219 listaPuteva.remove(naziv);
220 Canvas platno = platnaZaPuteve.remove(naziv);
221 centerPane.getChildren().remove(platno);
222 if (funkcijaZaPut != null && funkcijaZaVrednostPuta != null && boja != null) {
223 funkcijeZaPuteve.put(naziv, funkcijaZaPut);
224 funkcijeZaVrednostiPuteva.put(naziv, funkcijaZaVrednostPuta);
225 bojeZaPuteve.put(naziv, boja);
226 platno = new Canvas(Prikaz.platno.getWidth(), Prikaz.platno.getHeight());
227 platno.setOpacity(0.5);
228 platno.getGraphicsContext2D().setLineCap(StrokeLineCap.ROUND);
229 platno.getGraphicsContext2D().setLineJoin(StrokeLineJoin.ROUND);
230 platnaZaPuteve.put(naziv, platno);
231 centerPane.getChildren().add(1, platno);
232 listaPuteva.add(naziv);
233 crtajPut(naziv);
235 });
238 public static <T> void put(String naziv, List<T> lista, Function<T, Integer> x, Function<T, Integer> y, FunkcijaZaVrednostPuta funkcijaZaVrednostPuta, Paint boja) {
239 FunkcijaZaPut fja = (int indeks) -> {
240 try {
241 T element = lista.get(indeks);
242 return korak(x.apply(element), y.apply(element));
243 } catch (IndexOutOfBoundsException e) {
244 return null;
246 };
247 put(naziv, fja, funkcijaZaVrednostPuta, boja);
250 public static void osveziPut(String naziv) {
251 odradiKasnije(() -> {
252 crtajPut(naziv);
253 listaPuteva.set(listaPuteva.indexOf(naziv), naziv);
254 });
255 cekajAkoTreba();
258 /////////
259 // GUI //
260 /////////
262 protected static StackPane centerPane;
263 protected static ListView<String> listView;
264 protected static ObservableList<String> listaPuteva = FXCollections.observableArrayList();
266 @Override
267 public void start(Stage primaryStage) {
268 Label labelPutevi = new Label("Putevi:");
269 listView = new ListView<>(listaPuteva);
270 listView.setCellFactory(l -> new ListCell<String>() {
271 public void updateItem(String naziv, boolean empty) {
272 super.updateItem(naziv, empty);
273 if (empty || naziv == null) {
274 setText(null);
275 setGraphic(null);
276 } else {
277 Circle icon = new Circle(8);
278 icon.setFill(bojeZaPuteve.get(naziv));
279 setGraphic(icon);
280 FunkcijaZaVrednostPuta fja = funkcijeZaVrednostiPuteva.get(naziv);
281 try {
282 setText(naziv + ": " + fja.vrednost());
283 } catch (RuntimeException e) {
287 });
289 Label labelAnimacija = new Label();
290 Slider slider = new Slider(0, 4, 2);
291 Button button = new Button(">");
292 osveziPanelZaAnimaciju(labelAnimacija, button, slider.getValue());
293 slider.valueProperty().addListener((value, oldValue, newValue) -> {
294 osveziPanelZaAnimaciju(labelAnimacija, button, newValue.doubleValue());
295 });
296 button.setOnAction(e -> {
297 zavrsiCekanje();
298 });
299 button.setMaxHeight(Double.MAX_VALUE);
301 GridPane animationPane = new GridPane();
302 animationPane.setHgap(6);
303 animationPane.setVgap(6);
304 ColumnConstraints column = new ColumnConstraints();
305 column.setHgrow(Priority.ALWAYS);
306 animationPane.getColumnConstraints().add(column);
307 animationPane.add(labelAnimacija, 0, 0);
308 animationPane.add(slider, 0, 1);
309 animationPane.add(button, 1, 0, 1, 2);
311 VBox rightPane = new VBox();
312 rightPane.setPadding(new Insets(12, 12, 12, 12));
313 rightPane.setSpacing(6);
314 rightPane.getChildren().add(labelPutevi);
315 listView.setPrefHeight(0);
316 VBox.setVgrow(listView, Priority.ALWAYS);
317 rightPane.getChildren().add(listView);
318 VBox.setMargin(animationPane, new Insets(6, 0, 0, 0));
319 rightPane.getChildren().add(animationPane);
321 platno = new Canvas(ukupnaDuzina(sirinaMape), ukupnaDuzina(visinaMape));
322 osveziMapu();
323 centerPane = new StackPane(platno);
325 BorderPane rootPane = new BorderPane();
326 rootPane.setCenter(centerPane);
327 rootPane.setRight(rightPane);
328 Scene scene = new Scene(rootPane);
330 primaryStage.setTitle(naslovProzora + " - " + sirinaMape + " x " + visinaMape + "");
331 primaryStage.setAlwaysOnTop(true);
332 primaryStage.setResizable(false);
333 primaryStage.setOnCloseRequest(e -> podesiVreme(0));
334 primaryStage.setScene(scene);
335 primaryStage.show();
337 pokrenut.countDown();
341 protected static void osveziPanelZaAnimaciju(Label labela, Button dugme, double vrednost) {
342 long vreme = podesiVreme(vrednost);
343 String tekst = "Brzina animacije: " + String.format("%.2f", vreme / 1000.0) + "s";
344 dugme.setVisible(vreme >= 1000);
345 labela.setText(tekst);
348 /////////////
349 // Crtanje //
350 /////////////
352 protected static Canvas platno;
353 protected static Map<String, Canvas> platnaZaPuteve = new LinkedHashMap<>();
355 protected static void osveziMapu() {
356 crtajMapu(platno.getGraphicsContext2D(), platno.getWidth(), platno.getHeight());
359 protected static void crtajMapu(GraphicsContext gc, double sirina, double visina) {
360 gc.setTextAlign(TextAlignment.CENTER);
361 gc.setTextBaseline(VPos.CENTER);
362 gc.setFont(font);
363 crtajOkvir(gc, sirina, visina);
364 for (int j = 0; j < visinaMape; j++) {
365 for (int i = 0; i < sirinaMape; i++) {
366 int sadrzaj = funkcijaZaMapu.vrednostNa(i, j);
367 Paint bojaPozadina = bojaPoljaPozadina.get(sadrzaj);
368 Paint bojaTekst = bojaPoljaTekst.get(sadrzaj);
369 crtajPolje(gc, i, j, bojaPozadina, bojaTekst, "" + sadrzaj);
374 protected static void crtajOkvir(GraphicsContext gc, double sirina, double visina) {
375 gc.setFill(bojaPozadine);
376 gc.fillRect(0, 0, sirina, visina);
377 if (debljinaOkvira <= 0) {
378 return;
380 gc.setFill(bojaOkvira);
381 gc.fillRoundRect(x(-debljinaOkvira), x(-debljinaOkvira), w(sirinaMape + 2 * debljinaOkvira), w(visinaMape + 2 * debljinaOkvira), r(), r());
382 gc.setFill(bojaPozadine);
383 gc.fillRoundRect(x(-1, 1), x(-1, 1), w(sirinaMape, 2), w(visinaMape, 2), r(), r());
386 protected static void crtajPolje(GraphicsContext gc, int x, int y, Paint bojaPozadina, Paint bojaTekst, String tekst) {
387 if (bojaPozadina != null) {
388 gc.setFill(bojaPozadina);
389 gc.fillRoundRect(x(x), x(y), w(1), w(1), r(), r());
391 if (tekst != null && bojaTekst != null) {
392 gc.setFill(bojaTekst);
393 gc.fillText(tekst, x(x, 0.5), x(y, 0.5));
397 protected static void crtajPut(String naziv) {
398 Canvas platno = platnaZaPuteve.get(naziv);
399 GraphicsContext gc = platno.getGraphicsContext2D();
400 gc.clearRect(0, 0, platno.getWidth(), platno.getHeight());
401 FunkcijaZaPut fja = funkcijeZaPuteve.get(naziv);
402 Paint boja = bojeZaPuteve.get(naziv);
403 double debljina = debljinaPuta;
404 List<KorakPuta> koraci = new ArrayList<>();
405 int i = 0; KorakPuta korak;
406 while ((korak = fja.korak(i++)) != null) {
407 koraci.add(korak);
409 crtajPut(gc, koraci, boja, debljina);
412 protected static void crtajPut(GraphicsContext gc, List<KorakPuta> koraci, Paint boja, double debljina) {
413 gc.setStroke(boja);
414 gc.setLineWidth(debljina);
415 if (koraci.size() == 1) {
416 KorakPuta k = koraci.get(0);
417 gc.setFill(boja);
418 gc.fillOval(k(k.x) - debljina / 2, k(k.y) - debljina / 2, debljina, debljina);
420 for (int j = 1; j < koraci.size(); j++) {
421 KorakPuta k1 = koraci.get(j - 1);
422 KorakPuta k2 = koraci.get(j);
423 gc.strokeLine(k(k1.x), k(k1.y), k(k2.x), k(k2.y));
427 ///////////////
428 // Animacija //
429 ///////////////
431 protected static boolean nekoCeka = false;
432 protected static long vremeCekanja = 1000;
434 protected static synchronized void cekajAkoTreba() {
435 long pocetak = System.currentTimeMillis();
436 if (vremeCekanja == 0) {
437 return;
439 nekoCeka = true;
440 long vreme;
441 boolean bioPrekid = Thread.interrupted();
442 while (nekoCeka && (vreme = pocetak + vremeCekanja - System.currentTimeMillis()) > 0) {
443 try {
444 Prikaz.class.wait(vreme);
445 } catch (InterruptedException e) {
446 bioPrekid = true;
449 if (bioPrekid) {
450 Thread.currentThread().interrupt();
452 nekoCeka = false;
455 protected static synchronized void podesiVreme(long novoVremeCekanja) {
456 vremeCekanja = novoVremeCekanja;
457 Prikaz.class.notify();
460 protected static synchronized void zavrsiCekanje() {
461 nekoCeka = false;
462 Prikaz.class.notify();
465 protected static long podesiVreme(double stepen) {
466 stepen = 5 - stepen;
467 if (stepen <= 1) {
468 podesiVreme(0);
469 return 0;
471 long vrednost = (long) Math.pow(10, stepen);
472 podesiVreme(vrednost);
473 return vrednost;
476 ////////////////
477 // Pokretanje //
478 ////////////////
480 protected static CountDownLatch pokrenut = new CountDownLatch(1);
482 protected static void pokreni() {
483 Runnable launcher = () -> {
484 launch(new String[] {});
485 };
486 new Thread(launcher).start();
487 boolean bioPrekid = Thread.interrupted();
488 boolean ok = false;
489 do {
490 try {
491 pokrenut.await();
492 ok = true;
493 } catch (InterruptedException e) {
494 bioPrekid = true;
496 } while (!ok);
497 if (bioPrekid) {
498 Thread.currentThread().interrupt();
502 protected static void odradiKasnije(Runnable zadatak) {
503 Platform.runLater(zadatak);
Svarog.pmf.uns.ac.rs/gitweb maintanance Doni Pracner