saving JSON plus PNG preview
This commit is contained in:
parent
ad7562e3d2
commit
0eb53de222
@ -1,5 +1,6 @@
|
|||||||
package de.ph87.electro;
|
package de.ph87.electro;
|
||||||
|
|
||||||
|
import de.ph87.electro.circuit.CircuitIOService;
|
||||||
import de.ph87.electro.circuit.CircuitPanel;
|
import de.ph87.electro.circuit.CircuitPanel;
|
||||||
import de.ph87.electro.sidebar.Sidebar;
|
import de.ph87.electro.sidebar.Sidebar;
|
||||||
|
|
||||||
@ -17,7 +18,7 @@ public class Window extends JFrame {
|
|||||||
setExtendedState(MAXIMIZED_BOTH);
|
setExtendedState(MAXIMIZED_BOTH);
|
||||||
|
|
||||||
final CircuitPanel circuitPanel = new CircuitPanel();
|
final CircuitPanel circuitPanel = new CircuitPanel();
|
||||||
final Sidebar sidebar = new Sidebar(circuitPanel::newCircuit, circuitPanel::save);
|
final Sidebar sidebar = new Sidebar(circuitPanel::newCircuit, () -> CircuitIOService.save(circuitPanel.getCircuit()));
|
||||||
final JSplitPane splitter = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, sidebar, circuitPanel);
|
final JSplitPane splitter = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, sidebar, circuitPanel);
|
||||||
|
|
||||||
sidebar.setRepaintCallback(circuitPanel::repaint);
|
sidebar.setRepaintCallback(circuitPanel::repaint);
|
||||||
|
|||||||
@ -9,11 +9,9 @@ import de.ph87.electro.circuit.wire.Wire;
|
|||||||
import de.ph87.electro.circuit.wire.WireDto;
|
import de.ph87.electro.circuit.wire.WireDto;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.Setter;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -21,9 +19,6 @@ import java.util.List;
|
|||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import static de.ph87.electro.circuit.CircuitIOService.write;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
public class Circuit {
|
public class Circuit {
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@ -34,13 +29,19 @@ public class Circuit {
|
|||||||
|
|
||||||
private final List<Wire> wires = new ArrayList<>();
|
private final List<Wire> wires = new ArrayList<>();
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
private boolean dirty = false;
|
private boolean dirty = false;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
|
private File file = null;
|
||||||
|
|
||||||
public Circuit() {
|
public Circuit() {
|
||||||
this.created = ZonedDateTime.now().format(DateTimeFormatter.ISO_OFFSET_DATE_TIME);
|
this.created = ZonedDateTime.now().format(DateTimeFormatter.ISO_OFFSET_DATE_TIME);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Circuit(final CircuitDto dto) {
|
public Circuit(final File file, final CircuitDto dto) {
|
||||||
created = dto.getCreated();
|
created = dto.getCreated();
|
||||||
for (PartDto partDto : dto.getParts()) {
|
for (PartDto partDto : dto.getParts()) {
|
||||||
final Part part = Part.of(this, partDto);
|
final Part part = Part.of(this, partDto);
|
||||||
@ -96,22 +97,6 @@ public class Circuit {
|
|||||||
parts.forEach(Part::render);
|
parts.forEach(Part::render);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void save() {
|
|
||||||
if (!dirty) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
final File file = new File("./data/%s.json".formatted(created));
|
|
||||||
if (file.getParentFile().mkdirs()) {
|
|
||||||
log.info("Directory created: {}", file.getParent());
|
|
||||||
}
|
|
||||||
write(this, new FileOutputStream(file));
|
|
||||||
dirty = false;
|
|
||||||
} catch (IOException e) {
|
|
||||||
log.error(e.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void verifyFree(final Position position) {
|
private void verifyFree(final Position position) {
|
||||||
if (parts.stream().anyMatch(part -> part.getPosition().equals(position))) {
|
if (parts.stream().anyMatch(part -> part.getPosition().equals(position))) {
|
||||||
throw new RuntimeException();
|
throw new RuntimeException();
|
||||||
@ -146,4 +131,11 @@ public class Circuit {
|
|||||||
return wires.stream().filter(wire -> wire.intersects(position)).findFirst();
|
return wires.stream().filter(wire -> wire.intersects(position)).findFirst();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public File getPreviewFile() {
|
||||||
|
if (file == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new File(file.getAbsolutePath().replaceAll("\\.json$", ".png"));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,21 +1,55 @@
|
|||||||
package de.ph87.electro.circuit;
|
package de.ph87.electro.circuit;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import java.io.IOException;
|
import javax.imageio.ImageIO;
|
||||||
import java.io.InputStream;
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.OutputStream;
|
import java.io.*;
|
||||||
|
|
||||||
|
import static de.ph87.electro.circuit.CircuitPainter.paintCircuit;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
public class CircuitIOService {
|
public class CircuitIOService {
|
||||||
|
|
||||||
private static final ObjectMapper objectMapper = new ObjectMapper().findAndRegisterModules();
|
private static final ObjectMapper objectMapper = new ObjectMapper().findAndRegisterModules();
|
||||||
|
|
||||||
public static void write(final Circuit circuit, final OutputStream stream) throws IOException {
|
public static void save(final Circuit circuit) {
|
||||||
|
if (!circuit.isDirty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (circuit.getFile() == null) {
|
||||||
|
circuit.setFile(new File("./data/%s.json".formatted(circuit.getCreated())));
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (circuit.getFile().getParentFile().mkdirs()) {
|
||||||
|
log.info("Directory created: {}", circuit.getFile().getParent());
|
||||||
|
}
|
||||||
|
CircuitIOService.serialize(circuit, new FileOutputStream(circuit.getFile()));
|
||||||
|
circuit.setDirty(false);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error(e.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
final BufferedImage img = paintCircuit(circuit, 1920, 1080);
|
||||||
|
try {
|
||||||
|
ImageIO.write(img, "PNG", circuit.getPreviewFile());
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error(e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Circuit load(final File file) throws IOException {
|
||||||
|
return load(null, new FileInputStream(file));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Circuit load(final File file, final InputStream stream) throws IOException {
|
||||||
|
final CircuitDto dto = objectMapper.readValue(stream, CircuitDto.class);
|
||||||
|
return new Circuit(file, dto);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void serialize(final Circuit circuit, final OutputStream stream) throws IOException {
|
||||||
objectMapper.writeValue(stream, new CircuitDto(circuit));
|
objectMapper.writeValue(stream, new CircuitDto(circuit));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Circuit read(final InputStream stream) throws IOException {
|
|
||||||
return new Circuit(objectMapper.readValue(stream, CircuitDto.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
86
src/main/java/de/ph87/electro/circuit/CircuitPainter.java
Normal file
86
src/main/java/de/ph87/electro/circuit/CircuitPainter.java
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
package de.ph87.electro.circuit;
|
||||||
|
|
||||||
|
import de.ph87.electro.circuit.part.Part;
|
||||||
|
import de.ph87.electro.circuit.part.junction.Junction;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.geom.Rectangle2D;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
|
||||||
|
import static de.ph87.electro.CONFIG.*;
|
||||||
|
|
||||||
|
public class CircuitPainter {
|
||||||
|
|
||||||
|
public static BufferedImage paintCircuit(final Circuit circuit, final int w, final int h) {
|
||||||
|
final BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
|
||||||
|
final Graphics2D g = img.createGraphics();
|
||||||
|
paintCircuit(circuit, g, w, h);
|
||||||
|
return img;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void paintCircuit(final Circuit circuit, final Graphics2D g, final int w, final int h) {
|
||||||
|
drawBack(g, w, h);
|
||||||
|
drawParts(circuit, g);
|
||||||
|
drawRaster(g, w, h);
|
||||||
|
drawWires(circuit, g);
|
||||||
|
drawVoltages(circuit, g);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void drawBack(final Graphics2D g, final int w, final int h) {
|
||||||
|
g.setColor(Color.white);
|
||||||
|
g.fillRect(0, 0, w, h);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void drawParts(final Circuit circuit, final Graphics2D g) {
|
||||||
|
circuit.streamParts().forEach(part -> part.paint(g));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void drawRaster(final Graphics2D g, final int w, final int h) {
|
||||||
|
g.setStroke(RASTER_STROKE);
|
||||||
|
g.setColor(RASTER_COLOR);
|
||||||
|
for (int x = 0; x < w; x += RASTER) {
|
||||||
|
g.drawLine(x, 0, x, h);
|
||||||
|
}
|
||||||
|
for (int y = 0; y < h; y += RASTER) {
|
||||||
|
g.drawLine(0, y, w, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void drawWires(final Circuit circuit, final Graphics2D g) {
|
||||||
|
circuit.streamWires().forEach(wire -> wire.draw(g));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void drawVoltages(final Circuit circuit, final Graphics2D g) {
|
||||||
|
if (!SHOW_JUNCTION_VOLTAGES && !SHOW_JUNCTION_NAMES) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g.setColor(Color.BLACK);
|
||||||
|
g.setFont(LABEL_FONT);
|
||||||
|
final int third = g.getFont().getSize() / 3;
|
||||||
|
|
||||||
|
for (Part part : circuit.getParts()) {
|
||||||
|
for (final Junction junction : part.getJunctions()) {
|
||||||
|
if (SHOW_JUNCTION_NAMES) {
|
||||||
|
int offsetY = third;
|
||||||
|
if (SHOW_JUNCTION_VOLTAGES) {
|
||||||
|
offsetY -= third;
|
||||||
|
}
|
||||||
|
final String string = junction.getName();
|
||||||
|
final Rectangle2D bounds = g.getFontMetrics().getStringBounds(string, g);
|
||||||
|
g.drawString(string, junction.getPosition().absolute.x - (int) (bounds.getWidth() / 2), junction.getPosition().absolute.y + offsetY);
|
||||||
|
}
|
||||||
|
if (SHOW_JUNCTION_VOLTAGES) {
|
||||||
|
int offsetY = third;
|
||||||
|
if (SHOW_JUNCTION_NAMES) {
|
||||||
|
offsetY += 2 * third;
|
||||||
|
}
|
||||||
|
final String string = "%.1fV".formatted(junction.getVoltage());
|
||||||
|
final Rectangle2D bounds = g.getFontMetrics().getStringBounds(string, g);
|
||||||
|
g.drawString(string, junction.getPosition().absolute.x - (int) (bounds.getWidth() / 2), junction.getPosition().absolute.y + offsetY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,7 +1,5 @@
|
|||||||
package de.ph87.electro.circuit;
|
package de.ph87.electro.circuit;
|
||||||
|
|
||||||
import de.ph87.electro.circuit.part.Part;
|
|
||||||
import de.ph87.electro.circuit.part.junction.Junction;
|
|
||||||
import de.ph87.electro.circuit.part.parts.Battery;
|
import de.ph87.electro.circuit.part.parts.Battery;
|
||||||
import de.ph87.electro.circuit.part.parts.Light;
|
import de.ph87.electro.circuit.part.parts.Light;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
@ -9,9 +7,8 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.geom.Rectangle2D;
|
|
||||||
|
|
||||||
import static de.ph87.electro.CONFIG.*;
|
import static de.ph87.electro.circuit.CircuitPainter.paintCircuit;
|
||||||
import static de.ph87.electro.circuit.part.Position.RST;
|
import static de.ph87.electro.circuit.part.Position.RST;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@ -34,81 +31,14 @@ public class CircuitPanel extends JPanel {
|
|||||||
@Override
|
@Override
|
||||||
public void paint(final Graphics _g) {
|
public void paint(final Graphics _g) {
|
||||||
final Graphics2D g = (Graphics2D) _g;
|
final Graphics2D g = (Graphics2D) _g;
|
||||||
final int w = getWidth();
|
paintCircuit(circuit, g, getWidth(), getHeight());
|
||||||
final int h = getHeight();
|
|
||||||
drawBack(g, w, h);
|
|
||||||
drawParts(g);
|
|
||||||
drawRaster(g, w, h);
|
|
||||||
drawWires(g);
|
|
||||||
drawVoltages(g);
|
|
||||||
mouseAdapter.drawHover(g);
|
mouseAdapter.drawHover(g);
|
||||||
mouseAdapter.drawDrag(g);
|
mouseAdapter.drawDrag(g);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void drawBack(final Graphics2D g, final int w, final int h) {
|
|
||||||
g.setColor(Color.white);
|
|
||||||
g.fillRect(0, 0, w, h);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void drawParts(final Graphics2D g) {
|
|
||||||
circuit.streamParts().forEach(part -> part.paint(g));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void drawRaster(final Graphics2D g, final int w, final int h) {
|
|
||||||
g.setStroke(RASTER_STROKE);
|
|
||||||
g.setColor(RASTER_COLOR);
|
|
||||||
for (int x = 0; x < w; x += RASTER) {
|
|
||||||
g.drawLine(x, 0, x, h);
|
|
||||||
}
|
|
||||||
for (int y = 0; y < h; y += RASTER) {
|
|
||||||
g.drawLine(0, y, w, y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void drawWires(final Graphics2D g) {
|
|
||||||
circuit.streamWires().forEach(wire -> wire.draw(g));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void drawVoltages(final Graphics2D g) {
|
|
||||||
if (!SHOW_JUNCTION_VOLTAGES && !SHOW_JUNCTION_NAMES) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
g.setColor(Color.BLACK);
|
|
||||||
g.setFont(LABEL_FONT);
|
|
||||||
final int third = g.getFont().getSize() / 3;
|
|
||||||
|
|
||||||
for (Part part : circuit.getParts()) {
|
|
||||||
for (final Junction junction : part.getJunctions()) {
|
|
||||||
if (SHOW_JUNCTION_NAMES) {
|
|
||||||
int offsetY = third;
|
|
||||||
if (SHOW_JUNCTION_VOLTAGES) {
|
|
||||||
offsetY -= third;
|
|
||||||
}
|
|
||||||
final String string = junction.getName();
|
|
||||||
final Rectangle2D bounds = g.getFontMetrics().getStringBounds(string, g);
|
|
||||||
g.drawString(string, junction.getPosition().absolute.x - (int) (bounds.getWidth() / 2), junction.getPosition().absolute.y + offsetY);
|
|
||||||
}
|
|
||||||
if (SHOW_JUNCTION_VOLTAGES) {
|
|
||||||
int offsetY = third;
|
|
||||||
if (SHOW_JUNCTION_NAMES) {
|
|
||||||
offsetY += 2 * third;
|
|
||||||
}
|
|
||||||
final String string = "%.1fV".formatted(junction.getVoltage());
|
|
||||||
final Rectangle2D bounds = g.getFontMetrics().getStringBounds(string, g);
|
|
||||||
g.drawString(string, junction.getPosition().absolute.x - (int) (bounds.getWidth() / 2), junction.getPosition().absolute.y + offsetY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void newCircuit() {
|
public void newCircuit() {
|
||||||
circuit = new Circuit();
|
circuit = new Circuit();
|
||||||
repaint();
|
repaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void save() {
|
|
||||||
circuit.save();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package de.ph87.electro.circuit.io;
|
package de.ph87.electro.circuit.io;
|
||||||
|
|
||||||
import de.ph87.electro.circuit.Circuit;
|
import de.ph87.electro.circuit.Circuit;
|
||||||
|
import de.ph87.electro.circuit.CircuitIOService;
|
||||||
import de.ph87.electro.circuit.part.Part;
|
import de.ph87.electro.circuit.part.Part;
|
||||||
import de.ph87.electro.circuit.part.junction.Junction;
|
import de.ph87.electro.circuit.part.junction.Junction;
|
||||||
import de.ph87.electro.circuit.part.parts.Battery;
|
import de.ph87.electro.circuit.part.parts.Battery;
|
||||||
@ -12,8 +13,7 @@ import java.io.ByteArrayOutputStream;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
import static de.ph87.electro.circuit.CircuitIOService.read;
|
import static de.ph87.electro.circuit.CircuitIOService.serialize;
|
||||||
import static de.ph87.electro.circuit.CircuitIOService.write;
|
|
||||||
import static de.ph87.electro.circuit.part.Position.RST;
|
import static de.ph87.electro.circuit.part.Position.RST;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
@ -31,12 +31,12 @@ class CircuitIOServiceTest {
|
|||||||
|
|
||||||
private void check(final Circuit original) throws IOException {
|
private void check(final Circuit original) throws IOException {
|
||||||
final ByteArrayOutputStream output = new ByteArrayOutputStream();
|
final ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||||
write(original, output);
|
serialize(original, output);
|
||||||
|
|
||||||
System.out.println(output.toString(StandardCharsets.UTF_8));
|
System.out.println(output.toString(StandardCharsets.UTF_8));
|
||||||
|
|
||||||
final ByteArrayInputStream input = new ByteArrayInputStream(output.toByteArray());
|
final ByteArrayInputStream input = new ByteArrayInputStream(output.toByteArray());
|
||||||
final Circuit reloaded = read(input);
|
final Circuit reloaded = CircuitIOService.load(null, input);
|
||||||
|
|
||||||
assertEquals(original.getCreated(), reloaded.getCreated());
|
assertEquals(original.getCreated(), reloaded.getCreated());
|
||||||
assertEquals(original.getPartCount(), reloaded.getPartCount());
|
assertEquals(original.getPartCount(), reloaded.getPartCount());
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user