import java.awt.*;
import java.awt.event.*;
import java.net.*;
import java.net.Socket;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.*;
import javax.swing.*;
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.util.ArrayList;
public class Landkarte extends JFrame
{
public Image image; // in diesem Objekt wird das Hintergrundbild gespeichert
public PolylinePanel kartenPanel; // hierauf wird dann gezeichnet
public boolean darfzeichnen = false; // ist false wenn keine neue Kante gezeichnet werden darf und true wenn eine neue eingezeichnet wird
public int clickZaehler = 0; // speichert wie oft der Button Neue Kante erstellen gedrückt wurde um die Beschriftung anzupassen
public int anfangPolygon = 0; // Prüfvariable ob ich gerade angefangen habe das Polygon zu zeichnen
public ArrayList<Point> KnotenArray = new ArrayList<Point>();; // hier werden die Koordinaten der Knotenpunkte abgespeichert
public ArrayList<Point> KantenArray = new ArrayList<Point>();; // hier werden die Koordinaten der Punkte abgespeichert welche zu einer Kante (Polygonzug) gehören
public ArrayList<JButton> ButtonArray = new ArrayList<JButton>(); // Array das die Knoten, also die Buttons dort komplett abspeichert
public ArrayList<JButton> ButtonKantenArray = new ArrayList<JButton>(); // Array das die Straßen, also die Buttons der Straßen dort komplett abspeichert
public JButton neueKanteButton;
public JButton neuerButton;
public JButton polygonKante; // hier wird die Straße welche die Form eines Polygonzuges hat in einem Button gespeichert
public JButton neuZeichnenButton1; // Zwischenspeicher für die einzuzeichnenden Knotenpunkte (Buttons)
public JButton neuZeichnenButton2; // Zwischenspeicher für die einzuzeichnenden Straßenzüge (Buttons)
public JPanel panelWest;
public JToggleButton button;
public PolylinePanel linePanel;
public JLabel statusLabel;
public Polyline currentLine;
public Landkarte(String title)
{
super(title);
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
this.setBounds(0, 0, 800, 800);
this.setLocationRelativeTo(null);
image = null;
try
{
image = new ImageIcon(this.getClass().getResource("bilder/weiss.jpg")).getImage();
}
catch (NullPointerException exc)
{
exc.printStackTrace();
}
panelWest = new JPanel();
panelWest.setLayout(null);
panelWest.setPreferredSize(new Dimension(200, 900));
this.getContentPane().add(panelWest, BorderLayout.WEST);
neueKanteButton = new JButton("Neue Kante erstellen");
neueKanteButton.setToolTipText("Hiermit wird eine neue Kante erstellt");
neueKanteButton.setFont(new Font("MS Sans Serif", Font.BOLD, 13));
neueKanteButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent evt)
{
neueKanteButton_ActionPerformed(evt);
}
}
);
neueKanteButton.setBounds(10, 215, 180, 60); // (x-Wert, y-Wert, Breite, Höhe)
panelWest.add(neueKanteButton);
kartenPanel = new PolylinePanel();
kartenPanel.setBackground(Color.WHITE);
this.getContentPane().add(kartenPanel, BorderLayout.CENTER);
kartenPanel.setPreferredSize(new Dimension(4807,2296)); // hier legen wir die Größe der Mal-Fläche fest, damit wir Scrollen können
kartenPanel.addMouseListener(new MouseAdapter() // abfangen und behandeln des Mouseclicks
{
@Override
public void mouseClicked(MouseEvent e)
{
Point aktuellerClick = new Point();
if (darfzeichnen == true) // es wird nur auf die Mouseclicks reagiert wenn auch gezeichnet werden darf
{
aktuellerClick = e.getPoint(); // der Mouseclick wird abgefangen und in einen Pointer gespeichert welcher den x-Wert und den y-Wert des Mouseclicks erhält
ArraysVerwalten(aktuellerClick) ; // die Position des Clicks wird an die Methode ArraysVerwalten weitergegeben um den Click zu behandeln
}
}
}
);
setResizable(true); // Größe des gesamten Fensters ist veränderbar
setVisible(true); // gesamtes Fenster ist sichtbar
// neuer Quelltext
linePanel = new PolylinePanel();
linePanel.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
if(button.isSelected()) {
if (currentLine==null) {
currentLine = new Polyline(null, 10);
linePanel.addLine(currentLine);
}
currentLine.add(e.getPoint());
linePanel.repaint();
}
else {
int index = linePanel.getLineIndexFor(e.getPoint());
if (index >=0)
statusLabel.setText("You clicked on line: " + index);
else
statusLabel.setText("To draw a line press the button and click into the panel");
}
}
});
button = new JToggleButton("Activate Drawing");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
currentLine = null;
if (button.isSelected()) {
button.setText("Drawing...");
statusLabel.setText("Press the button when you want to finish drawing");
}
else {
button.setText("Activate Drawing");
statusLabel.setText("To draw a line press the button and click into the panel");
}
}
});
statusLabel = new JLabel();
statusLabel.setBackground(Color.WHITE);
statusLabel.setOpaque(true);
statusLabel.setBorder(BorderFactory.createEtchedBorder());
statusLabel.setText("To draw a line press the button and click into the panel");
this.getContentPane().add(linePanel, BorderLayout.CENTER);
this.getContentPane().add(button, BorderLayout.NORTH);
this.getContentPane().add(statusLabel, BorderLayout.SOUTH);
}
// ------------------------------------------------------------------------------------------------------------
public void neueKanteButton_ActionPerformed(ActionEvent evt)
{
clickZaehler++; // zählt wie oft auf den Button gedrückt wurde
if (anfangPolygon == 1)
{
anfangPolygon = 0; // auf 0 setzen damit ich bei neuer Kante später wieder neue Auswahl treffen kann
darfzeichnen = false;
KnotenArray.add(KantenArray.get(KantenArray.size()-1)); // fügt dem Knotenarray den letzten Eintrag der Kante hinzu
neuerButton = new JButton(); // neuer Button wird an den anfang der kante gezeichnet
neuerButton.addActionListener(new ActionListener() // es wird ein ActionListener für alle Buttons erzeugt, da alle Buttons die Eigenschaften auf der rechten Seite verändern können soll
{ // zudem soll nicht für jeden einzelnen Button eine extra Methode mit ActionPerformed erzeugt werden
public void actionPerformed(ActionEvent evt)
{
neuerButton_ActionPerformed(evt);
}
}
);
ButtonArray.add(neuerButton);
kartenPanel.repaint();
neueKanteButton.setText("Neue Kante erstellen");
clickZaehler = 0; // auf 0 setzen damit manuelles drücken auf den neue Kante Button funktioniert
neueKanteButton.setFont(new Font("MS Sans Serif", Font.BOLD, 13));
neueKanteButton.setForeground(Color.BLACK);
}
if (clickZaehler == 1) // einmal geklickt --> es dürfen Knoten und Straßen eingezeichnet werden
{
darfzeichnen = true;
neueKanteButton.setText("Kante fertigstellen");
neueKanteButton.setFont(new Font("Arial", Font.BOLD, 16));
neueKanteButton.setForeground(Color.RED);
kartenPanel.repaint();
}
else // mehr als einmal geklickt --> es dürfen keine Knoten und Straßen mehr eingezeichnet werden
{
darfzeichnen = false;
neueKanteButton.setText("Neue Kante erstellen");
clickZaehler = 0;
neueKanteButton.setFont(new Font("MS Sans Serif", Font.BOLD, 13));
neueKanteButton.setForeground(Color.BLACK);
kartenPanel.repaint();
int Punkteanzahl = KantenArray.size()*2; // Anzahl der Knotenpunke wird verdoppelt, da der Straßenzug verschoben wieder rückwärts geht
int[] xWerte = new int[Punkteanzahl]; // Array um die aktuellen x-Werte abzuspeichern der Punkte
int[] yWerte = new int[Punkteanzahl]; // Array um die aktuellen y-Werte abzuspeichern der Punkte
for (int i = 0; i < KantenArray.size(); i = i + 1)
{ // die erste Schleife dient den Originalwerten
Point t = KantenArray.get(i); // auslesen des Knotenpunktes an der Stelle i
xWerte[i] = t.x;
yWerte[i] = t.y;
}
for (int i = 0; i < KantenArray.size(); i = i + 1) // die zweite Schleife füllt das Array mit dem verschobenen Straßenzug in umgekehrter Reihenfolge auf
{
Point t = KantenArray.get(KantenArray.size()-1-i);
xWerte[KantenArray.size()+i] = t.x+7;
yWerte[KantenArray.size()+i] = t.y+7;
}
Polygon polygonzug = new Polygon(xWerte, yWerte, Punkteanzahl); // erstellen eines Polygon aus den abgespeicherten x-Werten, y-Werten und der Anzahl der Paare
polygonKante = new PolygonButton(polygonzug); // erstellen eines neuen dummyButtons für die Straße am Ende
polygonKante.addActionListener(new ActionListener() // es wird ein ActionListener für alle Buttons erzeugt, da alle Buttons die Eigenschaften auf der rechten Seite verändern können soll
{ // zudem soll nicht für jeden einzelnen Button eine extra Methode mit ActionPerformed erzeugt werden
public void actionPerformed(ActionEvent evt)
{
polygonKante_ActionPerformed(evt);
}
}
);
ButtonKantenArray.add(polygonKante); // fügt den Button dem Array hinzu welches die Straßenbuttons verwaltet
KantenArray.clear(); // alle Koordinaten der zuletzt gezeichneten Straße werden gelöscht um Platz zu machen für die nächste
}
}
public void neuerButton_ActionPerformed(ActionEvent evt)
{
int gefunden = 0;
JButton suchen = (JButton) evt.getSource();
for (int i = 0; i < ButtonArray.size(); i++ ) // hier wird das Buttonarray auf der suche nach dem gerade gedrückten Button durchsucht
{
if ( suchen == ButtonArray.get(i) )
{
gefunden = i;
break;
}
}
if (darfzeichnen == true) // man befindet sich im Modus eine neue Kante einzeichnen zu können
{
anfangPolygon++; // wird um eins erhöht wenn auf den Button geklickt wurde, nun Unterscheidung ob es der Anfangs- oder Endpunkt der Kante wird
if (anfangPolygon == 1) // hierbei handelt es sich um den Anfang einer Kante welche mit einem bereits existierenden Button beginnt
{ }
else if (anfangPolygon == 2) // hierbei handelt es sich um das Ende einer Kante welche mit einem bereits existierenden Button endet
{
neueKanteButton.setText("Neue Kante erstellen");
clickZaehler = 0; // auf 0 setzen damit manuelles drücken auf den neue Kante Button funktioniert
neueKanteButton.setFont(new Font("MS Sans Serif", Font.BOLD, 13));
neueKanteButton.setForeground(Color.BLACK);
darfzeichnen = false;
anfangPolygon = 0; // auf 0 setzen damit ich bei neuer Kante später wieder neue Auswahl treffen kann
}
}
}
public void polygonKante_ActionPerformed(ActionEvent evt) // zuständig um die Eigenschaften der Straßen im Array abzuspeichern
{
int gefunden = 0;
JButton suchen = (JButton) evt.getSource();
for (int i = 0; i < ButtonKantenArray.size(); i++ ) // hier wird das Buttonarray auf der suche nach dem gerade gedrückten Button durchsucht
{
if ( suchen == ButtonKantenArray.get(i) )
{
gefunden = i;
break;
}
}
}
public void ArraysVerwalten(Point Click)
{
Point aktuellerClick = new Point();
aktuellerClick = Click; // übernehmen des übergebenen Mouseclicks
if (anfangPolygon == 0) // 0 bedeutet dass eine neue Kante noch keinen Anfang und kein Ende hat
{
anfangPolygon = 1; // nun besitzt die Kante einen Anfang
KantenArray.add(aktuellerClick);
KnotenArray.add(aktuellerClick);
neuerButton = new JButton(); // neuer Button wird erzeugt
neuerButton.addActionListener(new ActionListener() // es wird ein ActionListener für alle Buttons erzeugt, da alle Buttons die Eigenschaften auf der rechten Seite verändern können soll
{ // zudem soll nicht für jeden einzelnen Button eine extra Methode mit ActionPerformed erzeugt werden
public void actionPerformed(ActionEvent evt)
{
neuerButton_ActionPerformed(evt);
}
}
);
ButtonArray.add(neuerButton);
validate();
kartenPanel.repaint();
}
else if (anfangPolygon == 1) // die Kante besitzt bereits einen Anfangsknoten aber noch kein Ende, dieses muss erstellt werden
{
KantenArray.add(aktuellerClick);
kartenPanel.repaint(); // damit aktuelle Kante gleich eingezeichnet wird
}
}
public static void main(String[] args)
{
new Landkarte("Route festlegen");
}
// ---------------------------------------------------------------------------
class PolylinePanel extends JPanel {
private ArrayList<LineContainer> lines;
private Color[] color;
public PolylinePanel() {
lines = new ArrayList<LineContainer>();
color = new Color[] {Color.BLACK, Color.ORANGE, Color.BLUE};
this.addMouseMotionListener(new MouseMotionAdapter() {
public void mouseMoved(MouseEvent evt) {
for (LineContainer line : lines) {
if (line.getStatus()!=2);
line.setStatus(0);
}
int index = getLineIndexFor(evt.getPoint());
if (index >= 0)
lines.get(index).setStatus(1);
repaint();
}
});
}
public void addLine(Polyline line) {
this.lines.add(new LineContainer(line, 0));
}
public int getLineIndexFor(Point p) {
for (int i=lines.size()-1 ; i>=0; i--) {
LineContainer lineContainer = lines.get(i);
if (lineContainer.getLine().contains(p)) {
return i;
}
}
return -1;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (image != null)
g.drawImage(image, 0, 0, null);
Graphics2D g2 = (Graphics2D)g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
for(LineContainer lineContainer : lines) {
g2.setColor(color[lineContainer.getStatus()]);
g2.setStroke(new BasicStroke(lineContainer.getStrokeWidth(), BasicStroke.CAP_ROUND, BasicStroke.JOIN_MITER));
lineContainer.getLine().paint(g2);
}
g2.dispose();
}
class LineContainer {
private Polyline line;
private int status;
public LineContainer(Polyline line, int status) {
this.line = line;
this.status = status;
}
public Polyline getLine() {
return line;
}
public int getStrokeWidth() {
return line.getStrokeWidth();
}
public void setStatus(int status) {
this.status = status;
}
public int getStatus() {
return status;
}
}
}
class Polyline {
private ArrayList<Point> points;
private Rectangle boundingRect;
private int strokeWidth;
private float tolerance;
public Polyline(ArrayList<Point> points) {
this(points, 0);
}
public Polyline(ArrayList<Point> points, int width) {
if (points==null)
this.points = new ArrayList<Point>();
else
this.points = points;
this.setStrokeWidth(width);
}
public void add(Point p) {
this.points.add(p);
this.calculateBounds();
}
public void setStrokeWidth(int width) {
this.strokeWidth = width;
this.tolerance = 0.5f;
this.calculateBounds();
}
public int getStrokeWidth() {
return this.strokeWidth;
}
private void calculateBounds() {
if (points.size()<=0) {
boundingRect = new Rectangle(0, 0, 0, 0);
return;
}
Point p = points.get(0);
int xMin, xMax, yMin, yMax;
xMin = xMax = p.x;
yMin = yMax = p.y;
for(int i=1; i<points.size(); i++) {
p = points.get(i);
xMin = (p.x<xMin)?p.x:xMin;
yMin = (p.y<yMin)?p.y:yMin;
xMax = (p.x>xMax)?p.x:xMax;
yMax = (p.y>yMax)?p.y:yMax;
}
int intTol = (int)tolerance;
boundingRect = new Rectangle(xMin-intTol, yMin-intTol,
(xMax-xMin)+ 2*intTol +1, (yMax-yMin) + 2*intTol +1);
}
public Rectangle getBounds() {
return this.boundingRect;
}
public boolean contains(Point p) {
return this.contains(p.x, p.y);
}
public boolean contains(double x, double y) {
if (this.boundingRect.contains(x, y)) {
if (points.size()<2)
return true;
Point p1 = points.get(0);
for(int i=1; i<points.size(); i++) {
Point p2 = points.get(i);
if (isBetween(p1, p2, x, y))
return true;
p1 = p2;
}
}
return false;
}
private boolean isBetween(Point p1, Point p2, double x, double y) {
double p1X = p1.x, p1Y = p1.y;
double p2X = p2.x, p2Y = p2.y;
double t = tolerance;
//Checking if values are the coordinates of one of the points
if ((p1X-t <= x && p1X+t >= x && p1Y-t <= y && p1Y+t >= y) ||
(p2X-t <= x && p2X+t >= x && p2Y-t <= y && p2Y+t >= y))
return true;
//Checking if values are between both points by calculating the distances
double distance = Math.sqrt(Math.pow(p1X - p2X, 2) + Math.pow(p1Y - p2Y, 2));
double distanceValue = Math.sqrt(Math.pow(x - p1X, 2) + Math.pow(y - p1Y, 2))
+ Math.sqrt(Math.pow(x - p2X, 2) + Math.pow(y - p2Y, 2));
int minDist = (int)((distance-t)*100);
int maxDist = (int)((distance+t)*100);
int calcDist = (int)((distanceValue)*100);
return (minDist<=calcDist && calcDist<=maxDist);
}
public void paint(Graphics2D g) {
if (points.size()>1) {
Point p1 = points.get(0);
for(int i=1; i<points.size(); i++) {
Point p2 = points.get(i);
g.drawLine(p1.x, p1.y, p2.x, p2.y);
p1 = p2;
}
}
}
}
}