gitweb on Svarog

projekti pod git sistemom za održavanje verzija -- projects under the git version control system
aa95160e1ea831dafe6b7d3ee242a2497ea07a5c
[spa2-materijali.git] / PretrazivanjeSaVracanjem / Lavirint / ObjedinjenoResenje / 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.function.Function;
8 import javafx.application.Application;
9 import javafx.application.Platform;
10 import javafx.collections.FXCollections;
11 import javafx.collections.ObservableList;
12 import javafx.geometry.Insets;
13 import javafx.geometry.VPos;
14 import javafx.scene.Scene;
15 import javafx.scene.canvas.Canvas;
16 import javafx.scene.canvas.GraphicsContext;
17 import javafx.scene.control.Button;
18 import javafx.scene.control.Label;
19 import javafx.scene.control.ListCell;
20 import javafx.scene.control.ListView;
21 import javafx.scene.control.Slider;
22 import javafx.scene.layout.BorderPane;
23 import javafx.scene.layout.ColumnConstraints;
24 import javafx.scene.layout.GridPane;
25 import javafx.scene.layout.Priority;
26 import javafx.scene.layout.StackPane;
27 import javafx.scene.layout.VBox;
28 import javafx.scene.paint.Color;
29 import javafx.scene.paint.Paint;
30 import javafx.scene.shape.Circle;
31 import javafx.scene.shape.StrokeLineCap;
32 import javafx.scene.shape.StrokeLineJoin;
33 import javafx.scene.text.Font;
34 import javafx.scene.text.FontWeight;
35 import javafx.scene.text.TextAlignment;
36 import javafx.stage.Stage;
38 public class Prikaz extends Application {
40 public static final Color STVARNO_BELA = Color.hsb(0, 0, 1.0);
41 public static final Color BELA = Color.hsb(0, 0, 0.95);
42 public static final Color SVETLO_SIVA = Color.hsb(0, 0, 0.8);
43 public static final Color SIVA = Color.hsb(0, 0, 0.6);
44 public static final Color TAMNO_SIVA = Color.hsb(0, 0, 0.4);
45 public static final Color CRNA = Color.hsb(0, 0, 0.2);
46 public static final Color STVARNO_CRNA = Color.hsb(0, 0, 0.0);
48 public static final Color SVETLO_CRVENA = Color.hsb( 0, 0.2, 1.0);
49 public static final Color SVETLO_NARANDZASTA = Color.hsb( 30, 0.2, 1.0);
50 public static final Color SVETLO_ZUTA = Color.hsb( 60, 0.2, 1.0);
51 public static final Color SVETLO_ZELENA = Color.hsb(120, 0.2, 1.0);
52 public static final Color SVETLO_TIRKIZNA = Color.hsb(180, 0.2, 1.0);
53 public static final Color SVETLO_AZURNA = Color.hsb(210, 0.2, 1.0);
54 public static final Color SVETLO_PLAVA = Color.hsb(240, 0.2, 1.0);
55 public static final Color SVETLO_PURPURNA = Color.hsb(270, 0.2, 1.0);
56 public static final Color SVETLO_LJUBICASTA = Color.hsb(300, 0.2, 1.0);
57 public static final Color SVETLO_RUZICASTA = Color.hsb(330, 0.2, 1.0);
59 public static final Color CRVENA = Color.hsb( 0, 0.9, 0.8);
60 public static final Color NARANDZASTA = Color.hsb( 30, 0.9, 0.8);
61 public static final Color ZUTA = Color.hsb( 60, 0.9, 0.8);
62 public static final Color ZELENA = Color.hsb(120, 0.9, 0.8);
63 public static final Color TIRKIZNA = Color.hsb(180, 0.9, 0.8);
64 public static final Color AZURNA = Color.hsb(210, 0.9, 0.8);
65 public static final Color PLAVA = Color.hsb(240, 0.9, 0.8);
66 public static final Color PURPURNA = Color.hsb(270, 0.9, 0.8);
67 public static final Color LJUBICASTA = Color.hsb(300, 0.9, 0.8);
68 public static final Color RUZICASTA = Color.hsb(330, 0.9, 0.8);
70 public static final Color TAMNO_CRVENA = Color.hsb( 0, 0.8, 0.4);
71 public static final Color TAMNO_NARANDZASTA = Color.hsb( 30, 0.8, 0.4);
72 public static final Color TAMNO_ZUTA = Color.hsb( 60, 0.8, 0.4);
73 public static final Color TAMNO_ZELENA = Color.hsb(120, 0.8, 0.4);
74 public static final Color TAMNO_TIRKIZNA = Color.hsb(180, 0.8, 0.4);
75 public static final Color TAMNO_AZURNA = Color.hsb(210, 0.8, 0.4);
76 public static final Color TAMNO_PLAVA = Color.hsb(240, 0.8, 0.4);
77 public static final Color TAMNO_PURPURNA = Color.hsb(270, 0.8, 0.4);
78 public static final Color TAMNO_LJUBICASTA = Color.hsb(300, 0.8, 0.4);
79 public static final Color TAMNO_RUZICASTA = Color.hsb(330, 0.8, 0.4);
81 ////////////////////
82 // Boje i stilovi //
83 ////////////////////
85 protected static Paint bojaPozadine = BELA;
86 protected static Paint bojaOkvira = CRNA;
87 protected static Map<Integer, Paint> bojaPoljaPozadina = new HashMap<>();
88 protected static Map<Integer, Paint> bojaPoljaTekst = new HashMap<>();
89 protected static Font font = Font.font("Arial", FontWeight.BOLD, 12);
91 public static void boja(Paint pozadina, Paint okvir) {
92 bojaPozadine = pozadina;
93 bojaOkvira = okvir;
94 }
96 public static void boja(int vrednost, Paint bojaPozadine, Paint bojaTeksta) {
97 if (bojaPozadine == null) {
98 bojaPoljaPozadina.remove(vrednost);
99 }
100 bojaPoljaPozadina.put(vrednost, bojaPozadine);
101 if (bojaTeksta == null) {
102 bojaPoljaTekst.remove(vrednost);
104 bojaPoljaTekst.put(vrednost, bojaTeksta);
107 public static void boja(int vrednostMin, int vrednostMax, Color bojaMin, Color bojaMax, Paint bojaTeksta) {
108 if (bojaMin == null || bojaMax == null) {
109 throw new IllegalArgumentException();
111 int n = vrednostMax - vrednostMin;
112 for (int i = 0; i <= n; i++) {
113 int vrednost = vrednostMin + i;
114 bojaPoljaPozadina.put(vrednost, bojaMin.interpolate(bojaMax, (double) (i) / n));
115 if (bojaTeksta == null) {
116 bojaPoljaTekst.remove(vrednost);
118 bojaPoljaTekst.put(vrednost, bojaTeksta);
122 ////////////////
123 // Geometrija //
124 ////////////////
126 private static double velicinaPolja = 32;
127 private static double velicinaRazmaka = 4;
128 private static int debljinaOkvira = 0;
129 private static double debljinaPuta = velicinaPolja / 2;
131 public static void velicina(double polje, double razmak, int okvir) {
132 velicinaPolja = polje;
133 velicinaRazmaka = razmak;
134 debljinaOkvira = okvir;
135 debljinaPuta = velicinaPolja / 2;
138 protected static double ukupnaDuzina(int brojPolja) {
139 return x(brojPolja + debljinaOkvira, 0.0);
142 protected static double x(int indeks, double delta) {
143 indeks = indeks + debljinaOkvira;
144 return indeks * (velicinaPolja + velicinaRazmaka) + velicinaRazmaka + velicinaPolja * delta;
147 protected static double x(int indeks) {
148 return x(indeks, 0.0);
151 protected static double k(int indeks) {
152 return x(indeks, 0.5);
155 protected static double w(int count, double delta) {
156 return (velicinaPolja + velicinaRazmaka) * count + velicinaRazmaka * (delta - 1);
159 protected static double w(int count) {
160 return w(count, 0);
163 protected static double r() {
164 return 2 * velicinaRazmaka;
167 /////////////
168 // Sadrzaj //
169 /////////////
171 protected static String naslovProzora;
172 protected static int sirinaMape;
173 protected static int visinaMape;
174 protected static FunkcijaZaMapu funkcijaZaMapu;
176 @FunctionalInterface
177 public static interface FunkcijaZaMapu {
178 public int vrednostNa(int x, int y);
181 public static void mapa(String naslov, int sirina, int visina, FunkcijaZaMapu funkcijaZaMapu) {
182 naslovProzora = naslov;
183 sirinaMape = sirina;
184 visinaMape = visina;
185 Prikaz.funkcijaZaMapu = funkcijaZaMapu;
186 pokreni();
189 protected static Map<String, FunkcijaZaPut> funkcijeZaPuteve = new LinkedHashMap<>();
190 protected static Map<String, FunkcijaZaVrednostPuta> funkcijeZaVrednostiPuteva = new LinkedHashMap<>();
191 protected static Map<String, Paint> bojeZaPuteve = new HashMap<>();
193 @FunctionalInterface
194 public static interface FunkcijaZaPut {
195 public KorakPuta korak(int indeks);
198 @FunctionalInterface
199 public static interface FunkcijaZaVrednostPuta {
200 public String vrednost();
203 public static class KorakPuta {
204 public int x, y;
207 public static KorakPuta korak(int x, int y) {
208 KorakPuta korak = new KorakPuta();
209 korak.x = x; korak.y = y;
210 return korak;
213 public static void put(String naziv, FunkcijaZaPut funkcijaZaPut, FunkcijaZaVrednostPuta funkcijaZaVrednostPuta, Paint boja) {
214 odradiKasnije(() -> {
215 funkcijeZaPuteve.remove(naziv);
216 funkcijeZaVrednostiPuteva.remove(naziv);
217 bojeZaPuteve.remove(naziv);
218 listaPuteva.remove(naziv);
219 Canvas platno = platnaZaPuteve.remove(naziv);
220 centerPane.getChildren().remove(platno);
221 if (funkcijaZaPut != null && funkcijaZaVrednostPuta != null && boja != null) {
222 funkcijeZaPuteve.put(naziv, funkcijaZaPut);
223 funkcijeZaVrednostiPuteva.put(naziv, funkcijaZaVrednostPuta);
224 bojeZaPuteve.put(naziv, boja);
225 platno = new Canvas(Prikaz.platno.getWidth(), Prikaz.platno.getHeight());
226 platno.setOpacity(0.5);
227 platno.getGraphicsContext2D().setLineCap(StrokeLineCap.ROUND);
228 platno.getGraphicsContext2D().setLineJoin(StrokeLineJoin.ROUND);
229 platnaZaPuteve.put(naziv, platno);
230 centerPane.getChildren().add(1, platno);
231 listaPuteva.add(naziv);
232 crtajPut(naziv);
234 });
237 public static <T> void put(String naziv, List<T> lista, Function<T, Integer> x, Function<T, Integer> y, FunkcijaZaVrednostPuta funkcijaZaVrednostPuta, Paint boja) {
238 FunkcijaZaPut fja = (int indeks) -> {
239 try {
240 T element = lista.get(indeks);
241 return korak(x.apply(element), y.apply(element));
242 } catch (IndexOutOfBoundsException e) {
243 return null;
245 };
246 put(naziv, fja, funkcijaZaVrednostPuta, boja);
249 public static void osveziPut(String naziv) {
250 odradiKasnije(() -> {
251 crtajPut(naziv);
252 listaPuteva.set(listaPuteva.indexOf(naziv), naziv);
253 });
254 cekajAkoTreba();
257 /////////
258 // GUI //
259 /////////
261 protected static StackPane centerPane;
262 protected static ListView<String> listView;
263 protected static ObservableList<String> listaPuteva = FXCollections.observableArrayList();
265 @Override
266 public void start(Stage primaryStage) {
267 Label labelPutevi = new Label("Putevi:");
268 listView = new ListView<>(listaPuteva);
269 listView.setCellFactory(l -> new ListCell<String>() {
270 public void updateItem(String naziv, boolean empty) {
271 super.updateItem(naziv, empty);
272 if (empty || naziv == null) {
273 setText(null);
274 setGraphic(null);
275 } else {
276 Circle icon = new Circle(8);
277 icon.setFill(bojeZaPuteve.get(naziv));
278 setGraphic(icon);
279 FunkcijaZaVrednostPuta fja = funkcijeZaVrednostiPuteva.get(naziv);
280 try {
281 setText(naziv + ": " + fja.vrednost());
282 } catch (RuntimeException e) {
286 });
288 Label labelAnimacija = new Label();
289 Slider slider = new Slider(0, 4, 2);
290 Button button = new Button(">");
291 osveziPanelZaAnimaciju(labelAnimacija, button, slider.getValue());
292 slider.valueProperty().addListener((value, oldValue, newValue) -> {
293 osveziPanelZaAnimaciju(labelAnimacija, button, newValue.doubleValue());
294 });
295 button.setOnAction(e -> {
296 zavrsiCekanje();
297 });
298 button.setMaxHeight(Double.MAX_VALUE);
300 GridPane animationPane = new GridPane();
301 animationPane.setHgap(6);
302 animationPane.setVgap(6);
303 ColumnConstraints column = new ColumnConstraints();
304 column.setHgrow(Priority.ALWAYS);
305 animationPane.getColumnConstraints().add(column);
306 animationPane.add(labelAnimacija, 0, 0);
307 animationPane.add(slider, 0, 1);
308 animationPane.add(button, 1, 0, 1, 2);
310 VBox rightPane = new VBox();
311 rightPane.setPadding(new Insets(12, 12, 12, 12));
312 rightPane.setSpacing(6);
313 rightPane.getChildren().add(labelPutevi);
314 listView.setPrefHeight(0);
315 VBox.setVgrow(listView, Priority.ALWAYS);
316 rightPane.getChildren().add(listView);
317 VBox.setMargin(animationPane, new Insets(6, 0, 0, 0));
318 rightPane.getChildren().add(animationPane);
320 platno = new Canvas(ukupnaDuzina(sirinaMape), ukupnaDuzina(visinaMape));
321 osveziMapu();
322 centerPane = new StackPane(platno);
324 BorderPane rootPane = new BorderPane();
325 rootPane.setCenter(centerPane);
326 rootPane.setRight(rightPane);
327 Scene scene = new Scene(rootPane);
329 primaryStage.setTitle(naslovProzora + " - " + sirinaMape + " x " + visinaMape + "");
330 primaryStage.setAlwaysOnTop(true);
331 primaryStage.setResizable(false);
332 primaryStage.setOnCloseRequest(e -> podesiVreme(0));
333 primaryStage.setScene(scene);
334 primaryStage.show();
338 protected static void osveziPanelZaAnimaciju(Label labela, Button dugme, double vrednost) {
339 long vreme = podesiVreme(vrednost);
340 String tekst = "Brzina animacije: " + String.format("%.2f", vreme / 1000.0) + "s";
341 dugme.setVisible(vreme >= 1000);
342 labela.setText(tekst);
345 /////////////
346 // Crtanje //
347 /////////////
349 protected static Canvas platno;
350 protected static Map<String, Canvas> platnaZaPuteve = new LinkedHashMap<>();
352 protected static void osveziMapu() {
353 crtajMapu(platno.getGraphicsContext2D(), platno.getWidth(), platno.getHeight());
356 protected static void crtajMapu(GraphicsContext gc, double sirina, double visina) {
357 gc.setTextAlign(TextAlignment.CENTER);
358 gc.setTextBaseline(VPos.CENTER);
359 gc.setFont(font);
360 crtajOkvir(gc, sirina, visina);
361 for (int j = 0; j < visinaMape; j++) {
362 for (int i = 0; i < sirinaMape; i++) {
363 int sadrzaj = funkcijaZaMapu.vrednostNa(i, j);
364 Paint bojaPozadina = bojaPoljaPozadina.get(sadrzaj);
365 Paint bojaTekst = bojaPoljaTekst.get(sadrzaj);
366 crtajPolje(gc, i, j, bojaPozadina, bojaTekst, "" + sadrzaj);
371 protected static void crtajOkvir(GraphicsContext gc, double sirina, double visina) {
372 gc.setFill(bojaPozadine);
373 gc.fillRect(0, 0, sirina, visina);
374 if (debljinaOkvira <= 0) {
375 return;
377 gc.setFill(bojaOkvira);
378 gc.fillRoundRect(x(-debljinaOkvira), x(-debljinaOkvira), w(sirinaMape + 2 * debljinaOkvira), w(visinaMape + 2 * debljinaOkvira), r(), r());
379 gc.setFill(bojaPozadine);
380 gc.fillRoundRect(x(-1, 1), x(-1, 1), w(sirinaMape, 2), w(visinaMape, 2), r(), r());
383 protected static void crtajPolje(GraphicsContext gc, int x, int y, Paint bojaPozadina, Paint bojaTekst, String tekst) {
384 if (bojaPozadina != null) {
385 gc.setFill(bojaPozadina);
386 gc.fillRoundRect(x(x), x(y), w(1), w(1), r(), r());
388 if (tekst != null && bojaTekst != null) {
389 gc.setFill(bojaTekst);
390 gc.fillText(tekst, x(x, 0.5), x(y, 0.5));
394 protected static void crtajPut(String naziv) {
395 Canvas platno = platnaZaPuteve.get(naziv);
396 GraphicsContext gc = platno.getGraphicsContext2D();
397 gc.clearRect(0, 0, platno.getWidth(), platno.getHeight());
398 FunkcijaZaPut fja = funkcijeZaPuteve.get(naziv);
399 Paint boja = bojeZaPuteve.get(naziv);
400 double debljina = debljinaPuta;
401 List<KorakPuta> koraci = new ArrayList<>();
402 int i = 0; KorakPuta korak;
403 while ((korak = fja.korak(i++)) != null) {
404 koraci.add(korak);
406 crtajPut(gc, koraci, boja, debljina);
409 protected static void crtajPut(GraphicsContext gc, List<KorakPuta> koraci, Paint boja, double debljina) {
410 gc.setStroke(boja);
411 gc.setLineWidth(debljina);
412 if (koraci.size() == 1) {
413 KorakPuta k = koraci.get(0);
414 gc.setFill(boja);
415 gc.fillOval(k(k.x) - debljina / 2, k(k.y) - debljina / 2, debljina, debljina);
417 for (int j = 1; j < koraci.size(); j++) {
418 KorakPuta k1 = koraci.get(j - 1);
419 KorakPuta k2 = koraci.get(j);
420 gc.strokeLine(k(k1.x), k(k1.y), k(k2.x), k(k2.y));
424 ///////////////
425 // Animacija //
426 ///////////////
428 protected static boolean nekoCeka = false;
429 protected static long vremeCekanja = 1000;
431 protected static synchronized void cekajAkoTreba() {
432 long pocetak = System.currentTimeMillis();
433 if (vremeCekanja == 0) {
434 return;
436 nekoCeka = true;
437 long vreme;
438 boolean bioPrekid = Thread.interrupted();
439 while (nekoCeka && (vreme = pocetak + vremeCekanja - System.currentTimeMillis()) > 0) {
440 try {
441 Prikaz.class.wait(vreme);
442 } catch (InterruptedException e) {
443 bioPrekid = true;
446 if (bioPrekid) {
447 Thread.currentThread().interrupt();
449 nekoCeka = false;
452 protected static synchronized void podesiVreme(long novoVremeCekanja) {
453 vremeCekanja = novoVremeCekanja;
454 Prikaz.class.notify();
457 protected static synchronized void zavrsiCekanje() {
458 nekoCeka = false;
459 Prikaz.class.notify();
462 protected static long podesiVreme(double stepen) {
463 stepen = 5 - stepen;
464 if (stepen <= 1) {
465 podesiVreme(0);
466 return 0;
468 long vrednost = (long) Math.pow(10, stepen);
469 podesiVreme(vrednost);
470 return vrednost;
473 ////////////////
474 // Pokretanje //
475 ////////////////
477 protected static void pokreni() {
478 Runnable launcher = () -> {
479 launch(new String[] {});
480 };
481 new Thread(launcher).start();
484 protected static void odradiKasnije(Runnable zadatak) {
485 Platform.runLater(zadatak);
Svarog.pmf.uns.ac.rs/gitweb maintanance Doni Pracner