This commit is contained in:
Branislav Stojkovic
2025-03-10 13:03:51 +01:00
parent ad9a575dc6
commit f820c23093
2148 changed files with 11547 additions and 48 deletions
@@ -0,0 +1,94 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.announcements;
import java.io.Serializable;
public class Announcement implements Serializable {
private static final long serialVersionUID = 1L;
private String title;
private String text;
private String date;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((date == null) ? 0 : date.hashCode());
result = prime * result + ((text == null) ? 0 : text.hashCode());
result = prime * result + ((title == null) ? 0 : title.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Announcement other = (Announcement) obj;
if (date == null) {
if (other.date != null)
return false;
} else if (!date.equals(other.date))
return false;
if (text == null) {
if (other.text != null)
return false;
} else if (!text.equals(other.text))
return false;
if (title == null) {
if (other.title != null)
return false;
} else if (!title.equals(other.title))
return false;
return true;
}
}
@@ -0,0 +1,94 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.announcements;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import org.diylc.appframework.miscutils.ConfigurationManager;
import org.diylc.plugins.cloud.model.IServiceAPI;
import com.diyfever.httpproxy.PhpFlatProxy;
import com.diyfever.httpproxy.ProxyFactory;
public class AnnouncementProvider {
private String serviceUrl = "http://www.diy-fever.com/diylc/api/v1/announcements.html";
private String LAST_READ_KEY = "announcement.lastReadDate";
private String USER_ID_KEY = "userId";
private IAnnouncementService service;
private Date lastDate;
private List<Announcement> announcements;
private DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
public AnnouncementProvider() {
String lastDateStr = ConfigurationManager.getInstance().readString(LAST_READ_KEY, null);
try {
this.lastDate = lastDateStr == null ? null : dateFormat.parse(lastDateStr);
} catch (ParseException e) {
}
serviceUrl =
ConfigurationManager.getInstance().readString(IServiceAPI.URL_KEY, "http://www.diy-fever.com/diylc/api/v1");
ProxyFactory factory = new ProxyFactory(new PhpFlatProxy());
service = factory.createProxy(IAnnouncementService.class, serviceUrl);
}
private String getUserId() {
String userId = ConfigurationManager.getInstance().readString(USER_ID_KEY, null);
if (userId == null) {
userId = UUID.randomUUID().toString();
ConfigurationManager.getInstance().writeValue(USER_ID_KEY, userId);
}
return userId;
}
public String getCurrentAnnouncements(boolean forceLast) throws ParseException {
announcements = service.getAnnouncements(getUserId());
if (announcements == null)
return null;
boolean hasUnread = false;
StringBuilder sb = new StringBuilder("<html>");
for (int i = 0; i < announcements.size(); i++) {
Date date = dateFormat.parse(announcements.get(i).getDate());
if (lastDate == null || lastDate.before(date) || lastDate.equals(date) || (forceLast && i == announcements.size() - 1)) {
sb.append("<font size='4'><b>").append(announcements.get(i).getTitle()).append("</b> on ")
.append(announcements.get(i).getDate()).append("</font>").append("<p>")
.append(announcements.get(i).getText()).append("</p>");
hasUnread = true;
}
}
if (!hasUnread)
return "";
sb.append("</html>");
return sb.toString();
}
public void dismissed() {
Date date = new Date();
ConfigurationManager.getInstance().writeValue(LAST_READ_KEY, dateFormat.format(date));
}
}
@@ -0,0 +1,30 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.announcements;
import java.util.List;
import com.diyfever.httpproxy.ParamName;
public interface IAnnouncementService {
public List<Announcement> getAnnouncements(@ParamName("userId")String userId);
}
@@ -0,0 +1,89 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;
import java.io.Serializable;
import java.util.List;
import java.util.Set;
import org.diylc.core.IDIYComponent;
/**
* Represents component selection as a {@link List} of {@link IDIYComponent} objects. Implements
* {@link Transferable}, so it is suitable for clipboard usage.
*
* @author Branislav Stojkovic
*/
public class ComponentTransferable implements Transferable, Serializable {
private static final long serialVersionUID = 1L;
public static final DataFlavor listFlavor = new DataFlavor(ComponentTransferable.class, "application/diylc");
private List<IDIYComponent<?>> components;
private Set<Set<IDIYComponent<?>>> groups;
public ComponentTransferable() {
super();
}
public ComponentTransferable(List<IDIYComponent<?>> components) {
super();
this.components = components;
this.groups = null;
}
public ComponentTransferable(List<IDIYComponent<?>> components, Set<Set<IDIYComponent<?>>> groups) {
super();
this.components = components;
this.groups = groups;
}
@Override
public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
if (flavor.equals(listFlavor)) {
return this;
}
throw new UnsupportedFlavorException(flavor);
}
@Override
public DataFlavor[] getTransferDataFlavors() {
return new DataFlavor[] {listFlavor};
}
@Override
public boolean isDataFlavorSupported(DataFlavor flavor) {
return flavor.equals(listFlavor);
}
public List<IDIYComponent<?>> getComponents() {
return components;
}
public Set<Set<IDIYComponent<?>>> getGroups() {
return groups;
}
}
@@ -0,0 +1,75 @@
/*
*
* DIY Layout Creator (DIYLC). Copyright (c) 2009-2018 held jointly by the individual authors.
*
* This file is part of DIYLC.
*
* DIYLC is free software: you can redistribute it and/or modify it under the terms of the GNU
* General Public License as published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* DIYLC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with DIYLC. If not, see
* <http://www.gnu.org/licenses/>.
*/
package org.diylc.clipboard;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.log4j.Logger;
import org.diylc.core.IDIYComponent;
public class ComponentTransferableFactory {
private static final Logger LOG = Logger.getLogger(ComponentTransferableFactory.class);
private static ComponentTransferableFactory instance;
public static ComponentTransferableFactory getInstance() {
if (instance == null)
instance = new ComponentTransferableFactory();
return instance;
}
public ComponentTransferable build(Collection<IDIYComponent<?>> selectedComponents, Set<Set<IDIYComponent<?>>> groups) {
Set<IDIYComponent<?>> originalComponentSet = new HashSet<IDIYComponent<?>>(selectedComponents);
List<IDIYComponent<?>> originalComponents = new ArrayList<IDIYComponent<?>>(selectedComponents);
List<IDIYComponent<?>> clonedComponents = originalComponents.stream(
).map(x -> {
try {
return x.clone();
} catch (CloneNotSupportedException e) {
LOG.error(e);
return null;
}
})
.filter(Objects::nonNull)
.collect(Collectors.toList());
Set<Set<IDIYComponent<?>>> clonedGroups = new HashSet<Set<IDIYComponent<?>>>();
for (Set<IDIYComponent<?>> group : groups) {
if (group.isEmpty())
continue;
if (originalComponentSet.contains(group.iterator().next())) {
Set<IDIYComponent<?>> clonedGroup = new HashSet<IDIYComponent<?>>();
clonedGroups.add(clonedGroup);
for (int i = 0; i < originalComponents.size(); i++) {
if (group.contains(originalComponents.get(i))) {
clonedGroup.add(clonedComponents.get(i));
}
}
}
}
return new ComponentTransferable(clonedComponents, clonedGroups);
}
}
@@ -0,0 +1,28 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.common;
public class BadPositionException extends Exception {
private static final long serialVersionUID = 1L;
}
@@ -0,0 +1,58 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.common;
import java.util.Collection;
import org.diylc.core.IDIYComponent;
public class BuildingBlock {
private String name;
private Collection<IDIYComponent<?>> components;
public BuildingBlock(String name, Collection<IDIYComponent<?>> components) {
super();
this.name = name;
this.components = components;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Collection<IDIYComponent<?>> getComponents() {
return components;
}
public void setComponents(Collection<IDIYComponent<?>> components) {
this.components = components;
}
@Override
public String toString() {
return name;
}
}
@@ -0,0 +1,49 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.common;
import java.util.List;
import java.util.Map;
import org.diylc.core.IDIYComponent;
public class BuildingBlockPackage {
private Map<String, List<IDIYComponent<?>>> block;
private String owner;
public BuildingBlockPackage() {
}
public BuildingBlockPackage(Map<String, List<IDIYComponent<?>>> blocks, String owner) {
super();
this.block = blocks;
this.owner = owner;
}
public Map<String, List<IDIYComponent<?>>> getBlocks() {
return block;
}
public String getOwner() {
return owner;
}
}
@@ -0,0 +1,164 @@
/*
*
* DIY Layout Creator (DIYLC). Copyright (c) 2009-2018 held jointly by the individual authors.
*
* This file is part of DIYLC.
*
* DIYLC is free software: you can redistribute it and/or modify it under the terms of the GNU
* General Public License as published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* DIYLC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with DIYLC. If not, see
* <http://www.gnu.org/licenses/>.
*/
package org.diylc.common;
import java.io.Serializable;
import java.util.List;
import javax.swing.Icon;
import org.diylc.core.CreationMethod;
import org.diylc.core.IDIYComponent;
import org.diylc.core.annotations.BomPolicy;
import org.diylc.core.annotations.KeywordPolicy;
/**
* Entity class used to describe a component type.
*
* @author Branislav Stojkovic
*
* @see IDIYComponent
*/
public class ComponentType implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private String description;
private CreationMethod creationMethod;
private String category;
private String namePrefix;
private String author;
private Icon icon;
private Class<? extends IDIYComponent<?>> instanceClass;
private double zOrder;
private boolean flexibleZOrder;
private BomPolicy bomPolicy;
private boolean autoEdit;
private IComponentTransformer transformer;
private KeywordPolicy keywordPolicy;
private String keywordTag;
private boolean enableCache;
private List<String[]> datasheet;
private int datasheetCreationStepCount;
public ComponentType() {
}
public ComponentType(String name, String description, CreationMethod creationMethod, String category,
String namePrefix, String author, Icon icon, Class<? extends IDIYComponent<?>> instanceClass, double zOrder,
boolean flexibleZOrder, BomPolicy bomPolicy, boolean autoEdit, IComponentTransformer transformer,
KeywordPolicy keywordPolicy, String keywordTag, boolean enableCache, List<String[]> datasheet,
int datasheetCreationStepCount) {
super();
this.name = name;
this.description = description;
this.creationMethod = creationMethod;
this.category = category;
this.namePrefix = namePrefix;
this.author = author;
this.icon = icon;
this.instanceClass = instanceClass;
this.zOrder = zOrder;
this.flexibleZOrder = flexibleZOrder;
this.bomPolicy = bomPolicy;
this.autoEdit = autoEdit;
this.transformer = transformer;
this.keywordPolicy = keywordPolicy;
this.keywordTag = keywordTag;
this.enableCache = enableCache;
this.datasheet = datasheet;
this.datasheetCreationStepCount = datasheetCreationStepCount;
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
public CreationMethod getCreationMethod() {
return creationMethod;
}
public String getCategory() {
return category;
}
public String getNamePrefix() {
return namePrefix;
}
public String getAuthor() {
return author;
}
public Icon getIcon() {
return icon;
}
public Class<? extends IDIYComponent<?>> getInstanceClass() {
return instanceClass;
}
public double getZOrder() {
return zOrder;
}
public boolean isFlexibleZOrder() {
return flexibleZOrder;
}
public BomPolicy getBomPolicy() {
return bomPolicy;
}
public boolean isAutoEdit() {
return autoEdit;
}
public IComponentTransformer getTransformer() {
return transformer;
}
public KeywordPolicy getKeywordPolicy() {
return keywordPolicy;
}
public String getKeywordTag() {
return keywordTag;
}
public boolean getEnableCache() {
return enableCache;
}
public List<String[]> getDatasheet() {
return datasheet;
}
public int getDatasheetCreationStepCount() {
return datasheetCreationStepCount;
}
@Override
public String toString() {
return name;
}
}
@@ -0,0 +1,116 @@
package org.diylc.common;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import org.apache.log4j.Logger;
import org.diylc.core.Angle;
import org.diylc.core.IDIYComponent;
import org.diylc.presenter.ComponentProcessor;
public class DefaultComponentTransformer implements IComponentTransformer {
private static final Logger LOG = Logger.getLogger(DefaultComponentTransformer.class);
@Override
public boolean canRotate(IDIYComponent<?> component) {
List<PropertyWrapper> properties =
ComponentProcessor.getInstance().extractProperties(component.getClass());
for (PropertyWrapper property : properties) {
if (property.getType().isAssignableFrom(Orientation.class)
|| property.getType().isAssignableFrom(OrientationHV.class)
|| property.getType().isAssignableFrom(Angle.class))
return true;
}
return false;
}
@Override
public boolean canMirror(IDIYComponent<?> component) {
return false;
}
@Override
public boolean mirroringChangesCircuit() {
return false;
}
@Override
public void rotate(IDIYComponent<?> component, Point2D center, int direction) {
boolean canRotate = false;
List<PropertyWrapper> properties =
ComponentProcessor.getInstance().extractProperties(component.getClass());
for (PropertyWrapper property : properties) {
try {
property.readFrom(component);
} catch (IllegalArgumentException | IllegalAccessException | InvocationTargetException
| SecurityException | NoSuchMethodException e) {
LOG.warn("Error while rotating component " + component.getName(), e);
}
try {
if (property.getType().isAssignableFrom(Orientation.class)) {
canRotate = true;
Orientation o = (Orientation) property.getValue();
int oValue = o.ordinal();
oValue += direction;
if (oValue < 0)
oValue = Orientation.values().length - 1;
if (oValue >= Orientation.values().length)
oValue = 0;
o = Orientation.values()[oValue];
property.setValue(o);
}
if (property.getType().isAssignableFrom(OrientationHV.class)) {
canRotate = true;
OrientationHV o = (OrientationHV) property.getValue();
int oValue = o.ordinal();
oValue += direction;
if (oValue < 0)
oValue = OrientationHV.values().length - 1;
if (oValue >= OrientationHV.values().length)
oValue = 0;
o = OrientationHV.values()[oValue];
property.setValue(o);
}
if (property.getType().isAssignableFrom(Angle.class)) {
canRotate = true;
Angle angle = (Angle) property.getValue();
Angle newAngle = angle.rotate(direction);
property.setValue(newAngle);
}
} catch (Exception e) {
LOG.warn("Error while rotating component " + component.getName(), e);
}
if (canRotate) {
AffineTransform rotate = AffineTransform.getRotateInstance(Math.PI / 2 * direction,
center.getX(), center.getY());
for (int index = 0; index < component.getControlPointCount(); index++) {
Point2D p = new Point2D.Double();
rotate.transform(component.getControlPoint(index), p);
component.setControlPoint(p, index);
}
try {
property.writeTo(component);
} catch (IllegalArgumentException | IllegalAccessException | InvocationTargetException
| SecurityException | NoSuchMethodException e) {
LOG.warn("Error while rotating component " + component.getName(), e);
}
break;
}
}
}
@Override
public void mirror(IDIYComponent<?> component, Point2D center, int direction) {}
}
@@ -0,0 +1,32 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.common;
public enum Display {
NAME, VALUE, NONE, BOTH;
@Override
public String toString() {
return name().substring(0, 1) + name().substring(1).toLowerCase();
}
}
@@ -0,0 +1,72 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.common;
import java.awt.Graphics;
/**
* Enumerates all options that can be used when drawing a project.
*
* @see IPlugInPort#draw(java.awt.Graphics2D, java.util.Set, IComponentFiler)
*
* @author Branislav Stojkovic
*/
public enum DrawOption {
/**
* Selection rectangle will be drawn when needed and selected components may be rendered
* differently.
*/
SELECTION,
/**
* Selected zoom level will be applied to scale the {@link Graphics} before drawing.
*/
ZOOM,
/**
* Grid lines are drawn.
*/
GRID,
/**
* Control points are drawn.
*/
CONTROL_POINTS,
/**
* Anti-aliasing is used when drawing.
*/
ANTIALIASING,
/**
* Draw components in outline mode.
*/
OUTLINE_MODE,
/**
* Include extra space around the layout.
*/
EXTRA_SPACE,
/**
* Whether components should be cached or not.
*/
ENABLE_CACHING,
/**
* Whether locked components should be rendered as transparent or not.
*/
LOCKED_ALPHA;
}
@@ -0,0 +1,109 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.common;
import java.awt.Rectangle;
import java.awt.geom.Point2D;
import org.diylc.core.Project;
/**
* Enumerates all possible events between {@link IPlugInPort} and {@link IPlugIn}. Some events
* overlap so be careful which ones you subscribe for and how you process them.
*
* @author Branislav Stojkovic
*/
public enum EventType {
/**
* Called when zoom level changes. Typically only one parameter of type {@link Double} is passed
* with new zoom level.
*/
ZOOM_CHANGED,
/**
* Called when a new project is loaded. New {@link Project} is the first parameter. Boolean flag
* is the second parameter and it's true when new project is loaded, false when the same project
* has been either reloaded or loaded with undo/redo operations.
*/
PROJECT_LOADED,
/**
* Called when either current file name or modified flag are changed. The first parameter is the
* current file name, the second one is a boolean modified flag.
*/
FILE_STATUS_CHANGED,
/**
* Called when selection rectangle is changed. Object of type {@link Rectangle} is the only
* parameter and it contains the new selection rectangle.
*/
SELECTION_RECT_CHANGED,
/**
* Called when component selection is changed. New {@link ComponentSelection} is attached as a
* parameter.
*/
SELECTION_CHANGED,
/**
* Called when selection size changes, together with a {@link Point2D} object containing selection
* size (x = width, y = height). Size is expressed in the default measure (cm for metric, inches
* for imperial).
*/
REPAINT,
/**
* Called when new component slot has been changed. The only parameter is {@link ComponentType}
* and may be null.
*/
SLOT_CHANGED,
/**
* Called when the current project has been modified. Two instances of {@link Project} are passed
* as parameters, one before and one after the change. The third parameter is a string containing
* change description.
*/
PROJECT_MODIFIED,
/**
* Called when control points under the cursor are changed. A single parameter is passed, an
* instance of <code>Map<IDIYComponent<?>, Set<Integer>></code> containing all the components and
* indices of their control points that are under the cursor.
*/
AVAILABLE_CTRL_POINTS_CHANGED,
/**
* Called when mouse cursor is moved. Point object is passed, containing the current cursor
* location (not taking zoom into account) in pixels and two {@link Point2D} objects with coordinates in
* inches and mm
*/
MOUSE_MOVED,
/**
* Called when a layer status is changed. The first parameter is a set of indices of locked
* layers. All layers not included are considered unlocked.
*/
LAYER_STATE_CHANGED,
/**
* Called when a layer visibility is changed. The first parameter is a set of indices of hidden
* layers. All layers not included are considered visible.
*/
LAYER_VISIBILITY_CHANGED,
/**
* Called to update the status message. New status message is passed as a first parameter.
*/
STATUS_MESSAGE_CHANGED,
/**
* Signals the listeners to scroll to selection.
*/
SCROLL_TO;
}
@@ -0,0 +1,93 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.common;
import java.io.Serializable;
public class Favorite implements Serializable, Comparable<Favorite> {
private static final long serialVersionUID = 1L;
private FavoriteType type;
private String name;
public Favorite(FavoriteType type, String name) {
super();
this.type = type;
this.name = name;
}
public FavoriteType getType() {
return type;
}
public String getName() {
return name;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((type == null) ? 0 : type.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Favorite other = (Favorite) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (type != other.type)
return false;
return true;
}
@Override
public String toString() {
return type + ":" + name;
}
public enum FavoriteType {
Component, Block
}
public String toDisplay() {
String[] parts = name.split("\\.");
return parts[parts.length - 1];
}
@Override
public int compareTo(Favorite o) {
return toDisplay().compareToIgnoreCase(o.toDisplay());
}
}
@@ -0,0 +1,27 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.common;
public enum GridType {
LINES, CROSSHAIR, DOT, NONE;
}
@@ -0,0 +1,30 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.common;
public enum HorizontalAlignment {
LEFT, CENTER, RIGHT;
public String toString() {
return name().substring(0, 1) + name().substring(1).toLowerCase();
}
}
@@ -0,0 +1,50 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.common;
import java.io.IOException;
public interface IBlockProcessor {
public static final String BLOCKS_KEY = "buildingBlocks";
public static final String DEFAULT_BLOCKS_IMPORTED_KEY = "defaultBlocksImported";
void saveSelectionAsBlock(String blockName);
void loadBlock(String blockName) throws InvalidBlockException;
void deleteBlock(String blockName);
int importBlocks(String fileName) throws IOException;
public class BlockAlreadyExistsException extends Exception {
private static final long serialVersionUID = 1L;
}
public class InvalidBlockException extends Exception {
private static final long serialVersionUID = 1L;
}
}
@@ -0,0 +1,29 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.common;
import org.diylc.core.IDIYComponent;
public interface IComponentFilter {
boolean testComponent(IDIYComponent<?> component);
}
@@ -0,0 +1,44 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.common;
import java.awt.geom.Point2D;
import org.diylc.core.IDIYComponent;
public interface IComponentTransformer {
public static final int CLOCKWISE = 1;
public static final int COUNTER_CLOCKWISE = 1;
public static final int HORIZONTAL = 0;
public static final int VERTICAL = 1;
boolean canRotate(IDIYComponent<?> component);
boolean canMirror(IDIYComponent<?> component);
boolean mirroringChangesCircuit();
void rotate(IDIYComponent<?> component, Point2D center, int direction);
void mirror(IDIYComponent<?> component, Point2D center, int direction);
}
@@ -0,0 +1,44 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.common;
public interface IKeyProcessor {
public static final int VK_LEFT = 0x25;
public static final int VK_UP = 0x26;
public static final int VK_RIGHT = 0x27;
public static final int VK_DOWN = 0x28;
public static final int VK_H = 0x48;
public static final int VK_V = 0x56;
/**
* Notifies the presenter that a key hes been pressed on the canvas.
*
* @param key
* @param ctrlDown
* @param shiftDown
* @param altDown
*
* @return true if the event should be consumed
*/
boolean keyPressed(int key, boolean ctrlDown, boolean shiftDown, boolean altDown);
}
@@ -0,0 +1,90 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.common;
import java.awt.Point;
public interface IMouseProcessor {
/**
* Notifies the presenter that mouse is clicked.
*
* Note: point coordinates are display based, i.e. scaled for zoom factor.
*
* @param point
* @param button
* @param ctrlDown
* @param shiftDown
* @param altDown
* @param clickCount
*/
void mouseClicked(Point point, int button, boolean ctrlDown, boolean shiftDown, boolean altDown, int clickCount);
/**
* Notifies the presenter that mouse is moved.
*
* Note: point coordinates are display based, i.e. scaled for zoom factor.
*
* @param point
* @param ctrlDown
* @param shiftDown
* @param altDown
*/
void mouseMoved(Point point, boolean ctrlDown, boolean shiftDown, boolean altDown);
/**
* Notification that drag has been started from the specified point.
*
* Note: point coordinates are scaled for zoom factor.
*
* @param point
* @param dragAction
* @param forceSelectionRect
*/
void dragStarted(Point point, int dragAction, boolean forceSelectionRect);
/**
* Checks if it's possible to drop over the specified point.
*
* Note: point coordinates are scaled for zoom factor.
*
* @param point
* @return
*/
boolean dragOver(Point point);
/**
* Changes the current drag action during the dragging.
*
* @param dragAction
*/
void dragActionChanged(int dragAction);
/**
* Notification that drag has been ended in the specified point.
*
* Note: point coordinates are scaled for zoom factor.
*
* @param point
*/
void dragEnded(Point point);
}
@@ -0,0 +1,61 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.common;
import java.util.List;
import org.diylc.netlist.Netlist;
import org.diylc.netlist.Node;
import org.diylc.netlist.Summary;
import org.diylc.netlist.TreeException;
public interface INetlistAnalyzer {
/**
* @return summarizer name
*/
String getName();
/**
* @return summarizer short name
*/
String getShortName();
/**
* @return name of the icon to use
*/
String getIconName();
/**
* Summarizes all {@link Netlist}s provided.
*
* @param netlists
* @param preferredOutput optional, needed only where there's more than one possible output node.
* @return
* @throws TreeException
*/
List<Summary> summarize(List<Netlist> netlists, Node preferredOutput) throws TreeException;
/**
* @return name of the font to be used for display.
*/
String getFontName();
}
@@ -0,0 +1,59 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.common;
import java.util.List;
import org.diylc.netlist.INetlistParser;
import org.diylc.netlist.Netlist;
import org.diylc.netlist.NetlistException;
/**
* Interface for {@link Netlist} related operations.
*
* @author Branislav Stojkovic
*/
public interface INetlistProcessor {
/**
* Finds all {@link Netlist}s for each switch position combination.
*
* @param includeSwitches
* @return
* @throws NetlistException
*/
List<Netlist> extractNetlists(boolean includeSwitches) throws NetlistException;
/**
* Finds all available {@link INetlistAnalyzer} implementations.
*
* @return
*/
List<INetlistAnalyzer> getNetlistAnalyzers();
/**
* Finds all available {@link INetlistParser} implementations.
*
* @return
*/
List<INetlistParser> getNetlistParserDefinitions();
}
@@ -0,0 +1,40 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.common;
import org.diylc.appframework.simplemq.IMessageListener;
/**
* Interface for plug-ins.
*
* @author Branislav Stojkovic
*/
public interface IPlugIn extends IMessageListener<EventType> {
/**
* Method that connects the plug-in with {@link IPlugInPort}. Called by the application when
* plug-in is installed.
*
* @param plugInPort
*/
void connect(IPlugInPort plugInPort);
}
@@ -0,0 +1,401 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.common;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.geom.Area;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.diylc.appframework.simplemq.IMessageListener;
import org.diylc.appframework.simplemq.MessageDispatcher;
import org.diylc.appframework.update.Version;
import org.diylc.appframework.update.VersionNumber;
import org.diylc.clipboard.ComponentTransferable;
import org.diylc.core.IDIYComponent;
import org.diylc.core.Project;
import org.diylc.core.Template;
import org.diylc.core.Theme;
import org.diylc.core.measures.Size;
import org.diylc.test.ITestProcessor;
/**
* Interface for communication between plug-ins and the application. Plug-ins may acquire
* information or make changes through this interface. Application events are dispatched to plug-ins
* through {@link MessageDispatcher}
*
* @author Branislav Stojkovic
*
* @see IPlugIn
* @see MessageDispatcher
* @see IMessageListener
* @see EventType
*/
public interface IPlugInPort extends ISelectionProcessor, IMouseProcessor, IKeyProcessor, IVariantProcessor,
IBlockProcessor, INetlistProcessor, ITestProcessor {
public static final String ANTI_ALIASING_KEY = "antiAliasing";
public static final String HI_QUALITY_RENDER_KEY = "hiQualityRender";
public static final String EXPORT_GRID_KEY = "exportGrid";
public static final String STICKY_POINTS_KEY = "stickyPoints";
public static final String METRIC_KEY = "metric";
public static final String SNAP_TO_KEY = "snapTo";
public static final String CONTINUOUS_CREATION_KEY = "continuousCreation";
public static final String AUTO_EDIT_KEY = "autoEdit";
// public static final String ABNORMAL_EXIT_KEY = "abnormalExit";
public static final String HEARTBEAT = "heartbeat";
public static final String WHEEL_ZOOM_KEY = "wheelZoom";
public static final String OUTLINE_KEY = "outline";
public static final String THEME_KEY = "theme";
public static final String RECENT_COMPONENTS_KEY = "recentComponents";
public static final String RECENT_FILES_KEY = "recentFiles";
public static final String SHOW_RULERS_KEY = "showRulers";
public static final String SHOW_GRID_KEY = "showGrid";
public static final String HIGHLIGHT_CONTINUITY_AREA = "highlightContinuityArea";
public static final String HARDWARE_ACCELERATION = "hardwareAcceleration";
public static final String EXTRA_SPACE_KEY = "extraSpace";
public static final String FAVORITES_KEY = "favorites";
public static final String RENUMBER_ON_PASTE_KEY = "renumberOnPaste";
public static final String RULER_IN_SUBDIVISION_KEY = "rulerInSubdivision";
public static final String CACHING_ENABLED_KEY = "cachingEnabled";
public static final String RULER_IN_SUBDIVISION_2 = "base of 2";
public static final String RULER_IN_SUBDIVISION_10 = "base of 10";
public static final String RULER_IN_SUBDIVISION_DEFAULT = RULER_IN_SUBDIVISION_10;
public static final String SNAP_TO_NONE = "None";
public static final String SNAP_TO_GRID = "Grid";
public static final String SNAP_TO_COMPONENTS = "Components";
public static final String SNAP_TO_DEFAULT = SNAP_TO_GRID;
public static final String LOCKED_ALPHA = "lockedAlpha";
public static final String LANGUAGE = "language";
public static final String LANGUAGE_DEFAULT = "English";
public static final int DND_TOGGLE_STICKY = 0x1;
public static final int DND_TOGGLE_SNAP = 0x40000000;
/**
* Mouse button constants.
*/
public static final int NOBUTTON = 0;
public static final int BUTTON1 = 1;
public static final int BUTTON2 = 2;
public static final int BUTTON3 = 3;
/**
* Returns size of the canvas that takes project dimensions into account as well as zoom level.
* Each dimension is calculated as the product of the actual size and the number of pixels per
* unit. If <code>useZoom</code> is set to true, the result is scaled by zoom factor.
*
* @param useZoom
* @param includeExtraSpace
*
* @return canvas dimensions
*/
Dimension getCanvasDimensions(boolean useZoom, boolean includeExtraSpace);
/**
* Returns an instance of {@link Cursor} that should be used at the specified location.
*
* Note: point coordinates are scaled for zoom factor.
*
* @param point
* @param ctrlDown
* @param shiftDown
* @param altDown
* @return cursor
*/
Cursor getCursorAt(Point point, boolean ctrlDown, boolean shiftDown, boolean altDown);
/**
* Returns an instance of currently loaded project.
*
* @return
*/
Project getCurrentProject();
/**
* Loads specified {@link Project}.
*
* @param project
* @param freshStart
* @param optional file name when loading from a file
*/
void loadProject(Project project, boolean freshStart, String filename);
/**
* Creates a new project.
*/
void createNewProject();
/**
* Loads a project from the specified file.
*
* @param fileName
*/
void loadProjectFromFile(String fileName);
/**
* Saves the current project into the specified file.
*
* @param fileName
* @param isBackup
*/
void saveProjectToFile(String fileName, boolean isBackup);
/**
* Exports the current project into one or more files - one per layer and potentially drill layer.
*
* @param fileNameBase
* @param g2d
*/
void exportToGerber(String fileNameBase, Graphics2D g2d);
/**
* @return the current file name.
*/
String getCurrentFileName();
/**
* @return true if the current project is modified.
*/
boolean isProjectModified();
/**
* Shows a user dialog if there are changes to confirm that it's safe to proceed.
*
* @return true, if file actions (new, open, close) can be taken
*/
boolean allowFileAction();
/**
* Returns all available {@link ComponentType}s classified by category. Result is a {@link Map}
* between category name to a {@link List} of all {@link ComponentType}s that share that category
* name.
*
* @return
*/
Map<String, List<ComponentType>> getComponentTypes();
/**
* Draws project on the provided {@link Graphics2D}. If the provided filter is not null, it will
* be used to filter the components that are shown.
*
* @param g2d
* @param drawOptions specific drawing options
* @param filter
* @param externalZoom
* @param scaleFactor
* @param visibleRect
*/
void draw(Graphics2D g2d, Set<DrawOption> drawOptions, IComponentFilter filter, Double externalZoom, Double scaleFactor, Rectangle2D visibleRect);
Double[] getAvailableZoomLevels();
/**
* Returns current zoom level where <code>zoomLevel = 1.0d</code> means 100%.
*
* @return current zoom level
*/
double getZoomLevel();
/**
* Changes current zoom level where <code>zoomLevel = 1.0d</code> means 100%
*
* @param zoomLevel new zoom leve
*/
void setZoomLevel(double zoomLevel);
/**
* Returns current version number.
*
* @return
*/
VersionNumber getCurrentVersionNumber();
/**
* Returns few most recent versions.
*
* @return
*/
List<Version> getRecentUpdates();
/**
* Adds a list of components to the project.
*
* @param componentTransferable
* @param autoGroup
* @param assignNewNames
*/
void pasteComponents(ComponentTransferable componentTransferable, boolean autoGroup, boolean assignNewNames);
/**
* Duplicates selected components and places them nearby.
*/
void duplicateSelection();
/**
* Deletes all the selected components from the project.
*/
void deleteSelectedComponents();
/**
* Sets default value for the specified property name for currently selected component types.
*
* @param propertyName display name for property
* @param value new default value, must not be null
*/
void setSelectionDefaultPropertyValue(String propertyName, Object value);
/**
* Sets default value for the specified property name for projects.
*
* @param clazz class to set defaults to
* @param propertyName display name for property
* @param value new default value, must not be null
*/
void setDefaultPropertyValue(Class<?> clazz, String propertyName, Object value);
/**
* @return a list of properties that are mutual for all the selected components. Resulting list
* may be empty if selected components do not have mutual properties or can be null if the
* selection is empty.
*/
List<PropertyWrapper> getMutualSelectionProperties();
void editSelection();
/**
* @return a list of editable properties of the current project.
*
* @param obj
*/
List<PropertyWrapper> getProperties(Object obj);
/**
* Applies specified properties to the current project.
*
* @param obj
* @param properties
*/
void applyProperties(Object obj, List<PropertyWrapper> properties);
/**
* Gets the current new component slot.
*/
ComponentType getNewComponentTypeSlot();
/**
* Sets the new component slot. Specified component type will be used to instantiate new
* component.
*
* @param componentType
* @param template optional
* @param model optional datasheet model
* @param forceInstatiate
*/
void setNewComponentTypeSlot(ComponentType componentType, Template template, String[] model, boolean forceInstatiate);
/**
* Locks or unlocks the specified layer. All components within +- 0.5 range will be affected by
* the change as well.
*
* @param layerZOrder
* @param locked
*/
void setLayerLocked(int layerZOrder, boolean locked);
/**
* Shows or hides the specified layer. All components within +- 0.5 range will be affected by the
* change as well.
*
* @param layerZOrder
* @param visible
*/
void setLayerVisibility(int layerZOrder, boolean visible);
/**
* @return selection size expressed in both inches or centimeters, respectively
*/
Point2D[] calculateSelectionDimension();
// /**
// * @return the smallest rectangle that encloses the selection
// */
// Rectangle2D getSelectedAreaRect();
/**
* Causes the display to refresh.
*/
void refresh();
/**
* @return currently selected theme.
*/
Theme getSelectedTheme();
/**
* Changes the current theme.
*
* @param theme
*/
void setSelectedTheme(Theme theme);
/**
* Renumbers all the selected components.
*
* @param xAxisFirst
*/
void renumberSelectedComponents(boolean xAxisFirst);
/**
* @return size of extra space around the canvas
*/
double getExtraSpace();
/**
* Applies changes to the current project as specified by the provided {@link IProjectEditor}.
*
* @param editor
*/
void applyEditor(IProjectEditor editor);
/**
* Locks or unlocks a single component.
*/
void lockComponent(IDIYComponent<?> c, boolean locked);
/**
* Checks for proximity between continuity areas and creates additional components around any problematic areas to visually identify them.
*
* @param threshold
*/
List<Area> checkContinuityAreaProximity(Size threshold);
}
@@ -0,0 +1,33 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.common;
import java.util.Set;
import org.diylc.core.IDIYComponent;
import org.diylc.core.Project;
public interface IProjectEditor {
Set<IDIYComponent<?>> edit(Project project, Set<IDIYComponent<?>> selection);
String getEditAction();
}
@@ -0,0 +1,157 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.common;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.Collection;
import java.util.List;
import org.diylc.clipboard.ComponentTransferable;
import org.diylc.core.ExpansionMode;
import org.diylc.core.IDIYComponent;
import org.diylc.core.measures.Size;
public interface ISelectionProcessor {
/**
* Returns the current {@link ComponentTransferable}.
*
* @return
*/
Collection<IDIYComponent<?>> getSelectedComponents();
/**
* Returns selected component types
*
* @return
*/
Collection<ComponentType> getSelectedComponentTypes();
/**
* Updates the selection with the specified list of component. Also, updates control point map
* with all components that are stuck to the newly selected components.
*
* @param newSelection
* @param panToSelection
*/
void setSelection(Collection<IDIYComponent<?>> newSelection, boolean panToSelection);
/**
* Finds all components at the specified location, sorted by z-index from top to bottom. Location
* depends on the current zoom level.
*
* @param point
* @param includeLocked
* @return
*/
List<IDIYComponent<?>> findComponentsAt(Point2D point, boolean includeLocked);
/**
* Expands the current selection to include surrounding components. Options are controlled with
* <code>expansionMode</code> flag.
*
* @param expansionMode
*/
void expandSelection(ExpansionMode expansionMode);
/**
* Selects all components in the project.
*
* @param int layer if > 0, designates which layer to select. If <= 0 we should select all
* regardless of layer
*/
void selectAll(int layer);
/**
* Rotates selection for 90 degrees.
*
* @param direction 1 for clockwise, -1 for counter-clockwise
*/
void rotateSelection(int direction);
/**
* Groups all selected components.
*/
void groupSelectedComponents();
/**
* Ungroups all selected components.
*/
void ungroupSelectedComponents();
/**
* Mirrors selected components in the given axis.
*
* @param direction
*/
void mirrorSelection(int direction);
/**
* Returns the minimum rectangle containing all selected components, or null if none exists.
* Rectangle is scaled by the current zoom level.
*
* @param applyZoom
*
* @return
*/
Rectangle2D getSelectionBounds(boolean applyZoom);
/**
* Moves selection for the specified offset.
*
* @param xOffset
* @param yOffset
* @param includeStuckComponents
*/
void nudgeSelection(Size xOffset, Size yOffset, boolean includeStuckComponents);
/**
* Selects components that match the criteria.
*
* @param criteria
*/
void selectMatching(String criteria);
/**
* Attempts to apply the specified model to all selected components.
*
* @param model
*/
void applyModelToSelection(String[] model);
/**
* Sends each of the selected components one step back.
*/
void sendSelectionToBack();
/**
* Brings each of the selected components one step to front.
*/
void bringSelectionToFront();
/**
* Move selected components to z index starting from the provided value
* @param zIndex
*/
void moveSelectionToZIndex(int zIndex);
}
@@ -0,0 +1,54 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.common;
/**
* Abstract layer between the app and platform worker thread implementation.
*
* @author Branislav Stojkovic
*
* @param <T>
*/
public interface ITask<T> {
/**
* Runs in background thread.
*
* @return
* @throws Exception
*/
T doInBackground() throws Exception;
/**
* Called if background thread fails.
*
* @param e
*/
void failed(Exception e);
/**
* Called if background thread is executed correctly, the result is passed as a parameter.
*
* @param result
*/
void complete(T result);
}
@@ -0,0 +1,55 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.common;
import java.io.IOException;
import java.util.List;
import org.diylc.core.Template;
public interface IVariantProcessor {
public static final String TEMPLATES_KEY = "templates";
public static final String DEFAULT_TEMPLATES_KEY = "defaultTemplates";
public static final String DEFAULT_TEMPLATES_IMPORT_DATE_KEY = "defaultTemplatesImportDate";
void saveSelectedComponentAsVariant(String variantName);
List<Template> getVariantsFor(ComponentType type);
List<Template> getVariantsForSelection();
void applyVariantToSelection(Template variant);
void deleteVariant(ComponentType type, String variantName);
void setDefaultVariant(ComponentType type, String variantName);
int importVariants(String fileName) throws IOException;
String getDefaultVariant(ComponentType type);
public class VariantAlreadyExistsException extends Exception {
private static final long serialVersionUID = 1L;
}
}
@@ -0,0 +1,32 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.common;
public enum LabelPosition {
ABOVE, BELOW;
@Override
public String toString() {
return name().substring(0, 1) + name().substring(1).toLowerCase();
}
}
@@ -0,0 +1,32 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.common;
public enum LineStyle {
SOLID, DASHED, DOTTED;
@Override
public String toString() {
return name().substring(0, 1) + name().substring(1).toLowerCase();
}
}
@@ -0,0 +1,86 @@
/*
*
* DIY Layout Creator (DIYLC). Copyright (c) 2009-2018 held jointly by the individual authors.
*
* This file is part of DIYLC.
*
* DIYLC is free software: you can redistribute it and/or modify it under the terms of the GNU
* General Public License as published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* DIYLC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with DIYLC. If not, see
* <http://www.gnu.org/licenses/>.
*/
package org.diylc.common;
import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Stroke;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
/**
* Repository for object that may be reused, such as {@link Stroke} or {@link AlphaComposite}.
*
* @author Branislav Stojkovic
*/
public class ObjectCache {
private static ObjectCache instance;
public static ObjectCache getInstance() {
if (instance == null) {
instance = new ObjectCache();
}
return instance;
}
private ObjectCache() {}
private Map<Float, Stroke> basicStrokeMap = new HashMap<Float, Stroke>();
private Map<Float, Stroke> zoomableStrokeMap = new HashMap<Float, Stroke>();
private Map<String, Stroke> dashStrokeMap = new HashMap<String, Stroke>();
public Stroke fetchBasicStroke(float width) {
if (basicStrokeMap.containsKey(width)) {
return basicStrokeMap.get(width);
}
Stroke stroke = new BasicStroke(width, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
basicStrokeMap.put(width, stroke);
return stroke;
}
public Stroke fetchZoomableStroke(float width) {
if (zoomableStrokeMap.containsKey(width)) {
return zoomableStrokeMap.get(width);
}
Stroke stroke = new ZoomableStroke(width, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
zoomableStrokeMap.put(width, stroke);
return stroke;
}
public Stroke fetchStroke(float width, float[] dash, float phase, int cap) {
String key = width + "|" + Arrays.toString(dash) + "|" + phase + "|" + cap;
if (dashStrokeMap.containsKey(key)) {
return dashStrokeMap.get(key);
}
Stroke stroke = new BasicStroke(width, cap, BasicStroke.JOIN_ROUND, 0, dash, phase);
dashStrokeMap.put(key, stroke);
return stroke;
}
public Stroke fetchStroke(float width, int cap) {
String key = width + "|" + cap;
if (dashStrokeMap.containsKey(key)) {
return dashStrokeMap.get(key);
}
Stroke stroke = new BasicStroke(width, cap, BasicStroke.JOIN_ROUND);
dashStrokeMap.put(key, stroke);
return stroke;
}
}
@@ -0,0 +1,56 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.common;
public enum Orientation {
DEFAULT, _90, _180, _270;
@Override
public String toString() {
if (this == DEFAULT) {
return "Default";
} else {
return name().replace("_", "") + " degrees clockwise";
}
}
public double toDegrees() {
switch (this) {
case DEFAULT:
return 0;
case _180:
return 180;
case _270:
return 270;
case _90:
return 90;
default:
break;
}
return 0;
}
public double toRadians() {
return Math.toRadians(toDegrees());
}
}
@@ -0,0 +1,32 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.common;
public enum OrientationHV {
VERTICAL, HORIZONTAL;
@Override
public String toString() {
return name().substring(0, 1) + name().substring(1).toLowerCase();
}
}
@@ -0,0 +1,52 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.common;
import org.diylc.core.gerber.GerberLayer;
public enum PCBLayer {
_1("Bottom"), _2("Top"), _3("Inner 1"), _4("Inner 2"), _5("Inner 3"), _6("Inner 4"), _7("Inner 5"), _8("Inner 6");
private String label;
private PCBLayer(String label) {
this.label = label;
}
public String toString() {
return label;
};
public int getId() {
return this.ordinal() + 1;
}
public GerberLayer toGerberCopperLayer() {
switch (this) {
case _1: return GerberLayer.CopperBot;
case _2: return GerberLayer.CopperTop;
default:
throw new RuntimeException("Unsupported PCB layer: " + this);
}
}
}
@@ -0,0 +1,209 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.common;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.diylc.core.IPropertyValidator;
/**
* Entity class for editable properties extracted from component objects. Represents a single
* editable property together with it's current value.
*
* @author Branislav Stojkovic
*/
public class PropertyWrapper implements Cloneable {
private String name;
private Class<?> type;
private Object value;
private String setter;
private String getter;
private boolean defaultable;
private IPropertyValidator validator;
private boolean unique = true;
private boolean changed = false;
private int sortOrder;
private Object ownerObject;
public PropertyWrapper(String name, Class<?> type, String getter, String setter, boolean defaultable,
IPropertyValidator validator, int sortOrder) {
super();
this.name = name;
this.type = type;
this.getter = getter;
this.setter = setter;
this.defaultable = defaultable;
this.validator = validator;
this.sortOrder = sortOrder;
this.ownerObject = null;
}
public void readFrom(Object object) throws IllegalArgumentException, IllegalAccessException,
InvocationTargetException, SecurityException, NoSuchMethodException {
this.ownerObject = object;
this.value = getGetter().invoke(object);
}
// public void readUniqueFrom(IDIYComponent component)
// throws IllegalArgumentException, IllegalAccessException,
// InvocationTargetException {
// Object newValue = getter.invoke(component);
// if (!newValue.equals(value)) {
// this.value = null;
// }
// }
public void writeTo(Object object) throws IllegalArgumentException, IllegalAccessException,
InvocationTargetException, SecurityException, NoSuchMethodException {
// nothing to do if no setter
if (setter == null)
return;
object.getClass().getMethod(setter, type).invoke(object, this.value);
}
public Method getGetter() throws SecurityException, NoSuchMethodException {
return getOwnerObject().getClass().getMethod(getter);
}
public boolean isReadOnly() {
return setter == null;
}
public String getName() {
return name;
}
public Class<?> getType() {
return type;
}
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
public Object getOwnerObject() {
return ownerObject;
}
public boolean isDefaultable() {
return defaultable;
}
public IPropertyValidator getValidator() {
return validator;
}
public boolean isUnique() {
return unique;
}
public void setUnique(boolean unique) {
this.unique = unique;
}
public boolean isChanged() {
return changed;
}
public void setChanged(boolean changed) {
this.changed = changed;
}
public int getSortOrder() {
return sortOrder;
}
// @Override
// public Object clone() throws CloneNotSupportedException {
// // Try to invoke clone method on value if possible.
// try {
// Method cloneMethod = value.getClass().getMethod("clone");
// return new Property(name, type, cloneMethod.invoke(value));
// } catch (Exception e) {
// }
// return new Property(name, type, value);
// }
@Override
public Object clone() throws CloneNotSupportedException {
PropertyWrapper clone =
new PropertyWrapper(this.name, this.type, this.getter, this.setter, this.defaultable, this.validator,
this.sortOrder);
clone.value = this.value;
clone.changed = this.changed;
clone.unique = this.unique;
return clone;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (defaultable ? 1231 : 1237);
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((setter == null) ? 0 : setter.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
PropertyWrapper other = (PropertyWrapper) obj;
if (defaultable != other.defaultable)
return false;
if (getter == null) {
if (other.getter != null)
return false;
} else if (!getter.equals(other.getter))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (setter == null) {
if (other.setter != null)
return false;
} else if (!setter.equals(other.setter))
return false;
if (type == null) {
if (other.type != null)
return false;
} else if (!type.equals(other.type))
return false;
return true;
}
@Override
public String toString() {
return name + " = " + value;
}
}
@@ -0,0 +1,35 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.common;
public enum ResistorColorCode {
NONE, _4_BAND, _5_BAND;
@Override
public String toString() {
if (name().startsWith("_")) {
return name().substring(1).replace("_", " ").toLowerCase();
}
return name().substring(0, 1).toUpperCase() + name().substring(1).toLowerCase();
}
}
@@ -0,0 +1,49 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.common;
import java.util.List;
import java.util.Map;
import org.diylc.core.Template;
public class VariantPackage {
private Map<String, List<Template>> variants;
private String owner;
public VariantPackage() {
}
public VariantPackage(Map<String, List<Template>> variants, String owner) {
super();
this.variants = variants;
this.owner = owner;
}
public Map<String, List<Template>> getVariants() {
return variants;
}
public String getOwner() {
return owner;
}
}
@@ -0,0 +1,30 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.common;
public enum VerticalAlignment {
TOP, CENTER, BOTTOM;
public String toString() {
return name().substring(0, 1) + name().substring(1).toLowerCase();
}
}
@@ -0,0 +1,57 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.common;
import java.awt.BasicStroke;
/***
* {@link BasicStroke} that will always be zoomed in when rendered.
*
* @author Branislav Stojkovic
*/
public class ZoomableStroke extends BasicStroke {
public ZoomableStroke() {
// TODO Auto-generated constructor stub
}
public ZoomableStroke(float width) {
super(width);
// TODO Auto-generated constructor stub
}
public ZoomableStroke(float width, int cap, int join) {
super(width, cap, join);
// TODO Auto-generated constructor stub
}
public ZoomableStroke(float width, int cap, int join, float miterlimit) {
super(width, cap, join, miterlimit);
// TODO Auto-generated constructor stub
}
public ZoomableStroke(float width, int cap, int join, float miterlimit, float[] dash, float dash_phase) {
super(width, cap, join, miterlimit, dash, dash_phase);
// TODO Auto-generated constructor stub
}
}
@@ -0,0 +1,67 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.components;
import java.awt.Shape;
import org.diylc.common.Orientation;
import org.diylc.core.Angle;
import org.diylc.core.annotations.EditableProperty;
public abstract class AbstractAngledComponent<T> extends AbstractTransparentComponent<T> {
private static final long serialVersionUID = 1L;
@Deprecated
protected Orientation orientation;
protected int angle;
transient protected Shape[] body;
protected abstract void updateControlPoints();
@EditableProperty
@SuppressWarnings("incomplete-switch")
public Angle getAngle() {
if (orientation != null) {
switch (orientation) {
case _90:
angle = 90;
break;
case _180:
angle = 180;
break;
case _270:
angle = 270;
break;
}
orientation = null;
}
return Angle.of(angle);
}
public void setAngle(Angle angle) {
this.angle = angle.getValue();
updateControlPoints();
// Reset body shape
body = null;
}
}
@@ -0,0 +1,295 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.components;
import java.awt.Color;
import java.awt.Font;
import java.awt.Shape;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.stream.Collectors;
import org.diylc.core.IDIYComponent;
import org.diylc.core.Project;
import org.diylc.core.annotations.EditableProperty;
import org.diylc.core.measures.Size;
/**
* Abstract implementation of {@link IDIYComponent} that contains component name and toString.
*
* IMPORTANT: to improve performance, all fields except for <code>Point</code> and
* <code>Point</code> arrays should be immutable. Failing to comply with this can result in annoying
* and hard to trace bugs.
*
* @author Branislav Stojkovic
*
* @param <T>
*/
public abstract class AbstractComponent<T> implements IDIYComponent<T> {
private static final long serialVersionUID = 1L;
protected String name = "";
public static Color SELECTION_COLOR = Color.red;
public static Color LABEL_COLOR = Color.black;
public static Color LABEL_COLOR_SELECTED = Color.red;
public static Font LABEL_FONT = new Font("Square721 BT", Font.PLAIN, 14);
public static Color METAL_COLOR = Color.decode("#759DAF");
public static Color LIGHT_METAL_COLOR = Color.decode("#EEEEEE");
public static Color COPPER_COLOR = Color.decode("#DA8A67");
public static Color GOLD_COLOR = Color.decode("#F4B301");
public static Color FR4_COLOR = Color.decode("#6B9B6B");
public static Color FR4_LIGHT_COLOR = Color.decode("#BABE71");
public static Color PHENOLIC_COLOR = Color.decode("#F8EBB3");
public static Color PHENOLIC_DARK_COLOR = Color.decode("#CD8500");
@EditableProperty(defaultable = false)
@Override
public String getName() {
return name;
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public boolean canControlPointOverlap(int index) {
return false;
}
@Override
public String toString() {
return name == null ? "(null)" : name;
}
@Override
public String getValueForDisplay() {
if (getValue() == null)
return "";
Object val = getValue();
if (val.getClass().isArray()) {
return String.join(" / ", Arrays.stream((Object[])val).map(x -> x == null ? "" : x.toString()).collect(Collectors.toList()));
}
return val.toString();
}
/**
* Returns the closest odd number, i.e. x when x is odd, or x + 1 when x is even.
*
* @param x
* @return
*/
protected int getClosestOdd(double x) {
return ((int) x / 2) * 2 + 1;
}
/**
* Returns the closest odd number, i.e. x when x is odd, or x + 1 when x is even.
*
* @param x
* @return
*/
protected int getClosestOdd(Size s) {
double x = s.convertToPixels();
return ((int) x / 2) * 2 + 1;
}
/**
* Returns darker color if possible, or lighter if it's already dark
*
* @param color
* @return
*/
protected Color darkerOrLighter(Color color) {
float[] hsb = new float[3];
Color.RGBtoHSB(color.getRed(), color.getGreen(), color.getBlue(), hsb);
return new Color(Color.HSBtoRGB(hsb[0], hsb[1], hsb[2] > 0.5 ? hsb[2] - 0.25f : hsb[2] + 0.25f));
}
/**
* @param clip
* @return true if none of the control points lie in the clip rectangle.
*/
protected boolean checkPointsClipped(Shape clip) {
if (clip == null) {
return false;
}
for (int i = 0; i < getControlPointCount(); i++) {
if (clip.contains(getControlPoint(i))) {
return false;
}
}
double minX = Integer.MAX_VALUE;
double minY = Integer.MAX_VALUE;
double maxX = Integer.MIN_VALUE;
double maxY = Integer.MIN_VALUE;
for (int i = 0; i < getControlPointCount(); i++) {
Point2D p = getControlPoint(i);
if (minX > p.getX()) {
minX = p.getX();
}
if (maxX < p.getX()) {
maxX = p.getX();
}
if (minY > p.getY()) {
minY = p.getY();
}
if (maxY < p.getY()) {
maxY = p.getY();
}
}
Rectangle2D rect = new Rectangle2D.Double(minX, minY, maxX - minX, maxY - minY);
return !clip.intersects(rect);
}
@SuppressWarnings("unchecked")
public IDIYComponent<T> clone() throws CloneNotSupportedException {
try {
// Instantiate object of the same type
Class<?> clazz = this.getClass();
AbstractComponent<T> newInstance = (AbstractComponent<T>) clazz.getDeclaredConstructor().newInstance();
while (AbstractComponent.class.isAssignableFrom(clazz)) {
Field[] fields = clazz.getDeclaredFields();
clazz = clazz.getSuperclass();
// fields = this.getClass().getDeclaredFields();
// Copy over all non-static, non-final fields that are declared
// in AbstractComponent or one of it's child classes
for (Field field : fields) {
if (!Modifier.isStatic(field.getModifiers()) && !Modifier.isFinal(field.getModifiers())) {
field.setAccessible(true);
Object value = field.get(this);
// Deep copy point arrays.
// TODO: something nicer
if (value != null && value.getClass().isArray()
&& value.getClass().getComponentType().isAssignableFrom(Point2D.class)) {
Object newArray = Array.newInstance(value.getClass().getComponentType(), Array.getLength(value));
for (int i = 0; i < Array.getLength(value); i++) {
Point2D p = (Point2D) Array.get(value, i);
if (p != null)
Array.set(newArray, i, new Point2D.Double(p.getX(), p.getY()));
}
value = newArray;
}
// Deep copy points.
// TODO: something nicer
if (value != null && value instanceof Point2D) {
Point2D p = (Point2D) value;
value = new Point2D.Double(p.getX(), p.getY());
}
field.set(newInstance, value);
}
}
}
return newInstance;
} catch (Exception e) {
throw new CloneNotSupportedException("Could not clone the component. Reason: " + e.getMessage());
}
}
@Override
public boolean equalsTo(IDIYComponent<?> other) {
if (other == null)
return false;
if (!other.getClass().equals(this.getClass()))
return false;
Class<?> clazz = this.getClass();
while (AbstractComponent.class.isAssignableFrom(clazz)) {
Field[] fields = clazz.getDeclaredFields();
clazz = clazz.getSuperclass();
// fields = this.getClass().getDeclaredFields();
// Copy over all non-static, non-final and non-transient fields that are declared
// in
// AbstractComponent or one of it's child classes
for (Field field : fields) {
if (!Modifier.isStatic(field.getModifiers()) && !Modifier.isFinal(field.getModifiers()) &&
!Modifier.isTransient(field.getModifiers())) {
field.setAccessible(true);
try {
Object value = field.get(this);
Object otherValue = field.get(other);
if (!compareObjects(value, otherValue))
return false;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
}
return true;
}
private boolean compareObjects(Object o1, Object o2) {
if (o1 == null && o2 == null)
return true;
if (o1 == null || o2 == null)
return false;
if (o1.getClass().isArray()) {
if (o1.getClass().getComponentType() == byte.class)
return Arrays.equals((byte[]) o1, (byte[]) o2);
if (o1.getClass().getComponentType() == double.class)
return Arrays.equals((double[]) o1, (double[]) o2);
if (o1.getClass().getComponentType() == int.class)
return Arrays.equals((int[]) o1, (int[]) o2);
return Arrays.equals((Object[]) o1, (Object[]) o2);
}
return o1.equals(o2);
}
@Override
public String getControlPointNodeName(int index) {
return Integer.toString(index + 1);
}
@Override
public String getInternalLinkName(int index1, int index2) {
return null;
}
@Override
public String[] getSectionNames(int pointIndex) {
return null;
}
@Override
public boolean canPointMoveFreely(int pointIndex) {
return true;
}
@Override
public Rectangle2D getCachingBounds() {
return null;
}
@Override
public void createdIn(Project project) {
// TODO Auto-generated method stub
}
}
@@ -0,0 +1,515 @@
/*
*
* DIY Layout Creator (DIYLC). Copyright (c) 2009-2018 held jointly by the individual authors.
*
* This file is part of DIYLC.
*
* DIYLC is free software: you can redistribute it and/or modify it under the terms of the GNU
* General Public License as published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* DIYLC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with DIYLC. If not, see
* <http://www.gnu.org/licenses/>.
*/
package org.diylc.components;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Graphics2D;
import java.awt.geom.CubicCurve2D;
import java.awt.geom.Path2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import org.apache.log4j.Logger;
import org.diylc.appframework.miscutils.ConfigurationManager;
import org.diylc.common.IPlugInPort;
import org.diylc.common.LineStyle;
import org.diylc.common.ObjectCache;
import org.diylc.core.ComponentState;
import org.diylc.core.IDrawingObserver;
import org.diylc.core.Project;
import org.diylc.core.VisibilityPolicy;
import org.diylc.core.annotations.EditableProperty;
import org.diylc.core.measures.Size;
import org.diylc.core.measures.SizeUnit;
import org.diylc.utils.Constants;
import com.google.common.collect.Streams;
import com.thoughtworks.xstream.annotations.XStreamOmitField;
public abstract class AbstractCurvedComponent<T> extends AbstractTransparentComponent<T> {
private static final long serialVersionUID = 1L;
private static final Logger LOG = Logger.getLogger(AbstractCurvedComponent.class);
public static Color GUIDELINE_COLOR = Color.blue;
public static Size DEFAULT_SIZE = new Size(1d, SizeUnit.in);
// for backward compatibility
protected Point2D[] controlPoints = null;
protected Point2D[] controlPoints2 = new Point2D[] {new Point2D.Double(0, 0),
new Point2D.Double(DEFAULT_SIZE.convertToPixels() / 2, 0),
new Point2D.Double(DEFAULT_SIZE.convertToPixels() / 2, DEFAULT_SIZE.convertToPixels()),
new Point2D.Double(DEFAULT_SIZE.convertToPixels(), DEFAULT_SIZE.convertToPixels())};
protected Color color = getDefaultColor();
protected PointCount pointCount = PointCount.FOUR;
protected LineStyle style = LineStyle.SOLID;
protected Boolean smooth = true;
private int lastUpdatePointIndex = -1;
/**
* Draws the specified curve onto graphics.
*
* @param curve
* @param g2d
* @param componentState
* @param theme
*/
protected abstract void drawCurve(Path2D curve, Graphics2D g2d, ComponentState componentState,
IDrawingObserver drawingObserver);
/**
* @return default color.
*/
protected abstract Color getDefaultColor();
@Override
public void drawIcon(Graphics2D g2d, int width, int height) {
g2d.setColor(getDefaultColor().darker());
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(3));
CubicCurve2D curve =
new CubicCurve2D.Double(1, height - 1, width / 4, height / 3, 3 * width / 4, 2 * height / 3, width - 1, 1);
g2d.draw(curve);
g2d.setColor(getDefaultColor());
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1));
g2d.draw(curve);
}
@Override
public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project,
IDrawingObserver drawingObserver) {
if (checkPointsClipped(g2d.getClip())) {
return;
}
Point2D[] p = getControlPoints();
// smoothen the curve if needed
if (getSmooth() && lastUpdatePointIndex >= 0) {
if (getPointCount() == PointCount.FIVE && (lastUpdatePointIndex == 1 || lastUpdatePointIndex == 2)) {
p[3] = findThirdPoint(p[2], p[1]);
}
if (getPointCount() == PointCount.FIVE && lastUpdatePointIndex == 3) {
p[1] = findThirdPoint(p[2], p[3]);
}
if (getPointCount() == PointCount.SEVEN && (lastUpdatePointIndex == 2 || lastUpdatePointIndex == 3)) {
p[4] = findThirdPoint(p[3], p[2]);
}
if (getPointCount() == PointCount.SEVEN && lastUpdatePointIndex == 4) {
p[2] = findThirdPoint(p[3], p[4]);
}
lastUpdatePointIndex = -1;
}
if (componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING) {
// Do not track guidelines.
drawingObserver.stopTracking();
g2d.setStroke(Constants.DASHED_STROKE);
g2d.setColor(GUIDELINE_COLOR);
for (int i = 0; i < p.length - 1; i++) {
g2d.drawLine((int)p[i].getX(), (int)p[i].getY(), (int)p[i + 1].getX(), (int)p[i + 1].getY());
}
drawingObserver.startTracking();
}
Path2D path = new Path2D.Double();
path.moveTo(p[0].getX(), p[0].getY());
if (getPointCount() == PointCount.TWO) {
path.lineTo(p[1].getX(), p[1].getY());
} else if (getPointCount() == PointCount.THREE) {
path.curveTo(p[1].getX(), p[1].getY(), p[1].getX(), p[1].getY(), p[2].getX(), p[2].getY());
} else if (getPointCount() == PointCount.FOUR) {
path.curveTo(p[1].getX(), p[1].getY(), p[2].getX(), p[2].getY(), p[3].getX(), p[3].getY());
} else if (getPointCount() == PointCount.FIVE) {
path.quadTo(p[1].getX(), p[1].getY(), p[2].getX(), p[2].getY());
path.quadTo(p[3].getX(), p[3].getY(), p[4].getX(), p[4].getY());
} else if (getPointCount() == PointCount.SEVEN) {
path.curveTo(p[1].getX(), p[1].getY(), p[2].getX(), p[2].getY(), p[3].getX(), p[3].getY());
path.curveTo(p[4].getX(), p[4].getY(), p[5].getX(), p[5].getY(), p[6].getX(), p[6].getY());
}
Composite oldComposite = g2d.getComposite();
if (alpha < MAX_ALPHA) {
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA));
}
drawCurve(path, g2d, componentState, drawingObserver);
g2d.setComposite(oldComposite);
}
@EditableProperty(name = "Point Count")
public PointCount getPointCount() {
if (pointCount == null) {
pointCount = PointCount.FOUR;
}
return pointCount;
}
protected Point2D[] getControlPoints() {
if (this.controlPoints != null) {
// ensure backward compatibility by copying points from the old structure to the new one
switch (getPointCount()) {
case TWO:
this.controlPoints2 = new Point2D[2];
this.controlPoints2[0] = this.controlPoints[0];
this.controlPoints2[1] = this.controlPoints[3];
break;
case THREE:
this.controlPoints2 = new Point2D[3];
this.controlPoints2[0] = this.controlPoints[0];
this.controlPoints2[1] = this.controlPoints[1];
this.controlPoints2[2] = this.controlPoints[3];
break;
case FOUR:
this.controlPoints2 = new Point2D[4];
this.controlPoints2[0] = this.controlPoints[0];
this.controlPoints2[1] = this.controlPoints[1];
this.controlPoints2[2] = this.controlPoints[2];
this.controlPoints2[3] = this.controlPoints[3];
break;
default: // shouldn't happen
this.controlPoints2 = this.controlPoints;
}
// we don't need old points anymore
this.controlPoints = null;
}
return this.controlPoints2;
}
public void setPointCount(PointCount pointCount) {
Point2D[] p = getControlPoints();
Point2D[] newPoints = new Point2D[pointCount.count];
newPoints[0] = p[0];
newPoints[pointCount.count - 1] = p[p.length - 1];
if (pointCount == PointCount.THREE) {
newPoints[1] =
new Point2D.Double((newPoints[pointCount.count - 1].getX() + newPoints[0].getX()) / 2,
(newPoints[pointCount.count - 1].getY() + newPoints[0].getY()) / 2);
} else if (pointCount == PointCount.FOUR) {
newPoints[1] =
new Point2D.Double((newPoints[pointCount.count - 1].getX() + newPoints[0].getX()) / 2,
(newPoints[pointCount.count - 1].getY() + newPoints[0].getY()) / 2);
newPoints[2] =
new Point2D.Double((newPoints[pointCount.count - 1].getX() + newPoints[0].getX()) / 2,
(newPoints[pointCount.count - 1].getY() + newPoints[0].getY()) / 2);
} else if (pointCount == PointCount.FIVE) {
newPoints[2] =
new Point2D.Double((newPoints[pointCount.count - 1].getX() + newPoints[0].getX()) / 2,
(newPoints[pointCount.count - 1].getY() + newPoints[0].getY()) / 2);
newPoints[1] = new Point2D.Double((newPoints[2].getX() + newPoints[0].getX()) / 2, (newPoints[2].getY() + newPoints[0].getY()) / 2);
newPoints[3] =
new Point2D.Double((newPoints[pointCount.count - 1].getX() + newPoints[2].getX()) / 2,
(newPoints[pointCount.count - 1].getY() + newPoints[2].getY()) / 2);
} else if (pointCount == PointCount.SEVEN) {
newPoints[3] =
new Point2D.Double((newPoints[pointCount.count - 1].getX() + newPoints[0].getX()) / 2,
(newPoints[pointCount.count - 1].getY() + newPoints[0].getY()) / 2);
newPoints[2] = new Point2D.Double((newPoints[3].getX() + newPoints[0].getX()) / 2, (newPoints[3].getY() + newPoints[0].getY()) / 2);
newPoints[1] = new Point2D.Double((newPoints[3].getX() + newPoints[0].getX()) / 2, (newPoints[3].getY() + newPoints[0].getY()) / 2);
newPoints[4] =
new Point2D.Double((newPoints[pointCount.count - 1].getX() + newPoints[3].getX()) / 2,
(newPoints[pointCount.count - 1].getY() + newPoints[3].getY()) / 2);
newPoints[5] =
new Point2D.Double((newPoints[pointCount.count - 1].getX() + newPoints[3].getX()) / 2,
(newPoints[pointCount.count - 1].getY() + newPoints[3].getY()) / 2);
}
this.controlPoints2 = newPoints;
this.pointCount = pointCount;
}
@Override
public int getControlPointCount() {
return getControlPoints().length;
}
@Override
public boolean isControlPointSticky(int index) {
return index == 0 || index == getControlPointCount() - 1;
}
@Override
public VisibilityPolicy getControlPointVisibilityPolicy(int index) {
return VisibilityPolicy.WHEN_SELECTED;
}
@Override
public boolean canControlPointOverlap(int index) {
return index > 0 && index < getControlPointCount() - 1;
}
@Override
public Point2D getControlPoint(int index) {
return getControlPoints()[index];
}
@Override
public void setControlPoint(Point2D point, int index) {
Point2D[] p = getControlPoints();
p[index].setLocation(point);
this.lastUpdatePointIndex = index;
// if (getSmooth()) {
// if (getPointCount() == PointCount.FIVE && (index == 1 || index == 2)) {
// p[3] = findThirdPoint(p[2], p[1]);
// }
// if (getPointCount() == PointCount.FIVE && index == 3) {
// p[1] = findThirdPoint(p[2], p[3]);
// }
// if (getPointCount() == PointCount.SEVEN && (index == 2 || index == 3)) {
// p[4] = findThirdPoint(p[3], p[2]);
// }
// if (getPointCount() == PointCount.SEVEN && index == 4) {
// p[2] = findThirdPoint(p[3], p[4]);
// }
// }
}
private Point2D findThirdPoint(Point2D p0, Point2D p) {
return new Point2D.Double(2 * p0.getX() - p.getX(), 2 * p0.getY() - p.getY());
}
@EditableProperty(name = "Color")
public Color getLeadColor() {
return color;
}
public void setLeadColor(Color color) {
this.color = color;
}
@EditableProperty(name = "Style")
public LineStyle getStyle() {
if (style == null)
style = LineStyle.SOLID;
return style;
}
public void setStyle(LineStyle style) {
this.style = style;
}
@EditableProperty
public Boolean getSmooth() {
if (smooth == null)
this.smooth = true;
return this.smooth;
}
public void setSmooth(Boolean smooth) {
this.smooth = smooth;
// make the current curve smooth if needed
// Point[] p = getControlPoints();
// if (smooth) {
// if (getPointCount() == PointCount.FIVE) {
// p[3] = findThirdPoint(p[2], p[1]);
// }
// if (getPointCount() == PointCount.SEVEN) {
// p[4] = findThirdPoint(p[3], p[2]);
// }
// }
}
@EditableProperty
public Size getLength() {
double d = 0;
try {
Point2D[] p = getControlPoints();
if (getPointCount() == PointCount.TWO) {
d = p[0].distance(p[1]);
} else if (getPointCount() == PointCount.THREE) {
d = calculateLength(p[0], p[1], p[1], p[2]);
} else if (getPointCount() == PointCount.FOUR) {
d = calculateLength(p[0], p[1], p[2], p[3]);
} else if (getPointCount() == PointCount.FIVE) {
d = calculateLength(p[0], p[1], p[2]) + calculateLength(p[2], p[3], p[4]);
} else if (getPointCount() == PointCount.SEVEN) {
d = calculateLength(p[0], p[1], p[2], p[3]) + calculateLength(p[3], p[4], p[5], p[6]);
}
SizeUnit unit;
if (ConfigurationManager.getInstance().readBoolean(IPlugInPort.METRIC_KEY, true))
unit = SizeUnit.mm;
else
unit = SizeUnit.in;
d = d * SizeUnit.px.getFactor() / unit.getFactor();
return new Size(d, unit);
} catch (Exception e) {
LOG.error("Error calculating length of " + getName(), e);
return null;
}
}
@Override
public Rectangle2D getCachingBounds() {
double minX = Integer.MAX_VALUE;
double maxX = Integer.MIN_VALUE;
double minY = Integer.MAX_VALUE;
double maxY = Integer.MIN_VALUE;
double margin = 50; // hard coded, replace with something meaningful
for (int i = 0; i < getControlPointCount(); i++) {
Point2D p = getControlPoint(i);
if (p.getX() < minX)
minX = p.getX();
if (p.getX() > maxX)
maxX = p.getX();
if (p.getY() < minY)
minY = p.getY();
if (p.getY() > maxY)
maxY = p.getY();
}
return new Rectangle2D.Double(minX - margin, minY - margin, maxX - minX + 2 * margin, maxY - minY + 2 * margin);
}
public enum PointCount {
TWO(2), THREE(3), FOUR(4), FIVE(5), SEVEN(7);
private int count;
private PointCount(int count) {
this.count = count;
}
@Override
public String toString() {
return name().substring(0, 1) + name().substring(1).toLowerCase();
}
}
// calculate length of quad curve
private double calculateLength(Point2D a, Point2D b, Point2D c) {
double vx = 2 * (b.getX() - a.getX());
double vy = 2 * (b.getY() - a.getY());
double wx = c.getX() - 2 * b.getX() + a.getX();
double wy = c.getY() - 2 * b.getY() + a.getY();
double uu = 4 * (wx * wx + wy * wy);
if (uu < 0.00001) {
return (float) Math.sqrt((c.getX() - a.getX()) * (c.getX() - a.getX()) + (c.getY() - a.getY()) * (c.getY() - a.getY()));
}
double vv = 4 * (vx * wx + vy * wy);
double ww = vx * vx + vy * vy;
double t1 = (float) (2 * Math.sqrt(uu * (uu + vv + ww)));
double t2 = 2 * uu + vv;
double t3 = vv * vv - 4 * uu * ww;
double t4 = (float) (2 * Math.sqrt(uu * ww));
return (float) ((t1 * t2 - t3 * Math.log(t2 + t1) - (vv * t4 - t3 * Math.log(vv + t4)))
/ (8 * Math.pow(uu, 1.5)));
}
// do not use this property
@XStreamOmitField
@Deprecated
private double curveThreshold;
// tweak this value if needed
private static final double curveDivisionThreshold = 5d;
// approximately calculate length of Bezier curves by subdivision
private double calculateLength(Point2D a, Point2D b, Point2D c, Point2D d) {
double distance = a.distance(d);
if (distance < curveDivisionThreshold)
return distance;
CubicCurve2D curve = new CubicCurve2D.Double(a.getX(), a.getY(), b.getX(), b.getY(), c.getX(), c.getY(), d.getX(), d.getY());
CubicCurve2D left = new CubicCurve2D.Double();
CubicCurve2D right = new CubicCurve2D.Double();
curve.subdivide(left, right);
return calculateLength(left.getP1(), left.getCtrlP1(), left.getCtrlP2(), left.getP2()) +
calculateLength(right.getP1(), right.getCtrlP1(), right.getCtrlP2(), right.getP2());
}
protected List<CubicCurve2D> subdivide(double d) {
Point2D[] p = getControlPoints();
Path2D path = new Path2D.Double();
path.moveTo(p[0].getX(), p[0].getY());
if (getPointCount() == PointCount.TWO) {
List<CubicCurve2D> result = new ArrayList<CubicCurve2D>();
result.add(new CubicCurve2D.Double(p[0].getX(), p[0].getY(),
(p[0].getX() + p[1].getX()) / 2,
(p[0].getY() + p[1].getY()) / 2,
(p[0].getX() + p[1].getX()) / 2,
(p[0].getY() + p[1].getY()) / 2,
p[1].getX(), p[1].getY()));
return result;
} else if (getPointCount() == PointCount.THREE) {
CubicCurve2D curve = new CubicCurve2D.Double(p[0].getX(), p[0].getY(),
(p[0].getX() + 2 * p[1].getX()) / 3,
(p[0].getY() + 2 * p[1].getY()) / 3,
(p[2].getX() + 2 * p[1].getX()) / 3,
(p[2].getY() + 2 * p[1].getY()) / 3,
p[2].getX(), p[2].getY());
return subdivide(curve, d);
} else if (getPointCount() == PointCount.FOUR) {
CubicCurve2D curve = new CubicCurve2D.Double(p[0].getX(), p[0].getY(),
p[1].getX(), p[1].getY(),
p[2].getX(), p[2].getY(),
p[3].getX(), p[3].getY());
return subdivide(curve, d);
} else if (getPointCount() == PointCount.FIVE) {
CubicCurve2D curve1 = new CubicCurve2D.Double(p[0].getX(), p[0].getY(),
(p[0].getX() + 2 * p[1].getX()) / 3,
(p[0].getY() + 2 * p[1].getY()) / 3,
(p[2].getX() + 2 * p[1].getX()) / 3,
(p[2].getY() + 2 * p[1].getY()) / 3,
p[2].getX(), p[2].getY());
CubicCurve2D curve2 = new CubicCurve2D.Double(p[2].getX(), p[2].getY(),
(p[2].getX() + 2 * p[3].getX()) / 3,
(p[2].getY() + 2 * p[3].getY()) / 3,
(p[4].getX() + 2 * p[3].getX()) / 3,
(p[4].getY() + 2 * p[3].getY()) / 3,
p[4].getX(), p[4].getY());
return Streams.concat(subdivide(curve1, d).stream(), subdivide(curve2, d).stream()).collect(Collectors.toList());
} else if (getPointCount() == PointCount.SEVEN) {
CubicCurve2D curve1 = new CubicCurve2D.Double(p[0].getX(), p[0].getY(),
p[1].getX(), p[1].getY(),
p[2].getX(), p[2].getY(),
p[3].getX(), p[3].getY());
CubicCurve2D curve2 = new CubicCurve2D.Double(p[3].getX(), p[3].getY(),
p[4].getX(), p[4].getY(),
p[5].getX(), p[5].getY(),
p[6].getX(), p[6].getY());
return Streams.concat(subdivide(curve1, d).stream(), subdivide(curve2, d).stream()).collect(Collectors.toList());
}
return null;
}
private List<CubicCurve2D> subdivide(CubicCurve2D curve, double d) {
if (curve.getFlatness() < d || new Point2D.Double(curve.getX1(), curve.getY1()).distance(curve.getX2(), curve.getY2()) < d) {
List<CubicCurve2D> result = new ArrayList<CubicCurve2D>();
result.add(curve);
return result;
}
CubicCurve2D left = new CubicCurve2D.Double();
CubicCurve2D right = new CubicCurve2D.Double();
curve.subdivide(left, right);
return Streams.concat(subdivide(left, d).stream(), subdivide(right, d).stream()).collect(Collectors.toList());
}
}
@@ -0,0 +1,40 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.components;
import org.diylc.core.annotations.EditableProperty;
public abstract class AbstractLabeledComponent<T> extends AbstractTransparentComponent<T> {
private static final long serialVersionUID = 1L;
protected Integer fontSizeOverride;
@EditableProperty(name = "Font Size Override")
public Integer getFontSizeOverride() {
return fontSizeOverride;
}
public void setFontSizeOverride(Integer fontSizeOverride) {
this.fontSizeOverride = fontSizeOverride;
}
}
@@ -0,0 +1,42 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.components;
import org.diylc.core.annotations.EditableProperty;
public abstract class AbstractTransparentComponent<T> extends AbstractComponent<T> {
private static final long serialVersionUID = 1L;
public static byte MAX_ALPHA = 127;
protected byte alpha = MAX_ALPHA;
@EditableProperty
public Byte getAlpha() {
return alpha;
}
public void setAlpha(Byte alpha) {
this.alpha = alpha;
}
}
@@ -0,0 +1,53 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.components.transform;
import java.awt.geom.Point2D;
import org.diylc.common.IComponentTransformer;
import org.diylc.core.IDIYComponent;
public class DefaultTransformer implements IComponentTransformer {
@Override
public boolean canRotate(IDIYComponent<?> component) {
return false;
}
@Override
public boolean canMirror(IDIYComponent<?> component) {
return false;
}
@Override
public boolean mirroringChangesCircuit() {
return false;
}
@Override
public void rotate(IDIYComponent<?> component, Point2D center, int direction) {
}
@Override
public void mirror(IDIYComponent<?> component, Point2D center, int direction) {
}
}
@@ -0,0 +1,68 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.components.transform;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import org.diylc.common.IComponentTransformer;
import org.diylc.core.IDIYComponent;
public class LeadedComponentTransformer implements IComponentTransformer {
@Override
public boolean canRotate(IDIYComponent<?> component) {
return true;
}
@Override
public boolean canMirror(IDIYComponent<?> component) {
return true;
}
@Override
public boolean mirroringChangesCircuit() {
return false;
}
@Override
public void rotate(IDIYComponent<?> component, Point2D center, int direction) {
AffineTransform rotate = AffineTransform.getRotateInstance(Math.PI / 2 * direction, center.getX(), center.getY());
for (int index = 0; index < component.getControlPointCount(); index++) {
Point2D p = new Point2D.Double();
rotate.transform(component.getControlPoint(index), p);
component.setControlPoint(p, index);
}
}
@Override
public void mirror(IDIYComponent<?> component, Point2D center, int direction) {
for (int i = 0; i < component.getControlPointCount(); i++) {
Point2D p = component.getControlPoint(i);
if (direction == IComponentTransformer.HORIZONTAL) {
component.setControlPoint(new Point2D.Double(p.getX() - 2 * (p.getX() - center.getX()), p.getY()), i);
} else {
component.setControlPoint(new Point2D.Double(p.getX(), p.getY() - 2 * (p.getY() - center.getY())), i);
}
}
}
}
@@ -0,0 +1,69 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.components.transform;
import java.awt.Point;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import org.diylc.common.IComponentTransformer;
import org.diylc.core.IDIYComponent;
public class SimpleComponentTransformer implements IComponentTransformer {
@Override
public boolean canRotate(IDIYComponent<?> component) {
return true;
}
@Override
public boolean canMirror(IDIYComponent<?> component) {
return true;
}
@Override
public boolean mirroringChangesCircuit() {
return false;
}
@Override
public void rotate(IDIYComponent<?> component, Point2D center, int direction) {
AffineTransform rotate = AffineTransform.getRotateInstance(Math.PI / 2 * direction, center.getX(), center.getY());
for (int index = 0; index < component.getControlPointCount(); index++) {
Point2D p = new Point2D.Double();
rotate.transform(component.getControlPoint(index), p);
component.setControlPoint(p, index);
}
}
@Override
public void mirror(IDIYComponent<?> component, Point2D center, int direction) {
for (int i = 0; i < component.getControlPointCount(); i++) {
Point2D p = component.getControlPoint(i);
if (direction == IComponentTransformer.HORIZONTAL) {
component.setControlPoint(new Point2D.Double(p.getX() - 2 * (p.getX() - center.getX()), p.getY()), i);
} else {
component.setControlPoint(new Point.Double(p.getX(), p.getY() - 2 * (p.getY() - center.getY())), i);
}
}
}
}
@@ -0,0 +1,33 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.core;
/**
* Validator that allows all values.
*
* @author Branislav Stojkovic
*/
public class AllowAllValidator implements IPropertyValidator {
@Override
public void validate(Object owner, Object value) throws ValidationException {}
}
@@ -0,0 +1,65 @@
package org.diylc.core;
import java.util.HashMap;
import java.util.Map;
public class Angle {
private int value;
private Angle(int value) {
super();
this.value = value;
}
public int getValue() {
return value;
}
public double getValueRad() {
return Math.toRadians(value);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + value;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Angle other = (Angle) obj;
if (value != other.value)
return false;
return true;
}
@Override
public String toString() {
return Integer.toString(value);
}
private static Map<Integer, Angle> valueCache = new HashMap<Integer, Angle>();
public synchronized static Angle of(int angle) {
int newValue = angle;
while (newValue < 0)
newValue += 360;
while (newValue >= 360)
newValue -= 360;
return valueCache.computeIfAbsent(newValue, (value) -> new Angle(value));
}
public Angle rotate(int direction) {
int newValue = value + direction * 90;
return Angle.of(newValue);
}
}
@@ -0,0 +1,53 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.core;
/**
* Component with all extra info for it to be rendered on the screen.
*
* @author Branislav Stojkovic
*/
public class ComponentForRender {
private IDIYComponent<?> component;
private ComponentState state;
private int zOrder;
public ComponentForRender(IDIYComponent<?> component, ComponentState state, int zOrder) {
super();
this.component = component;
this.state = state;
this.zOrder = zOrder;
}
public IDIYComponent<?> getComponent() {
return component;
}
public ComponentState getState() {
return state;
}
public int getZOrder() {
return zOrder;
}
}
@@ -0,0 +1,32 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.core;
/**
* Enumerates all possible states that a component can be in.
*
* @author Branislav Stojkovic
*/
public enum ComponentState {
NORMAL, SELECTED, LOCKED, DRAGGING
}
@@ -0,0 +1,27 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.core;
public enum CreationMethod {
SINGLE_CLICK, POINT_BY_POINT;
}
@@ -0,0 +1,27 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.core;
public enum ExpansionMode {
ALL, SAME_TYPE, IMMEDIATE,
}
@@ -0,0 +1,29 @@
/*
*
* DIY Layout Creator (DIYLC). Copyright (c) 2009-2018 held jointly by the individual authors.
*
* This file is part of DIYLC.
*
* DIYLC is free software: you can redistribute it and/or modify it under the terms of the GNU
* General Public License as published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* DIYLC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with DIYLC. If not, see
* <http://www.gnu.org/licenses/>.
*
*/
package org.diylc.core;
public interface ICommonNode {
/***
* @return label of the common node. All nodes with the same labels will be considered as
* connected, e.g. B+ or A, B, C
*/
String getCommonNodeLabel();
}
@@ -0,0 +1,34 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.core;
public interface IContinuity {
/**
* Tests control point connectivity.
*
* @param index1
* @param index2
* @return true if the two points are connected, false otherwise.
*/
boolean arePointsConnected(int index1, int index2);
}
@@ -0,0 +1,201 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.core;
import java.awt.Graphics2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.Serializable;
import org.diylc.core.annotations.ComponentDescriptor;
import org.diylc.core.annotations.EditableProperty;
/**
* Interface for component instance. Implementation classes of this interface will be instantiated
* by the application when component is added to the canvas. <br>
* <br>
* <b>Implementing classes should meet the following: </b>
* <ul>
* <li>Must have an empty constructor.</li>
* <li>Class should be annotated with {@link ComponentDescriptor}.</li>
* <li>Getters for properties editable by users should be annotated with {@link EditableProperty}.</li>
* <li>Component configuration should be stored int <code>public static</code> fields so they can be
* set through config file.</li>
* </ul>
*
* @author Branislav Stojkovic
*
* @param <T> type of component values, e.g. Resistance for resistors or String for transistors.
*/
public interface IDIYComponent<T> extends Serializable, Cloneable {
public static final int CHASSIS = 1;
public static final int BOARD = 2;
public static final int TRACE = 3;
public static final int COMPONENT = 4;
public static final int WIRING = 5;
public static final int TEXT = 6;
/**
* @return component instance name.
*/
String getName();
/**
* Updates component instance name.
*
* @param name
*/
void setName(String name);
/**
* @return component value.
*/
T getValue();
/**
* Updates component value.
*
* @param value
*/
void setValue(T value);
/**
* @return number of control points for this component instance. May vary between two instances of
* the same type, e.g. DIL IC with 8 and 16 pins will have 8 or 16 pins although they are
* of the same type.
*/
int getControlPointCount();
/**
* @param index
* @return control point at the specified index.
*/
Point2D getControlPoint(int index);
/**
* Updates the control point at the specified index.
*
* @param point
* @param index
*/
void setControlPoint(Point2D point, int index);
/**
* @param index
* @return true, if the specified control point may stick to control points of other components.
*/
boolean isControlPointSticky(int index);
/**
* @param index
* @return true, if the specified control point may overlap with other control points <b>of the
* same component</b>. The other control point must be able to overlap too.
*/
boolean canControlPointOverlap(int index);
/**
* @param index
* @return {@link VisibilityPolicy} of the control point.
*/
VisibilityPolicy getControlPointVisibilityPolicy(int index);
/**
* @param index
* @return name of the control point node, if the control point represents a graph node, null otherwise.
*/
String getControlPointNodeName(int index);
/**
* @param index1
* @param index2
* @return name of the internal linked formed by the two control points, null if they do not form an internal link
*/
String getInternalLinkName(int index1, int index2);
/**
* @param pointIndex
* @return name of the internal section containing the specified point, or null if the component does not have internal sections.
* One point can be shared between multiple sections, in which case, the result may contain more than one element.
*/
String[] getSectionNames(int pointIndex);
/**
* @param pointIndex
* @return true if the control point can move without affecting other points' position, false otherwise
*/
boolean canPointMoveFreely(int pointIndex);
/**
* Draws the component onto the {@link Graphics2D}.
*
* @param g2d
* @param componentState
* @param outlineMode
* @param project
* @param drawingObserver
*/
void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project,
IDrawingObserver drawingObserver);
/**
* Draws icon representation of the component. This should not depend on component state, i.e. it
* should be treated as a static method.
*
* @param g2d
* @param width
* @param height
*/
void drawIcon(Graphics2D g2d, int width, int height);
/**
* Clones the component.
*
* @return
*/
IDIYComponent<T> clone() throws CloneNotSupportedException;
/**
* @return full value for BOM.
*/
String getValueForDisplay();
/**
* Checks if two components are equal.
*
* @param other
* @return
*/
boolean equalsTo(IDIYComponent<?> other);
/**
* Used only if {@link ComponentDescriptor#enableCache()} is set to true.
* @return
*/
Rectangle2D getCachingBounds();
/**
* Notifies the component that it's being created in the context of the specified project
*
* @param project
*/
void createdIn(Project project);
}
@@ -0,0 +1,27 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.core;
public interface IDatasheetSupport {
void applyModel(String[] model);
}
@@ -0,0 +1,68 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.core;
/**
* Interface for tracking component drawing process. Components may use it to stop or restart
* tracking. Anything drawn while tracking is stopped will not be added to the mouse hot-spot area.
*
* @author Branislav Stojkovic
*/
public interface IDrawingObserver {
/**
* Notifies the observer that it should start tracking the drawing process.
*/
void stopTracking();
/**
* Notifies the observer that it should stop tracking the drawing process.
*/
void startTracking();
/**
* Notifies the observer that it should start tracking conductive continuity areas.
*
* @param positive designates if the area should be additive or subtractive
*/
void startTrackingContinuityArea(boolean positive);
/**
* Notifies the observer that it should stop tracking conductive continuity areas.
*/
void stopTrackingContinuityArea();
/**
* Checks if we are tracking continuity ares.
*
* @return
*/
boolean isTrackingContinuityArea();
/**
* Allows us to connect multiple disjoint continuity areas by specifying the same continuity markers.
* By default it is set to null and does not connect disjoint areas.
*
* @param marker
*/
void setContinuityMarker(String marker);
}
@@ -0,0 +1,6 @@
package org.diylc.core;
public interface ILayeredComponent {
int getLayerId();
}
@@ -0,0 +1,37 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.core;
/**
* Interface for validating property value changes.
*
* @author Branislav Stojkovic
*/
public interface IPropertyValidator {
/**
* @param owner
* @param value
* @throws ValidationException if validation fails. Message will contain the reason.
*/
void validate(Object owner, Object value) throws ValidationException;
}
@@ -0,0 +1,51 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.core;
/**
* Interface for all component that can act as switches. They must have at least one position.
*
* @author Branislav Stojkovic
*/
public interface ISwitch {
/**
* @return a positive number of positions.
*/
int getPositionCount();
/**
* @param position
* @return name of switch positions, e.g. "ON", "OFF"...
*/
String getPositionName(int position);
/**
* Tests control point connectivity.
*
* @param index1
* @param index2
* @param position
* @return true if the two points are connected in the given switch position, false otherwise.
*/
boolean arePointsConnected(int index1, int index2, int position);
}
@@ -0,0 +1,63 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.core;
import java.io.File;
import java.util.List;
import java.util.Set;
import org.diylc.common.PropertyWrapper;
/**
* Base interface for the main GUI component.
*
* @author Branislav Stojkovic
*/
public interface IView {
public static final int ERROR_MESSAGE = 0;
public static final int INFORMATION_MESSAGE = 1;
public static final int WARNING_MESSAGE = 2;
public static final int QUESTION_MESSAGE = 3;
public static final int PLAIN_MESSAGE = -1;
public static final int DEFAULT_OPTION = -1;
public static final int YES_NO_OPTION = 0;
public static final int YES_NO_CANCEL_OPTION = 1;
public static final int OK_CANCEL_OPTION = 2;
public static final int YES_OPTION = 0;
public static final int NO_OPTION = 1;
public static final int CANCEL_OPTION = 2;
public static final int OK_OPTION = 0;
public static final String CHECK_BOX_MENU_ITEM = "org.diylc.checkBoxMenuItem";
public static final String RADIO_BUTTON_GROUP_KEY = "org.diylc.radioButtonGroup";
void showMessage(String message, String title, int messageType);
int showConfirmDialog(String message, String title, int optionType, int messageType);
boolean editProperties(List<PropertyWrapper> properties, Set<PropertyWrapper> defaultedProperties, String title);
String showInputDialog(String message, String title);
File promptFileSave();
}
@@ -0,0 +1,371 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.core;
import java.awt.Font;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.diylc.appframework.update.VersionNumber;
import org.diylc.core.annotations.EditableProperty;
import org.diylc.core.annotations.MultiLineText;
import org.diylc.core.annotations.PositiveMeasureValidator;
import org.diylc.core.annotations.PositiveNonZeroMeasureValidator;
import org.diylc.core.measures.Size;
import org.diylc.core.measures.SizeUnit;
/**
* Entity class that defines a project. Contains project properties and a collection of
* components.This class is serialized to file. Some filed getters are tagged with
* {@link EditableProperty} to enable for user to edit them.
*
* @author Branislav Stojkovic
*/
public class Project implements Serializable, Cloneable {
private static final long serialVersionUID = 1L;
public static String DEFAULT_TITLE = "New Project";
public static Size DEFAULT_WIDTH = new Size(29d, SizeUnit.cm);
public static Size DEFAULT_HEIGHT = new Size(21d, SizeUnit.cm);
public static Size DEFAULT_GRID_SPACING = new Size(0.1d, SizeUnit.in);
public static Font DEFAULT_FONT = new Font("Square721 BT", Font.PLAIN, 14);
private VersionNumber fileVersion;
private String title;
private String author;
private String description;
private Size width;
private Size height;
private Size gridSpacing;
private Integer dotSpacing;
private List<IDIYComponent<?>> components;
private Set<Set<IDIYComponent<?>>> groups;
private Set<Integer> lockedLayers;
private Set<IDIYComponent<?>> lockedComponents;
private Set<Integer> hiddenLayers;
private Font font = DEFAULT_FONT;
public Project() {
components = new ArrayList<IDIYComponent<?>>();
groups = new HashSet<Set<IDIYComponent<?>>>();
lockedLayers = new HashSet<Integer>();
hiddenLayers = new HashSet<Integer>();
lockedComponents = new HashSet<IDIYComponent<?>>();
title = DEFAULT_TITLE;
author = System.getProperty("user.name");
width = DEFAULT_WIDTH;
height = DEFAULT_HEIGHT;
gridSpacing = DEFAULT_GRID_SPACING;
}
@EditableProperty(defaultable = false, sortOrder = 1)
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
@EditableProperty(sortOrder = 3)
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
@MultiLineText
@EditableProperty(defaultable = false, sortOrder = 2)
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
@EditableProperty(sortOrder = 4)
public Size getWidth() {
return width;
}
public void setWidth(Size width) {
this.width = width;
}
@EditableProperty(sortOrder = 5)
public Size getHeight() {
return height;
}
public void setHeight(Size height) {
this.height = height;
}
@EditableProperty(name = "Grid Spacing", validatorClass = SpacingValidator.class, sortOrder = 6)
public Size getGridSpacing() {
return gridSpacing;
}
public void setGridSpacing(Size gridSpacing) {
this.gridSpacing = gridSpacing;
}
@EditableProperty(name = "Dot Spacing", validatorClass = PositiveNonZeroMeasureValidator.class)
public Integer getDotSpacing() {
if (dotSpacing == null)
dotSpacing = 1;
return dotSpacing;
}
public void setDotSpacing(Integer dotSpacing) {
this.dotSpacing = dotSpacing;
}
/**
* List of components sorted by z-order ascending.
*
* @return
*/
public List<IDIYComponent<?>> getComponents() {
return components;
}
/**
* Set of grouped components.
*
* @return
*/
public Set<Set<IDIYComponent<?>>> getGroups() {
return groups;
}
public Set<IDIYComponent<?>> getLockedComponents() {
if (lockedComponents == null)
lockedComponents = new HashSet<IDIYComponent<?>>();
return lockedComponents;
}
public Set<Integer> getLockedLayers() {
return lockedLayers;
}
public Set<Integer> getHiddenLayers() {
if (hiddenLayers == null)
hiddenLayers = new HashSet<Integer>();
return hiddenLayers;
}
public VersionNumber getFileVersion() {
return fileVersion;
}
public void setFileVersion(VersionNumber fileVersion) {
this.fileVersion = fileVersion;
}
@EditableProperty(name = "Default Font")
public Font getFont() {
if (font == null)
font = DEFAULT_FONT;
return font;
}
public void setFont(Font font) {
this.font = font;
}
@EditableProperty(name = "Default Font Size")
public int getFontSize() {
if (font == null)
font = DEFAULT_FONT;
return font.getSize();
}
public void setFontSize(int size) {
font = font.deriveFont((float) size);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((author == null) ? 0 : author.hashCode());
result = prime * result + ((components == null) ? 0 : components.hashCode());
result = prime * result + ((description == null) ? 0 : description.hashCode());
result = prime * result + ((height == null) ? 0 : height.hashCode());
result = prime * result + ((title == null) ? 0 : title.hashCode());
result = prime * result + ((width == null) ? 0 : width.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Project other = (Project) obj;
if (author == null) {
if (other.author != null)
return false;
} else if (!author.equals(other.author))
return false;
if (components == null) {
if (other.components != null)
return false;
} else if (components.size() != other.components.size()) {
return false;
} else {
Iterator<IDIYComponent<?>> i1 = components.iterator();
Iterator<IDIYComponent<?>> i2 = other.components.iterator();
while (i1.hasNext()) {
IDIYComponent<?> c1 = i1.next();
IDIYComponent<?> c2 = i2.next();
if (!c1.equalsTo(c2))
return false;
}
}
if (description == null) {
if (other.description != null)
return false;
} else if (!description.equals(other.description))
return false;
if (height == null) {
if (other.height != null)
return false;
} else if (!height.equals(other.height))
return false;
if (title == null) {
if (other.title != null)
return false;
} else if (!title.equals(other.title))
return false;
if (width == null) {
if (other.width != null)
return false;
} else if (!width.equals(other.width))
return false;
if (gridSpacing == null) {
if (other.gridSpacing != null)
return false;
} else if (!gridSpacing.equals(other.gridSpacing))
return false;
if (font == null) {
if (other.font != null)
return false;
} else if (!font.getFamily().equals(other.font.getFamily()) || font.getSize() != other.font.getSize() || font.getStyle() != other.font.getStyle())
return false;
if (groups == null) {
if (other.groups != null)
return false;
} else if (!groups.equals(other.groups))
return false;
if (lockedLayers == null) {
if (other.lockedLayers != null)
return false;
} else if (!lockedLayers.equals(other.lockedLayers))
return false;
if (getLockedComponents() == null) {
if (other.lockedComponents != null)
return false;
} else if (!getLockedComponents().equals(other.lockedComponents))
return false;
if (hiddenLayers == null) {
if (other.hiddenLayers != null)
return false;
} else if (!hiddenLayers.equals(other.hiddenLayers))
return false;
return true;
}
@Override
public String toString() {
return title;
}
public static class SpacingValidator extends PositiveMeasureValidator {
@Override
public void validate(Object owner, Object value) throws ValidationException {
super.validate(owner, value);
Size size = (Size) value;
if (size.compareTo(new Size(0.1d, SizeUnit.mm)) < 0) {
throw new ValidationException("must be at least 0.1mm");
}
if (size.compareTo(new Size(1d, SizeUnit.in)) > 0) {
throw new ValidationException("must be less than 1in");
}
}
}
@Override
public Project clone() {
Project project = new Project();
project.setTitle(this.getTitle());
project.setAuthor(this.getAuthor());
project.setDescription(this.getDescription());
project.setFileVersion(this.getFileVersion());
project.setGridSpacing(this.getGridSpacing());
project.setHeight(this.getHeight());
project.setWidth(this.getWidth());
project.getLockedLayers().addAll(this.getLockedLayers());
project.getHiddenLayers().addAll(this.getHiddenLayers());
project.setFont(this.getFont());
Map<IDIYComponent<?>, IDIYComponent<?>> cloneMap = new HashMap<IDIYComponent<?>, IDIYComponent<?>>();
for (IDIYComponent<?> component : this.components) {
try {
IDIYComponent<?> clone = component.clone();
project.getComponents().add(clone);
cloneMap.put(component, clone);
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
for (Set<IDIYComponent<?>> group : this.groups) {
Set<IDIYComponent<?>> cloneGroup = new HashSet<IDIYComponent<?>>();
for (IDIYComponent<?> component : group) {
cloneGroup.add(cloneMap.get(component));
}
project.groups.add(cloneGroup);
}
for (IDIYComponent<?> component : this.getLockedComponents()) {
project.lockedComponents.add(cloneMap.get(component));
}
return project;
}
}
@@ -0,0 +1,132 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.core;
import java.awt.geom.Point2D;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
public class Template {
private String name;
private Map<String, Object> values;
private List<Point2D> points;
@SuppressWarnings("unused")
@Deprecated
private boolean defaultFlag;
private LocalDateTime createdOn;
public Template() {
}
public Template(String name, Map<String, Object> values, List<Point2D> points) {
this(name, values, points, LocalDateTime.now());
}
public Template(String name, Map<String, Object> values, List<Point2D> points, LocalDateTime createdOn) {
this.name = name;
this.values = values;
this.points = points;
this.createdOn = createdOn;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Map<String, Object> getValues() {
return values;
}
public void setValues(Map<String, Object> values) {
this.values = values;
}
public List<Point2D> getPoints() {
return points;
}
public void setPoints(List<Point2D> points) {
this.points = points;
}
public LocalDateTime getCreatedOn() {
return createdOn;
}
public void setCreatedOn(LocalDateTime createdOn) {
this.createdOn = createdOn;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((createdOn == null) ? 0 : createdOn.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((points == null) ? 0 : points.hashCode());
result = prime * result + ((values == null) ? 0 : values.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Template other = (Template) obj;
if (createdOn == null) {
if (other.createdOn != null)
return false;
} else if (!createdOn.equals(other.createdOn))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (points == null) {
if (other.points != null)
return false;
} else if (!points.equals(other.points))
return false;
if (values == null) {
if (other.values != null)
return false;
} else if (!values.equals(other.values))
return false;
return true;
}
@Override
public String toString() {
return name;
}
}
@@ -0,0 +1,97 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.core;
import java.awt.Color;
import java.io.Serializable;
public class Theme implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private Color bgColor;
private Color gridColor;
private Color outlineColor;
private Color dotColor;
public Theme(String name, Color bgColor, Color gridColor, Color dotColor, Color outlineColor) {
super();
this.name = name;
this.bgColor = bgColor;
this.gridColor = gridColor;
this.dotColor = dotColor;
this.outlineColor = outlineColor;
}
public String getName() {
return name;
}
public Color getBgColor() {
return bgColor;
}
public Color getGridColor() {
return gridColor;
}
public Color getDotColor() {
if (dotColor == null)
dotColor = gridColor;
return dotColor;
}
public Color getOutlineColor() {
return outlineColor;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Theme other = (Theme) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
@Override
public String toString() {
return name;
}
}
@@ -0,0 +1,31 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.core;
public class ValidationException extends Exception {
private static final long serialVersionUID = 1L;
public ValidationException(String message) {
super(message);
}
}
@@ -0,0 +1,43 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.core;
/**
* Enumerates control point visibility policies.
*
* @author Branislav Stojkovic
*/
public enum VisibilityPolicy {
/**
* Control point should be rendered all the time.
*/
ALWAYS,
/**
* Control point should be rendered only when the component is selected.
*/
WHEN_SELECTED,
/**
* Control point should not be rendered regardless of component selection.
*/
NEVER;
}
@@ -0,0 +1,5 @@
package org.diylc.core.annotations;
public enum BinaryType {
IMAGE, SVG
}
@@ -0,0 +1,33 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.core.annotations;
/**
* Tells the system how to represent components in the B.O.M.
*
* @see ComponentDescriptor
*
* @author Branislav Stojkovic
*/
public enum BomPolicy {
SHOW_ALL_NAMES, SHOW_ONLY_TYPE_NAME, NEVER_SHOW,
}
@@ -0,0 +1,31 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.core.annotations;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface ByteArrayProperty {
public BinaryType binaryType();
}
@@ -0,0 +1,130 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.core.annotations;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import org.diylc.common.DefaultComponentTransformer;
import org.diylc.common.IComponentTransformer;
import org.diylc.core.CreationMethod;
import org.diylc.core.IDIYComponent;
/**
* Annotation that needs to be used for each {@link IDIYComponent} implementation. Describes
* component properties and how component should be represented and interact with the rest of the
* system.
*
* @author Branislav Stojkovic
*/
@Retention(RetentionPolicy.RUNTIME)
public @interface ComponentDescriptor {
/**
* @return component type name.
*/
String name();
/**
* @return component type description.
*/
String description();
/**
* @return method that should be used to create a component. If
* <code>CreationMethod.POINT_BY_POINT</code> is used, user will have to select ending
* points before the component is created.
*/
CreationMethod creationMethod() default CreationMethod.SINGLE_CLICK;
/**
* @return component category, e.g. "Passive", "Semiconductors", etc.
*/
String category();
/**
* @return component author name.
*/
String author();
/**
* @return prefix that will be used to generate component instance names, e.g. "R" for resistors
* or "Q" for transistors.
*/
String instanceNamePrefix();
/**
* @return Z-order of the component.
*/
double zOrder();
/**
* @return true if the component may go beyond it's predefined layer without warning the user.
*/
boolean flexibleZOrder() default false;
/**
* @return controls what should be shown the BOM
*/
BomPolicy bomPolicy() default BomPolicy.SHOW_ALL_NAMES;
/**
* @return when true, component editor dialog should be shown in Auto-Edit mode.
*/
boolean autoEdit() default true;
/**
* @return if the component can be rotated and/or mirrored, returns a class of the transformer that can do it
*/
Class<? extends IComponentTransformer> transformer() default DefaultComponentTransformer.class;
/**
* Defines if and how a component should appear in auto-generated project keywords. See
* {@link KeywordPolicy} for more info.
*
* @return
*/
KeywordPolicy keywordPolicy() default KeywordPolicy.NEVER_SHOW;
/**
* Only used if {@link KeywordPolicy} is set to {@link KeywordPolicy#SHOW_TAG}.
*
* @return
*/
String keywordTag() default "";
/**
* @return true if the component drawing should be cached
*/
boolean enableCache() default false;
/**
* @return true if component datasheet should be loaded from the corresponding file
*/
boolean enableDatasheet() default false;
/**
* If datasheet is enabled, this property determines how many columns define a component, e.g. in how many steps we can instantiate a component
*
* @return
*/
int datasheetCreationStepCount() default 0;
}
@@ -0,0 +1,31 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.core.annotations;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface DynamicList {
public String availableValueFunction();
}
@@ -0,0 +1,86 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.core.annotations;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import org.diylc.core.AllowAllValidator;
import org.diylc.core.IPropertyValidator;
/**
* Used to annotate editable component property. Editable property XYZ must have both getter and
* setter named <code>getXYZ</code> and <code>setXYZ</code> respectively and this annotation must be
* placed on the getter method. <br>
* <br>
* In the example below, {@code category} is the property we want to edit and
* {@code getCategories()} provides a list of available values for category.
*
* <pre>
* <code>
* &#64;EditableProperty(additionalOptions = EditableProperty.DYNAMIC_LIST
* + "getCategories")
* public String getCategory() {
* return category;
* }
*
* public String[] getCategories() {
* return categories;
* }
* </code>
* </pre>
*
* @author Branislav Stojkovic
*/
@Retention(RetentionPolicy.RUNTIME)
public @interface EditableProperty {
/**
* Returns property name. If left blank property name will be extracted from the getter name, e.g.
* getter <code>getXYZ</code> will induce property name <code>XYZ</code>. <br>
* Default value is blank.
*
* @return
*/
String name() default "";
/**
* If true, application may set default value for this property. <br>
* Default value is true.
*
* @return
*/
boolean defaultable() default true;
/**
* Class of validator to use to
*
* @return
*/
Class<? extends IPropertyValidator> validatorClass() default AllowAllValidator.class;
/**
* Optional parameter in case we want to force an order of properties.
*
* @return
*/
int sortOrder() default 100;
}
@@ -0,0 +1,27 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.core.annotations;
public @interface ElementLabel {
public String functionName();
}
@@ -0,0 +1,41 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.core.annotations;
import java.util.List;
import org.diylc.core.IDIYComponent;
/**
* Interface for creating components automatically each time a component is created by the user.
*
* @author Branislav Stojkovic
*/
public interface IAutoCreator {
/**
* @param lastAdded the component created by the user
* @return {@link List} of {@link IDIYComponent}s that will be automatically created as a result.
* Empty {@link List} or {@code null} are valid responses for cases when no components
* should be auto-created.
*/
public List<IDIYComponent<?>> createIfNeeded(IDIYComponent<?> lastAdded);
}
@@ -0,0 +1,53 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.core.annotations;
/**
* Tells the system how keywords should be extracted from a component.
*
* @see ComponentDescriptor
*
* @author Branislav Stojkovic
*/
public enum KeywordPolicy {
/**
* The component is represented with its type.
*/
SHOW_TYPE_NAME,
/**
* The component is represented with its value.
*/
SHOW_VALUE,
/**
* The component is not important enough and will not be shown in the keywords.
*/
NEVER_SHOW,
/**
* The component is represented with the value of {@link ComponentDescriptor#keywordTag()}
*/
SHOW_TAG,
/**
* The component is represented with both the value of {@link ComponentDescriptor#keywordTag()}
* and the actual component value
*/
SHOW_TAG_AND_VALUE,
}
@@ -0,0 +1,30 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.core.annotations;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface MultiLineText {
}
@@ -0,0 +1,31 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.core.annotations;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface PercentEditor {
public byte _100PercentValue();
}
@@ -0,0 +1,53 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.core.annotations;
import org.diylc.core.IPropertyValidator;
import org.diylc.core.ValidationException;
import org.diylc.core.measures.AbstractMeasure;
/**
* Validates any generic {@link AbstractMeasure} descendants and makes sure that the value is
* positive.
*
* @author Branislav Stojkovic
*/
public class PositiveMeasureValidator implements IPropertyValidator {
@Override
public void validate(Object owner, Object value) throws ValidationException {
if (value == null)
return;
if (value instanceof AbstractMeasure) {
AbstractMeasure<?> measure = (AbstractMeasure<?>) value;
if (measure.getValue() < 0) {
throw new ValidationException("must be greater or equal to zero.");
}
} else if (value instanceof Integer) {
Integer i = (Integer) value;
if (i < 0)
throw new ValidationException("must be greater or equal to zero.");
} else {
throw new ValidationException("wrong data type.");
}
}
}
@@ -0,0 +1,53 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.core.annotations;
import org.diylc.core.IPropertyValidator;
import org.diylc.core.ValidationException;
import org.diylc.core.measures.AbstractMeasure;
/**
* Validates any generic {@link AbstractMeasure} descendants and makes sure that the value is
* positive.
*
* @author Branislav Stojkovic
*/
public class PositiveNonZeroMeasureValidator implements IPropertyValidator {
@Override
public void validate(Object owner, Object value) throws ValidationException {
if (value == null)
return;
if (value instanceof AbstractMeasure) {
AbstractMeasure<?> measure = (AbstractMeasure<?>) value;
if (measure.getValue() <= 0) {
throw new ValidationException("must be greater than zero.");
}
} else if (value instanceof Integer) {
Integer i = (Integer) value;
if (i < 0)
throw new ValidationException("must be greater or equal to zero.");
} else {
throw new ValidationException("wrong data type.");
}
}
}
@@ -0,0 +1,157 @@
package org.diylc.core.gerber;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.log4j.Logger;
import org.diylc.core.ComponentState;
import org.diylc.core.IDIYComponent;
import org.diylc.core.IView;
import org.diylc.core.Project;
import org.diylc.core.measures.Size;
import org.diylc.core.measures.SizeUnit;
import org.diylc.lang.LangUtil;
import com.bancika.gerberwriter.DataLayer;
public class GerberExporter {
public static final double OUTLINE_THICKNESS = new Size(0.3d, SizeUnit.mm).convertToPixels();
private static final Logger LOG = Logger.getLogger(GerberExporter.class);
public static void exportGerber(String fileNameBase, Project currentProject, IView view,
Graphics2D graphics2d, String diylcVersion) {
List<IGerberBoard> gerberBoards =
currentProject.getComponents().stream().filter(c -> c instanceof IGerberBoard)
.map(x -> (IGerberBoard) x).collect(Collectors.toList());
Map<IGerberBoard, List<IDIYComponent<?>>> boardComponentMap =
new HashMap<IGerberBoard, List<IDIYComponent<?>>>();
// DefaultGerberBoard defaultGerberBoard = new DefaultGerberBoard();
List<IDIYComponent<?>> componentsWithoutBoard = new ArrayList<IDIYComponent<?>>();
currentProject.getComponents().stream().filter(c -> c instanceof IGerberComponent)
.forEach(c -> {
Point2D firstPoint = c.getControlPoint(0);
IGerberBoard board = gerberBoards.stream()
.filter(b -> b.getBoardRectangle().contains(firstPoint)).findFirst().orElse(null);
if (board == null) {
componentsWithoutBoard.add(c);
} else {
boardComponentMap.computeIfAbsent(board, k -> new ArrayList<IDIYComponent<?>>()).add(c);
}
});
// defaultGerberBoard.setComponents(boardComponentMap.get(defaultGerberBoard));
if (boardComponentMap.isEmpty()) {
view.showMessage(LangUtil.translate("Nothing to export."),
LangUtil.translate("Gerber Export"), IView.WARNING_MESSAGE);
return;
}
if (componentsWithoutBoard.size() > 0) {
if (view.showConfirmDialog(String.format(
LangUtil.translate("There are some components that are outside of the bounds of boards.%s"
+ "They will be ignored unless you add a board component underneath them.%sDo you want to continue?"),
"\n", "\n"), LangUtil.translate("Gerber Export"), IView.YES_NO_OPTION,
IView.WARNING_MESSAGE) != IView.YES_OPTION) {
return;
}
}
List<String> generatedFiles = new ArrayList<String>();
gerberBoards.forEach(b -> {
IDIYComponent<?> boardComponent = (IDIYComponent<?>) b;
GerberLayer gerberLayer = GerberLayer.Outline;
DataLayer outlineLayer = gerberLayer.buildLayer(diylcVersion);
Rectangle2D boardRect = b.getBoardRectangle();
final AffineTransform boardTx = AffineTransform.getScaleInstance(1, -1);
boardTx.translate(-boardRect.getX(), -boardRect.getMaxY());
final PathIterator pathIterator = boardRect.getPathIterator(boardTx);
GerberPathRenderer.outputPathOutline(pathIterator, outlineLayer, 1d, false, "Profile", OUTLINE_THICKNESS);
String fileNameOutline = GerberLayer.Outline.formatFileName(fileNameBase, boardComponent.getName());
try {
LOG.info(String.format(LangUtil.translate("Exporting outline for board %s to file %s"),
boardComponent.getName(), fileNameOutline));
outlineLayer.dumpGerberToFile(fileNameOutline);
generatedFiles.add(fileNameOutline);
} catch (IOException e) {
LOG.error("Error writing gerber file: " + e.getMessage());
view.showMessage(
LangUtil.translate(
"Failed to export the project to gerber. Please check the log for details"),
LangUtil.translate("Gerber Export"), IView.ERROR_MESSAGE);
return;
}
GerberG2DWrapper g2d = new GerberG2DWrapper(graphics2d, diylcVersion, boardRect);
boardComponentMap.get(b).forEach(c -> {
IGerberComponent gerberComponent = (IGerberComponent) c;
Set<GerberRenderMode> supportedRenderModes = gerberComponent.getGerberRenderModes();
if (supportedRenderModes.contains(GerberRenderMode.Normal)) {
drawComponent(currentProject, g2d, c, false);
}
if (supportedRenderModes.contains(GerberRenderMode.Outline)) {
drawComponent(currentProject, g2d, c, true);
}
});
g2d.getLayerMap().entrySet().forEach(entry -> {
org.diylc.core.gerber.GerberLayer layer = entry.getKey();
DataLayer dataLayer = entry.getValue();
try {
String fileName = layer.formatFileName(fileNameBase, boardComponent.getName());
LOG.info("Exporting layer: " + layer + " for board " + boardComponent.getName()
+ " to file: " + fileName);
dataLayer.dumpGerberToFile(fileName);
generatedFiles.add(fileName);
} catch (IOException e) {
LOG.error("Error writing gerber file: " + e.getMessage());
view.showMessage(
LangUtil.translate(
"Failed to export the project to gerber. Please check the log for details"),
LangUtil.translate("Gerber Export"), IView.ERROR_MESSAGE);
return;
}
});
});
view.showMessage(
String.format(
LangUtil.translate(
"Gerber export completed successfully. The following files were created:%s"),
"\n\n" + String.join("\n", generatedFiles)),
LangUtil.translate("Gerber Export"), IView.INFORMATION_MESSAGE);
LOG.info("Completed export to gerber");
}
private static void drawComponent(Project currentProject, GerberG2DWrapper g2d,
IDIYComponent<?> c, boolean outlineMode) {
IGerberComponent gerberComponent = (IGerberComponent) c;
g2d.startedDrawingComponent();
if (gerberComponent instanceof IGerberComponentCustom) {
IGerberComponentCustom gerberComponentCustom = (IGerberComponentCustom) gerberComponent;
gerberComponentCustom.draw(g2d, ComponentState.NORMAL, outlineMode, currentProject, g2d, g2d);
} else if (gerberComponent instanceof IGerberComponentSimple) {
IGerberComponentSimple gerberComponentSimple = (IGerberComponentSimple) gerberComponent;
g2d.startGerberOutput(gerberComponentSimple.getGerberLayer(),
gerberComponentSimple.getGerberFunction(), gerberComponentSimple.isGerberNegative());
c.draw(g2d, ComponentState.NORMAL, outlineMode, currentProject, g2d);
g2d.stopGerberOutput();
}
}
}
@@ -0,0 +1,552 @@
package org.diylc.core.gerber;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.Image;
import java.awt.Paint;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.RenderingHints.Key;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.awt.image.ImageObserver;
import java.awt.image.RenderedImage;
import java.awt.image.renderable.RenderableImage;
import java.text.AttributedCharacterIterator;
import java.util.HashMap;
import java.util.Map;
import org.diylc.core.IDrawingObserver;
import org.diylc.core.measures.SizeUnit;
import org.diylc.utils.Constants;
import com.bancika.gerberwriter.DataLayer;
import com.bancika.gerberwriter.Point;
import com.bancika.gerberwriter.padmasters.Circle;
public class GerberG2DWrapper extends Graphics2D
implements IDrawingObserver, IGerberDrawingObserver {
private static final double CURVE_APPROXIMATION_TOLERANCE = 1d;
private Map<GerberLayer, DataLayer> layerMap;
private boolean trackingGerber = false;
private Map<GerberLayer, GerberProperties> currentLayers =
new HashMap<GerberLayer, GerberProperties>();
private String diylcVersion;
private Graphics2D graphics2d;
private Color color;
private Stroke stroke;
private Font font;
private AffineTransform tx;
private double tolerance;
private Rectangle2D boardRect;
public GerberG2DWrapper(Graphics2D graphics2d, String diylcVersion, Rectangle2D boardRect) {
super();
this.graphics2d = graphics2d;
this.boardRect = boardRect;
this.layerMap = new HashMap<GerberLayer, DataLayer>();
this.diylcVersion = diylcVersion;
}
public void startedDrawingComponent() {
this.tx = new AffineTransform();
this.tolerance = Double.NaN;
}
public boolean isTrackingGerber() {
return trackingGerber;
}
@Override
public void stopTracking() {
// TODO Auto-generated method stub
}
@Override
public void startTracking() {
// TODO Auto-generated method stub
}
@Override
public void startTrackingContinuityArea(boolean positive) {
// TODO Auto-generated method stub
}
@Override
public void stopTrackingContinuityArea() {
// TODO Auto-generated method stub
}
@Override
public boolean isTrackingContinuityArea() {
// TODO Auto-generated method stub
return false;
}
@Override
public void setContinuityMarker(String marker) {
// TODO Auto-generated method stub
}
@Override
public void startGerberOutput(GerberLayer layer, String function, boolean negative) {
layerMap.computeIfAbsent(layer, k -> layer.buildLayer(diylcVersion));
currentLayers.put(layer, new GerberProperties(function, negative));
trackingGerber = true;
}
@Override
public void setGerberFunction(GerberLayer layer, String function) {
currentLayers.get(layer).function = function;
}
@Override
public void setGerberNegative(GerberLayer layer, boolean negative) {
currentLayers.get(layer).negative = negative;
}
@Override
public void setApproximationToleranceOverride(double tolerance) {
this.tolerance = tolerance;
// TODO Auto-generated method stub
}
@Override
public void stopGerberOutput(GerberLayer layer) {
currentLayers.remove(layer);
if (currentLayers.isEmpty()) {
trackingGerber = false;
}
}
@Override
public void stopGerberOutput() {
currentLayers.clear();
trackingGerber = false;
}
public Map<GerberLayer, DataLayer> getLayerMap() {
return layerMap;
}
@Override
public void draw(Shape s) {
if (trackingGerber && !getColor().equals(Constants.TRANSPARENT_COLOR)) {
currentLayers.entrySet().forEach(entry -> {
double width = 1;
if (stroke != null && stroke instanceof BasicStroke) {
width = ((BasicStroke) stroke).getLineWidth();
}
DataLayer dataLayer = layerMap.get(entry.getKey());
AffineTransform finalTx = getFinalTx(entry.getKey().isMirrored());
GerberPathRenderer.outputPathOutline(s.getPathIterator(finalTx), dataLayer,
Double.isNaN(tolerance) ? CURVE_APPROXIMATION_TOLERANCE : tolerance,
entry.getValue().negative, entry.getValue().function, width);
});
}
}
@Override
public void drawString(String str, float x, float y) {
if (str == null || str.trim().isEmpty()) {
return;
}
GlyphVector gv = font.createGlyphVector(graphics2d.getFontRenderContext(), str);
AffineTransform translateInstance = AffineTransform.getTranslateInstance(x, y);
for (int i = 0; i < gv.getNumGlyphs(); i++) {
Shape glyphShape = gv.getGlyphOutline(i);
fillShape(translateInstance.createTransformedShape(glyphShape));
}
// Font f = getFont();
// TextLayout layout = new TextLayout(str, f, graphics2d.getFontRenderContext());
// Shape shape = layout.getOutline(AffineTransform.getTranslateInstance(x, y));
// fillShape(shape);
}
@Override
public void fill(Shape s) {
if (s instanceof Ellipse2D
&& (((Ellipse2D) s).getWidth() - ((Ellipse2D) s).getHeight()) < 0.1) {
Ellipse2D e = (Ellipse2D) s;
fillFlash(e);
} else {
fillShape(s);
}
}
public void fillShape(Shape s) {
if (trackingGerber && !getColor().equals(Constants.TRANSPARENT_COLOR)) {
currentLayers.entrySet().forEach(entry -> {
DataLayer dataLayer = layerMap.get(entry.getKey());
AffineTransform finalTx = getFinalTx(entry.getKey().isMirrored());
GerberPathRenderer.outputPathArea(s.getPathIterator(finalTx), dataLayer,
Double.isNaN(tolerance) ? CURVE_APPROXIMATION_TOLERANCE : tolerance,
entry.getValue().negative, entry.getValue().function);
});
}
}
private void fillFlash(Ellipse2D c) {
if (trackingGerber && !getColor().equals(Constants.TRANSPARENT_COLOR)) {
currentLayers.entrySet().forEach(entry -> {
DataLayer dataLayer = layerMap.get(entry.getKey());
AffineTransform finalTx = getFinalTx(entry.getKey().isMirrored());
if (Math.abs(c.getWidth() - c.getHeight()) < 0.1 && finalTx.getShearX() == 0
&& finalTx.getShearY() == 0
&& Math.abs(Math.abs(finalTx.getScaleX()) - Math.abs(finalTx.getScaleY())) < 0.0001) {
final double d = Math.abs(c.getWidth() * finalTx.getScaleX()) * SizeUnit.px.getFactor();
Circle circle = new Circle(d, entry.getValue().function, entry.getValue().negative);
dataLayer.addPad(circle, new Point(
(c.getX() * finalTx.getScaleX() + finalTx.getTranslateX()) * SizeUnit.px.getFactor()
+ (entry.getKey().isMirrored() ? -1 : 1) * d / 2,
(c.getY() * finalTx.getScaleY() + finalTx.getTranslateY()) * SizeUnit.px.getFactor()
- d / 2));
} else {
// not a circle after transformation, default to polygon approximation
fillShape(c);
}
});
}
}
private AffineTransform getFinalTx(boolean isMirrored) {
AffineTransform finalTx = new AffineTransform();
if (isMirrored) {
finalTx.translate(boardRect.getWidth(), 0);
finalTx.scale(-1, 1);
}
finalTx.scale(1, -1);
finalTx.translate(-boardRect.getMinX(), -boardRect.getMaxY());
finalTx.concatenate(tx);
return finalTx;
}
@Override
public RenderingHints getRenderingHints() {
return null;
}
@Override
public void translate(int x, int y) {
this.tx.translate(x, y);
}
@Override
public void translate(double tx, double ty) {
this.tx.translate(tx, ty);
}
@Override
public void rotate(double theta) {
this.tx.rotate(theta);
}
@Override
public void rotate(double theta, double x, double y) {
this.tx.rotate(theta, x, y);
}
@Override
public void scale(double sx, double sy) {
this.tx.scale(sx, sy);
}
@Override
public void shear(double shx, double shy) {
this.tx.shear(shx, shy);
}
@Override
public void transform(AffineTransform Tx) {
this.tx.concatenate(Tx);
}
@Override
public void setTransform(AffineTransform Tx) {
this.tx = Tx;
}
@Override
public AffineTransform getTransform() {
return tx;
}
@Override
public FontRenderContext getFontRenderContext() {
return graphics2d.getFontRenderContext();
}
@Override
public Color getColor() {
return color;
}
@Override
public void setColor(Color c) {
this.color = c;
}
@Override
public Font getFont() {
return this.font;
}
@Override
public void setFont(Font font) {
this.font = font;
}
@Override
public FontMetrics getFontMetrics(Font f) {
return graphics2d.getFontMetrics(f);
}
@Override
public void setStroke(Stroke s) {
this.stroke = s;
}
@Override
public Stroke getStroke() {
return stroke;
}
@Override
public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints) {
fillShape(new Polygon(xPoints, yPoints, nPoints));
}
@Override
public void drawString(String str, int x, int y) {
drawString(str, (float) x, (float) y);
}
@Override
public void drawLine(int x1, int y1, int x2, int y2) {
draw(new Line2D.Double(x1, y1, x2, y2));
}
@Override
public void fillRect(int x, int y, int width, int height) {
fillShape(new Rectangle2D.Double(x, y, width, height));
}
@Override
public void drawOval(int x, int y, int width, int height) {
draw(new Ellipse2D.Double(x, y, width, height));
}
@Override
public void fillOval(int x, int y, int width, int height) {
if (width == height) {
fillFlash(new Ellipse2D.Double(x, y, width, height));
} else {
fillShape(new Ellipse2D.Double(x, y, width, height));
}
}
@Override
public boolean drawImage(Image img, AffineTransform xform, ImageObserver obs) {
return false;
}
@Override
public void drawImage(BufferedImage img, BufferedImageOp op, int x, int y) {}
@Override
public void drawRenderedImage(RenderedImage img, AffineTransform xform) {}
@Override
public void drawRenderableImage(RenderableImage img, AffineTransform xform) {}
@Override
public void drawString(AttributedCharacterIterator iterator, int x, int y) {}
@Override
public void drawString(AttributedCharacterIterator iterator, float x, float y) {}
@Override
public void drawGlyphVector(GlyphVector g, float x, float y) {}
@Override
public boolean hit(Rectangle rect, Shape s, boolean onStroke) {
return false;
}
@Override
public GraphicsConfiguration getDeviceConfiguration() {
return null;
}
@Override
public void setComposite(Composite comp) {}
@Override
public void setPaint(Paint paint) {}
@Override
public void setRenderingHint(Key hintKey, Object hintValue) {}
@Override
public Object getRenderingHint(Key hintKey) {
return null;
}
@Override
public void setRenderingHints(Map<?, ?> hints) {}
@Override
public void addRenderingHints(Map<?, ?> hints) {}
@Override
public Paint getPaint() {
return null;
}
@Override
public Composite getComposite() {
return null;
}
@Override
public void setBackground(Color color) {}
@Override
public Color getBackground() {
return null;
}
@Override
public void clip(Shape s) {}
@Override
public Graphics create() {
return null;
}
@Override
public void setPaintMode() {}
@Override
public void setXORMode(Color c1) {}
@Override
public Rectangle getClipBounds() {
return null;
}
@Override
public void clipRect(int x, int y, int width, int height) {}
@Override
public void setClip(int x, int y, int width, int height) {}
@Override
public Shape getClip() {
return null;
}
@Override
public void setClip(Shape clip) {}
@Override
public void copyArea(int x, int y, int width, int height, int dx, int dy) {}
@Override
public void clearRect(int x, int y, int width, int height) {}
@Override
public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) {}
@Override
public void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) {}
@Override
public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) {}
@Override
public void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle) {}
@Override
public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints) {}
@Override
public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) {}
@Override
public boolean drawImage(Image img, int x, int y, ImageObserver observer) {
return false;
}
@Override
public boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) {
return false;
}
@Override
public boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer) {
return false;
}
@Override
public boolean drawImage(Image img, int x, int y, int width, int height, Color bgcolor,
ImageObserver observer) {
return false;
}
@Override
public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2,
int sy2, ImageObserver observer) {
return false;
}
@Override
public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2,
int sy2, Color bgcolor, ImageObserver observer) {
return false;
}
@Override
public void dispose() {}
static class GerberProperties {
String function;
boolean negative;
public GerberProperties(String function, boolean negative) {
super();
this.function = function;
this.negative = negative;
}
}
}
@@ -0,0 +1,62 @@
package org.diylc.core.gerber;
import com.bancika.gerberwriter.DataLayer;
import com.bancika.gerberwriter.GenerationSoftware;
public enum GerberLayer {
Outline("Profile,NP", "gko", "Edge-Cuts", false, false),
DrillNonPlated("NonPlated,1,2,NPTH", "drl", "NPTH", false, false),
DrillPlated("Plated,1,2,PTH", "drl", "PTH", false, false),
CopperBot("Copper,L1,Bot", "gbl", "B_Cu", false, false),
CopperTop("Copper,L1,Top", "gtl", "T_Cu", false, false),
SilkscreenBot("Legend,Bot", "gbo", "B_Silkscreen", false, false),
SilkscreenTop("Legend,Top", "gto", "T_Silkscreen", false, false),
SolderMaskBot("Soldermask,Bot", "gbs", "B_Mask", true, false),
SolderMaskTop("Soldermask,Top", "gts", "T_Mask", true, false);
private String function;
private String extension;
private boolean negative;
private boolean mirrored;
private String suffix;
private GerberLayer(String function, String extension, String suffix, boolean negative, boolean mirrored) {
this.function = function;
this.extension = extension;
this.suffix = suffix;
this.negative = negative;
this.mirrored = mirrored;
}
public DataLayer buildLayer(String diylcVersion) {
GenerationSoftware genSoftware =
new GenerationSoftware("bancika", "DIY Layout Creator", diylcVersion);
return new DataLayer(function, negative, genSoftware);
}
public String getExtension() {
return extension;
}
public String getSuffix() {
return suffix;
}
public String getFunction() {
return function;
}
public boolean isNegative() {
return negative;
}
public boolean isMirrored() {
return mirrored;
}
public String formatFileName(String fileNameBase, String boardName) {
return fileNameBase + (fileNameBase.endsWith(".") ? "" : ".")
+ boardName + "-" + getSuffix() + "." + getExtension();
}
}
@@ -0,0 +1,261 @@
package org.diylc.core.gerber;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.geom.Area;
import java.awt.geom.CubicCurve2D;
import java.awt.geom.Path2D;
import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import java.awt.geom.QuadCurve2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import javax.imageio.ImageIO;
import org.diylc.core.ComponentState;
import org.diylc.core.IDIYComponent;
import org.diylc.core.Project;
import org.diylc.core.measures.SizeUnit;
import com.bancika.gerberwriter.DataLayer;
import com.bancika.gerberwriter.Point;
import com.bancika.gerberwriter.path.MoveTo;
import com.bancika.gerberwriter.path.Path;
public class GerberPathRenderer {
public static void drawComponent(Project currentProject, GerberG2DWrapper g2d, IDIYComponent<?> c,
boolean outlineMode) {
IGerberComponent gerberComponent = (IGerberComponent) c;
g2d.startedDrawingComponent();
if (gerberComponent instanceof IGerberComponentCustom) {
IGerberComponentCustom gerberComponentCustom = (IGerberComponentCustom) gerberComponent;
gerberComponentCustom.draw(g2d, ComponentState.NORMAL, outlineMode, currentProject, g2d, g2d);
} else if (gerberComponent instanceof IGerberComponentSimple) {
IGerberComponentSimple gerberComponentSimple = (IGerberComponentSimple) gerberComponent;
g2d.startGerberOutput(gerberComponentSimple.getGerberLayer(),
gerberComponentSimple.getGerberFunction(), gerberComponentSimple.isGerberNegative());
c.draw(g2d, ComponentState.NORMAL, outlineMode, currentProject, g2d);
g2d.stopGerberOutput();
}
}
public static void outputPathArea(PathIterator pathIterator, DataLayer dataLayer, double d,
boolean isNegative, String function) {
List<PathWithNegative> outputPath =
approximatePathWithPolygonPaths(pathIterator, d, isNegative);
outputPath.forEach(p -> dataLayer.addRegion(p.path, function, p.negative));
}
public static void outputPathOutline(PathIterator pathIterator, DataLayer dataLayer, double d,
boolean isNegative, String function, double width) {
List<PathWithNegative> outputPath =
approximatePathWithPolygonPaths(pathIterator, d, isNegative);
outputPath.forEach(p -> dataLayer.addTracesPath(p.path, width * SizeUnit.px.getFactor(),
function, p.negative));
}
public static List<PathWithNegative> approximatePathWithPolygonPaths(PathIterator pathIterator,
double d, boolean isNegative) {
// List<PathWithNegative> convert = PathIteratorConverter.convert(pathIterator, d, isNegative);
// convert.forEach(c -> outputAction.write(c.path, c.negative));
// if (true)
// return;
List<PathWithNegative> results = new ArrayList<PathWithNegative>();
double x = 0;
double y = 0;
Path path = null;
Path2D lastPath = null;
Area lastArea = null;
while (!pathIterator.isDone()) {
double[] coords = new double[6];
int operation = pathIterator.currentSegment(coords);
// int windingRule = pathIterator.getWindingRule();
switch (operation) {
case PathIterator.SEG_MOVETO:
path = new Path();
lastPath = new Path2D.Double();
lastPath.moveTo(coords[0], coords[1]);
path.moveTo(
new Point(coords[0] * SizeUnit.px.getFactor(), coords[1] * SizeUnit.px.getFactor()));
x = coords[0];
y = coords[1];
break;
case PathIterator.SEG_LINETO:
lastPath.lineTo(coords[0], coords[1]);
path.lineTo(
new Point(coords[0] * SizeUnit.px.getFactor(), coords[1] * SizeUnit.px.getFactor()));
x = coords[0];
y = coords[1];
break;
case PathIterator.SEG_CLOSE:
// safety check, do it better
if (!path.isContour()) {
path.lineTo(((MoveTo) path.getOperators().get(0)).getTo());
}
lastPath.closePath();
if (lastArea == null) {
results.add(new PathWithNegative(path, lastPath));
} else {
lastArea.intersect(new Area(lastPath));
results.add(new PathWithNegative(path, lastPath));
}
lastArea = new Area(lastPath);
path = null;
break;
case PathIterator.SEG_CUBICTO:
lastPath.curveTo(coords[0], coords[1], coords[2], coords[3], coords[4], coords[5]);
CubicCurve2D curve1 = new CubicCurve2D.Double(x, y, coords[0], coords[1], coords[2],
coords[3], coords[4], coords[5]);
subdivide(curve1, path, d);
x = coords[4];
y = coords[5];
break;
case PathIterator.SEG_QUADTO:
lastPath.curveTo(coords[0], coords[1], (coords[0] + 2 * coords[2]) / 3,
(coords[3] + 2 * coords[1]) / 3, coords[2], coords[3]);
QuadCurve2D curve2 =
new QuadCurve2D.Double(x, y, coords[0], coords[1], coords[2], coords[3]);
subdivide(curve2, path, d);
x = coords[2];
y = coords[3];
break;
}
pathIterator.next();
}
// check any leftover open path
if (path != null) {
results.add(new PathWithNegative(path, lastPath));
}
results.sort(Comparator.comparing(a -> a.getArea(), Comparator.reverseOrder()));
assignNegativeFlags(results, isNegative);
return results;
}
public static void assignNegativeFlags(List<PathWithNegative> paths, boolean initialNegative) {
if (paths == null || paths.isEmpty())
return;
// Assume the list is already sorted with larger (outer) paths first.
// Set the first one to the given initial value.
paths.get(0).negative = initialNegative;
// For each subsequent path...
for (int i = 1; i < paths.size(); i++) {
boolean foundParent = false;
// Check larger paths (starting from the closest; i.e. immediately before i)
for (int j = i - 1; j >= 0; j--) {
if (paths.get(j).contains(paths.get(i).currentPoint)) {
// If candidate is inside parent, assign the opposite polarity.
paths.get(i).negative = !paths.get(j).negative;
foundParent = true;
break; // stop after the first containing parent is found
}
}
// If no parent was found, assign the initial value.
if (!foundParent) {
paths.get(i).negative = initialNegative;
}
}
}
private static void subdivide(CubicCurve2D curve, Path path, double d) {
if (curve.getFlatness() < d / 3 || new Point2D.Double(curve.getX1(), curve.getY1())
.distance(curve.getX2(), curve.getY2()) < d) {
path.lineTo(new Point(curve.getX2() * SizeUnit.px.getFactor(),
curve.getY2() * SizeUnit.px.getFactor()));
return;
}
CubicCurve2D left = new CubicCurve2D.Double();
CubicCurve2D right = new CubicCurve2D.Double();
curve.subdivide(left, right);
subdivide(left, path, d);
subdivide(right, path, d);
}
private static void subdivide(QuadCurve2D curve, Path path, double d) {
if (curve.getFlatness() < d / 3 || new Point2D.Double(curve.getX1(), curve.getY1())
.distance(curve.getX2(), curve.getY2()) < d) {
path.lineTo(new Point(curve.getX2() * SizeUnit.px.getFactor(),
curve.getY2() * SizeUnit.px.getFactor()));
return;
}
QuadCurve2D left = new QuadCurve2D.Double();
QuadCurve2D right = new QuadCurve2D.Double();
curve.subdivide(left, right);
subdivide(left, path, d);
subdivide(right, path, d);
}
public static void renderShapeToPNG(Shape shape, String outputPath) throws IOException {
// 1. Determine the bounding box of the shape.
Rectangle2D bounds = shape.getBounds2D();
// Ensure we have a positive width/height.
// (You may want to add padding or checks if shape is empty or negative sized.)
int width = (int) Math.ceil(bounds.getWidth());
int height = (int) Math.ceil(bounds.getHeight());
if (width <= 0 || height <= 0) {
throw new IllegalArgumentException("Shape has invalid bounds: " + bounds);
}
// 2. Create a BufferedImage (RGB) with the required dimensions.
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
// 3. Draw the shape.
Graphics2D g2d = image.createGraphics();
try {
// Enable anti-aliasing if desired
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// White background
g2d.setColor(Color.WHITE);
g2d.fillRect(0, 0, width, height);
// Translate the graphics context so the shape appears at (0,0)
g2d.translate(-bounds.getX(), -bounds.getY());
// Draw the shape in black
g2d.setColor(Color.BLACK);
g2d.fill(shape);
} finally {
g2d.dispose();
}
// 4. Write the result to a PNG file
ImageIO.write(image, "png", new File(outputPath));
}
private static class PathWithNegative {
Path path;
boolean negative;
Area lastPath;
Point2D currentPoint;
public PathWithNegative(Path path, Path2D lastPath) {
this.path = path;
this.lastPath = new Area(lastPath);
currentPoint = lastPath.getCurrentPoint();
}
double getArea() {
return lastPath.getBounds2D().getWidth() * lastPath.getBounds2D().getHeight();
}
boolean contains(Point2D point) {
return lastPath.contains(point);
}
}
}
@@ -0,0 +1,5 @@
package org.diylc.core.gerber;
public enum GerberRenderMode {
Normal, Outline
}
@@ -0,0 +1,8 @@
package org.diylc.core.gerber;
import java.awt.geom.Rectangle2D;
public interface IGerberBoard {
Rectangle2D getBoardRectangle();
}
@@ -0,0 +1,11 @@
package org.diylc.core.gerber;
import java.util.EnumSet;
import java.util.Set;
public interface IGerberComponent {
default Set<GerberRenderMode> getGerberRenderModes() {
return EnumSet.of(GerberRenderMode.Outline);
}
}
@@ -0,0 +1,19 @@
package org.diylc.core.gerber;
import java.awt.Graphics2D;
import java.util.EnumSet;
import java.util.Set;
import org.diylc.core.ComponentState;
import org.diylc.core.IDrawingObserver;
import org.diylc.core.Project;
public interface IGerberComponentCustom extends IGerberComponent {
void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project,
IDrawingObserver drawingObserver, IGerberDrawingObserver gerberDrawingObserver);
@Override
default Set<GerberRenderMode> getGerberRenderModes() {
return EnumSet.of(GerberRenderMode.Normal);
}
}
@@ -0,0 +1,16 @@
package org.diylc.core.gerber;
public interface IGerberComponentSimple extends IGerberComponent {
default GerberLayer getGerberLayer() {
return GerberLayer.SilkscreenTop;
}
default String getGerberFunction() {
return "ComponentOutline,Footprint";
}
default boolean isGerberNegative() {
return false;
}
}
@@ -0,0 +1,16 @@
package org.diylc.core.gerber;
public interface IGerberDrawingObserver {
void startGerberOutput(GerberLayer layer, String function, boolean negative);
void setGerberFunction(GerberLayer layer, String function);
void setGerberNegative(GerberLayer layer, boolean negative);
void stopGerberOutput(GerberLayer layer);
void setApproximationToleranceOverride(double tolerance);
void stopGerberOutput();
}
@@ -0,0 +1,8 @@
package org.diylc.core.gerber;
import com.bancika.gerberwriter.path.Path;
public interface IGerberOutput {
void write(Path path, boolean negative);
}
@@ -0,0 +1,78 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.core.images;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.Icon;
import javax.swing.ImageIcon;
/**
* Loads image resources as Icons.
*
* @author Branislav Stojkovic
*/
public enum IconLoader {
Delete("delete.png"), Add("add.png"), FolderOut("folder_out.png"), Garbage("garbage.png"), DiskBlue("disk_blue.png"), SaveAs(
"save_as.png"), Exit("exit.png"), DocumentPlainYellow("document_plain_yellow.png"), PhotoScenery(
"photo_scenery.png"), LightBulbOn("lightbulb_on.png"), LightBulbOff("lightbulb_off.png"), NotebookAdd(
"notebook_add.png"), FormGreen("form_green.png"), Gears("gears.png"), About("about.png"), WindowColors(
"window_colors.png"), WindowGear("window_gear.png"), NavigateCheck("navigate_check.png"), Undo("undo.png"), Error(
"error.png"), Warning("warning.png"), ZoomSmall("zoom_small.png"), MoveSmall("move_small.png"), Print("print.png"), PDF(
"pdf.png"), Excel("excel.png"), CSV("csv.png"), HTML("html.png"), Image("image.png"), Cut("cut.png"), Copy(
"copy.png"), Paste("paste.png"), Selection("selection.png"), BOM("bom.png"), BlackBoard("blackboard.png"), IdCard(
"id_card.png"), IdCardAdd("id_card_add.png"), Chest("chest.png"), Upload("upload.png"), Wrench("wrench.png"), Group(
"group.png"), Ungroup("ungroup.png"), TraceMask("trace_mask.png"), Faq("faq.png"), Component("component.png"), Plugin(
"plugin.png"), Manual("manual.png"), Donate("donate.png"), Bug("bug.png"), IconLarge("icon_large.png"), IconMedium(
"icon_medium.png"), IconSmall("icon_small.png"), DocumentEdit("document_edit.png"), EditComponent(
"edit_component.png"), Size("size.png"), Front("front.png"), Back("back.png"), Pens("pens.png"), Sort("sort.png"), ElementsSelection(
"elements_selection.png"), Schaller("schaller.png");
protected String name;
private IconLoader(String name) {
this.name = name;
}
public Icon getIcon() {
java.net.URL imgURL = getClass().getResource(name);
if (imgURL != null) {
return new ImageIcon(imgURL, name);
} else {
System.err.println("Couldn't find file: " + name);
return null;
}
}
public Image getImage() {
BufferedImage img = null;
try {
img = ImageIO.read(getClass().getResourceAsStream(name));
} catch (IOException e) {
System.err.println("Couldn't find file: " + name);
}
return img;
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 875 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 729 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 749 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 736 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 707 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 714 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 993 B

Some files were not shown because too many files have changed in this diff Show More