First commit, added all projects

This commit is contained in:
2026-05-31 14:39:57 -04:00
commit d2930f7af5
247 changed files with 22376354 additions and 0 deletions
+26
View File
@@ -0,0 +1,26 @@
package gui;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
/**
* @param <T> The type of elements in the document
*/
public interface Cartographer<T>
{
/**
* @param model The document to paint
* @param g2 The graphics context to paint on
* @param at The affine transform to apply to the graphics context before painting
*/
public void paintHighlights(final CartographyDocument<T> model, final Graphics2D g2,
final AffineTransform at);
/**
* @param model The document to paint
* @param g2 The graphics context to paint on
* @param at The affine transform to apply to the graphics context before painting
*/
public void paintShapes(final CartographyDocument<T> model, final Graphics2D g2,
final AffineTransform at);
}
+67
View File
@@ -0,0 +1,67 @@
package gui;
import java.awt.geom.Rectangle2D;
import java.util.Iterator;
import java.util.Map;
/**
* @param <T> The type of elements in the document
*/
public class CartographyDocument<T> implements Iterable<T>
{
private Map<String, T> highlighted;
private Map<String, T> elements;
private Rectangle2D.Double bounds;
/**
* @param elements The elements in the document, mapped by their id
* @param bounds The bounds of the document
*/
public CartographyDocument(final Map<String, T> elements, final Rectangle2D.Double bounds)
{
this.elements = elements;
this.bounds = bounds;
this.highlighted = Map.of();
}
/**
* @return The bounds of the document
*/
public Rectangle2D.Double getBounds()
{
return bounds;
}
/**
* @param id The id of the element to get
* @return The element with the given id, or null if no such element exists
*/
public T getElement(final String id)
{
return elements.get(id);
}
/**
* @return The iterator of highlighted elements in the document
*/
public Iterator<T> highlighted()
{
return highlighted.values().iterator();
}
/**
* @return The iterator of all elements in the document
*/
public Iterator<T> iterator()
{
return elements.values().iterator();
}
/**
* @param highlighted The new highlighted elements, mapped by their id
*/
public void setHighlighted(final Map<String, T> highlighted)
{
this.highlighted = highlighted;
}
}
+288
View File
@@ -0,0 +1,288 @@
package gui;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.geom.*;
import java.util.*;
import math.*;
/**
* A GUI component that can be extended to draw maps of various kinds.
*
* @param <T> The type of the data
*
* @author Prof. David Bernstein, James Madison University
* @version 1.0
*/
public class CartographyPanel<T> extends JPanel implements MouseListener, MouseMotionListener
{
private static final long serialVersionUID = 1L;
protected DisplayCoordinatesTransformation displayTransform;
protected LinkedList<Rectangle2D.Double> zoomStack;
private CartographyDocument<T> model;
private Cartographer<T> cartographer;
private int[] rbMax, rbMin, rbStart, rbStop; // For the rubber-band-box
/**
* Explicit Value Constructor.
*
* @param model The model to use
* @param cartographer The cartographer to use
*/
public CartographyPanel(final CartographyDocument<T> model,
final Cartographer<T> cartographer)
{
displayTransform = new DisplayCoordinatesTransformation();
this.model = model;
zoomStack = new LinkedList<Rectangle2D.Double>();
zoomStack.add(model.getBounds());
this.cartographer = cartographer;
rbStart = new int[2];
rbStop = new int[2];
rbMax = new int[2];
rbMin = new int[2];
addMouseListener(this);
addMouseMotionListener(this);
setDoubleBuffered(false);
}
/**
* Handle a de-selection event (i.e., a zoom-out).
*/
public void handleDeselect()
{
if (zoomStack.size() > 1)
{
zoomStack.removeFirst();
repaint();
}
}
/**
* Handle a selection event (i.e., a zoom-in).
*
* @param min The upper-left of the selection (in screen coordinates)
* @param max The lower-right of the selection (in screen coordinates)
*/
protected void handleSelect(final double[] min, final double[] max)
{
double scale = displayTransform.getLastTransform().getScaleX();
double translateX = displayTransform.getLastTransform().getTranslateX();
double translateY = displayTransform.getLastTransform().getTranslateY();
double x = (min[0] - translateX) / scale;
double y = (min[1] - translateY) / scale;
double width = (max[0] - translateX) / scale - x;
double height = (max[1] - translateY) / scale - y;
Rectangle2D.Double r = new Rectangle2D.Double(x, y, width, height);
zoomStack.addFirst((Rectangle2D.Double)
(displayTransform.getLastReflection().createTransformedShape(r).getBounds2D()));
repaint();
}
/**
* Initialize the zoom stack.
*
* @param bounds The initial bounds
*/
private void initializeZoomStack(final Rectangle2D.Double bounds)
{
zoomStack = new LinkedList<Rectangle2D.Double>();
zoomStack.add(bounds);
}
/**
* Handle mouseClicked events.
*
* @param evt The MouseEvent
*/
@Override
public void mouseClicked(final MouseEvent evt)
{
if (evt.getClickCount() > 1)
{
handleDeselect();
}
}
/**
* Handle mouseDragged events.
*
* @param evt The MouseEvent
*/
@Override
public void mouseDragged(final MouseEvent evt)
{
int over = evt.getX();
int down = evt.getY();
Graphics g = getGraphics();
setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
// Erase the old rubber-band-box
g.setXORMode(getBackground());
g.setColor(Color.green);
g.drawRect(rbMin[0], rbMin[1], rbMax[0]-rbMin[0], rbMax[1]-rbMin[1]);
// Calculate the coordinates of the new rubber-band-box
rbStop[0] = over;
rbStop[1] = down;
rbMin[0] = Math.min(rbStart[0],rbStop[0]);
rbMin[1] = Math.min(rbStart[1],rbStop[1]);
rbMax[0] = Math.max(rbStart[0],rbStop[0]);
rbMax[1] = Math.max(rbStart[1],rbStop[1]);
// Draw the new rubber-band-box
g.drawRect(rbMin[0], rbMin[1], rbMax[0]-rbMin[0], rbMax[1]-rbMin[1]);
g.setPaintMode();
g.dispose();
}
/**
* Handle mouseEntered events.
*
* @param evt The MouseEvent
*/
@Override
public void mouseEntered(final MouseEvent evt)
{
}
/**
* Handle mouseExited events.
*
* @param evt The MouseEvent
*/
@Override
public void mouseExited(final MouseEvent evt)
{
}
/**
* Handle mouseMoved events.
*
* @param evt The MouseEvent
*/
@Override
public void mouseMoved(final MouseEvent evt)
{
}
/**
* Handle mousePressed events.
*
* @param evt The MouseEvent
*/
@Override
public void mousePressed(final MouseEvent evt)
{
int over = evt.getX();
int down = evt.getY();
rbStart[0] = over;
rbStart[1] = down;
rbStop[0] = over;
rbStop[1] = down;
rbMin[0] = over;
rbMin[1] = down;
rbMax[0] = over;
rbMax[1] = down;
}
/**
* Handle mouseReleased events.
*
* @param evt The MouseEvent
*/
@Override
public void mouseReleased(final MouseEvent evt)
{
Graphics g = getGraphics();
Dimension d = getSize();
g.setClip(0, 0, d.width, d.height);
// Erase the old line
g.setXORMode(getBackground());
g.setColor(Color.green);
g.drawRect(rbMin[0], rbMin[1], rbMax[0]-rbMin[0], rbMax[1]-rbMin[1]);
// Determine the selected region
double[] min = new double[2];
min[0] = (double)(rbMin[0]);
min[1] = (double)(rbMin[1] - 1);
double[] max = new double[2];
max[0] = (double)(rbMax[0]);
max[1] = (double)(rbMax[1] - 1);
// Reset the graphics environment
g.setPaintMode();
g.dispose();
setCursor(Cursor.getDefaultCursor());
// Notify any children of the selection
if ((min[0] != max[0]) || (min[1] != max[1]))
{
handleSelect(min, max);
}
}
/**
* Render this component.
*
* @param g The rendering engine to use
*/
@Override
public void paint(final Graphics g)
{
Graphics2D g2 = (Graphics2D)g;
Rectangle screenBounds = g2.getClipBounds();
g2.setColor(getBackground());
g2.fill(screenBounds);
g2.setColor(Color.BLACK);
Rectangle2D.Double bounds = zoomStack.getFirst();
AffineTransform at = displayTransform.getTransform(screenBounds, bounds);
cartographer.paintShapes(model, g2, at);
cartographer.paintHighlights(model, g2, at);
}
/**
* Set the model.
*
* @param model The model
*/
public void setModel(final CartographyDocument<T> model)
{
this.model = model;
initializeZoomStack(model.getBounds());
repaint();
}
}
+292
View File
@@ -0,0 +1,292 @@
package gui;
import dataprocessing.*;
import feature.Street;
import feature.StreetSegmentObserver;
import feature.StreetSegmentSubject;
import java.awt.*;
import java.awt.event.*;
import java.util.Arrays;
import java.util.List;
import java.util.ArrayList;
import javax.swing.*;
import javax.swing.event.*;
/**
* A dialog box for a Geocoder.
*
* @author Prof. David Bernstein, James Madison University
* @version 1.0
*/
public class GeocodeDialog extends JDialog implements
ActionListener, ListSelectionListener, StreetSegmentSubject
{
// Constants with package visibility
static final String CATEGORY = "Category";
static final String GEOCODE = "Geocode";
static final String NAME = "Name";
static final String NUMBER = "Number";
static final String PREFIX = "Prefix";
static final String SUFFIX = "Suffix";
// Constants with private visibility
private static final String QUOTE = "\"";
private static final long serialVersionUID = 1L;
// Attributes
private List<String> ids;
private List<StreetSegmentObserver> observers;
private Geocoder geocoder;
private JButton geocodeButton;
private JComboBox<String> categoryField, prefixField, suffixField;
private JList<String> resultsArea;
private JTextField nameField, numberField;
/**
* Explicit Value Constructor.
*
* @param owner The owning JFrame
* @param geocoder The Geocoder
*/
public GeocodeDialog(final JFrame owner, final Geocoder geocoder)
{
super(owner, "Geocoder", false);
this.geocoder = geocoder;
observers = new ArrayList<StreetSegmentObserver>();
numberField = createJTextField();
prefixField = createJComboBox(null);
nameField = createJTextField();
categoryField = createJComboBox(null);
suffixField = createJComboBox(null);
geocodeButton = new JButton(GEOCODE);
geocodeButton.addActionListener(this);
resultsArea = new JList<String>(new DefaultListModel<String>());
resultsArea.addListSelectionListener(this);
String[] directions = new String[] {"E","N","NE","NW","S","SE","SW","W"};
populate(prefixField, directions);
populate(categoryField, new String[] {"Aly","Arc","Ave","Blvd","Br","Brg","Byp","Cir",
"Cres","Cswy","Ct","Ctr","Cv","Dr","Expy","Fwy","Grd","Hwy","Ln","Loop","Mal","Pass",
"Path","Pike","Pky","Pl","Plz","Ramp","Rd","Row","Rte","Rue","Run","Spur","Sq","St",
"Ter","Tpke","Trce","Trl","Tunl","Walk","Way","Xing"});
populate(suffixField, directions);
performLayout();
setSize(800, 400);
}
/**
* Handle actionPerformed() messages.
*
* @param evt The event that generated the message.
*/
public void actionPerformed(final ActionEvent evt)
{
DefaultListModel<String> listModel = (DefaultListModel<String>)resultsArea.getModel();
listModel.clear();
String prefix = prefixField.getItemAt(prefixField.getSelectedIndex());
String name = nameField.getText();
String category = categoryField.getItemAt(categoryField.getSelectedIndex());
String suffix = suffixField.getItemAt(suffixField.getSelectedIndex());
int number = 0;
try
{
number = Integer.parseInt(numberField.getText());
String canonicalName = Street.createCanonicalName(prefix, name, category, suffix);
ids = new ArrayList<String>();
List<double[]> locations = geocoder.geocode(canonicalName, number, ids);
List<String> lonlat = new ArrayList<String>();
for (double[] location: locations) lonlat.add(location[0] + "," + location[1]);
displayResults(lonlat);
}
catch (NumberFormatException nfe)
{
JOptionPane.showMessageDialog(this, QUOTE+numberField.getText()+QUOTE
+ " is not a valid street number!",
"Input Error", JOptionPane.ERROR_MESSAGE);
}
}
/**
* Add a StreetSegmentObserver to this subject.
*
* @param observer The observer
*/
@Override
public void addStreetSegmentObserver(final StreetSegmentObserver observer)
{
observers.add(observer);
}
/**
* Create a JPanel containing a Jcomponent and a titled-border.
*
* @param title The title
* @param component The JComponent
* @return The JPanel
*/
private JPanel createTitledComponent(final String title, final JComponent component)
{
JPanel result = new JPanel();
result.setLayout(new BorderLayout());
result.add(component, BorderLayout.CENTER);
result.setBorder(BorderFactory.createTitledBorder(title));
return result;
}
/**
* Create a JComboBox.
*
* @param items The items to include (after the blank)
* @return The JComboBox
*/
private JComboBox<String> createJComboBox(final String[] items)
{
JComboBox<String> result = new JComboBox<String>();
result.setEditable(false);
populate(result, items);
return result;
}
/**
* Create a JTextField.
*
* @return The JTextField
*/
private JTextField createJTextField()
{
JTextField result = new JTextField("", 6);
return result;
}
/**
* Display result.
*
* @param results The results to display
*/
private void displayResults(final List<String> results)
{
DefaultListModel<String> model = (DefaultListModel<String>)resultsArea.getModel();
model.clear();
if (results != null)
{
for (String line: results) model.addElement(line);
}
}
/**
* Notify all of the StreetSegmentObserver objects of a
* handleStreetSegment() message.
*
* @param segmendIDs The IDs of the StreetSegment objects
*/
private void notifyStreetSegmentObservers(final List<String> segmendIDs)
{
for (StreetSegmentObserver observer: observers) observer.handleStreetSegments(segmendIDs);
}
/**
* Layout this Component.
*
*/
private void performLayout()
{
JPanel contentPane = (JPanel)getContentPane();
contentPane.setLayout(new BorderLayout());
JToolBar toolBar = new JToolBar();
toolBar.setFloatable(false);
toolBar.addSeparator();
toolBar.add(geocodeButton);
contentPane.add(toolBar, BorderLayout.SOUTH);
Row entryPanel = new Row();
entryPanel.add(createTitledComponent(NUMBER, numberField), 1, 0.0);
entryPanel.add(createTitledComponent(PREFIX, prefixField), 1, 0.0);
entryPanel.add(createTitledComponent(NAME, nameField), 3, 100.0);
entryPanel.add(createTitledComponent(CATEGORY, categoryField), 1, 0.0);
entryPanel.add(createTitledComponent(SUFFIX, suffixField), 1, 0.0);
JPanel center = new JPanel();
center.setLayout(new BorderLayout());
center.add(entryPanel, BorderLayout.NORTH);
JScrollPane sp = new JScrollPane(resultsArea);
sp.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
sp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
center.add(sp, BorderLayout.CENTER);
contentPane.add(center, BorderLayout.CENTER);
}
/**
* Populate a JComboBox.
*
* @param comboBox The JComboBox to populate
* @param items The items to populate it with (or null to reset)
*/
private void populate(final JComboBox<String> comboBox, final String[] items)
{
comboBox.removeAllItems();
comboBox.addItem("");
if (items != null)
{
Arrays.sort(items);
for (String item: items) comboBox.addItem(item);
}
}
/**
* Remove a StreetSegmentObserver from this subject.
*
* @param observer The observer
*/
@Override
public void removeStreetSegmentObserver(final StreetSegmentObserver observer)
{
observers.remove(observer);
}
/**
* Set the selection mode (e.g., ListSelectionModel.SINGLE_SELECTION) for the JList.
*
* @param mode The selection mode
*/
public void setSelectionMode(final int mode)
{
resultsArea.setSelectionMode(mode);
}
/**
* Handle valueChanged() messages.
*
* @param evt The event that generated the message
*/
@Override
public void valueChanged(final ListSelectionEvent evt)
{
if (!evt.getValueIsAdjusting())
{
int indexes[] = resultsArea.getSelectedIndices();
List<String> selectedIDs = new ArrayList<String>();
for (int i=0; i<indexes.length; i++)
{
selectedIDs.add(ids.get(indexes[i]));
}
notifyStreetSegmentObservers(selectedIDs);
}
}
}
@@ -0,0 +1,49 @@
package gui;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import geography.GeographicShape;
/**
*
*/
public class GeographicShapeCartographer implements Cartographer<GeographicShape>
{
private Color color;
/**
* @param color
* The color to use when rendering the shapes.
*/
public GeographicShapeCartographer(final Color color)
{
this.color = color;
}
@Override
public void paintHighlights(final CartographyDocument<GeographicShape> model, final Graphics2D g2,
final AffineTransform at)
{
g2.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), 128));
GeographicShape shape;
while (model.highlighted().hasNext())
{
shape = model.highlighted().next();
g2.fill(at.createTransformedShape(shape.getShape()));
}
}
@Override
public void paintShapes(final CartographyDocument<GeographicShape> model, final Graphics2D g2,
final AffineTransform at)
{
g2.setColor(color);
for (GeographicShape shape : model)
{
g2.draw(at.createTransformedShape(shape.getShape()));
}
}
}
+56
View File
@@ -0,0 +1,56 @@
package gui;
import java.awt.*;
import javax.swing.*;
/**
* A JPanel that is layed-out in the horizontal dimension.
* Individual elements can be sized relative to each other and
* their "expandability" can be specified.
*
* @author Prof. David Bernstein, James Madsion University
* @version 1.0
*/
public class Row extends JPanel
{
private static final long serialVersionUID = 1L;
private GridBagLayout layout;
private int column;
/**
* Default Constructor.
*/
public Row()
{
super();
column = 0;
layout = new GridBagLayout();
setLayout(layout);
}
/**
* Add a Component to this Row.
* Note: The expandability of all Component objects normally sum to 100.
*
* @param component The Component to add
* @param width The width (in cells) of this Component
* @param expandability The percentage of extra space that this Component should use
*/
public void add(final Component component, final int width, final double expandability)
{
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = column;
gbc.gridy = 0;
gbc.gridwidth = width;
gbc.gridheight = 1;
if (expandability > 0.0) gbc.fill = GridBagConstraints.HORIZONTAL;
else gbc.fill = GridBagConstraints.NONE;
gbc.weightx = expandability;
layout.setConstraints(component, gbc);
add(component);
column += width;
}
}
@@ -0,0 +1,54 @@
package gui;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.util.Iterator;
import feature.StreetSegment;
import feature.StreetThemeLibrary;
import geography.Theme;
import geography.ThemeLibrary;
/**
* A cartographer for rendering street segments.
*/
public class StreetSegmentCartographer implements Cartographer<StreetSegment>
{
private ThemeLibrary themeLibrary = new StreetThemeLibrary();
/**
*
*/
public StreetSegmentCartographer()
{
}
@Override
public void paintHighlights(final CartographyDocument<StreetSegment> model, final Graphics2D g2,
final AffineTransform at)
{
StreetSegment segment;
Iterator<StreetSegment> it = model.highlighted();
while (it.hasNext())
{
segment = it.next();
Theme theme = themeLibrary.getHighlightTheme();
g2.setColor(theme.getColor());
g2.setStroke(theme.getStroke());
g2.draw(at.createTransformedShape(segment.getGeographicShape().getShape()));
}
}
@Override
public void paintShapes(final CartographyDocument<StreetSegment> model, final Graphics2D g2,
final AffineTransform at)
{
for (StreetSegment segment : model)
{
Theme theme = themeLibrary.getTheme(segment.getCode());
g2.setColor(theme.getColor());
g2.setStroke(theme.getStroke());
g2.draw(at.createTransformedShape(segment.getGeographicShape().getShape()));
}
}
}