mirror of
https://github.com/bancika/diy-layout-creator
synced 2026-11-07 12:24:58 +10:00
Derive the z-order of a building blocks placed as a single component based on its child components
This commit is contained in:
@@ -118,16 +118,10 @@ public class ComparatorFactory {
|
||||
if (componentZOrderComparator == null) {
|
||||
componentZOrderComparator = new Comparator<IDIYComponent<?>>() {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public int compare(IDIYComponent<?> o1, IDIYComponent<?> o2) {
|
||||
ComponentType type1 =
|
||||
ComponentProcessor.getInstance().extractComponentTypeFrom(
|
||||
(Class<? extends IDIYComponent<?>>) o1.getClass());
|
||||
ComponentType type2 =
|
||||
ComponentProcessor.getInstance().extractComponentTypeFrom(
|
||||
(Class<? extends IDIYComponent<?>>) o2.getClass());
|
||||
return Double.valueOf(type1.getZOrder()).compareTo(type2.getZOrder());
|
||||
return Double.compare(ComponentProcessor.getInstance().getZOrder(o1),
|
||||
ComponentProcessor.getInstance().getZOrder(o2));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -409,6 +409,31 @@ public class ComponentProcessor {
|
||||
return type.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the z-order (layer) of the component. A {@link CompositeComponent} sits on the lowest
|
||||
* layer among its children rather than the one its class declares: it is drawn as a
|
||||
* single unit, so it takes one place in the stack, and that place has to be under
|
||||
* whatever is later put on top of it. A block of chassis panels therefore stays on the
|
||||
* chassis layer, and a block built from a board, pads and silkscreen text on the board
|
||||
* layer.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public double getZOrder(IDIYComponent<?> component) {
|
||||
if (component instanceof CompositeComponent) {
|
||||
double zOrder = Double.MAX_VALUE;
|
||||
for (IDIYComponent<?> child : ((CompositeComponent) component).getChildComponents()) {
|
||||
zOrder = Math.min(zOrder, getZOrder(child));
|
||||
}
|
||||
if (zOrder < Double.MAX_VALUE) {
|
||||
return zOrder;
|
||||
}
|
||||
}
|
||||
ComponentType type =
|
||||
extractComponentTypeFrom((Class<? extends IDIYComponent<?>>) component.getClass());
|
||||
// internal types without a descriptor do not take part in layering
|
||||
return type == null ? Double.MAX_VALUE : type.getZOrder();
|
||||
}
|
||||
|
||||
public static boolean hasStickyPoint(IDIYComponent<?> c) {
|
||||
for (int i = 0; i < c.getControlPointCount(); i++)
|
||||
if (c.isControlPointSticky(0))
|
||||
|
||||
@@ -94,7 +94,8 @@ public class GroupAndLockIndex {
|
||||
if (componentType == null) {
|
||||
return false;
|
||||
}
|
||||
return project.getLockedLayers().contains((int) Math.round(componentType.getZOrder()))
|
||||
return project.getLockedLayers()
|
||||
.contains((int) Math.round(ComponentProcessor.getInstance().getZOrder(component)))
|
||||
|| project.getLockedComponents().contains(component);
|
||||
}
|
||||
|
||||
|
||||
@@ -494,7 +494,8 @@ public class Presenter implements IPlugInPort {
|
||||
// for internal types
|
||||
if (componentType == null)
|
||||
return true;
|
||||
return !currentProject.getHiddenLayers().contains((int) Math.round(componentType.getZOrder()));
|
||||
return !currentProject.getHiddenLayers()
|
||||
.contains((int) Math.round(ComponentProcessor.getInstance().getZOrder(component)));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1076,10 +1077,9 @@ public class Presenter implements IPlugInPort {
|
||||
Iterator<IDIYComponent<?>> i = newSelection.iterator();
|
||||
while (i.hasNext()) {
|
||||
IDIYComponent<?> c = i.next();
|
||||
ComponentType type =
|
||||
ComponentProcessor.getInstance().extractComponentTypeFrom((Class<? extends IDIYComponent<?>>) c.getClass());
|
||||
if ((int) type.getZOrder() != layer)
|
||||
if ((int) ComponentProcessor.getInstance().getZOrder(c) != layer) {
|
||||
i.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
updateSelection(newSelection);
|
||||
@@ -2229,6 +2229,7 @@ public class Presenter implements IPlugInPort {
|
||||
ComponentType componentType =
|
||||
ComponentProcessor.getInstance().extractComponentTypeFrom(
|
||||
(Class<? extends IDIYComponent<?>>) component.getClass());
|
||||
long layer = Math.round(ComponentProcessor.getInstance().getZOrder(component));
|
||||
int index = currentProject.getComponents().indexOf(component);
|
||||
if (index < 0) {
|
||||
LOG.warn("Component not found in the project: " + component.getName());
|
||||
@@ -2236,11 +2237,8 @@ public class Presenter implements IPlugInPort {
|
||||
while (index > 0) {
|
||||
IDIYComponent<?> componentBefore = currentProject.getComponents().get(index - 1);
|
||||
if (!selectedComponents.contains(componentBefore)) {
|
||||
ComponentType componentBeforeType =
|
||||
ComponentProcessor.getInstance().extractComponentTypeFrom(
|
||||
(Class<? extends IDIYComponent<?>>) componentBefore.getClass());
|
||||
if (!componentType.isFlexibleZOrder()
|
||||
&& Math.round(componentBeforeType.getZOrder()) < Math.round(componentType.getZOrder())
|
||||
&& Math.round(ComponentProcessor.getInstance().getZOrder(componentBefore)) < layer
|
||||
&& forceConfirmation != IView.YES_OPTION
|
||||
&& (forceConfirmation =
|
||||
this.view
|
||||
@@ -2278,6 +2276,7 @@ public class Presenter implements IPlugInPort {
|
||||
ComponentType componentType =
|
||||
ComponentProcessor.getInstance().extractComponentTypeFrom(
|
||||
(Class<? extends IDIYComponent<?>>) component.getClass());
|
||||
long layer = Math.round(ComponentProcessor.getInstance().getZOrder(component));
|
||||
int index = currentProject.getComponents().indexOf(component);
|
||||
if (index < 0) {
|
||||
LOG.warn("Component not found in the project: " + component.getName());
|
||||
@@ -2285,11 +2284,8 @@ public class Presenter implements IPlugInPort {
|
||||
while (index < currentProject.getComponents().size() - 1) {
|
||||
IDIYComponent<?> componentAfter = currentProject.getComponents().get(index + 1);
|
||||
if (!selectedComponents.contains(componentAfter)) {
|
||||
ComponentType componentAfterType =
|
||||
ComponentProcessor.getInstance().extractComponentTypeFrom(
|
||||
(Class<? extends IDIYComponent<?>>) componentAfter.getClass());
|
||||
if (!componentType.isFlexibleZOrder()
|
||||
&& Math.round(componentAfterType.getZOrder()) > Math.round(componentType.getZOrder())
|
||||
&& Math.round(ComponentProcessor.getInstance().getZOrder(componentAfter)) > layer
|
||||
&& forceConfirmation != IView.YES_OPTION
|
||||
&& (forceConfirmation =
|
||||
this.view
|
||||
@@ -2684,13 +2680,9 @@ public class Presenter implements IPlugInPort {
|
||||
@SuppressWarnings("unchecked")
|
||||
private void addComponent(IDIYComponent<?> component, boolean allowAutoCreate) {
|
||||
int index = currentProject.getComponents().size();
|
||||
while (index > 0
|
||||
&& ComponentProcessor.getInstance()
|
||||
.extractComponentTypeFrom((Class<? extends IDIYComponent<?>>) component.getClass()).getZOrder() < ComponentProcessor
|
||||
.getInstance()
|
||||
.extractComponentTypeFrom(
|
||||
(Class<? extends IDIYComponent<?>>) currentProject.getComponents().get(index - 1).getClass())
|
||||
.getZOrder()) {
|
||||
double zOrder = ComponentProcessor.getInstance().getZOrder(component);
|
||||
while (index > 0 && zOrder < ComponentProcessor.getInstance()
|
||||
.getZOrder(currentProject.getComponents().get(index - 1))) {
|
||||
index--;
|
||||
}
|
||||
if (index < currentProject.getComponents().size()) {
|
||||
@@ -2724,12 +2716,9 @@ public class Presenter implements IPlugInPort {
|
||||
int maxIndex = 0;
|
||||
for (IDIYComponent<?> component : components) {
|
||||
int index = currentProject.getComponents().size();
|
||||
while (index > maxIndex && ComponentProcessor.getInstance()
|
||||
.extractComponentTypeFrom((Class<? extends IDIYComponent<?>>) component.getClass())
|
||||
.getZOrder() < ComponentProcessor.getInstance()
|
||||
.extractComponentTypeFrom((Class<? extends IDIYComponent<?>>) currentProject
|
||||
.getComponents().get(index - 1).getClass())
|
||||
.getZOrder()) {
|
||||
double zOrder = ComponentProcessor.getInstance().getZOrder(component);
|
||||
while (index > maxIndex && zOrder < ComponentProcessor.getInstance()
|
||||
.getZOrder(currentProject.getComponents().get(index - 1))) {
|
||||
index--;
|
||||
}
|
||||
|
||||
@@ -3132,12 +3121,9 @@ public class Presenter implements IPlugInPort {
|
||||
return GroupAndLockIndex.isLocked(currentProject, component);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private boolean isComponentLayerLocked(IDIYComponent<?> component) {
|
||||
ComponentType componentType =
|
||||
ComponentProcessor.getInstance().extractComponentTypeFrom(
|
||||
(Class<? extends IDIYComponent<?>>) component.getClass());
|
||||
return currentProject.getLockedLayers().contains((int) Math.round(componentType.getZOrder()));
|
||||
return currentProject.getLockedLayers()
|
||||
.contains((int) Math.round(ComponentProcessor.getInstance().getZOrder(component)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -517,6 +517,10 @@
|
||||
<changeType>IMPROVEMENT</changeType>
|
||||
<description>Re-modeled factory variants of Resistor component type as datasheet in order to make them available to the AI; this will produce more accurate AI-driven edits</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>IMPROVEMENT</changeType>
|
||||
<description>Derive the z-order of a building blocks placed as a single component based on its child components</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>NEW_FEATURE</changeType>
|
||||
<description>Added datasheets to 'DIP IC', 'SIP IC' and 'Multiwatt IC' - pick a part by its number from the component's submenu to set its pin count, spacing and pin names at once; the AI Assistant can place these parts by part number too</description>
|
||||
|
||||
+78
@@ -35,7 +35,12 @@ import java.util.UUID;
|
||||
|
||||
import org.diylc.common.Percentage;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.Project;
|
||||
import org.diylc.core.annotations.ComponentDescriptor;
|
||||
import org.diylc.netlist.Node;
|
||||
import org.diylc.presenter.ComparatorFactory;
|
||||
import org.diylc.presenter.ComponentProcessor;
|
||||
import org.diylc.presenter.GroupAndLockIndex;
|
||||
import org.diylc.serialization.ProjectFileManager;
|
||||
import org.diylc.testcomponents.OnePointTestComponent;
|
||||
import org.diylc.testcomponents.TwoPointTestComponent;
|
||||
@@ -326,4 +331,77 @@ public class CompositeComponentTest {
|
||||
assertNotNull(blank.getChildComponents());
|
||||
assertTrue(blank.getChildComponents().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void layerOfAChassisOnlyCompositeIsTheChassisLayer() {
|
||||
CompositeComponent composite = customBoard(new ChassisTestComponent(),
|
||||
new ChassisTestComponent());
|
||||
|
||||
assertEquals(IDIYComponent.CHASSIS, ComponentProcessor.getInstance().getZOrder(composite), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void layerOfAMixedCompositeIsItsLowestChildLayer() {
|
||||
CompositeComponent composite = customBoard(new TextTestComponent(), twoPoint("R1"),
|
||||
new BoardTestComponent());
|
||||
|
||||
assertEquals(IDIYComponent.BOARD, ComponentProcessor.getInstance().getZOrder(composite), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void layerOfANestedCompositeLooksThroughTheInnerComposite() {
|
||||
CompositeComponent inner = customBoard(new ChassisTestComponent());
|
||||
CompositeComponent outer = customBoard(twoPoint("R1"), inner);
|
||||
|
||||
assertEquals(IDIYComponent.CHASSIS, ComponentProcessor.getInstance().getZOrder(outer), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void layerOfAChildlessCompositeIsTheDeclaredOne() {
|
||||
assertEquals(IDIYComponent.COMPONENT,
|
||||
ComponentProcessor.getInstance().getZOrder(new CompositeComponent()), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void lockingTheChildLayerLocksTheComposite() {
|
||||
Project project = new Project();
|
||||
CompositeComponent chassis = customBoard(new ChassisTestComponent());
|
||||
project.getComponents().add(chassis);
|
||||
|
||||
project.getLockedLayers().add(IDIYComponent.COMPONENT);
|
||||
assertFalse(GroupAndLockIndex.isLocked(project, chassis));
|
||||
|
||||
project.getLockedLayers().add(IDIYComponent.CHASSIS);
|
||||
assertTrue(GroupAndLockIndex.isLocked(project, chassis));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void compositeSortsByItsChildLayer() {
|
||||
CompositeComponent chassis = customBoard(new ChassisTestComponent());
|
||||
BoardTestComponent board = new BoardTestComponent();
|
||||
|
||||
assertTrue(ComparatorFactory.getInstance().getComponentZOrderComparator().compare(chassis,
|
||||
board) < 0);
|
||||
}
|
||||
|
||||
@ComponentDescriptor(name = "Chassis Test", category = "Test", author = "Test",
|
||||
description = "test", instanceNamePrefix = "CT", zOrder = IDIYComponent.CHASSIS)
|
||||
public static class ChassisTestComponent extends TwoPointTestComponent {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
}
|
||||
|
||||
@ComponentDescriptor(name = "Board Test", category = "Test", author = "Test",
|
||||
description = "test", instanceNamePrefix = "BT", zOrder = IDIYComponent.BOARD)
|
||||
public static class BoardTestComponent extends TwoPointTestComponent {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
}
|
||||
|
||||
@ComponentDescriptor(name = "Text Test", category = "Test", author = "Test",
|
||||
description = "test", instanceNamePrefix = "TT", zOrder = IDIYComponent.TEXT)
|
||||
public static class TextTestComponent extends TwoPointTestComponent {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
}
|
||||
}
|
||||
|
||||
+10
-16
@@ -37,11 +37,11 @@ import javax.swing.SwingUtilities;
|
||||
import javax.swing.event.ListSelectionEvent;
|
||||
import javax.swing.event.ListSelectionListener;
|
||||
|
||||
import org.diylc.common.ComponentType;
|
||||
import org.diylc.common.IPlugInPort;
|
||||
import org.diylc.core.ComponentGroup;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.lang.LangUtil;
|
||||
import org.diylc.presenter.ComponentProcessor;
|
||||
import org.diylc.swing.ISwingUI;
|
||||
import org.diylc.swing.gui.ComponentPopupMenu;
|
||||
import org.diylc.swing.gui.DragDropList;
|
||||
@@ -257,7 +257,7 @@ public class ExplorerPane extends JPanel {
|
||||
0, false, false)
|
||||
.getPreferredSize().height);
|
||||
componentList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
|
||||
componentList.setCellRenderer(new ComponentListCellRenderer(plugInPort.getComponentTypes()));
|
||||
componentList.setCellRenderer(new ComponentListCellRenderer());
|
||||
selectionListener = new ListSelectionListener() {
|
||||
|
||||
@Override
|
||||
@@ -586,13 +586,6 @@ public class ExplorerPane extends JPanel {
|
||||
|
||||
protected DefaultListCellRenderer defaultRenderer = new DefaultListCellRenderer();
|
||||
|
||||
private Map<String, ComponentType> componentTypes;
|
||||
|
||||
public ComponentListCellRenderer(Map<String, List<ComponentType>> componentTypeMap) {
|
||||
this.componentTypes = componentTypeMap.values().stream().flatMap(x -> x.stream())
|
||||
.collect(Collectors.toMap(x -> x.getInstanceClass().getCanonicalName(), x -> x));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getListCellRendererComponent(JList<? extends ComponentGroupItem> list,
|
||||
ComponentGroupItem value, int index, boolean isSelected, boolean cellHasFocus) {
|
||||
@@ -605,14 +598,15 @@ public class ExplorerPane extends JPanel {
|
||||
if (groupItem.getComponentCount() == 1) {
|
||||
// Render as individual component (ungrouped)
|
||||
IDIYComponent<?> component = groupItem.getGroup().iterator().next();
|
||||
ComponentType componentType = componentTypes.get(component.getClass().getCanonicalName());
|
||||
|
||||
if (componentType == null) {
|
||||
double zOrder = ComponentProcessor.getInstance().getZOrder(component);
|
||||
|
||||
// internal types without a descriptor have no layer
|
||||
if (zOrder == Double.MAX_VALUE) {
|
||||
renderer.setText(component.toString());
|
||||
return renderer;
|
||||
}
|
||||
|
||||
int layerId = (int) Math.round(componentType.getZOrder());
|
||||
int layerId = (int) Math.round(zOrder);
|
||||
|
||||
String valueForDisplay = component.getValueForDisplay();
|
||||
if (isSelected) {
|
||||
@@ -637,9 +631,9 @@ public class ExplorerPane extends JPanel {
|
||||
// Calculate maximum layer from components in the group
|
||||
int maxLayerId = 0;
|
||||
for (IDIYComponent<?> component : groupItem.getGroup()) {
|
||||
ComponentType componentType = componentTypes.get(component.getClass().getCanonicalName());
|
||||
if (componentType != null) {
|
||||
int layerId = (int) Math.round(componentType.getZOrder());
|
||||
double zOrder = ComponentProcessor.getInstance().getZOrder(component);
|
||||
if (zOrder != Double.MAX_VALUE) {
|
||||
int layerId = (int) Math.round(zOrder);
|
||||
if (layerId > maxLayerId) {
|
||||
maxLayerId = layerId;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.diylc;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
@@ -14,10 +15,13 @@ import org.junit.Test;
|
||||
|
||||
import org.diylc.appframework.miscutils.ConfigurationManager;
|
||||
import org.diylc.appframework.miscutils.InMemoryConfigurationManager;
|
||||
import org.diylc.clipboard.ComponentTransferable;
|
||||
import org.diylc.common.ComponentType;
|
||||
import org.diylc.common.EventType;
|
||||
import org.diylc.common.IPlugIn;
|
||||
import org.diylc.common.IPlugInPort;
|
||||
import org.diylc.components.chassis.ChassisPanel;
|
||||
import org.diylc.components.composite.CompositeComponent;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.Template;
|
||||
import org.diylc.presenter.Presenter;
|
||||
@@ -45,6 +49,24 @@ public class PresenterTests extends TestBase {
|
||||
Assert.assertEquals(1, presenter.getCurrentProject().getComponents().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChassisCompositeIsPlacedUnderExistingComponents() {
|
||||
instantiateTwoClick("Passive", "Resistor", new Point(1000, 1000), new Point(1200, 1000));
|
||||
|
||||
CompositeComponent chassis = new CompositeComponent();
|
||||
chassis.initBlockName("Chassis");
|
||||
chassis.getChildComponents().add(new ChassisPanel());
|
||||
chassis.getChildComponents().add(new ChassisPanel());
|
||||
List<IDIYComponent<?>> clipboard = new ArrayList<IDIYComponent<?>>();
|
||||
clipboard.add(chassis);
|
||||
presenter.pasteComponents(new ComponentTransferable(clipboard, "Chassis"), false, true);
|
||||
presenter.mouseClicked(new Point(500, 500), MouseEvent.BUTTON1, false, false, false, 1);
|
||||
|
||||
List<IDIYComponent<?>> components = presenter.getCurrentProject().getComponents();
|
||||
Assert.assertEquals(2, components.size());
|
||||
Assert.assertTrue(components.get(0) instanceof CompositeComponent);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNodeNameHover() {
|
||||
final String[] receivedTooltip = new String[1];
|
||||
|
||||
@@ -0,0 +1,296 @@
|
||||
# Chassis and Enclosures
|
||||
|
||||
Covering the Hammond pedal and amplifier chassis lineup with a `ChassisPanel` datasheet, and
|
||||
shipping the common pedal enclosures as exploded five-panel factory building blocks.
|
||||
|
||||
## 1. Current state
|
||||
|
||||
- `ChassisPanel` (`diylc-library`, `org.diylc.components.chassis`) is a two-point
|
||||
`AbstractShape` on the `CHASSIS` layer with an `Edge Radius`. One instance is one side of a
|
||||
chassis; its `@AiNote` already fixes the exploded-view convention (top in the centre, front
|
||||
against its upper edge, back against its lower edge, left and right against the side edges).
|
||||
- Four factory variants in `variants.xml` (`125B`, `A`, `B`, `BB`) store nothing but corner points
|
||||
and a 5 mm radius. Their sizes are not Hammond's (the `125B` variant is 122.3 x 67.1 mm, the
|
||||
1590N1 drawing says 121.2 x 65.5).
|
||||
- Factory building blocks (`import-defaults/blocks.xml`, three entries) are imported once, behind
|
||||
the boolean `DEFAULT_BLOCKS_IMPORTED_KEY`; blocks added later never reach existing users.
|
||||
- Composites take the lowest layer of their children (`ComponentProcessor.getZOrder`), so a
|
||||
composite of chassis panels sits on the Chassis layer, under parts placed before it, and
|
||||
follows that layer's hide/lock. Done; see §3.1.
|
||||
|
||||
## 2. Design decisions
|
||||
|
||||
| # | Decision | Rationale |
|
||||
|---|---|---|
|
||||
| D1 | Chassis sizes move to a datasheet, `datasheets/ChassisPanel.datasheet`, two creation steps (Group > Model) | Same mechanism as `DIL_IC` and `Resistor`; the AI can name a model; one row serves every side of the enclosure (D3). |
|
||||
| D2 | Row format `Group,Model,Length,Width,Height,Radius`. Sizes in mm unless a unit follows (`8 in`), parsed like `Resistor.parseDatasheetSize` | Pedal drawings are metric, Hammond chassis are nominal inches; writing each in its native unit keeps the file checkable against the drawings. |
|
||||
| D3 | `ChassisPanel` gets a `Value` property holding the model, and a new `Side` (`TOP`, `FRONT`, `BACK`, `LEFT`, `RIGHT`). `applyModel` sets `Value` to the model and sizes the panel from the row according to its side: top = Length x Width, front/back = Length x Height, left/right = Width x Height, keeping the first control point. Changing `Side` on a panel that has a model resizes it | One class, no per-side types. `Value` is backed by `AbstractShape.value`, a `String` that every shape already serializes and nothing reads (always `""`), so no new field is needed for it; since `AbstractShape.getValue()` is typed `Void`, the getter is `getModel()` with `@EditableProperty(name = "Value")`. `side` is new and reads `null` from old files: `getSide()` defaults to `TOP`. An empty value means "free-form panel" exactly as today. |
|
||||
| D4 | Top panel is drawn landscape, Length along X | Matches the four existing variants and the amp chassis front-panel orientation; pedal builders rotate (the transformer already supports it, and a composite rotates as a unit). |
|
||||
| D5 | Length/Width are Hammond's outside dimensions; Height is the drillable wall: box height without the lid for die-cast boxes, outside height for 1441/1444 | The lid of a 1590 is the pedal's bottom, which the exploded view leaves out. |
|
||||
| D6 | Die-cast taper is ignored: the top panel uses the outer size at the lid opening and side panels are rectangles | Hammond does not publish the floor size; the walls slope at most 2 deg, so the floor is 0.7-1.9 mm smaller per side. Recorded in §5 as unsourced. |
|
||||
| D7 | The four variants are withdrawn as `deletedOn` stubs | The mechanism from the Resistor and DIP migrations (`Template.deletedOn`, `DeletedVariantsTest`). |
|
||||
| D8 | Factory blocks get variant-style import tracking: each factory block has `createdOn`/`deletedOn`, the import date is stored under a new key | Mirrors `VariantManager`; lets new factory blocks reach existing users. |
|
||||
| D9 | Exploded factory blocks only for the common enclosures: pedals 1590A, 1590B, 125B, 1590BB, 1590XX, 1590DD; amps 1441-10, 1441-18, 1441-28, 1441-32 (§3.4) | The block toolbar is a flat list of buttons; the full lineup stays in the datasheet. |
|
||||
| D10 | A composite's z-order is the **minimum** of its children's, computed per instance | A composite occupies one slot in the stack and is drawn as a unit, so it should sit under what is placed on it afterwards. For a chassis block min = max = `CHASSIS`. For a maker board built from a board, pads and silkscreen text, max would be `TEXT` and the board would cover every part placed later; min is `BOARD`, and locking the Board layer locks the whole board. |
|
||||
| D11 | Die-cast boxes come from the 1590 and 1550 series only, natural finish only, plus generic sizes such as 125B under `Others`. HWCHAS walnut chassis and rack cases are out of this change | Painted and black versions share the natural part's dimensions, and the shaped 1590 STOMP boxes (TRPB, TRPC, STPC) are sold painted only. The others are listed in §6. |
|
||||
| D12 | BOM: one line per enclosure, valued by model. `getValueForDisplay()` returns the model for a `TOP` panel and `null` for any other side; `bomPolicy` stays `SHOW_ONLY_TYPE_NAME` | `BomMaker` keys rows by type + value and skips a `null` value, so an exploded 1590BB reads `Chassis Panel / 1590BB / 1` instead of five panels. Free-form and old-file panels are `TOP` with an empty value and list as they do today. An exploded block placed as a composite lists under its block name, so the block's `CompositeComponent` carries the model as its value too (§3.4). |
|
||||
|
||||
## 3. Implementation
|
||||
|
||||
Step 4 depends on 2 and 3.
|
||||
|
||||
### 3.1 Composite z-order (core) - done
|
||||
|
||||
- `ComponentProcessor.getZOrder(IDIYComponent<?>)`: for a `CompositeComponent`, the minimum over
|
||||
its children, recursing into nested composites; a childless composite and any other component
|
||||
use the type's z-order. Not cached: a type lookup is a map hit and composites are few.
|
||||
- Every class-level layer read goes through it: `Presenter` insertion (`addComponent`,
|
||||
`addComponents`), hidden and locked layers, `selectAll(layer)`, send to back / bring to front;
|
||||
`GroupAndLockIndex.isLocked`; `ComparatorFactory.getComponentZOrderComparator`; the `[L#]` tag
|
||||
in `ExplorerPane`, which now shows composites too.
|
||||
- Paint order is the project list order, so existing files render the same; only hide/lock and
|
||||
future insertion change. `flexibleZOrder = true` stays.
|
||||
- Tests: `CompositeComponentTest` (chassis-only, mixed, nested and childless composites; layer
|
||||
lock; comparator) and `PresenterTests.testChassisCompositeIsPlacedUnderExistingComponents`.
|
||||
|
||||
### 3.2 `ChassisPanel` datasheet (library)
|
||||
|
||||
- `enableDatasheet = true, datasheetCreationStepCount = 2, datasheetModelColumn = 1`,
|
||||
`implements IDatasheetSupport`, `ChassisPanel(String[] model)` constructor.
|
||||
- `getModel()` / `setModel()` over the inherited `value` field as `Value`, and a new serialized
|
||||
`side` whose getter tolerates `null` (D3). Override `getValueForDisplay()` for the BOM (D12).
|
||||
- `@AiNote`: a datasheet model is a Hammond part number such as 1590BB or 1444-32 and is stored as
|
||||
'Value'; it sets the panel size for the panel's `Side`, so set `Side` before or together with
|
||||
the model. Only the top panel carries the enclosure into the BOM. "125B" is a generic size
|
||||
sold by several makers (about 122 x 66 x 40 mm with the lid, often with thinner walls) and has
|
||||
its own row under `Others`; its Hammond equivalent is 1590N1.
|
||||
- `ChassisPanel.datasheet` from §4. Rows are listed per group in the order given there.
|
||||
- `variants.xml`: `125B`, `A`, `B`, `BB` become `deletedOn` stubs; extend `DeletedVariantsTest`.
|
||||
- `ChassisPanelDatasheetTest`, modelled on `ResistorDatasheetTest`: every row parses; each side
|
||||
gets the expected size; changing `Side` resizes; a panel from an old file (empty value, null
|
||||
side) keeps its geometry; the BOM lists one line per top panel, valued by model, and none for
|
||||
side panels.
|
||||
- Localization: `Side`, `Top`, `Front`, `Back`, `Left`, `Right` in
|
||||
every `lang/` file. Fix the description typo "withouth".
|
||||
- Regenerate `catalog_full.json` as the Resistor change did.
|
||||
|
||||
### 3.3 Factory block import tracking (core)
|
||||
|
||||
- New `org.diylc.core.FactoryBlock` (`name`, `createdOn`, `deletedOn`, `components`), the shape of
|
||||
`Template`. `blocks.xml` becomes a list of these; the user's `BLOCKS_KEY` map is unchanged.
|
||||
- `BuildingBlockManager.importDefaultBlocks` mirrors `VariantManager`: import a block when its
|
||||
`createdOn` is after the stored `DEFAULT_BLOCKS_IMPORT_DATE_KEY` and the user has no block of
|
||||
that name; remove it when `deletedOn` is after the import date.
|
||||
- Migration: the three existing blocks keep `createdOn = null` and are imported only when the
|
||||
legacy `DEFAULT_BLOCKS_IMPORTED_KEY` is false (a fresh install), so users who deleted them do not
|
||||
get them back.
|
||||
- Test alongside the variant import tests: fresh install, upgrade from the boolean flag, new block
|
||||
after an import, deleted block, user block with a clashing name.
|
||||
|
||||
### 3.4 Exploded blocks
|
||||
|
||||
- Ten blocks named `Hammond <model> (Exploded)`, or `<model> (Exploded)` for a generic size
|
||||
(`125B (Exploded)`): the six pedal enclosures from D9 and four amp chassis, one per size class.
|
||||
The amp picks are the steel 1441 sizes amp builders and kit
|
||||
suppliers stock (Tube Town, an amp-parts shop, carries 1441-10, -18, -28 and -32); steel over
|
||||
the 1444 because builders warn that thin chassis sag under heavy transformers.
|
||||
|
||||
| Class | Typical build | Block | W x D x H | Why this size |
|
||||
|---|---|---|---|---|
|
||||
| Small | Tweed Champ (5F1) | 1441-10 | 8 x 4 x 2 in | Closest Hammond to the original 5F1 chassis (8-3/4 x 4-1/8 x 2-5/8 in). |
|
||||
| Medium | 18 W Marshall (TMB) | 1441-18 | 13.5 x 5 x 2 in | The Hammond size suggested for 18 W builds; dedicated 18 W chassis are similarly long and narrow (17 x 6-1/2 x 2-1/2 in), which fits the in-line tube row. |
|
||||
| Larger | 50 W Plexi / JTM45 | 1441-28 | 16 x 8 x 3 in | 16 x 8 x 2-3 in is the size quoted for 50 W Marshall builds; 3 in clears the transformers. |
|
||||
| Large | 100 W modern (SLO-style) | 1441-32 | 17 x 10 x 3 in | Largest common format; room for two channels, four power tubes and large iron. |
|
||||
|
||||
- No source names a Hammond for the SLO specifically (the real head is 25 in wide, wider than
|
||||
any Hammond chassis); 1441-32 is a size judgement.
|
||||
- Each block is five `ChassisPanel`s with `Value` (model) and `Side` set; the block's composite
|
||||
value is the model as well, so the BOM line reads `Hammond 1590BB (Exploded) / 1590BB`. With the top at (0,0)-(L,W): front (0,-H)-(L,0), back (0,W)-(L,W+H), left (-H,0)-(0,W),
|
||||
right (L,0)-(L+H,W). Edge radius on the top panel only.
|
||||
- Generate the XML once from the datasheet rather than by hand, and add a test that every panel of
|
||||
every factory chassis block matches its datasheet row and touches its neighbours edge to edge,
|
||||
so the two cannot drift.
|
||||
|
||||
### 3.5 Verify
|
||||
|
||||
`mvn -q test` (spans core and library), then offer the regression suite: §3.1 changes hide/lock
|
||||
behaviour of existing composites and §3.2 touches serialization.
|
||||
|
||||
## 4. Datasheet rows
|
||||
|
||||
Sources: Hammond per-part drawings, `https://www.hammfg.com/files/parts/pdf/<PART>.pdf`; series
|
||||
tables on hammfg.com (1590, 1590-STOMP, 1441, 1444). Die-cast sizes are drawing outside dimensions
|
||||
at the lid opening; heights are the box without the 4 mm lid. Chassis sizes are Hammond's nominal
|
||||
outside W x D x H. Radius 5 on die-cast boxes is carried over from the old variants, **unverified**
|
||||
(§5); sheet-metal chassis are drawn square.
|
||||
|
||||
Die-cast boxes are grouped by series only (1590, 1550), in Hammond's catalogue order, and only
|
||||
natural-finish (unpainted) part numbers are rows. Chassis are grouped by family, then height. The
|
||||
1590 group has 37 rows; the toolbox already splits a datasheet submenu longer than
|
||||
`MAX_MENU_ITEMS` (30) into ranged submenus, so it needs no further split.
|
||||
|
||||
```
|
||||
Diecast (1590),1590LLB,50.5,50.5,21,5
|
||||
Diecast (1590),1590LB,50.55,50.6,27,5
|
||||
Diecast (1590),1590H,53,38,27,5
|
||||
Diecast (1590),1590Y,92,92,38,5
|
||||
Diecast (1590),1590A,92.6,38.5,27,5
|
||||
Diecast (1590),1590G,100,50,21.5,5
|
||||
Diecast (1590),1590G2,100,50,27,5
|
||||
Diecast (1590),1590S,110.5,82.4,40,5
|
||||
Diecast (1590),1590B,112.4,60.5,27,5
|
||||
Diecast (1590),1590B2,112.4,60.5,33.5,5
|
||||
Diecast (1590),1590BS,112,60.5,38,5
|
||||
Diecast (1590),1590B3,116,77,33.5,5
|
||||
Diecast (1590),1590BB,119.5,94,30,5
|
||||
Diecast (1590),1590BB2,119.5,94,33.75,5
|
||||
Diecast (1590),1590BBS,119.5,94,38.1,5
|
||||
Diecast (1590),1590Q,120,120,30,5
|
||||
Diecast (1590),1590U,120,120,55,5
|
||||
Diecast (1590),1590V,120,120,90,5
|
||||
Diecast (1590),1590C,119.5,94,52.5,5
|
||||
Diecast (1590),1590T,120,80,55,5
|
||||
Diecast (1590),1590CE,120,100,61,5
|
||||
Diecast (1590),1590N1,121.2,65.5,35.8,5
|
||||
Diecast (1590),1590KK,125,125,53,5
|
||||
Diecast (1590),1590K,125,125,75,5
|
||||
Diecast (1590),1590J,145,95,45.1,5
|
||||
Diecast (1590),1590XX,145.2,121.2,35.2,5
|
||||
Diecast (1590),1590X,145.2,121.2,52.3,5
|
||||
Diecast (1590),1590P1,153,83.1,46.4,5
|
||||
Diecast (1590),1590D,187.75,119.5,52,5
|
||||
Diecast (1590),1590DD,188,120,33,5
|
||||
Diecast (1590),1590E,188,120,78,5
|
||||
Diecast (1590),1590F,188,188,63,5
|
||||
Diecast (1590),1590R1,192,112,57,5
|
||||
Diecast (1590),1590DE,200,120,60,5
|
||||
Diecast (1590),1590EE,200,120,81,5
|
||||
Diecast (1590),1590BX2,254,70,31,5
|
||||
Diecast (1590),1590BX,254,70,46,5
|
||||
Diecast (1550),1550Q,60,55,26,5
|
||||
Diecast (1550),1550P,80,55,21,5
|
||||
Diecast (1550),1550A,89,35,26,5
|
||||
Diecast (1550),1550B,114.5,64,26,5
|
||||
Diecast (1550),1550D,115,64,51,5
|
||||
Diecast (1550),1550C,115,90,51,5
|
||||
Diecast (1550),1550M,120,100,31,5
|
||||
Diecast (1550),1550K,140,102,73,5
|
||||
Diecast (1550),1550L,165,127,73,5
|
||||
Diecast (1550),1550E,171,121,51,5
|
||||
Diecast (1550),1550F,171,121,101,5
|
||||
Diecast (1550),1550G,222,146,51,5
|
||||
Diecast (1550),1550H,222,146,101,5
|
||||
Diecast (1550),1550N,250,250,97,5
|
||||
Diecast (1550),1550J,275,175,63,5
|
||||
Others,125B,122,66,36,5
|
||||
Chassis - Steel (1441),1441-9,8 in,4 in,1 in,0
|
||||
Chassis - Steel (1441),1441-15,10 in,6 in,1 in,0
|
||||
Chassis - Steel (1441),1441-6,4 in,4 in,2 in,0
|
||||
Chassis - Steel (1441),1441-8,6 in,4 in,2 in,0
|
||||
Chassis - Steel (1441),1441-12,7 in,5 in,2 in,0
|
||||
Chassis - Steel (1441),1441-10,8 in,4 in,2 in,0
|
||||
Chassis - Steel (1441),1441-14,9 in,5 in,2 in,0
|
||||
Chassis - Steel (1441),1441-16,10 in,6 in,2 in,0
|
||||
Chassis - Steel (1441),1441-22,12 in,8 in,2 in,0
|
||||
Chassis - Steel (1441),1441-29,12 in,10 in,2 in,0
|
||||
Chassis - Steel (1441),1441-18,13.5 in,5 in,2 in,0
|
||||
Chassis - Steel (1441),1441-26,16 in,8 in,2 in,0
|
||||
Chassis - Steel (1441),1441-30,17 in,10 in,2 in,0
|
||||
Chassis - Steel (1441),1441-34,17 in,12 in,2 in,0
|
||||
Chassis - Steel (1441),1441-24,12 in,8 in,3 in,0
|
||||
Chassis - Steel (1441),1441-28,16 in,8 in,3 in,0
|
||||
Chassis - Steel (1441),1441-20,17 in,4 in,3 in,0
|
||||
Chassis - Steel (1441),1441-32,17 in,10 in,3 in,0
|
||||
Chassis - Steel (1441),1441-36,17 in,12 in,3 in,0
|
||||
Chassis - Steel (1441),1441-38,17 in,14 in,3 in,0
|
||||
Chassis - Steel (1441),1441-33,17 in,10 in,4 in,0
|
||||
Chassis - Steel (1441),1441-40,17 in,14 in,4 in,0
|
||||
Chassis - Steel (1441),1441-42,17 in,14 in,5 in,0
|
||||
Chassis - Aluminium (1444) 1-2 in,1444-45351,4.5 in,3.5 in,1 in,0
|
||||
Chassis - Aluminium (1444) 1-2 in,1444-9,8 in,4 in,1 in,0
|
||||
Chassis - Aluminium (1444) 1-2 in,1444-15,10 in,6 in,1 in,0
|
||||
Chassis - Aluminium (1444) 1-2 in,1444-6415,6 in,4 in,1.5 in,0
|
||||
Chassis - Aluminium (1444) 1-2 in,1444-84515,8 in,4.5 in,1.5 in,0
|
||||
Chassis - Aluminium (1444) 1-2 in,1444-6,4 in,4 in,2 in,0
|
||||
Chassis - Aluminium (1444) 1-2 in,1444-542,5 in,4 in,2 in,0
|
||||
Chassis - Aluminium (1444) 1-2 in,1444-8,6 in,4 in,2 in,0
|
||||
Chassis - Aluminium (1444) 1-2 in,1444-12,7 in,5 in,2 in,0
|
||||
Chassis - Aluminium (1444) 1-2 in,1444-772,7 in,7 in,2 in,0
|
||||
Chassis - Aluminium (1444) 1-2 in,1444-10,8 in,4 in,2 in,0
|
||||
Chassis - Aluminium (1444) 1-2 in,1444-862,8 in,6 in,2 in,0
|
||||
Chassis - Aluminium (1444) 1-2 in,1444-14,9 in,5 in,2 in,0
|
||||
Chassis - Aluminium (1444) 1-2 in,1444-972,9 in,7 in,2 in,0
|
||||
Chassis - Aluminium (1444) 1-2 in,1444-9552,9.5 in,5 in,2 in,0
|
||||
Chassis - Aluminium (1444) 1-2 in,1444-16,10 in,6 in,2 in,0
|
||||
Chassis - Aluminium (1444) 1-2 in,1444-1172,11 in,7 in,2 in,0
|
||||
Chassis - Aluminium (1444) 1-2 in,1444-22,12 in,8 in,2 in,0
|
||||
Chassis - Aluminium (1444) 1-2 in,1444-29,12 in,10 in,2 in,0
|
||||
Chassis - Aluminium (1444) 1-2 in,1444-1372,13 in,7 in,2 in,0
|
||||
Chassis - Aluminium (1444) 1-2 in,1444-18,13.5 in,5 in,2 in,0
|
||||
Chassis - Aluminium (1444) 1-2 in,1444-26,16 in,8 in,2 in,0
|
||||
Chassis - Aluminium (1444) 1-2 in,1444-30,17 in,10 in,2 in,0
|
||||
Chassis - Aluminium (1444) 1-2 in,1444-17132,17 in,13 in,2 in,0
|
||||
Chassis - Aluminium (1444) 2.5-3 in,1444-95525,9.5 in,5 in,2.5 in,0
|
||||
Chassis - Aluminium (1444) 2.5-3 in,1444-10825,10 in,8 in,2.5 in,0
|
||||
Chassis - Aluminium (1444) 2.5-3 in,1444-12825,12 in,8 in,2.5 in,0
|
||||
Chassis - Aluminium (1444) 2.5-3 in,1444-643,6 in,4 in,3 in,0
|
||||
Chassis - Aluminium (1444) 2.5-3 in,1444-753,7 in,5 in,3 in,0
|
||||
Chassis - Aluminium (1444) 2.5-3 in,1444-9553,9.5 in,5 in,3 in,0
|
||||
Chassis - Aluminium (1444) 2.5-3 in,1444-1053,10 in,5 in,3 in,0
|
||||
Chassis - Aluminium (1444) 2.5-3 in,1444-1273,12 in,7 in,3 in,0
|
||||
Chassis - Aluminium (1444) 2.5-3 in,1444-24,12 in,8 in,3 in,0
|
||||
Chassis - Aluminium (1444) 2.5-3 in,1444-12103,12 in,10 in,3 in,0
|
||||
Chassis - Aluminium (1444) 2.5-3 in,1444-12123,12 in,12 in,3 in,0
|
||||
Chassis - Aluminium (1444) 2.5-3 in,1444-1463,14 in,6 in,3 in,0
|
||||
Chassis - Aluminium (1444) 2.5-3 in,1444-14103,14 in,10 in,3 in,0
|
||||
Chassis - Aluminium (1444) 2.5-3 in,1444-1573,15 in,7 in,3 in,0
|
||||
Chassis - Aluminium (1444) 2.5-3 in,1444-1593,15 in,9 in,3 in,0
|
||||
Chassis - Aluminium (1444) 2.5-3 in,1444-28,16 in,8 in,3 in,0
|
||||
Chassis - Aluminium (1444) 2.5-3 in,1444-20,17 in,4 in,3 in,0
|
||||
Chassis - Aluminium (1444) 2.5-3 in,1444-1763,17 in,6 in,3 in,0
|
||||
Chassis - Aluminium (1444) 2.5-3 in,1444-1773,17 in,7 in,3 in,0
|
||||
Chassis - Aluminium (1444) 2.5-3 in,1444-1783,17 in,8 in,3 in,0
|
||||
Chassis - Aluminium (1444) 2.5-3 in,1444-32,17 in,10 in,3 in,0
|
||||
Chassis - Aluminium (1444) 2.5-3 in,1444-17123,17 in,12 in,3 in,0
|
||||
Chassis - Aluminium (1444) 2.5-3 in,1444-17133,17 in,13 in,3 in,0
|
||||
Chassis - Aluminium (1444) 2.5-3 in,1444-17143,17 in,14 in,3 in,0
|
||||
Chassis - Aluminium (1444) 2.5-3 in,1444-17173,17 in,17 in,3 in,0
|
||||
Chassis - Aluminium (1444) 4-6 in,1444-33,17 in,10 in,4 in,0
|
||||
Chassis - Aluminium (1444) 4-6 in,1444-17134,17 in,13 in,4 in,0
|
||||
Chassis - Aluminium (1444) 4-6 in,1444-17154,17 in,15 in,4 in,0
|
||||
Chassis - Aluminium (1444) 4-6 in,1444-17174,17 in,17 in,4 in,0
|
||||
Chassis - Aluminium (1444) 4-6 in,1444-17105,17 in,10 in,5 in,0
|
||||
Chassis - Aluminium (1444) 4-6 in,1444-17135,17 in,13 in,5 in,0
|
||||
Chassis - Aluminium (1444) 4-6 in,1444-17156,17 in,15 in,6 in,0
|
||||
```
|
||||
|
||||
Group sizes: 37 (1590), 15 (1550), 1 (Others); 23 / 24 / 25 / 7 chassis (132 rows). `Others`
|
||||
holds generic sizes sold by several makers under one name, currently only 125B (122 x 66 x 40 mm
|
||||
with the backplate, per a maker's listing). The 1590 rows already in the research were read from the per-part drawings; 1590H, U,
|
||||
V, CE, KK, K, E, F, R1, DE, EE, BX2 and BX, and all 1550 rows except 1550B, come from Hammond's
|
||||
series tables (whole mm, lid included).
|
||||
Finish and option suffixes are not rows: `BK3` (black 1441), `BK` (black 1550), colour codes on
|
||||
1590 (`RD`, `CB`, ...), `W` prefix (watertight; IP66/IP67 gaskets on the 1550), `F`/`FL`
|
||||
(flanged), `CWW` (walnut sides on sizes 12/16/22/24/32/33, which shorten the usable front, back and
|
||||
top by about 22 mm).
|
||||
|
||||
## 5. Unsourced or conflicting figures
|
||||
|
||||
| Item | Status |
|
||||
|---|---|
|
||||
| Die-cast corner radius (top view) and top-to-side edge fillet | Not published; 5 mm is the old variants' figure. Measure from Hammond STEP models or a box. |
|
||||
| Die-cast floor size (pedal top face) | Not published; between the outer size and outer minus 2 x (box height x tan 2 deg). |
|
||||
| 1590DD box height | Drawing gives 37.00 both overall and box; 33 assumes the usual 4 mm lid. |
|
||||
| 1590D box height | ~52, same assumption. |
|
||||
| Box heights of the table-only 1590 rows (H, U, V, CE, KK, K, E, F, R1, DE, EE, BX2, BX) | Table height minus the 4 mm lid; length and width are the table's rounded figures. Read the drawings to firm them up. |
|
||||
| 125B box height | 40 mm with the backplate minus an assumed 4 mm backplate (the 1590 lid); makers do not state the plate thickness. |
|
||||
| 1550 box heights (all but 1550B) | Series table height (lid included) minus 4 mm, the overall-to-box difference on the 1550B drawing (30.10 / 26.00). |
|
||||
| 1590BS / 1590B2 height | Web table 38 for both; drawings 42.00 overall / 38.00 box and 37.50 overall. Drawings used. |
|
||||
| 1444-10/-12/-14 height | Drawings say 49.78 mm; catalogue and inner height fit 50.80 (2 in). 2 in used. |
|
||||
| 1441-42 sheet | Drawing 0.057", product page 18 ga. Irrelevant to the outline. |
|
||||
|
||||
## 6. Later
|
||||
|
||||
- HWCHAS walnut-frame chassis (HWCHAS1310 / 1710; aluminium top 298.45 x 222.25 / 400.05 x
|
||||
222.25 mm on a 19.05 mm walnut frame): a different construction from the folded sheet metal.
|
||||
- Hammond rack cases (RM, RMCS) and the 1458 instrument enclosure.
|
||||
Reference in New Issue
Block a user