From f9759b8cc46333d36c023c086f8d6050178e984d Mon Sep 17 00:00:00 2001 From: Bane Stojkovic Date: Sun, 9 Oct 2022 22:04:19 +0200 Subject: [PATCH] Added rotary switch (sealed) --- .../src/org/diylc/presenter/update.xml | 4 + .../electromechanical/RotarySwitchSealed.java | 375 ++++++++++++++++++ .../electromechanical/RotarySwitchType.java | 50 +++ .../org/diylc/components/guitar/S1Switch.java | 3 +- .../components/guitar/SingleCoilPickup.java | 1 - 5 files changed, 430 insertions(+), 3 deletions(-) create mode 100644 diylc/diylc-library/src/org/diylc/components/electromechanical/RotarySwitchSealed.java create mode 100644 diylc/diylc-library/src/org/diylc/components/electromechanical/RotarySwitchType.java diff --git a/diylc/diylc-core/src/org/diylc/presenter/update.xml b/diylc/diylc-core/src/org/diylc/presenter/update.xml index b3845abd..8178bdef 100644 --- a/diylc/diylc-core/src/org/diylc/presenter/update.xml +++ b/diylc/diylc-core/src/org/diylc/presenter/update.xml @@ -4002,6 +4002,10 @@ 2022-10-04 00:00:00.000 CET + + NEW_FEATURE + Added 'Rotary Switch (Sealed)' component + NEW_FEATURE Added 'S1 Switch' component that can be combined with potentiometer component or used on its own diff --git a/diylc/diylc-library/src/org/diylc/components/electromechanical/RotarySwitchSealed.java b/diylc/diylc-library/src/org/diylc/components/electromechanical/RotarySwitchSealed.java new file mode 100644 index 00000000..f305f515 --- /dev/null +++ b/diylc/diylc-library/src/org/diylc/components/electromechanical/RotarySwitchSealed.java @@ -0,0 +1,375 @@ +/* + + DIY Layout Creator (DIYLC). + Copyright (c) 2009-2018 held jointly by the individual authors. + + This file is part of DIYLC. + + DIYLC is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + DIYLC is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with DIYLC. If not, see . + +*/ +package org.diylc.components.electromechanical; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Graphics2D; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.Area; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import org.diylc.appframework.miscutils.ConfigurationManager; +import org.diylc.awt.StringUtils; +import org.diylc.common.HorizontalAlignment; +import org.diylc.common.IPlugInPort; +import org.diylc.common.ObjectCache; +import org.diylc.common.VerticalAlignment; +import org.diylc.components.AbstractAngledComponent; +import org.diylc.components.transform.AngledComponentTransformer; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.ISwitch; +import org.diylc.core.Project; +import org.diylc.core.Theme; +import org.diylc.core.VisibilityPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.annotations.KeywordPolicy; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; +import org.diylc.utils.Constants; + +@ComponentDescriptor(name = "Rotary Switch (Sealed)", author = "Branislav Stojkovic", category = "Electro-Mechanical", + instanceNamePrefix = "SW", description = "Sealed plastic rotary switch in several different switching configurations", + zOrder = IDIYComponent.COMPONENT, keywordPolicy = KeywordPolicy.SHOW_VALUE, enableCache = true, + transformer = AngledComponentTransformer.class) +public class RotarySwitchSealed extends AbstractAngledComponent implements ISwitch { + + private static final int OUTER_ANGLE_OFFSET = 15; + private static final int INNER_ANGLE_OFFSET = 30; + + private static final Size DIAMETER = new Size(26d, SizeUnit.mm); + private static final Size OUTER_PIN_DIAMETER = new Size(21.5d, SizeUnit.mm); + private static final Size INNER_PIN_DIAMETER = new Size(8d, SizeUnit.mm); + + private static final long serialVersionUID = 1L; + + private static Color BODY_COLOR = Color.decode("#F7F7EF"); + private static Color LABEL_COLOR = BODY_COLOR.darker(); + public static Color PIN_COLOR = Color.decode("#00B2EE"); + public static Color PIN_BORDER_COLOR = PIN_COLOR.darker(); + public static Size PIN_DIAMETER = new Size(1d, SizeUnit.mm); + private static Size PIN_WIDTH = new Size(0.08d, SizeUnit.in); + private static Size PIN_THICKNESS = new Size(0.02d, SizeUnit.in); + + private RotarySwitchType configuration = RotarySwitchType._4P3T; + private Color color = BODY_COLOR; + private Mount mount = Mount.CHASSIS; + private Color labelColor = LABEL_COLOR; + + private Point2D[] controlPoints = new Point2D[] {new Point2D.Double(0, 0)}; + private double[] pointAngles; + + public RotarySwitchSealed() { + super(); + updateControlPoints(); + } + + @EditableProperty(name = "Type") + public RotarySwitchType getValue() { + return configuration; + } + + public void setValue(RotarySwitchType configuration) { + this.configuration = configuration; + updateControlPoints(); + // Reset body shape + body = null; + } + + @EditableProperty + public Color getColor() { + if (color == null) { + color = BODY_COLOR; + } + return color; + } + + public void setColor(Color color) { + this.color = color; + } + + @Override + protected void updateControlPoints() { + Point2D firstPoint = controlPoints[0]; + int outerPinCount = 12; + int innerPinCount = configuration.getPoleCount(); + int outerPinDiameter = getClosestOdd(OUTER_PIN_DIAMETER.convertToPixels()); + int innerPinDiameter = getClosestOdd(INNER_PIN_DIAMETER.convertToPixels()); + + double outerAngleIncrement = - Math.PI * 2 / outerPinCount; + double innerAngleIncrement = - Math.PI * 2 / innerPinCount; + double outerAngleOffset = Math.toRadians(OUTER_ANGLE_OFFSET); + double innerAngleOffset = Math.toRadians(INNER_ANGLE_OFFSET); + + controlPoints = new Point2D[outerPinCount + innerPinCount + 1]; + pointAngles = new double[controlPoints.length]; + + double theta = outerAngleOffset + Math.toRadians(getAngle().getValue()); + controlPoints[0] = firstPoint; + + for (int i = 0; i < outerPinCount; i++) { + controlPoints[i + 1] = + new Point2D.Double(firstPoint.getX() + Math.cos(theta) * outerPinDiameter / 2, + firstPoint.getY() + Math.sin(theta) * outerPinDiameter / 2); + pointAngles[i + 1] = theta; + theta += outerAngleIncrement; + } + + theta = innerAngleOffset + Math.toRadians(getAngle().getValue()); + for (int i = 0; i < innerPinCount; i++) { + controlPoints[i + outerPinCount + 1] = + new Point2D.Double(firstPoint.getX() + Math.cos(theta) * innerPinDiameter / 2, + firstPoint.getY() + Math.sin(theta) * innerPinDiameter / 2); + pointAngles[i + outerPinCount + 1] = theta; + theta += innerAngleIncrement; + } + } + + public Shape[] getBody() { + if (body == null) { + int bodyDiameter = getClosestOdd(DIAMETER.convertToPixels()); + + Ellipse2D baseShape = + new Ellipse2D.Double(controlPoints[0].getX() - bodyDiameter / 2, controlPoints[0].getY() - bodyDiameter / 2, + bodyDiameter, bodyDiameter); + + body = new Shape[] { baseShape }; + } + return body; + } + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, + IDrawingObserver drawingObserver) { + + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + + // Draw body + Shape[] body = getBody(); + Composite oldComposite = g2d.getComposite(); + if (alpha < MAX_ALPHA) { + g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); + } + if (componentState != ComponentState.DRAGGING) { + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : getColor()); + g2d.fill(body[0]); + } + g2d.setComposite(oldComposite); + Color finalBorderColor; + if (outlineMode) { + Theme theme = + (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); + finalBorderColor = + componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR + : theme.getOutlineColor(); + } else { + finalBorderColor = + componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR + : getColor().darker(); + } + g2d.setColor(finalBorderColor); + g2d.draw(body[0]); + + drawingObserver.stopTracking(); + + // Draw pins + if (!outlineMode) { + for (int i = 1; i < controlPoints.length; i++) { + Shape pinShape; + if (getMount() == Mount.PCB) { + int pinSize = getClosestOdd(PIN_DIAMETER.convertToPixels()); + pinShape = new Ellipse2D.Double(controlPoints[i].getX() - pinSize / 2, controlPoints[i].getY() - pinSize / 2, pinSize, pinSize); + } else { + int pinWidth = getClosestOdd(PIN_WIDTH.convertToPixels()); + int pinThickness = getClosestOdd(PIN_THICKNESS.convertToPixels()); + pinShape = new Rectangle2D.Double(controlPoints[i].getX() - pinWidth / 2, controlPoints[i].getY() - pinThickness / 2, pinWidth, pinThickness); + double theta = Math.atan2(controlPoints[i].getY() - controlPoints[0].getY(), controlPoints[i].getX() - controlPoints[0].getX()) + Math.PI / 2; + Area rotatedPin = new Area(pinShape); + rotatedPin.transform(AffineTransform.getRotateInstance(theta, controlPoints[i].getX(), controlPoints[i].getY())); + pinShape = rotatedPin; + } + g2d.setColor(PIN_COLOR); + g2d.fill(pinShape); + g2d.setColor(PIN_BORDER_COLOR); + g2d.fill(pinShape); + } + } + + int outerPinDiameter = getClosestOdd(OUTER_PIN_DIAMETER.convertToPixels()); + int innerPinDiameter = getClosestOdd(INNER_PIN_DIAMETER.convertToPixels()); + int outerPinCount = 12; + int innerPinCount = configuration.getPoleCount(); + g2d.setColor(labelColor); + double relativeLabelLocation = 0.85; + Point2D firstPoint = controlPoints[0]; + for (int i = 0; i < outerPinCount; i++) { + int x = (int) (firstPoint.getX() + Math.cos(pointAngles[i + 1]) * relativeLabelLocation * outerPinDiameter / 2); + int y = (int) (firstPoint.getY() + Math.sin(pointAngles[i + 1]) * relativeLabelLocation * outerPinDiameter / 2); + StringUtils.drawCenteredText(g2d, Integer.toString(i + 1), x, y, HorizontalAlignment.CENTER, VerticalAlignment.CENTER); + } + relativeLabelLocation = 0.65; + int labelStep = 1; + if (configuration.getPoleCount() == 2) { + labelStep = 2; + } + for (int i = 0; i < innerPinCount; i++) { + int x = (int) (firstPoint.getX() + Math.cos(pointAngles[i + outerPinCount + 1]) * relativeLabelLocation * innerPinDiameter / 2); + int y = (int) (firstPoint.getY() + Math.sin(pointAngles[i + outerPinCount + 1]) * relativeLabelLocation * innerPinDiameter / 2); + StringUtils.drawCenteredText(g2d, Character.toString((char)('A' + labelStep * i)), x, y, + HorizontalAlignment.CENTER, VerticalAlignment.CENTER); + } + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + g2d.setColor(BODY_COLOR); + g2d.fillOval(0, 0, width * 2, width * 2); + g2d.setColor(BODY_COLOR.darker()); + g2d.drawOval(0, 0, width * 2, width * 2); + + int commonX = (int) (width - 8 * width / 32d); + int commonY = (int) (height - 8 * width / 32d); + g2d.setColor(PIN_COLOR); + g2d.fillOval(commonX - 1, commonY - 1, 3, 3); + g2d.setColor(PIN_BORDER_COLOR); + g2d.drawOval(commonX - 1, commonY - 1, 3, 3); + + int radius = (int) (width - 6 * width / 32d); + for (int i = 0; i < 4; i++) { + int x = (int) (width + Math.cos(1.1 * Math.PI + i * Math.PI / 6) * radius); + int y = (int) (height + Math.sin(1.1 * Math.PI + i * Math.PI / 6) * radius); + g2d.setColor(PIN_COLOR); + g2d.fillOval(x - 1, y - 1, 3, 3); + g2d.setColor(PIN_BORDER_COLOR); + g2d.drawOval(x - 1, y - 1, 3, 3); + } + + g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR)); + g2d.drawLine(0, height - 1, width, height - 1); + g2d.drawLine(width - 1, 0, width - 1, height - 1); + } + + @Override + public Point2D getControlPoint(int index) { + return controlPoints[index]; + } + + @Override + public int getControlPointCount() { + return controlPoints.length; + } + + @Override + public VisibilityPolicy getControlPointVisibilityPolicy(int index) { + return VisibilityPolicy.NEVER; + } + + @Override + public boolean isControlPointSticky(int index) { + return index > 0; + } + + @Override + public void setControlPoint(Point2D point, int index) { + controlPoints[index].setLocation(point); + + body = null; + } + + @Override + public boolean canPointMoveFreely(int pointIndex) { + return false; + } + + @EditableProperty(name = "Label") + public Color getLabelColor() { + if (labelColor == null) + labelColor = LABEL_COLOR; + return labelColor; + } + + public void setLabelColor(Color labelColor) { + this.labelColor = labelColor; + } + + @EditableProperty(name = "Mount") + public Mount getMount() { + if (mount == null) + mount = Mount.CHASSIS; + return mount; + } + + public void setMount(Mount mount) { + this.mount = mount; + + updateControlPoints(); + // Reset body shape + body = null; + } + + @Override + public Rectangle2D getCachingBounds() { + Rectangle2D rect = getBody()[0].getBounds2D(); + int margin = 40; // to catch the pins that are outside the body, if needed + return new Rectangle2D.Double(rect.getX() - margin, rect.getY() - margin, rect.getWidth() + 2 * margin, rect.getHeight() + 2 * margin); + } + + public static enum Mount { + CHASSIS("Chassis"), PCB("PCB"); + + String name; + + private Mount(String name) { + this.name = name; + } + + @Override + public String toString() { + return name; + } + } + + @Override + public int getPositionCount() { + return configuration.getPositionCount(); + } + + @Override + public String getPositionName(int position) { + return Integer.toString(position + 1); + } + + @Override + public boolean arePointsConnected(int index1, int index2, int position) { + if (index2 < 13) + return false; + + int pole = index2 - 13; + return index1 == 1 + pole * 12 / configuration.getPoleCount() + position; + } +} diff --git a/diylc/diylc-library/src/org/diylc/components/electromechanical/RotarySwitchType.java b/diylc/diylc-library/src/org/diylc/components/electromechanical/RotarySwitchType.java new file mode 100644 index 00000000..f47efaeb --- /dev/null +++ b/diylc/diylc-library/src/org/diylc/components/electromechanical/RotarySwitchType.java @@ -0,0 +1,50 @@ +/* + + DIY Layout Creator (DIYLC). + Copyright (c) 2009-2018 held jointly by the individual authors. + + This file is part of DIYLC. + + DIYLC is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + DIYLC is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with DIYLC. If not, see . + +*/ +package org.diylc.components.electromechanical; + +public enum RotarySwitchType { + _1P12T("1P12T", 1, 12), _2P6T("2P6T", 2, 6), _3P4T("3P4T", 3, 4), _4P3T("4P3T", 4, 3); + + private String name; + private int positionCount; + private int poleCount; + + + private RotarySwitchType(String name, int poleCount, int positionCount) { + this.name = name; + this.poleCount = poleCount; + this.positionCount = positionCount; + } + + @Override + public String toString() { + return name; + } + + public int getPoleCount() { + return poleCount; + } + + public int getPositionCount() { + return positionCount; + } +} diff --git a/diylc/diylc-library/src/org/diylc/components/guitar/S1Switch.java b/diylc/diylc-library/src/org/diylc/components/guitar/S1Switch.java index 3f2f03a4..cca1221b 100644 --- a/diylc/diylc-library/src/org/diylc/components/guitar/S1Switch.java +++ b/diylc/diylc-library/src/org/diylc/components/guitar/S1Switch.java @@ -37,7 +37,6 @@ import org.diylc.common.IPlugInPort; import org.diylc.common.ObjectCache; import org.diylc.common.VerticalAlignment; import org.diylc.components.AbstractTransparentComponent; -import org.diylc.components.transform.MiniToggleSwitchTransformer; import org.diylc.core.ComponentState; import org.diylc.core.IDIYComponent; import org.diylc.core.IDrawingObserver; @@ -53,7 +52,7 @@ import org.diylc.utils.Constants; @ComponentDescriptor(name = "S1 Switch", category = "Guitar", author = "Branislav Stojkovic", description = "Fender S1 4 pole pushbutton switch", zOrder = IDIYComponent.COMPONENT, - instanceNamePrefix = "SW", autoEdit = false, enableCache = true, transformer = MiniToggleSwitchTransformer.class) + instanceNamePrefix = "SW", autoEdit = false, enableCache = true) public class S1Switch extends AbstractTransparentComponent implements ISwitch { private static final long serialVersionUID = 1L; diff --git a/diylc/diylc-library/src/org/diylc/components/guitar/SingleCoilPickup.java b/diylc/diylc-library/src/org/diylc/components/guitar/SingleCoilPickup.java index 909f1410..076fca65 100644 --- a/diylc/diylc-library/src/org/diylc/components/guitar/SingleCoilPickup.java +++ b/diylc/diylc-library/src/org/diylc/components/guitar/SingleCoilPickup.java @@ -434,7 +434,6 @@ public class SingleCoilPickup extends AbstractSingleOrHumbuckerPickup { this.lugColor = lugColor; } - public enum SingleCoilType { Stratocaster, Telecaster; }