Improved performance math calculations used to model "Twisted Wires"

This commit is contained in:
bancika
2020-04-08 15:53:33 +02:00
parent fd8640ba3d
commit 9676a21b76
3 changed files with 80 additions and 55 deletions
@@ -2898,6 +2898,10 @@
<changeType>NEW_FEATURE</changeType>
<description>Added component-level caching that should speed up rendering dramatically. While in experimental phase, it will be exposed as "Enable Cache Boost" item in the "Config" menu so it can be turned off if it causes any issues</description>
</org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change>
<changeType>IMPROVEMENT</changeType>
<description>Improved performance math calculations used to model "Twisted Wires"</description>
</org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change>
<changeType>BUG_FIX</changeType>
<description>Older files that contain "Open Jack 1/4" components sometimes open with the jacks rotated the wrong way</description>
@@ -30,6 +30,7 @@ import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.diylc.common.LineStyle;
@@ -314,23 +315,26 @@ public class TwistedWire extends AbstractCurvedComponent<Void> implements IConti
else
stroke = ObjectCache.getInstance().fetchBasicStroke(thickness);
double segmentLength = thickness * 6;
double segmentLength = thickness * 6; // chosen empirically
// Convert to polygon
List<Line2D> polygon = new ArrayList<Line2D>();
for (CubicCurve2D curve : curves)
polygon.addAll(split(curve, segmentLength));
List<Path2D> firstCurves = new ArrayList<Path2D>();
List<Path2D> secondCurves = new ArrayList<Path2D>();
List<List<Path2D>> segments = new ArrayList<List<Path2D>>();
segments.add(new ArrayList<Path2D>());
segments.add(new ArrayList<Path2D>());
Path2D current1 = new Path2D.Double();
Path2D current2 = new Path2D.Double();
double offset = thickness * 1.5;
double rectSize = thickness * 3.5;
Path2D[] currentPaths = new Path2D[2];
currentPaths[0] = new Path2D.Double();
currentPaths[1] = new Path2D.Double();
current1.moveTo(polygon.get(0).getX1(), polygon.get(0).getY1());
current2.moveTo(polygon.get(0).getX1(), polygon.get(0).getY1());
double offset = thickness * 1.5; // chosen empirically
double rectSize = thickness * 3.5; // chosen empirically
currentPaths[0].moveTo(polygon.get(0).getX1(), polygon.get(0).getY1());
currentPaths[1].moveTo(polygon.get(0).getX1(), polygon.get(0).getY1());
// create curved paths for each segment of the twisted pair
for (int i = 0; i < polygon.size(); i++) {
@@ -340,59 +344,74 @@ public class TwistedWire extends AbstractCurvedComponent<Void> implements IConti
double theta = Math.atan2(line.getY2() - line.getY1(), line.getX2() - line.getX1());
double sign = i % 2 == 0 ? 1 : -1;
double[] thetas = new double[] { theta - sign * Math.PI / 2, theta + sign * Math.PI / 2};
double theta1 = theta - sign * Math.PI / 2;
double theta2 = theta + sign * Math.PI / 2;
int finalI = i;
current1.quadTo(centerX + offset * Math.cos(theta1),
centerY + offset * Math.sin(theta1), line.getX2(), line.getY2());
current2.quadTo(centerX + offset * Math.cos(theta2),
centerY + offset * Math.sin(theta2), line.getX2(), line.getY2());
// calculate curve segments in parallel
Arrays.stream(new Integer[] { 0, 1 }).parallel().forEach((j) -> {
currentPaths[j].quadTo(centerX + offset * Math.cos(thetas[j]),
centerY + offset * Math.sin(thetas[j]), line.getX2(), line.getY2());
if (finalI % 2 == 0 || finalI == polygon.size() - 1) {
segments.get(j).add(currentPaths[j]);
currentPaths[j] = new Path2D.Double();
currentPaths[j].moveTo(line.getX2(), line.getY2());
}
});
}
if (i % 2 == 0 || i == polygon.size() - 1) {
firstCurves.add(current1);
current1 = new Path2D.Double();
current1.moveTo(line.getX2(), line.getY2());
Area[] outputAreas = new Area[] { new Area(), new Area() };
// create stroked areas in parallel
Arrays.stream(new Integer[] { 0, 1 }).parallel().forEach((j) -> {
for (Path2D p : segments.get(j)) {
outputAreas[j].add(new Area(stroke.createStrokedShape(p)));
}
if (i % 2 == 1 || i == polygon.size() - 1) {
secondCurves.add(current2);
current2 = new Path2D.Double();
current2.moveTo(line.getX2(), line.getY2());
}
}
// convert to Area
for (Path2D p : firstCurves) {
firstLeadArea.add(new Area(stroke.createStrokedShape(p)));
}
for (Path2D p : secondCurves) {
secondLeadArea.add(new Area(stroke.createStrokedShape(p)));
}
});
// at overlapping points, decide which lead goes on top and clear the overlapping area from the lead below
Integer[] idx = new Integer[polygon.size()];
for (int i = 0; i < polygon.size(); i++) {
idx[i] = i;
}
Arrays.stream(idx).parallel().forEach(i -> {
Line2D line = polygon.get(i);
Area pointRect1 = new Area(new Rectangle2D.Double(line.getX1() - rectSize / 2, line.getY1() - rectSize / 2, rectSize, rectSize));
Area pointRect1 = new Area(new Rectangle2D.Double(line.getX1() - rectSize / 2,
line.getY1() - rectSize / 2, rectSize, rectSize));
if (i % 2 == 1) {
pointRect1.intersect(firstLeadArea);
secondLeadArea.subtract(pointRect1);
pointRect1.intersect(outputAreas[0]);
synchronized (outputAreas[1]) {
outputAreas[1].subtract(pointRect1);
}
} else {
pointRect1.intersect(secondLeadArea);
firstLeadArea.subtract(pointRect1);
pointRect1.intersect(outputAreas[1]);
synchronized (outputAreas[0]) {
outputAreas[0].subtract(pointRect1);
}
}
if (i == polygon.size() - 1) {
Area pointRect2 = new Area(new Rectangle2D.Double(line.getX2() - rectSize / 2, line.getY2() - rectSize / 2, rectSize, rectSize));
Area pointRect2 = new Area(new Rectangle2D.Double(line.getX2() - rectSize / 2,
line.getY2() - rectSize / 2, rectSize, rectSize));
if (i % 2 == 0) {
pointRect2.intersect(firstLeadArea);
secondLeadArea.subtract(pointRect2);
pointRect2.intersect(outputAreas[0]);
synchronized (outputAreas[1]) {
outputAreas[1].subtract(pointRect2);
}
} else {
pointRect2.intersect(secondLeadArea);
firstLeadArea.subtract(pointRect2);
pointRect2.intersect(outputAreas[1]);
synchronized (outputAreas[0]) {
outputAreas[0].subtract(pointRect2);
}
}
}
}
});
// dump to the output areas
firstLeadArea.add(outputAreas[0]);
secondLeadArea.add(outputAreas[1]);
}
// splits a curve into a series of lines
@@ -23,6 +23,7 @@ package org.diylc.swing.gui;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
@@ -108,6 +109,7 @@ public class MainFrame extends JFrame implements ISwingUI {
public MainFrame() {
super("DIYLC 3");
setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
setPreferredSize(new Dimension(1024, 700));
createBasePanels();
menuMap = new HashMap<String, JMenu>();
buttonGroupMap = new HashMap<String, ButtonGroup>();