Vastly improved orientation calculation and implementation
authorChristian Femers <femers@in.tum.de>
Sun, 1 Sep 2019 00:47:04 +0000 (02:47 +0200)
committerChristian Femers <femers@in.tum.de>
Sun, 1 Sep 2019 00:47:04 +0000 (02:47 +0200)
Let's be serious, nobody understood the old one and it was completely
unreadable. This is much better now and can be reused as needed, even
for asymmetric components. Performance should be roughly the same as
before.

net.mograsim.logic.model/src/net/mograsim/logic/model/model/components/Orientation.java [new file with mode: 0644]
net.mograsim.logic.model/src/net/mograsim/logic/model/model/components/OrientationCalculator.java [new file with mode: 0644]
net.mograsim.logic.model/src/net/mograsim/logic/model/model/components/atomic/GUITriStateBuffer.java

diff --git a/net.mograsim.logic.model/src/net/mograsim/logic/model/model/components/Orientation.java b/net.mograsim.logic.model/src/net/mograsim/logic/model/model/components/Orientation.java
new file mode 100644 (file)
index 0000000..9fba366
--- /dev/null
@@ -0,0 +1,65 @@
+package net.mograsim.logic.model.model.components;
+
+/**
+ * For components that can have different orientations. The meaning is not clearly defined, however it is common that the orientation
+ * denotes the direction the output is facing or the general flow of signals. <code>_ALT</code> represents an alternative, which is normally
+ * a mirrored version. A component can choose to not support some variants.
+ * <p>
+ * In terms of calculation, {@link #RIGHT} is considered the default.
+ * <p>
+ * Note that this needs to be interpreted using the GUI coordinate system, meaning that UP and DOWN are swapped.
+ * 
+ * @author Christian Femers
+ */
+public enum Orientation
+{
+       /**
+        * The orientation <code>RIGHT</code> is the default orientation, all others are defined relative to it.
+        */
+       RIGHT(1, 0, 0, 1), LEFT(-1, 0, 0, -1), UP(0, 1, -1, 0), DOWN(0, -1, 1, 0), RIGHT_ALT(1, 0, 0, -1), LEFT_ALT(-1, 0, 0, 1),
+       UP_ALT(0, -1, -1, 0), DOWN_ALT(0, 1, 1, 0);
+
+       // simple 2D transformation matrix
+       final double trans11;
+       final double trans12;
+       final double trans21;
+       final double trans22;
+
+       private Orientation(double trans11, double trans12, double trans21, double trans22)
+       {
+               this.trans11 = trans11;
+               this.trans12 = trans12;
+               this.trans21 = trans21;
+               this.trans22 = trans22;
+       }
+
+       /**
+        * Performs a simple rotation around the origin. This does not work for the display coordinate system.
+        * 
+        * @return the point's new X coordinate
+        */
+       public double getNewX(double rightX, double rightY)
+       {
+               return rightX * trans11 + rightY * trans12;
+       }
+
+       /**
+        * Performs a simple rotation around the origin. This does not work for the display coordinate system.
+        * 
+        * @return the point's new Y coordinate
+        */
+       public double getNewY(double rightX, double rightY)
+       {
+               return rightX * trans21 + rightY * trans22;
+       }
+
+       public boolean doesMirror()
+       {
+               return ordinal() > 3;
+       }
+
+       public boolean swapsWidthAndHeight()
+       {
+               return trans11 == 0;
+       }
+}
\ No newline at end of file
diff --git a/net.mograsim.logic.model/src/net/mograsim/logic/model/model/components/OrientationCalculator.java b/net.mograsim.logic.model/src/net/mograsim/logic/model/model/components/OrientationCalculator.java
new file mode 100644 (file)
index 0000000..f16eaa9
--- /dev/null
@@ -0,0 +1,76 @@
+package net.mograsim.logic.model.model.components;
+
+/**
+ * This class simplifies the calculation of coordinates, especially for GUI components.
+ * <p>
+ * Supply it with the original width and height and an orientation, and use the methods {@link #newX(double, double)} and
+ * {@link #newY(double, double)} to retrieve the new coordinates, relative to the upper left corner of {@link Orientation#RIGHT}. The
+ * {@link #height()} and {@link #width()} methods return the width and height in the new orientation.
+ * <p>
+ * This is meant to be used in the context of a a classic display coordinate system, as done in the {@link GUIComponent}s.
+ *
+ * @see Orientation
+ * @author Christian Femers
+ */
+public class OrientationCalculator
+{
+       final Orientation o;
+       final double oldWHalf;
+       final double oldHHalf;
+       final double w;
+       final double h;
+       final double wHalf;
+       final double hHalf;
+
+       public OrientationCalculator(Orientation o, double width, double height)
+       {
+               this.o = o;
+               this.oldWHalf = width / 2;
+               this.oldHHalf = height / 2;
+
+               if (o.swapsWidthAndHeight())
+               {
+                       w = height;
+                       h = width;
+                       wHalf = oldHHalf;
+                       hHalf = oldWHalf;
+               } else
+               {
+                       w = width;
+                       h = height;
+                       wHalf = oldWHalf;
+                       hHalf = oldHHalf;
+               }
+       }
+
+       /**
+        * Returns the new height (that equals the old width if {@link Orientation#swapsWidthAndHeight()} is true)
+        */
+       public double height()
+       {
+               return h;
+       }
+
+       /**
+        * Returns the new width (that equals the old height if {@link Orientation#swapsWidthAndHeight()} is true)
+        */
+       public double width()
+       {
+               return w;
+       }
+
+       public double newX(double x, double y)
+       {
+               return (x - oldWHalf) * o.trans11 + (y - oldHHalf) * o.trans12 + wHalf;
+       }
+
+       public double newY(double x, double y)
+       {
+               return (x - oldWHalf) * o.trans21 + (y - oldHHalf) * o.trans22 + hHalf;
+       }
+
+       public final Orientation getOrientation()
+       {
+               return o;
+       }
+}
index a81a158..c9036d2 100644 (file)
@@ -10,6 +10,8 @@ import net.haspamelodica.swt.helper.gcs.GeneralGC;
 import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;
 import net.mograsim.logic.model.model.ViewModelModifiable;
 import net.mograsim.logic.model.model.components.GUIComponent;
