mirror of
https://github.com/bancika/diy-layout-creator
synced 2026-11-13 02:32:09 +10:00
Review fixes: a drag in the Underside Display picks the part a click would, the part being placed there is drawn like the parts already there, a bottom Dot no longer adds an empty silkscreen page; one helper decides a part's board side and copper layers share an interface
This commit is contained in:
@@ -46,4 +46,13 @@ public interface IBoardSideComponent {
|
||||
* @param boardSide {@link PCBLayer#_2} for the top or {@link PCBLayer#_1} for the bottom
|
||||
*/
|
||||
void setBoardSide(PCBLayer boardSide);
|
||||
|
||||
/**
|
||||
* @return {@link PCBLayer#_1} for a component mounted on the bottom of the board, and
|
||||
* {@link PCBLayer#_2} for any other, including components that have no side
|
||||
*/
|
||||
static PCBLayer sideOf(IDIYComponent<?> component) {
|
||||
return component instanceof IBoardSideComponent sided && sided.getBoardSide() == PCBLayer._1
|
||||
? PCBLayer._1 : PCBLayer._2;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2025 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
package org.diylc.core;
|
||||
|
||||
import org.diylc.common.PCBLayer;
|
||||
|
||||
/**
|
||||
* Interface for copper drawn on a layer of a PCB, such as a trace, pad, ground fill or PCB text.
|
||||
* Unlike {@link IBoardSideComponent}, the layer is where the copper itself is, and it also decides
|
||||
* which other copper it connects to.
|
||||
*
|
||||
* @author Branislav Stojkovic
|
||||
*/
|
||||
public interface IPCBLayerComponent {
|
||||
|
||||
PCBLayer getLayer();
|
||||
|
||||
void setLayer(PCBLayer layer);
|
||||
}
|
||||
@@ -162,8 +162,7 @@ public class GerberExporter {
|
||||
IGerberComponentSimple gerberComponentSimple = (IGerberComponentSimple) gerberComponent;
|
||||
GerberLayer layer = gerberComponentSimple.getGerberLayer();
|
||||
// components emit their top-side layer; a part mounted underneath goes to the bottom one
|
||||
boolean bottomSide = c instanceof IBoardSideComponent
|
||||
&& ((IBoardSideComponent) c).getBoardSide() == PCBLayer._1;
|
||||
boolean bottomSide = IBoardSideComponent.sideOf(c) == PCBLayer._1;
|
||||
if (bottomSide) {
|
||||
layer = layer.flip();
|
||||
}
|
||||
|
||||
@@ -21,10 +21,9 @@
|
||||
*/
|
||||
package org.diylc.filter;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.diylc.common.PCBLayer;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.IPCBLayerComponent;
|
||||
|
||||
public class PCBLayerFilter implements IComponentFilter {
|
||||
|
||||
@@ -37,13 +36,6 @@ public class PCBLayerFilter implements IComponentFilter {
|
||||
|
||||
@Override
|
||||
public boolean testComponent(IDIYComponent<?> component) {
|
||||
Class<?> clazz = component.getClass();
|
||||
try {
|
||||
Method m = clazz.getMethod("getLayer");
|
||||
PCBLayer l = (PCBLayer) m.invoke(component);
|
||||
return layer == l;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
return component instanceof IPCBLayerComponent copper && copper.getLayer() == layer;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,16 +33,10 @@ public class SilkScreenFilter implements IComponentFilter {
|
||||
if (!(component instanceof IGerberComponent gerberComponent)) {
|
||||
return false;
|
||||
}
|
||||
if (side != null && getSide(component) != side) {
|
||||
if (side != null && IBoardSideComponent.sideOf(component) != side) {
|
||||
return false;
|
||||
}
|
||||
Set<GerberRenderMode> gerberRenderModes = gerberComponent.getGerberRenderModes();
|
||||
return gerberRenderModes.contains(GerberRenderMode.Outline);
|
||||
}
|
||||
|
||||
// components that do not say which side they are on are on top
|
||||
private static PCBLayer getSide(IDIYComponent<?> component) {
|
||||
return component instanceof IBoardSideComponent sided && sided.getBoardSide() == PCBLayer._1
|
||||
? PCBLayer._1 : PCBLayer._2;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ import org.diylc.common.ComponentType;
|
||||
import org.diylc.common.DrawOption;
|
||||
import org.diylc.core.ComponentForRender;
|
||||
import org.diylc.core.ComponentState;
|
||||
import org.diylc.core.IBoardSideComponent;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.Project;
|
||||
import org.diylc.core.annotations.ComponentDescriptor;
|
||||
@@ -351,7 +352,7 @@ public class DrawingCache {
|
||||
|
||||
// initialize wrapper
|
||||
wrapper.startedDrawingComponent(zOrder);
|
||||
wrapper.setUndeclaredSide(DrawingManager.getMountedSide(component));
|
||||
wrapper.setUndeclaredSide(IBoardSideComponent.sideOf(component));
|
||||
|
||||
long componentStart = System.nanoTime();
|
||||
|
||||
|
||||
@@ -307,7 +307,7 @@ public class DrawingManager {
|
||||
g2d.setComposite(lockedComposite);
|
||||
}
|
||||
// after the locked composite, which is set on the canvas and would replace the fade
|
||||
g2dWrapper.setUndeclaredSide(getMountedSide(component));
|
||||
g2dWrapper.setUndeclaredSide(IBoardSideComponent.sideOf(component));
|
||||
// Draw the component through the g2dWrapper.
|
||||
long componentStart = System.nanoTime();
|
||||
try {
|
||||
@@ -433,8 +433,7 @@ public class DrawingManager {
|
||||
g2dWrapper.startedDrawingComponent(project.getComponents().size());
|
||||
g2dWrapper.setComposite(slotComposite);
|
||||
if (slotTx != null) {
|
||||
g2dWrapper.transform(slotTx);
|
||||
g2dWrapper.setMirrorDirection(UndersideMirror.getMirrorDirection(slotMirrorBoard));
|
||||
viewThroughMirror(g2dWrapper, slotMirrorBoard, slotTx, component);
|
||||
}
|
||||
try {
|
||||
component.draw(g2dWrapper, ComponentState.NORMAL,
|
||||
@@ -443,7 +442,9 @@ public class DrawingManager {
|
||||
LOG.error("Error drawing " + component.getName(), e);
|
||||
failedComponents.add(component);
|
||||
} finally {
|
||||
g2dWrapper.setMirrorDirection(G2DWrapper.MirrorDirection.NONE);
|
||||
if (slotTx != null) {
|
||||
stopViewingThroughMirror(g2dWrapper);
|
||||
}
|
||||
g2dWrapper.finishedDrawingComponent();
|
||||
}
|
||||
}
|
||||
@@ -544,15 +545,6 @@ public class DrawingManager {
|
||||
return failedComponents;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the side of the board the component is mounted on; components that do not say are
|
||||
* on top
|
||||
*/
|
||||
static PCBLayer getMountedSide(IDIYComponent<?> component) {
|
||||
return component instanceof IBoardSideComponent
|
||||
? ((IBoardSideComponent) component).getBoardSide() : PCBLayer._2;
|
||||
}
|
||||
|
||||
private static void drawSelectedControlPoint(G2DWrapper g2dWrapper, Point2D controlPoint) {
|
||||
g2dWrapper.setColor(SELECTED_CONTROL_POINT_COLOR.darker());
|
||||
g2dWrapper.fillOval((int) Math.round(controlPoint.getX() - CONTROL_POINT_SIZE / 2),
|
||||
@@ -571,29 +563,40 @@ public class DrawingManager {
|
||||
return;
|
||||
}
|
||||
|
||||
G2DWrapper.MirrorDirection mirrorDirection = UndersideMirror.getMirrorDirection(board);
|
||||
|
||||
AffineTransform oldTx = g2dWrapper.getTransform();
|
||||
Composite oldComposite = g2dWrapper.getComposite();
|
||||
g2dWrapper.setMirrorDirection(mirrorDirection);
|
||||
try {
|
||||
g2dWrapper.transform(mirrorTx);
|
||||
// the mirror is the copper side, so copper and the parts mounted on it are drawn solid and
|
||||
// the component side faded
|
||||
g2dWrapper.setViewedSide(PCBLayer._1, Boolean.TRUE.equals(board.getUndersideTransparency()),
|
||||
component instanceof IBoard ? PCBLayer._1 : getMountedSide(component));
|
||||
viewThroughMirror(g2dWrapper, board, mirrorTx, component);
|
||||
component.draw(g2dWrapper, state, outlineMode, project, g2dWrapper);
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error drawing mirrored " + component.getName(), e);
|
||||
} finally {
|
||||
g2dWrapper.setMirrorDirection(G2DWrapper.MirrorDirection.NONE);
|
||||
stopViewingThroughMirror(g2dWrapper);
|
||||
g2dWrapper.setTransform(oldTx);
|
||||
g2dWrapper.stopDrawingSide();
|
||||
g2dWrapper.resetViewedSide();
|
||||
g2dWrapper.setComposite(oldComposite);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the wrapper up to draw the component into the board's underside mirror: reflected, with
|
||||
* text kept readable, and seen from the bottom.
|
||||
*/
|
||||
private static void viewThroughMirror(G2DWrapper g2dWrapper, IBoard board,
|
||||
AffineTransform mirrorTx, IDIYComponent<?> component) {
|
||||
g2dWrapper.setMirrorDirection(UndersideMirror.getMirrorDirection(board));
|
||||
g2dWrapper.transform(mirrorTx);
|
||||
// the mirror is the copper side, so copper and the parts mounted on it are drawn solid and
|
||||
// the component side faded
|
||||
g2dWrapper.setViewedSide(PCBLayer._1, Boolean.TRUE.equals(board.getUndersideTransparency()),
|
||||
component instanceof IBoard ? PCBLayer._1 : IBoardSideComponent.sideOf(component));
|
||||
}
|
||||
|
||||
private static void stopViewingThroughMirror(G2DWrapper g2dWrapper) {
|
||||
g2dWrapper.setMirrorDirection(G2DWrapper.MirrorDirection.NONE);
|
||||
g2dWrapper.stopDrawingSide();
|
||||
g2dWrapper.resetViewedSide();
|
||||
}
|
||||
|
||||
private static void drawComponent(Project project, Set<DrawOption> drawOptions, Double scaleFactor,
|
||||
Rectangle2D visibleRect, IDIYComponent<?> component, G2DWrapper g2dWrapper, ComponentState state,
|
||||
double zoom, int i, boolean outlineMode, boolean cacheable) {
|
||||
|
||||
@@ -21,14 +21,12 @@
|
||||
*/
|
||||
package org.diylc.presenter;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import org.diylc.common.PCBLayer;
|
||||
import org.diylc.core.IBoardSideComponent;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.IPCBLayerComponent;
|
||||
|
||||
/**
|
||||
* Puts components placed through an Underside Display mirror on the bottom of the board. A part
|
||||
@@ -37,29 +35,15 @@ import org.diylc.core.IDIYComponent;
|
||||
*/
|
||||
public class MirrorPlacement {
|
||||
|
||||
private static final Logger LOG = Logger.getLogger(MirrorPlacement.class);
|
||||
|
||||
private MirrorPlacement() {
|
||||
}
|
||||
|
||||
public static void placeOnBottom(Collection<IDIYComponent<?>> components) {
|
||||
for (IDIYComponent<?> component : components) {
|
||||
if (component instanceof IBoardSideComponent) {
|
||||
((IBoardSideComponent) component).setBoardSide(PCBLayer._1);
|
||||
continue;
|
||||
}
|
||||
// traces, pads and PCB text share no interface for their layer, so it is found the same way
|
||||
// PCBLayerFilter reads it
|
||||
Method setLayer;
|
||||
try {
|
||||
setLayer = component.getClass().getMethod("setLayer", PCBLayer.class);
|
||||
} catch (NoSuchMethodException e) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
setLayer.invoke(component, PCBLayer._1);
|
||||
} catch (Exception e) {
|
||||
LOG.warn("Could not put " + component.getName() + " on the bottom layer", e);
|
||||
if (component instanceof IBoardSideComponent sided) {
|
||||
sided.setBoardSide(PCBLayer._1);
|
||||
} else if (component instanceof IPCBLayerComponent copper) {
|
||||
copper.setLayer(PCBLayer._1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,11 +172,12 @@ public class Presenter implements IPlugInPort {
|
||||
private Point2D dragStartPoint = null;
|
||||
private boolean dragShiftDown = false;
|
||||
private AxisLock lockedAxis = null;
|
||||
// The reflection of the Underside Display mirror a drag started in. Every point of that drag goes
|
||||
// through it, so the drag acts on the components themselves; null for a drag in the main view.
|
||||
private AffineTransform dragMirrorTx = null;
|
||||
// the reflection of the mirror that the control points in controlPointMap were found through
|
||||
private AffineTransform hoverMirrorTx = null;
|
||||
// The board whose Underside Display mirror a drag started in. Every point of that drag is
|
||||
// reflected through it, so the drag acts on the components themselves; null for a drag in the
|
||||
// main view.
|
||||
private IBoard dragMirrorBoard = null;
|
||||
// the board whose mirror the control points in controlPointMap were found through
|
||||
private IBoard hoverMirrorBoard = null;
|
||||
// the board whose Underside Display mirror the component in the slot is being placed through;
|
||||
// null when it is placed in the main view
|
||||
private IBoard placementMirrorBoard = null;
|
||||
@@ -310,6 +311,7 @@ public class Presenter implements IPlugInPort {
|
||||
public void loadProject(Project project, boolean freshStart, String filename) {
|
||||
LOG.info(String.format("loadProject(%s, %s)", project.getTitle(), freshStart));
|
||||
this.currentProject = project;
|
||||
placementMirrorBoard = null;
|
||||
groupAndLockIndex.invalidate();
|
||||
drawingManager.clearComponentAreaMap();
|
||||
drawingManager.clearContinuityArea();
|
||||
@@ -632,7 +634,7 @@ public class Presenter implements IPlugInPort {
|
||||
return;
|
||||
}
|
||||
updatePlacementMirror(scaledPoint);
|
||||
scaledPoint = toPlacementSpace(scaledPoint);
|
||||
scaledPoint = UndersideMirror.reflect(placementMirrorBoard, scaledPoint);
|
||||
// Keep the reference to component type for later.
|
||||
ComponentType componentTypeSlot = instantiationManager.getComponentTypeSlot();
|
||||
Template template = instantiationManager.getTemplate();
|
||||
@@ -965,7 +967,8 @@ public class Presenter implements IPlugInPort {
|
||||
* specified point, one per component. When the point was reflected out of the underside mirror of
|
||||
* a board, only the components that mirror shows are considered.
|
||||
*/
|
||||
private Map<IDIYComponent<?>, Set<Integer>> findControlPointsAt(Point2D point, IBoard mirrorBoard) {
|
||||
private Map<IDIYComponent<?>, Set<Integer>> findControlPointsAt(Point2D point,
|
||||
IBoard mirrorBoard) {
|
||||
Map<IDIYComponent<?>, Set<Integer>> components = new HashMap<IDIYComponent<?>, Set<Integer>>();
|
||||
// Go backwards so we take the highest z-order components first.
|
||||
for (int i = currentProject.getComponents().size() - 1; i >= 0; i--) {
|
||||
@@ -988,7 +991,8 @@ public class Presenter implements IPlugInPort {
|
||||
break;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.warn("Error reading control point for component of type: " + component.getClass().getName());
|
||||
LOG.warn("Error reading control point for component of type: "
|
||||
+ component.getClass().getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1023,11 +1027,12 @@ public class Presenter implements IPlugInPort {
|
||||
IBoard oldPlacementMirrorBoard = placementMirrorBoard;
|
||||
updatePlacementMirror(previousScaledPoint);
|
||||
// reflected before snapping, so that a component placed through a mirror lands on the grid
|
||||
Point2D placementPoint = toPlacementSpace(previousScaledPoint);
|
||||
Point2D placementPoint = UndersideMirror.reflect(placementMirrorBoard, previousScaledPoint);
|
||||
if (isSnapToGrid()) {
|
||||
CalcUtils.snapPointToGrid(placementPoint, currentProject.getGridSpacing());
|
||||
} else if (isSnapToObjects()) {
|
||||
CalcUtils.snapPointToObjects(placementPoint, currentProject.getGridSpacing(), null, currentProject.getComponents());
|
||||
CalcUtils.snapPointToObjects(placementPoint, currentProject.getGridSpacing(), null,
|
||||
currentProject.getComponents());
|
||||
}
|
||||
// What the cursor does is decided by how the slot was armed rather than by the creation
|
||||
// method: a slot instantiated up front carries a whole component that follows the cursor,
|
||||
@@ -1040,22 +1045,24 @@ public class Presenter implements IPlugInPort {
|
||||
currentProject.getGridSpacing());
|
||||
} else {
|
||||
refresh = instantiationManager.updatePointByPoint(
|
||||
constrainToAxis(instantiationManager.getFirstControlPoint(), placementPoint, shiftDown));
|
||||
constrainToAxis(instantiationManager.getFirstControlPoint(), placementPoint,
|
||||
shiftDown));
|
||||
}
|
||||
if (refresh || placementMirrorBoard != oldPlacementMirrorBoard) {
|
||||
messageDispatcher.dispatchMessage(EventType.REPAINT);
|
||||
}
|
||||
} else {
|
||||
components = findControlPointsAt(previousScaledPoint, null);
|
||||
hoverMirrorTx = null;
|
||||
for (IBoard board : UndersideMirror.findBoardsMirroredAt(currentProject, previousScaledPoint)) {
|
||||
hoverMirrorBoard = null;
|
||||
for (IBoard board :
|
||||
UndersideMirror.findBoardsMirroredAt(currentProject, previousScaledPoint)) {
|
||||
if (!components.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
AffineTransform mirrorTx = UndersideMirror.createTransform(board);
|
||||
components = findControlPointsAt(mirrorTx.transform(previousScaledPoint, null), board);
|
||||
components =
|
||||
findControlPointsAt(UndersideMirror.reflect(board, previousScaledPoint), board);
|
||||
if (!components.isEmpty()) {
|
||||
hoverMirrorTx = mirrorTx;
|
||||
hoverMirrorBoard = board;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1404,20 +1411,26 @@ public class Presenter implements IPlugInPort {
|
||||
this.dragAction = dragAction;
|
||||
this.preDragProject = currentProject.clone();
|
||||
Point2D scaledPoint = scalePoint(point);
|
||||
List<IDIYComponent<?>> components =
|
||||
forceSelectionRect ? null : findComponentsAtScaled(scaledPoint, false, false);
|
||||
if (controlPointMap != null && !controlPointMap.isEmpty()) {
|
||||
this.dragMirrorTx = hoverMirrorTx;
|
||||
} else if (forceSelectionRect || !findComponentsAtScaled(scaledPoint, false, false).isEmpty()) {
|
||||
this.dragMirrorTx = null;
|
||||
this.dragMirrorBoard = hoverMirrorBoard;
|
||||
} else if (components == null || !components.isEmpty()) {
|
||||
this.dragMirrorBoard = null;
|
||||
} else {
|
||||
this.dragMirrorTx = findMirrorWithComponentAt(scaledPoint);
|
||||
// the parts a click there would select, not whatever covers the reflected point
|
||||
this.dragMirrorBoard = findMirrorBoardWithComponentAt(scaledPoint);
|
||||
if (dragMirrorBoard != null) {
|
||||
components =
|
||||
drawingManager.findMirroredComponentsAt(scaledPoint, currentProject, dragMirrorBoard);
|
||||
removeUnselectable(components, false);
|
||||
}
|
||||
}
|
||||
scaledPoint = toDragSpace(scaledPoint);
|
||||
scaledPoint = UndersideMirror.reflect(dragMirrorBoard, scaledPoint);
|
||||
this.previousDragPoint = scaledPoint;
|
||||
this.dragStartPoint = new Point2D.Double(scaledPoint.getX(), scaledPoint.getY());
|
||||
this.dragShiftDown = shiftDown;
|
||||
this.lockedAxis = null;
|
||||
List<IDIYComponent<?>> components =
|
||||
forceSelectionRect ? null : findComponentsAtScaled(scaledPoint, false, false);
|
||||
if (controlPointMap != null && !this.controlPointMap.isEmpty()) {
|
||||
// If we're dragging control points reset selection.
|
||||
updateSelection(new ArrayList<IDIYComponent<?>>(this.controlPointMap.keySet()));
|
||||
@@ -1634,7 +1647,7 @@ public class Presenter implements IPlugInPort {
|
||||
|
||||
boolean resizeInProgress = false;
|
||||
|
||||
Point2D scaledPoint = toDragSpace(scalePoint(point));
|
||||
Point2D scaledPoint = UndersideMirror.reflect(dragMirrorBoard, scalePoint(point));
|
||||
if (controlPointMap != null && !controlPointMap.isEmpty()) {
|
||||
// We're dragging control point(s).
|
||||
Point2D targetPoint = constrainToAxis(dragStartPoint, scaledPoint, dragShiftDown);
|
||||
@@ -1671,7 +1684,8 @@ public class Presenter implements IPlugInPort {
|
||||
// a component dragged in from the component tree or the toolbox
|
||||
this.previousScaledPoint = scalePoint(point);
|
||||
updatePlacementMirror(previousScaledPoint);
|
||||
instantiationManager.updateSingleClick(toPlacementSpace(previousScaledPoint), isSnapToGrid(),
|
||||
instantiationManager.updateSingleClick(
|
||||
UndersideMirror.reflect(placementMirrorBoard, previousScaledPoint), isSnapToGrid(),
|
||||
currentProject.getGridSpacing());
|
||||
}
|
||||
|
||||
@@ -2055,7 +2069,7 @@ public class Presenter implements IPlugInPort {
|
||||
test.addStep(DIYTest.DRAG_END, params);
|
||||
}
|
||||
|
||||
Point2D scaledPoint = toDragSpace(scalePoint(point));
|
||||
Point2D scaledPoint = UndersideMirror.reflect(dragMirrorBoard, scalePoint(point));
|
||||
|
||||
if (!dragInProgress && instantiationManager.getComponentSlot() == null) {
|
||||
return;
|
||||
@@ -2110,7 +2124,7 @@ public class Presenter implements IPlugInPort {
|
||||
dragStartPoint = null;
|
||||
dragShiftDown = false;
|
||||
lockedAxis = null;
|
||||
dragMirrorTx = null;
|
||||
dragMirrorBoard = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -3210,11 +3224,6 @@ public class Presenter implements IPlugInPort {
|
||||
return p;
|
||||
}
|
||||
|
||||
private Point2D toDragSpace(Point2D scaledPoint) {
|
||||
return dragMirrorTx == null || scaledPoint == null ? scaledPoint
|
||||
: dragMirrorTx.transform(scaledPoint, null);
|
||||
}
|
||||
|
||||
// a component placed point by point stays in the mirror its first point went into
|
||||
private void updatePlacementMirror(Point2D scaledPoint) {
|
||||
if (instantiationManager.getFirstControlPoint() != null) {
|
||||
@@ -3224,24 +3233,17 @@ public class Presenter implements IPlugInPort {
|
||||
placementMirrorBoard = boards.isEmpty() ? null : boards.get(0);
|
||||
}
|
||||
|
||||
private Point2D toPlacementSpace(Point2D scaledPoint) {
|
||||
AffineTransform mirrorTx =
|
||||
placementMirrorBoard == null ? null : UndersideMirror.createTransform(placementMirrorBoard);
|
||||
return mirrorTx == null || scaledPoint == null ? scaledPoint
|
||||
: mirrorTx.transform(scaledPoint, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the reflection of the first underside mirror that shows a selectable component at the
|
||||
* specified point, or null
|
||||
* @return the topmost board whose underside mirror shows a selectable component at the specified
|
||||
* point, or null
|
||||
*/
|
||||
private AffineTransform findMirrorWithComponentAt(Point2D scaledPoint) {
|
||||
private IBoard findMirrorBoardWithComponentAt(Point2D scaledPoint) {
|
||||
for (IBoard board : UndersideMirror.findBoardsMirroredAt(currentProject, scaledPoint)) {
|
||||
List<IDIYComponent<?>> components =
|
||||
drawingManager.findMirroredComponentsAt(scaledPoint, currentProject, board);
|
||||
removeUnselectable(components, false);
|
||||
if (!components.isEmpty()) {
|
||||
return UndersideMirror.createTransform(board);
|
||||
return board;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -161,18 +161,28 @@ public class UndersideMirror {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the boards whose mirror contains the point, in z-order
|
||||
* @return the boards whose mirror contains the point, the topmost first, which is the one drawn
|
||||
* over the others where mirrors overlap
|
||||
*/
|
||||
public static List<IBoard> findBoardsMirroredAt(Project project, Point2D point) {
|
||||
List<IBoard> boards = new ArrayList<IBoard>();
|
||||
for (IBoard board : getMirroringBoards(project)) {
|
||||
if (getMirrorRegion(board).contains(point)) {
|
||||
boards.add(board);
|
||||
boards.add(0, board);
|
||||
}
|
||||
}
|
||||
return boards;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the point reflected through the board's mirror, or the point itself when the board is
|
||||
* null or shows no mirror
|
||||
*/
|
||||
public static Point2D reflect(IBoard board, Point2D point) {
|
||||
AffineTransform mirrorTx = board == null ? null : createTransform(board);
|
||||
return mirrorTx == null || point == null ? point : mirrorTx.transform(point, null);
|
||||
}
|
||||
|
||||
// the board rectangle may be stored with its corners in either order
|
||||
private static Rectangle2D getBoardBounds(IBoard board) {
|
||||
Rectangle2D rect = board.getBoardRectangle();
|
||||
|
||||
@@ -24,6 +24,7 @@ import org.diylc.appframework.simplemq.MessageDispatcher;
|
||||
import org.diylc.common.DrawOption;
|
||||
import org.diylc.common.EventType;
|
||||
import org.diylc.common.PCBLayer;
|
||||
import org.diylc.common.Percentage;
|
||||
import org.diylc.core.BoardUndersideDisplay;
|
||||
import org.diylc.core.ComponentState;
|
||||
import org.diylc.core.IBoard;
|
||||
@@ -687,8 +688,10 @@ public class DrawingManagerTest {
|
||||
@Test
|
||||
public void testBottomMountedPartFadedOnlyWithOption() {
|
||||
Project project = new Project();
|
||||
project.getComponents().add(new MountedComponent(new Rectangle2D.Double(150, 150, 10, 10), PCBLayer._2));
|
||||
project.getComponents().add(new MountedComponent(new Rectangle2D.Double(200, 200, 10, 10), PCBLayer._1));
|
||||
project.getComponents()
|
||||
.add(new MountedComponent(new Rectangle2D.Double(150, 150, 10, 10), PCBLayer._2));
|
||||
project.getComponents()
|
||||
.add(new MountedComponent(new Rectangle2D.Double(200, 200, 10, 10), PCBLayer._1));
|
||||
|
||||
BufferedImage faded = renderSides(project, EnumSet.of(DrawOption.ZOOM, DrawOption.FADE_FAR_SIDE));
|
||||
assertSolid(faded, 155, 155);
|
||||
@@ -701,7 +704,8 @@ public class DrawingManagerTest {
|
||||
@Test
|
||||
public void testCachedBottomMountedPartFaded() {
|
||||
Project project = new Project();
|
||||
project.getComponents().add(new MountedComponent(new Rectangle2D.Double(200, 200, 10, 10), PCBLayer._1));
|
||||
project.getComponents()
|
||||
.add(new MountedComponent(new Rectangle2D.Double(200, 200, 10, 10), PCBLayer._1));
|
||||
|
||||
BufferedImage img = renderSides(project,
|
||||
EnumSet.of(DrawOption.ZOOM, DrawOption.FADE_FAR_SIDE, DrawOption.ENABLE_CACHING));
|
||||
@@ -717,8 +721,10 @@ public class DrawingManagerTest {
|
||||
board.setUndersideOffset(new Size(20.0, SizeUnit.px));
|
||||
board.setUndersideTransparency(true);
|
||||
project.getComponents().add(board);
|
||||
project.getComponents().add(new MountedComponent(new Rectangle2D.Double(150, 150, 10, 10), PCBLayer._2));
|
||||
project.getComponents().add(new MountedComponent(new Rectangle2D.Double(200, 200, 10, 10), PCBLayer._1));
|
||||
project.getComponents()
|
||||
.add(new MountedComponent(new Rectangle2D.Double(150, 150, 10, 10), PCBLayer._2));
|
||||
project.getComponents()
|
||||
.add(new MountedComponent(new Rectangle2D.Double(200, 200, 10, 10), PCBLayer._1));
|
||||
|
||||
// reflection across y = 410 puts the top part at y 660..670 and the bottom one at 610..620
|
||||
BufferedImage img = renderSides(project, EnumSet.of(DrawOption.ZOOM, DrawOption.FADE_FAR_SIDE));
|
||||
@@ -726,10 +732,44 @@ public class DrawingManagerTest {
|
||||
assertSolid(img, 205, 615);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPartBeingPlacedInMirrorSeenFromBelow() {
|
||||
Percentage farSideAlpha = DrawingManager.FAR_SIDE_ALPHA;
|
||||
// below the 50% of a part being placed, so that a far-side fade would show
|
||||
DrawingManager.FAR_SIDE_ALPHA = new Percentage(20);
|
||||
try {
|
||||
Project project = new Project();
|
||||
MockBoard board = new MockBoard();
|
||||
board.setBoardRectangle(new Rectangle2D.Double(100, 100, 200, 300));
|
||||
board.setUndersideDisplay(BoardUndersideDisplay.BELOW);
|
||||
board.setUndersideOffset(new Size(20.0, SizeUnit.px));
|
||||
board.setUndersideTransparency(true);
|
||||
project.getComponents().add(board);
|
||||
// bottom copper, which the mirror shows as the near side
|
||||
SidePaintingComponent copper =
|
||||
new SidePaintingComponent(new Rectangle2D.Double(200, 200, 10, 10), PCBLayer._1);
|
||||
|
||||
DrawingManager drawingManager = createDrawingManager();
|
||||
drawingManager.setSlotMirrorBoard(board);
|
||||
BufferedImage img = new BufferedImage(1000, 1000, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D g2d = img.createGraphics();
|
||||
drawingManager.drawProject(g2d, project, EnumSet.of(DrawOption.ZOOM, DrawOption.FADE_FAR_SIDE),
|
||||
null, null, Collections.emptyList(), Collections.emptySet(), Collections.emptySet(),
|
||||
null, Collections.singletonList(copper), false, Collections.emptySet(), 1.0, 1.0, null);
|
||||
g2d.dispose();
|
||||
|
||||
// drawn at the 50% of a part being placed, not faded further; the square lands at 610..620
|
||||
assertFaded(img, 205, 615, 0.5f);
|
||||
} finally {
|
||||
DrawingManager.FAR_SIDE_ALPHA = farSideAlpha;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLockedBottomMountedPartNotFadedTwice() {
|
||||
Project project = new Project();
|
||||
MountedComponent bottom = new MountedComponent(new Rectangle2D.Double(200, 200, 10, 10), PCBLayer._1);
|
||||
MountedComponent bottom =
|
||||
new MountedComponent(new Rectangle2D.Double(200, 200, 10, 10), PCBLayer._1);
|
||||
project.getComponents().add(bottom);
|
||||
|
||||
DrawingManager drawingManager = createDrawingManager();
|
||||
@@ -1052,10 +1092,12 @@ public class DrawingManagerTest {
|
||||
|
||||
// paints an opaque black square, declared on the given side or, when null, left undeclared
|
||||
// paints an undeclared black square, like a part that leaves its side to the Board Side property
|
||||
@ComponentDescriptor(name = "Mounted", author = "test", category = "Test", instanceNamePrefix = "M",
|
||||
@ComponentDescriptor(name = "Mounted", author = "test", category = "Test",
|
||||
instanceNamePrefix = "M",
|
||||
description = "Part mounted on one side of the board", zOrder = IDIYComponent.COMPONENT,
|
||||
enableCache = true)
|
||||
public static class MountedComponent extends SidePaintingComponent implements IBoardSideComponent {
|
||||
public static class MountedComponent extends SidePaintingComponent
|
||||
implements IBoardSideComponent {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ import java.util.Arrays;
|
||||
|
||||
import org.diylc.common.PCBLayer;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.IPCBLayerComponent;
|
||||
import org.diylc.presenter.DrawingManagerTest.MountedComponent;
|
||||
import org.diylc.testcomponents.MockDIYComponent;
|
||||
import org.junit.Test;
|
||||
@@ -46,16 +47,18 @@ public class MirrorPlacementTest {
|
||||
assertEquals(PCBLayer._1, copper.getLayer());
|
||||
}
|
||||
|
||||
public static class LayeredComponent extends MockDIYComponent {
|
||||
public static class LayeredComponent extends MockDIYComponent implements IPCBLayerComponent {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private PCBLayer layer = PCBLayer._2;
|
||||
|
||||
@Override
|
||||
public PCBLayer getLayer() {
|
||||
return layer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLayer(PCBLayer layer) {
|
||||
this.layer = layer;
|
||||
}
|
||||
|
||||
@@ -71,7 +71,8 @@ public class UndersideMirrorTest {
|
||||
public void testMirrorRegionFollowsOffset() {
|
||||
MockBoard board = board(BoardUndersideDisplay.BELOW);
|
||||
board.setUndersideOffset(new Size(60.0, SizeUnit.px));
|
||||
assertEquals(new Rectangle2D.Double(100, 460, 200, 300), UndersideMirror.getMirrorRegion(board));
|
||||
assertEquals(new Rectangle2D.Double(100, 460, 200, 300),
|
||||
UndersideMirror.getMirrorRegion(board));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -111,7 +112,8 @@ public class UndersideMirrorTest {
|
||||
|
||||
assertEquals(Collections.singletonList(below),
|
||||
UndersideMirror.findBoardsMirroredAt(project, new Point2D.Double(150, 500)));
|
||||
assertTrue(UndersideMirror.findBoardsMirroredAt(project, new Point2D.Double(150, 300)).isEmpty());
|
||||
assertTrue(
|
||||
UndersideMirror.findBoardsMirroredAt(project, new Point2D.Double(150, 300)).isEmpty());
|
||||
}
|
||||
|
||||
private static MockBoard board(BoardUndersideDisplay display) {
|
||||
|
||||
+5
-1
@@ -36,6 +36,7 @@ import org.diylc.core.IConnective;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.IDrawingObserver;
|
||||
import org.diylc.core.ILayeredComponent;
|
||||
import org.diylc.core.IPCBLayerComponent;
|
||||
import org.diylc.core.Project;
|
||||
import org.diylc.core.VisibilityPolicy;
|
||||
import org.diylc.core.annotations.AiNote.Scope;
|
||||
@@ -58,7 +59,8 @@ import org.diylc.core.measures.SizeUnit;
|
||||
description = "Straight copper trace", zOrder = IDIYComponent.TRACE, bomPolicy = BomPolicy.NEVER_SHOW,
|
||||
keywordPolicy = KeywordPolicy.SHOW_TAG, keywordTag = "PCB",
|
||||
transformer = SimpleComponentTransformer.class)
|
||||
public class CopperTrace extends AbstractLeadedComponent<Void> implements IConnective, ILayeredComponent, IGerberComponentSimple {
|
||||
public class CopperTrace extends AbstractLeadedComponent<Void>
|
||||
implements IConnective, ILayeredComponent, IGerberComponentSimple, IPCBLayerComponent {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@@ -116,6 +118,7 @@ public class CopperTrace extends AbstractLeadedComponent<Void> implements IConne
|
||||
}
|
||||
|
||||
@EditableProperty
|
||||
@Override
|
||||
public PCBLayer getLayer() {
|
||||
if (layer == null) {
|
||||
layer = PCBLayer._1;
|
||||
@@ -123,6 +126,7 @@ public class CopperTrace extends AbstractLeadedComponent<Void> implements IConne
|
||||
return layer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLayer(PCBLayer layer) {
|
||||
this.layer = layer;
|
||||
}
|
||||
|
||||
+5
-1
@@ -38,6 +38,7 @@ import org.diylc.core.IConnective;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.IDrawingObserver;
|
||||
import org.diylc.core.ILayeredComponent;
|
||||
import org.diylc.core.IPCBLayerComponent;
|
||||
import org.diylc.core.annotations.AiNote.Scope;
|
||||
import org.diylc.core.annotations.AiNote;
|
||||
import org.diylc.core.annotations.BomPolicy;
|
||||
@@ -58,7 +59,8 @@ import org.diylc.core.measures.SizeUnit;
|
||||
zOrder = IDIYComponent.TRACE, bomPolicy = BomPolicy.NEVER_SHOW,
|
||||
keywordPolicy = KeywordPolicy.SHOW_TAG, keywordTag = "PCB", transformer = SimpleComponentTransformer.class,
|
||||
enableCache = true, creationMethod = CreationMethod.POINT_BY_POINT)
|
||||
public class CurvedTrace extends AbstractCurvedComponent<Void> implements IConnective, ILayeredComponent, IGerberComponentSimple {
|
||||
public class CurvedTrace extends AbstractCurvedComponent<Void>
|
||||
implements IConnective, ILayeredComponent, IGerberComponentSimple, IPCBLayerComponent {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@@ -104,6 +106,7 @@ public class CurvedTrace extends AbstractCurvedComponent<Void> implements IConne
|
||||
}
|
||||
|
||||
@EditableProperty
|
||||
@Override
|
||||
public PCBLayer getLayer() {
|
||||
if (layer == null) {
|
||||
layer = PCBLayer._1;
|
||||
@@ -111,6 +114,7 @@ public class CurvedTrace extends AbstractCurvedComponent<Void> implements IConne
|
||||
return layer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLayer(PCBLayer layer) {
|
||||
this.layer = layer;
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ import org.diylc.core.ComponentState;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.IDrawingObserver;
|
||||
import org.diylc.core.ILayeredComponent;
|
||||
import org.diylc.core.IPCBLayerComponent;
|
||||
import org.diylc.core.Project;
|
||||
import org.diylc.core.VisibilityPolicy;
|
||||
import org.diylc.core.annotations.BomPolicy;
|
||||
@@ -53,7 +54,7 @@ import org.diylc.core.measures.SizeUnit;
|
||||
instanceNamePrefix = "GF", description = "Polygonal ground fill area", zOrder = IDIYComponent.TRACE,
|
||||
bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false, transformer = SimpleComponentTransformer.class)
|
||||
public class GroundFill extends AbstractTransparentComponent<Void>
|
||||
implements ILayeredComponent, IGerberComponentSimple {
|
||||
implements ILayeredComponent, IGerberComponentSimple, IPCBLayerComponent {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@@ -152,6 +153,7 @@ public class GroundFill extends AbstractTransparentComponent<Void>
|
||||
}
|
||||
|
||||
@EditableProperty
|
||||
@Override
|
||||
public PCBLayer getLayer() {
|
||||
if (layer == null) {
|
||||
layer = PCBLayer._1;
|
||||
@@ -159,6 +161,7 @@ public class GroundFill extends AbstractTransparentComponent<Void>
|
||||
return layer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLayer(PCBLayer layer) {
|
||||
this.layer = layer;
|
||||
}
|
||||
|
||||
+2
-1
@@ -54,7 +54,8 @@ import org.diylc.utils.Constants;
|
||||
author = "Branislav Stojkovic", description = "Horizontal PCB terminal block with configurable pitch",
|
||||
zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "TB",
|
||||
enableCache = true, transformer = PCBTerminalBlockTransformer.class)
|
||||
public class PCBTerminalBlock extends AbstractTransparentComponent<PCBTerminalBlockCount> implements IGerberComponentSimple, IBoardSideComponent {
|
||||
public class PCBTerminalBlock extends AbstractTransparentComponent<PCBTerminalBlockCount>
|
||||
implements IGerberComponentSimple, IBoardSideComponent {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ import org.diylc.core.IConnective;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.IDrawingObserver;
|
||||
import org.diylc.core.ILayeredComponent;
|
||||
import org.diylc.core.IPCBLayerComponent;
|
||||
import org.diylc.core.Project;
|
||||
import org.diylc.core.VisibilityPolicy;
|
||||
import org.diylc.core.annotations.AiNote.Scope;
|
||||
@@ -60,7 +61,7 @@ import org.diylc.utils.Constants;
|
||||
keywordPolicy = KeywordPolicy.SHOW_TAG, keywordTag = "PCB",
|
||||
transformer = SimpleComponentTransformer.class, enableCache = true)
|
||||
public class SolderPad extends AbstractTransparentComponent<Void>
|
||||
implements IConnective, ILayeredComponent, IGerberComponentCustom {
|
||||
implements IConnective, ILayeredComponent, IGerberComponentCustom, IPCBLayerComponent {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@@ -190,6 +191,7 @@ public class SolderPad extends AbstractTransparentComponent<Void>
|
||||
}
|
||||
|
||||
@EditableProperty
|
||||
@Override
|
||||
public PCBLayer getLayer() {
|
||||
if (layer == null) {
|
||||
layer = PCBLayer._1;
|
||||
@@ -197,6 +199,7 @@ public class SolderPad extends AbstractTransparentComponent<Void>
|
||||
return layer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLayer(PCBLayer layer) {
|
||||
this.layer = layer;
|
||||
}
|
||||
|
||||
+2
-1
@@ -64,7 +64,8 @@ import org.diylc.utils.Constants;
|
||||
description = "Cliff-style closed panel mount 1/4\" phono jack",
|
||||
zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "J", transformer = CliffJackTransformer.class,
|
||||
enableCache = true)
|
||||
public class CliffJack1_4 extends AbstractMultiPartComponent<JackType> implements IGerberComponentSimple, IBoardSideComponent {
|
||||
public class CliffJack1_4 extends AbstractMultiPartComponent<JackType>
|
||||
implements IGerberComponentSimple, IBoardSideComponent {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
||||
+2
-1
@@ -58,7 +58,8 @@ import org.diylc.utils.Constants;
|
||||
author = "Branislav Stojkovic", description = "Cliff-style closed 1/8\" phono jack",
|
||||
zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "J",
|
||||
transformer = CliffJackTransformer.class, enableCache = true)
|
||||
public class CliffJack1_8 extends AbstractMultiPartComponent<JackType> implements IGerberComponentSimple, IBoardSideComponent {
|
||||
public class CliffJack1_8 extends AbstractMultiPartComponent<JackType>
|
||||
implements IGerberComponentSimple, IBoardSideComponent {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
||||
+2
-1
@@ -64,7 +64,8 @@ import org.diylc.utils.Constants;
|
||||
@ComponentDescriptor(name = "Closed 1/4\" Jack", category = "Electro-Mechanical", author = "Branislav Stojkovic",
|
||||
description = "Enclosed panel mount 1/4\" phono jack", zOrder = IDIYComponent.COMPONENT,
|
||||
instanceNamePrefix = "J", transformer = ClosedJackTransformer.class, enableCache = true)
|
||||
public class ClosedJack1_4 extends AbstractMultiPartComponent<JackType> implements IGerberComponentSimple, IBoardSideComponent {
|
||||
public class ClosedJack1_4 extends AbstractMultiPartComponent<JackType>
|
||||
implements IGerberComponentSimple, IBoardSideComponent {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
||||
+2
-1
@@ -60,7 +60,8 @@ import org.diylc.utils.Constants;
|
||||
@ComponentDescriptor(name = "Mini Relay", author = "Branislav Stojkovic", category = "Electro-Mechanical",
|
||||
instanceNamePrefix = "RY", description = "Miniature PCB mount relay, like Omron G5V-1/G5V-2 or Fujitsu FTR-B3",
|
||||
zOrder = IDIYComponent.COMPONENT, enableCache = true)
|
||||
public class MiniRelay extends AbstractLabeledComponent<String> implements IGerberComponentSimple, IBoardSideComponent {
|
||||
public class MiniRelay extends AbstractLabeledComponent<String>
|
||||
implements IGerberComponentSimple, IBoardSideComponent {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
||||
+2
-1
@@ -63,7 +63,8 @@ import org.diylc.utils.SwitchUtils;
|
||||
@ComponentDescriptor(name = "Mini Toggle Switch", category = "Electro-Mechanical", author = "Branislav Stojkovic",
|
||||
description = "Panel mounted mini toggle switch", zOrder = IDIYComponent.COMPONENT,
|
||||
instanceNamePrefix = "SW", enableCache = true, transformer = MiniToggleSwitchTransformer.class)
|
||||
public class MiniToggleSwitch extends AbstractTransparentComponent<ToggleSwitchType> implements ISwitch, ILayeredComponent, IGerberComponentSimple, IBoardSideComponent {
|
||||
public class MiniToggleSwitch extends AbstractTransparentComponent<ToggleSwitchType>
|
||||
implements ISwitch, ILayeredComponent, IGerberComponentSimple, IBoardSideComponent {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
||||
+2
-1
@@ -58,7 +58,8 @@ import org.diylc.utils.Constants;
|
||||
@ComponentDescriptor(name = "Plastic DC Jack", category = "Electro-Mechanical", author = "Branislav Stojkovic",
|
||||
description = "Panel mount plastic DC jack", zOrder = IDIYComponent.COMPONENT,
|
||||
instanceNamePrefix = "J", autoEdit = false, enableCache = true)
|
||||
public class PlasticDCJack extends AbstractMultiPartComponent<String> implements IGerberComponentSimple, IBoardSideComponent {
|
||||
public class PlasticDCJack extends AbstractMultiPartComponent<String>
|
||||
implements IGerberComponentSimple, IBoardSideComponent {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
||||
+2
-1
@@ -63,7 +63,8 @@ import org.diylc.utils.Constants;
|
||||
description = "Single pole rotary switch, typically used for impedance selector",
|
||||
zOrder = IDIYComponent.COMPONENT, transformer = PotentiometerTransformer.class,
|
||||
enableCache = true)
|
||||
public class RotarySelectorSwitch extends AbstractMultiPartComponent<String> implements IGerberComponentSimple, IBoardSideComponent {
|
||||
public class RotarySelectorSwitch extends AbstractMultiPartComponent<String>
|
||||
implements IGerberComponentSimple, IBoardSideComponent {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
||||
+2
-1
@@ -62,7 +62,8 @@ import org.diylc.utils.Constants;
|
||||
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<RotarySwitchSealedType> implements ISwitch, IGerberComponentSimple, IBoardSideComponent {
|
||||
public class RotarySwitchSealed extends AbstractAngledComponent<RotarySwitchSealedType>
|
||||
implements ISwitch, IGerberComponentSimple, IBoardSideComponent {
|
||||
|
||||
private static final int OUTER_ANGLE_OFFSET = 15;
|
||||
private static final int INNER_ANGLE_OFFSET = 30;
|
||||
|
||||
+2
-1
@@ -62,7 +62,8 @@ import org.diylc.utils.SwitchUtils;
|
||||
author = "Branislav Stojkovic", description = "Panel mounted slide switch",
|
||||
zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "SW",
|
||||
enableCache = true, transformer = MiniToggleSwitchTransformer.class)
|
||||
public class SlideSwitch extends AbstractTransparentComponent<SlideSwitchType> implements ISwitch, IGerberComponentSimple, IBoardSideComponent {
|
||||
public class SlideSwitch extends AbstractTransparentComponent<SlideSwitchType>
|
||||
implements ISwitch, IGerberComponentSimple, IBoardSideComponent {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ import org.diylc.core.ComponentState;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.IDrawingObserver;
|
||||
import org.diylc.core.ILayeredComponent;
|
||||
import org.diylc.core.IPCBLayerComponent;
|
||||
import org.diylc.core.Project;
|
||||
import org.diylc.core.VisibilityPolicy;
|
||||
import org.diylc.core.annotations.BomPolicy;
|
||||
@@ -53,7 +54,8 @@ import org.diylc.core.gerber.IGerberDrawingObserver;
|
||||
@ComponentDescriptor(name = "PCB Text", author = "Branislav Stojkovic", category = "Misc",
|
||||
description = "Mirrored text for PCB artwork", instanceNamePrefix = "L", zOrder = IDIYComponent.TRACE,
|
||||
flexibleZOrder = false, bomPolicy = BomPolicy.NEVER_SHOW, transformer = TextTransformer.class)
|
||||
public class PCBText extends AbstractComponent<Void> implements ILayeredComponent, IGerberComponentCustom {
|
||||
public class PCBText extends AbstractComponent<Void>
|
||||
implements ILayeredComponent, IGerberComponentCustom, IPCBLayerComponent {
|
||||
|
||||
public static String DEFAULT_TEXT = "Double click to edit text";
|
||||
|
||||
@@ -324,6 +326,7 @@ public class PCBText extends AbstractComponent<Void> implements ILayeredComponen
|
||||
}
|
||||
|
||||
@EditableProperty
|
||||
@Override
|
||||
public PCBLayer getLayer() {
|
||||
if (layer == null) {
|
||||
layer = PCBLayer._1;
|
||||
@@ -331,6 +334,7 @@ public class PCBText extends AbstractComponent<Void> implements ILayeredComponen
|
||||
return layer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLayer(PCBLayer layer) {
|
||||
this.layer = layer;
|
||||
}
|
||||
|
||||
+2
-1
@@ -36,7 +36,8 @@ import org.diylc.core.measures.Size;
|
||||
import org.diylc.core.measures.SizeUnit;
|
||||
import org.diylc.utils.Constants;
|
||||
|
||||
public abstract class AbstractFilmCapacitor extends AbstractLeadedComponent<Capacitance> implements IGerberComponentSimple, IBoardSideComponent {
|
||||
public abstract class AbstractFilmCapacitor extends AbstractLeadedComponent<Capacitance>
|
||||
implements IGerberComponentSimple, IBoardSideComponent {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
||||
+2
-1
@@ -33,7 +33,8 @@ import org.diylc.core.annotations.PositiveMeasureValidator;
|
||||
import org.diylc.core.gerber.IGerberComponentSimple;
|
||||
import org.diylc.core.measures.Resistance;
|
||||
|
||||
public abstract class AbstractPotentiometer extends AbstractLabeledComponent<Resistance> implements IGerberComponentSimple, IBoardSideComponent {
|
||||
public abstract class AbstractPotentiometer extends AbstractLabeledComponent<Resistance>
|
||||
implements IGerberComponentSimple, IBoardSideComponent {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
||||
+2
-1
@@ -41,7 +41,8 @@ import org.diylc.core.measures.SizeUnit;
|
||||
* @param <T>
|
||||
*/
|
||||
@AiNote("The two control points are the holes; the body's own leads are 'Lead Spacing' apart and centred between them, with lead wire drawn out to each hole. Place the points exactly 'Lead Spacing' apart for straight leads")
|
||||
public abstract class AbstractRadialComponent<T> extends AbstractLeadedComponent<T> implements IGerberComponentSimple, IBoardSideComponent {
|
||||
public abstract class AbstractRadialComponent<T> extends AbstractLeadedComponent<T>
|
||||
implements IGerberComponentSimple, IBoardSideComponent {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
||||
+2
-1
@@ -64,7 +64,8 @@ import org.diylc.utils.Constants;
|
||||
@ComponentDescriptor(name = "Mini Signal Transformer", author = "Branislav Stojkovic", category = "Passive",
|
||||
instanceNamePrefix = "TR", description = "Miniature PCB-mount signal transformer with EI core",
|
||||
zOrder = IDIYComponent.COMPONENT, keywordPolicy = KeywordPolicy.SHOW_VALUE)
|
||||
public class AudioTransformer extends AbstractMultiPartComponent<String> implements IGerberComponentSimple, IBoardSideComponent {
|
||||
public class AudioTransformer extends AbstractMultiPartComponent<String>
|
||||
implements IGerberComponentSimple, IBoardSideComponent {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
||||
+2
-1
@@ -55,7 +55,8 @@ import org.diylc.utils.Constants;
|
||||
description = "Axial electrolytic capacitor, similar to Sprague Atom, F&T, etc",
|
||||
zOrder = IDIYComponent.COMPONENT, transformer = SimpleComponentTransformer.class,
|
||||
enableCache = true, enableDatasheet = true, datasheetCreationStepCount = 3)
|
||||
public class AxialElectrolyticCapacitor extends AbstractLeadedComponent<Capacitance> implements IDatasheetSupport, IGerberComponentSimple, IBoardSideComponent {
|
||||
public class AxialElectrolyticCapacitor extends AbstractLeadedComponent<Capacitance>
|
||||
implements IDatasheetSupport, IGerberComponentSimple, IBoardSideComponent {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
||||
+2
-1
@@ -45,7 +45,8 @@ import org.diylc.core.measures.SizeUnit;
|
||||
creationMethod = CreationMethod.POINT_BY_POINT, instanceNamePrefix = "X",
|
||||
description = "Radial crystal oscillator", zOrder = IDIYComponent.COMPONENT,
|
||||
transformer = SimpleComponentTransformer.class)
|
||||
public class CrystalOscillator extends AbstractLeadedComponent<Frequency> implements IGerberComponentSimple, IBoardSideComponent {
|
||||
public class CrystalOscillator extends AbstractLeadedComponent<Frequency>
|
||||
implements IGerberComponentSimple, IBoardSideComponent {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
||||
+2
-1
@@ -65,7 +65,8 @@ import org.diylc.utils.Constants;
|
||||
@ComponentDescriptor(name = "Multi-Section Capacitor", author = "Branislav Stojkovic", category = "Passive",
|
||||
instanceNamePrefix = "C", description = "Multi-section vertically mounted electrolytic capacitor, similar to JJ, CE and others",
|
||||
zOrder = IDIYComponent.COMPONENT, keywordPolicy = KeywordPolicy.SHOW_VALUE, enableCache = true)
|
||||
public class MultiSectionCapacitor extends AbstractLabeledComponent<Capacitance[]> implements IGerberComponentSimple, IBoardSideComponent {
|
||||
public class MultiSectionCapacitor extends AbstractLabeledComponent<Capacitance[]>
|
||||
implements IGerberComponentSimple, IBoardSideComponent {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
||||
+2
-1
@@ -47,7 +47,8 @@ import org.diylc.core.measures.SizeUnit;
|
||||
creationMethod = CreationMethod.POINT_BY_POINT, instanceNamePrefix = "L",
|
||||
description = "Ferrite core toroidal inductor mounted vertically", zOrder = IDIYComponent.COMPONENT,
|
||||
transformer = SimpleComponentTransformer.class)
|
||||
public class ToroidalInductor extends AbstractLeadedComponent<Inductance> implements IGerberComponentSimple, IBoardSideComponent {
|
||||
public class ToroidalInductor extends AbstractLeadedComponent<Inductance>
|
||||
implements IGerberComponentSimple, IBoardSideComponent {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
||||
+2
-1
@@ -59,7 +59,8 @@ import org.diylc.utils.Constants;
|
||||
category = "Semiconductors", instanceNamePrefix = "BR",
|
||||
description = "Few variations of bridge rectifier chips", zOrder = IDIYComponent.COMPONENT,
|
||||
keywordPolicy = KeywordPolicy.SHOW_VALUE, enableCache = true)
|
||||
public class BridgeRectifier extends AbstractLabeledComponent<String> implements IGerberComponentSimple, IBoardSideComponent {
|
||||
public class BridgeRectifier extends AbstractLabeledComponent<String>
|
||||
implements IGerberComponentSimple, IBoardSideComponent {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
||||
@@ -51,7 +51,8 @@ import org.diylc.core.measures.Size;
|
||||
import org.diylc.core.measures.SizeUnit;
|
||||
import org.diylc.utils.Constants;
|
||||
|
||||
public abstract class PassiveSMDComponent<T> extends AbstractLabeledComponent<T> implements IGerberComponentSimple, IBoardSideComponent {
|
||||
public abstract class PassiveSMDComponent<T> extends AbstractLabeledComponent<T>
|
||||
implements IGerberComponentSimple, IBoardSideComponent {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
||||
+4
-3
@@ -24,7 +24,7 @@ package org.diylc.swing.plugins.file;
|
||||
import org.diylc.common.DrawOption;
|
||||
import org.diylc.common.IPlugInPort;
|
||||
import org.diylc.common.PCBLayer;
|
||||
import org.diylc.core.IBoardSideComponent;
|
||||
import org.diylc.core.IBoard;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.filter.PCBLayerFilter;
|
||||
import org.diylc.filter.SilkScreenFilter;
|
||||
@@ -59,11 +59,12 @@ public class SilkScreenDrawingProvider implements IDrawingProvider {
|
||||
new SilkScreenFilter(page == 0 ? PCBLayer._2 : PCBLayer._1), zoomFactor, null, null);
|
||||
}
|
||||
|
||||
// the top side, followed by the bottom side when a part is mounted there
|
||||
// the top side, followed by the bottom side when it has silkscreen other than board outlines
|
||||
@Override
|
||||
public int getPageCount() {
|
||||
SilkScreenFilter bottom = new SilkScreenFilter(PCBLayer._1);
|
||||
for (IDIYComponent<?> c : plugInPort.getCurrentProject().getComponents()) {
|
||||
if (c instanceof IBoardSideComponent && ((IBoardSideComponent) c).getBoardSide() == PCBLayer._1) {
|
||||
if (!(c instanceof IBoard) && bottom.testComponent(c)) {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
+3
-7
@@ -24,7 +24,6 @@ package org.diylc.swing.plugins.file;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
@@ -37,6 +36,7 @@ import org.diylc.common.DrawOption;
|
||||
import org.diylc.common.IPlugInPort;
|
||||
import org.diylc.common.PCBLayer;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.IPCBLayerComponent;
|
||||
import org.diylc.filter.PCBLayerFilter;
|
||||
|
||||
/**
|
||||
@@ -72,12 +72,8 @@ public class TraceMaskDrawingProvider implements IDrawingProvider {
|
||||
private PCBLayer[] getUsedLayers() {
|
||||
Set<PCBLayer> layers = EnumSet.noneOf(PCBLayer.class);
|
||||
for (IDIYComponent<?> c : plugInPort.getCurrentProject().getComponents()) {
|
||||
Class<?> clazz = c.getClass();
|
||||
try {
|
||||
Method m = clazz.getMethod("getLayer");
|
||||
PCBLayer l = (PCBLayer) m.invoke(c);
|
||||
layers.add(l);
|
||||
} catch (Exception e) {
|
||||
if (c instanceof IPCBLayerComponent copper) {
|
||||
layers.add(copper.getLayer());
|
||||
}
|
||||
}
|
||||
List<PCBLayer> sorted = new ArrayList<PCBLayer>(layers);
|
||||
|
||||
@@ -27,6 +27,7 @@ import org.diylc.common.IPlugInPort;
|
||||
import org.diylc.common.PCBLayer;
|
||||
import org.diylc.components.boards.BlankBoard;
|
||||
import org.diylc.components.chassis.ChassisPanel;
|
||||
import org.diylc.components.connectivity.Jumper;
|
||||
import org.diylc.components.passive.Resistor;
|
||||
import org.diylc.components.composite.CompositeComponent;
|
||||
import org.diylc.core.BoardUndersideDisplay;
|
||||
@@ -296,7 +297,8 @@ public class PresenterTests extends TestBase {
|
||||
instantiateTwoClick("Passive", "Resistor", new Point(1000, 1000), new Point(1200, 1000));
|
||||
IDIYComponent<?> resistor = presenter.getCurrentProject().getComponents().get(0);
|
||||
IBoard board = boardUnder(resistor);
|
||||
Point2D start = new Point2D.Double(resistor.getControlPoint(1).getX(), resistor.getControlPoint(1).getY());
|
||||
Point2D start = new Point2D.Double(resistor.getControlPoint(1).getX(),
|
||||
resistor.getControlPoint(1).getY());
|
||||
Point inMirror = toScreen(UndersideMirror.createTransform(board).transform(start, null));
|
||||
|
||||
presenter.mouseMoved(inMirror, false, false, false);
|
||||
@@ -314,8 +316,10 @@ public class PresenterTests extends TestBase {
|
||||
instantiateTwoClick("Passive", "Resistor", new Point(1000, 1000), new Point(1200, 1000));
|
||||
IDIYComponent<?> resistor = presenter.getCurrentProject().getComponents().get(0);
|
||||
IBoard board = boardUnder(resistor);
|
||||
Point2D start0 = new Point2D.Double(resistor.getControlPoint(0).getX(), resistor.getControlPoint(0).getY());
|
||||
Point2D start1 = new Point2D.Double(resistor.getControlPoint(1).getX(), resistor.getControlPoint(1).getY());
|
||||
Point2D start0 = new Point2D.Double(resistor.getControlPoint(0).getX(),
|
||||
resistor.getControlPoint(0).getY());
|
||||
Point2D start1 = new Point2D.Double(resistor.getControlPoint(1).getX(),
|
||||
resistor.getControlPoint(1).getY());
|
||||
// the hit test reads the areas recorded while drawing
|
||||
BufferedImage img = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D g2d = img.createGraphics();
|
||||
@@ -399,6 +403,39 @@ public class PresenterTests extends TestBase {
|
||||
|
||||
// a board reaching 200px past the component on every side, with its underside mirror below it;
|
||||
// the component stays selected
|
||||
@Test
|
||||
public void testDragThroughUndersideMirrorIgnoresPartsTheMirrorDoesNotShow() {
|
||||
instantiateTwoClick("Passive", "Resistor", new Point(1000, 1000), new Point(1200, 1000));
|
||||
IDIYComponent<?> resistor = presenter.getCurrentProject().getComponents().get(0);
|
||||
IBoard board = boardUnder(resistor);
|
||||
// a jumper drawn over the resistor with both ends off the board, so the mirror does not show it
|
||||
double y = resistor.getControlPoint(0).getY();
|
||||
Jumper jumper = new Jumper();
|
||||
jumper.setControlPoint(new Point2D.Double(board.getBoardRectangle().getMinX() - 100, y), 0);
|
||||
jumper.setControlPoint(new Point2D.Double(board.getBoardRectangle().getMaxX() + 100, y), 1);
|
||||
presenter.getCurrentProject().getComponents().add(jumper);
|
||||
Point2D jumperStart =
|
||||
new Point2D.Double(jumper.getControlPoint(0).getX(), jumper.getControlPoint(0).getY());
|
||||
Point2D resistorStart =
|
||||
new Point2D.Double(resistor.getControlPoint(0).getX(), resistor.getControlPoint(0).getY());
|
||||
BufferedImage img = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D g2d = img.createGraphics();
|
||||
presenter.draw(g2d, EnumSet.of(DrawOption.ZOOM), null, null, null, null);
|
||||
g2d.dispose();
|
||||
Point2D middle = new Point2D.Double(
|
||||
(resistor.getControlPoint(0).getX() + resistor.getControlPoint(1).getX()) / 2,
|
||||
resistor.getControlPoint(0).getY());
|
||||
Point inMirror = toScreen(UndersideMirror.createTransform(board).transform(middle, null));
|
||||
|
||||
presenter.mouseMoved(inMirror, false, false, false);
|
||||
presenter.dragStarted(inMirror, java.awt.dnd.DnDConstants.ACTION_MOVE, false, false);
|
||||
presenter.dragOver(new Point(inMirror.x + 100, inMirror.y + 100));
|
||||
presenter.dragEnded(new Point(inMirror.x + 100, inMirror.y + 100));
|
||||
|
||||
Assert.assertTrue(resistor.getControlPoint(0).getX() > resistorStart.getX());
|
||||
Assert.assertEquals(jumperStart, jumper.getControlPoint(0));
|
||||
}
|
||||
|
||||
private IBoard boardUnder(IDIYComponent<?> component) {
|
||||
Point2D first = component.getControlPoint(0);
|
||||
Point2D last = component.getControlPoint(component.getControlPointCount() - 1);
|
||||
|
||||
+11
@@ -27,6 +27,7 @@ import java.awt.Point;
|
||||
|
||||
import org.diylc.TestBase;
|
||||
import org.diylc.common.PCBLayer;
|
||||
import org.diylc.components.connectivity.Dot;
|
||||
import org.diylc.components.passive.Resistor;
|
||||
import org.junit.Test;
|
||||
|
||||
@@ -47,4 +48,14 @@ public class SilkScreenDrawingProviderTest extends TestBase {
|
||||
|
||||
assertEquals(2, new SilkScreenDrawingProvider(presenter).getPageCount());
|
||||
}
|
||||
|
||||
// a dot has no silkscreen, so a bottom page would show nothing but the board outline
|
||||
@Test
|
||||
public void testNoBottomPageForBottomDot() {
|
||||
Dot dot = new Dot();
|
||||
dot.setBoardSide(PCBLayer._1);
|
||||
presenter.getCurrentProject().getComponents().add(dot);
|
||||
|
||||
assertEquals(1, new SilkScreenDrawingProvider(presenter).getPageCount());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,11 @@ projects; the open questions below remain.
|
||||
default (resistors, film and radial capacitors, diodes, LEDs, transistor packages, DIL/SIL ICs,
|
||||
SMD passives, switches, jacks, relays, transformers, tube sockets, ...). None of them emit copper.
|
||||
Their pads are separate `SolderPad` components, which already have a layer.
|
||||
- `IBoardSideComponent.sideOf(component)` is the one place that answers which side a component is
|
||||
on (Top for components without a side); drawing, the Gerber export and the silkscreen filter all
|
||||
use it. Copper that sits on a layer - `CopperTrace`, `CurvedTrace`, `GroundFill`, `SolderPad` and
|
||||
`PCBText` - implements `IPCBLayerComponent` (`getLayer`/`setLayer`), which `PCBLayerFilter`, the
|
||||
trace-mask print-out and `MirrorPlacement` use instead of looking the methods up by name.
|
||||
- One method decides the layer for a simple component: `GerberExporter.drawComponent`. It is
|
||||
package-private so that `GerberExporterTest` can call it. It uses `getGerberLayer()`, flipped
|
||||
with `GerberLayer.flip()` when the component is an `IBoardSideComponent` on `_1` (Bottom).
|
||||
@@ -55,7 +60,7 @@ projects; the open questions below remain.
|
||||
- **Canvas rendering (done)**: bottom-side parts use the far-side fade from `copper-side-view.md`,
|
||||
set centrally rather than in each component. Wherever a component is drawn - the main loop in
|
||||
`DrawingManager`, `DrawingCache` rendering an image, and the Underside Display mirror - the
|
||||
wrapper's undeclared side is set to `DrawingManager.getMountedSide(component)` with
|
||||
wrapper's undeclared side is set to `IBoardSideComponent.sideOf(component)` with
|
||||
`G2DWrapper.setUndeclaredSide`. A bottom part is therefore faded in the main view (with Fade
|
||||
Copper Under Board on) and solid in the mirror, the same as bottom copper. In the main loop the
|
||||
side is set after the locked composite, which is set on the canvas directly and would otherwise
|
||||
@@ -89,7 +94,8 @@ projects; the open questions below remain.
|
||||
### diylc-swing
|
||||
|
||||
- **PCB print-outs (done)**: `SilkScreenDrawingProvider` prints the top side, and a second page for
|
||||
the bottom when a part is mounted there, so a project without bottom parts still prints one page.
|
||||
the bottom when the bottom has silkscreen other than board outlines, so a project without bottom
|
||||
parts, or with only a bottom `Dot`, still prints one page.
|
||||
`SilkScreenFilter` takes the side: a part with a Board Side goes on its own side's page, parts
|
||||
without one count as top, and board outlines go on both pages so that they line up. Neither
|
||||
page is mirrored or captioned, the same as the trace-mask pages.
|
||||
@@ -114,22 +120,24 @@ order.
|
||||
delete, copy and the popup menu all work unchanged. Selection highlighting and the selected
|
||||
control points are drawn on both copies.
|
||||
- **Stage 2: dragging in the mirror (done).** A drag that starts on a part in a mirror, or on a
|
||||
control point of a selected part there, keeps that mirror's reflection in
|
||||
`Presenter.dragMirrorTx` and reflects every mouse point of the drag before it reaches the existing
|
||||
drag code. Movement along the mirrored axis is therefore reversed, which is what the user sees,
|
||||
control point of a selected part there, keeps that mirror's board in `Presenter.dragMirrorBoard`
|
||||
and reflects every mouse point of the drag through it (`UndersideMirror.reflect`) before it
|
||||
reaches the existing drag code. The part it picks is one the mirror shows, the same one a click
|
||||
there selects, even where something else covers the reflected point on the board. Movement along the mirrored axis is therefore reversed, which is what the user sees,
|
||||
and snapping and the shift axis lock apply to the reflected point. Control-point hover
|
||||
(`Presenter.findControlPointsAt`) and the hand cursor look through the mirror when the main view
|
||||
has nothing. A drag that starts on empty mirror space still draws a selection rectangle in
|
||||
screen space. Moving the board, or changing its Underside Offset, cancels nothing; the mirror
|
||||
has nothing. Where mirrors overlap, the topmost board's wins, here and for placing. A drag that
|
||||
starts on empty mirror space still draws a selection rectangle in screen space. Moving the board, or changing its Underside Offset, cancels nothing; the mirror
|
||||
simply follows.
|
||||
- **Stage 3: placing in the mirror (done).** While a component is being placed,
|
||||
`Presenter.placementMirrorBoard` holds the board whose mirror the cursor is in; a single-click
|
||||
part follows the cursor in and out of mirrors, and a part placed point by point stays in the
|
||||
mirror its first point went into. The cursor is reflected before it is snapped to the grid, so
|
||||
the part lands on the grid, and `DrawingManager.setSlotMirrorBoard` draws the part being placed
|
||||
through that mirror, under the cursor. On placement, `MirrorPlacement.placeOnBottom` sets an
|
||||
`IBoardSideComponent` to `_1` (Bottom) and a component with a `PCBLayer` (`setLayer`, found the
|
||||
same way `PCBLayerFilter` reads `getLayer`) to `_1`; nothing is mirrored. Anything else, such as
|
||||
through that mirror, under the cursor, seen from below like the parts already there. The board is
|
||||
forgotten when a project is loaded. On placement, `MirrorPlacement.placeOnBottom` sets an
|
||||
`IBoardSideComponent` to `_1` (Bottom) and an `IPCBLayerComponent` to layer `_1`; nothing is
|
||||
mirrored. Anything else, such as
|
||||
a jumper, eyelet or wire, is placed at the reflected point unchanged. A part dragged in from
|
||||
the component tree or the toolbox goes through `Presenter.dragOver` and `dragEnded` instead,
|
||||
which pick the mirror and put the part on the bottom the same way.
|
||||
@@ -152,8 +160,13 @@ order.
|
||||
`PresenterTests.testPlaceThroughUndersideMirror` and `testPlaceUnsidedPartThroughUndersideMirror`
|
||||
place a resistor and an eyelet in a mirror and check that they land on the board, the resistor on
|
||||
the bottom; `testDropFromComponentTreeIntoUndersideMirror` does the same for a drag and drop.
|
||||
`testDragThroughUndersideMirrorIgnoresPartsTheMirrorDoesNotShow` drags a resistor in the mirror
|
||||
under a jumper that only crosses the board, and `DrawingManagerTest`
|
||||
`.testPartBeingPlacedInMirrorSeenFromBelow` checks that the part being placed is drawn as the
|
||||
mirror draws placed parts.
|
||||
- `SilkScreenFilterTest` covers which side's page each part and board outline goes on, and
|
||||
`SilkScreenDrawingProviderTest` checks that the bottom page appears only for a bottom part.
|
||||
`SilkScreenDrawingProviderTest` checks that the bottom page appears only for a bottom part with
|
||||
silkscreen, not for a bottom `Dot`.
|
||||
- `DrawingManagerTest` checks rendered pixels for a part that reports its own side: a bottom part
|
||||
is faded only with `FADE_FAR_SIDE`, also when drawn from the image cache; it is solid in the
|
||||
mirror, where a top part is faded; and a locked bottom part is faded once, not twice.
|
||||
|
||||
Reference in New Issue
Block a user