+import net.mograsim.logic.model.model.components.Orientation;
+import net.mograsim.logic.model.model.components.OrientationCalculator;
 import net.mograsim.logic.model.model.wires.Pin;
 import net.mograsim.logic.model.model.wires.PinUsage;
 import net.mograsim.logic.model.modeladapter.ViewLogicModelAdapter;
@@ -29,6 +31,7 @@ public class GUITriStateBuffer extends GUIComponent
        private double[] path;
 
        private GUITriStateBufferParams params;
+       private OrientationCalculator oc;
 
        public GUITriStateBuffer(ViewModelModifiable model, GUITriStateBufferParams params)
        {
@@ -40,27 +43,19 @@ public class GUITriStateBuffer extends GUIComponent
                super(model, name);
                this.params = params;
 
+               oc = new OrientationCalculator(params.orientation, width, height);
+
                double wHalf = width / 2;
                double hHalf = height / 2;
-               double wQuar = width / 4;
                double hQuar = height / 4;
-               int ordi = params.orientation.ordinal();
-               int isVerti = (ordi % 4) / 2;
-               int isHori = 1 ^ isVerti;
-               int isAlt = ordi / 4;
-               int isInv = ordi % 2;
-               int isStd = 1 ^ isInv;
-
-               this.input = new Pin(this, "IN", params.logicWidth, PinUsage.INPUT, width * isInv * isHori + wHalf * isVerti,
-                               height * isVerti * isStd + hHalf * isHori);
-               this.output = new Pin(this, "OUT", params.logicWidth, PinUsage.OUTPUT, width * isStd * isHori + wHalf * isVerti,
-                               height * isVerti * isInv + hHalf * isHori);
-               this.enable = new Pin(this, "EN", 1, PinUsage.INPUT, wQuar * isVerti + wHalf * (isAlt | isHori),
-                               hQuar * isHori + hHalf * (isAlt | isVerti));
-               this.path = new double[] { width * (isStd ^ isHori), height * (isStd ^ isHori), width * isInv, height * isStd,
-                               width * isStd * isHori + wHalf * isVerti, height * isVerti * isInv + hHalf * isHori };
-
-               setSize(width, height);
+
+               this.input = new Pin(this, "IN", params.logicWidth, PinUsage.INPUT, oc.newX(0, hHalf), oc.newY(0, hHalf));
+               this.output = new Pin(this, "OUT", params.logicWidth, PinUsage.OUTPUT, oc.newX(width, hHalf), oc.newY(width, hHalf));
+               this.enable = new Pin(this, "EN", 1, PinUsage.INPUT, oc.newX(wHalf, hQuar), oc.newY(wHalf, hQuar));
+               this.path = new double[] { oc.newX(0, 0), oc.newY(0, 0), oc.newX(width, hHalf), oc.newY(width, hHalf), oc.newX(0, height),
+                               oc.newY(0, height) };
+
+               setSize(oc.width(), oc.height());
                addPin(input);
                addPin(output);
                addPin(enable);
@@ -75,15 +70,6 @@ public class GUITriStateBuffer extends GUIComponent
                double x = getPosX();
                double y = getPosY();
                gc.drawPolygon(new double[] { x + path[0], y + path[1], x + path[2], y + path[3], x + path[4], y + path[5] });
-//             Font oldFont = gc.getFont();
-//             Font labelFont = new Font(oldFont.getName(), fontHeight, oldFont.getStyle());
-//             gc.setFont(labelFont);
-//             Point textExtent = gc.textExtent(label);
-//             Color textColor = Preferences.current().getColor("net.mograsim.logic.model.color.text");
-//             if (textColor != null)
-//                     gc.setForeground(textColor);
-//             gc.drawText(label, getPosX() + (rectWidth - textExtent.x) / 2, getPosY() + (height - textExtent.y) / 2, true);
-//             gc.setFont(oldFont);
        }
 
        @Override
@@ -104,14 +90,15 @@ public class GUITriStateBuffer extends GUIComponent
                });
        }
 
-       private static class GUITriStateBufferParams
+       public static class GUITriStateBufferParams
        {
                int logicWidth;
                Orientation orientation;
-       }
 
-       public enum Orientation
-       {
-               RIGHT, LEFT, UP, DOWN, RIGHT_ALT, LEFT_ALT, UP_ALT, DOWN_ALT;
+               public GUITriStateBufferParams(int logicWidth, Orientation orientation)
+               {
+                       this.logicWidth = logicWidth;
+                       this.orientation = orientation;
+               }
        }
 }