Added read-only "Length" property to curved components (i.e. "Hookup

Wire") that calculates total length of the curve
This commit is contained in:
bancika
2020-03-26 01:12:00 +01:00
parent 88d4d021ff
commit 759df0ac8f
25 changed files with 174 additions and 44 deletions
@@ -75,12 +75,19 @@ public class PropertyWrapper implements Cloneable {
// }
public void writeTo(Object object) throws IllegalArgumentException, IllegalAccessException,
InvocationTargetException, SecurityException, NoSuchMethodException {
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() {
@@ -24,7 +24,10 @@ import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.geom.CubicCurve2D;
import java.awt.geom.Path2D;
import java.awt.geom.Point2D;
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;
@@ -299,7 +302,7 @@ public abstract class AbstractCurvedComponent<T> extends AbstractTransparentComp
public void setStyle(LineStyle style) {
this.style = style;
}
}
@EditableProperty
public Boolean getSmooth() {
@@ -321,6 +324,32 @@ public abstract class AbstractCurvedComponent<T> extends AbstractTransparentComp
// }
// }
}
@EditableProperty
public Size getLength() {
double d = 0;
Point[] 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);
}
public enum PointCount {
TWO(2), THREE(3), FOUR(4), FIVE(5), SEVEN(7);
@@ -336,4 +365,44 @@ public abstract class AbstractCurvedComponent<T> extends AbstractTransparentComp
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)));
}
private double curveThreshold = 10;
// 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 < curveThreshold)
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());
}
}
@@ -41,9 +41,6 @@ public class AbstractMeasure<T extends Enum<? extends Unit>> implements Serializ
protected Double value;
protected T unit;
// public AbstractMeasure() {
// }
public AbstractMeasure(Double value, T unit) {
super();
this.value = value;
@@ -54,23 +51,19 @@ public class AbstractMeasure<T extends Enum<? extends Unit>> implements Serializ
return value;
}
// public void setValue(Double value) {
// this.value = value;
// }
public T getUnit() {
return unit;
}
/***
* Flag that designates if measure value should be converted between different units. eg. 2.54mm <-> 0.1in
*
* @return
*/
public boolean isConvertible() {
return false;
}
// public void setUnit(T multiplier) {
// this.unit = multiplier;
// }
// @Override
// public Object clone() throws CloneNotSupportedException {
// return super.clone();
// }
@Override
public int hashCode() {
final int prime = 31;
@@ -65,5 +65,10 @@ public class Size extends AbstractMeasure<SizeUnit> implements Comparable<Size>
@Override
public int compareTo(Size o) {
return new Double(value * unit.getFactor()).compareTo(o.getValue() * o.getUnit().getFactor());
}
@Override
public boolean isConvertible() {
return true;
}
}
@@ -98,7 +98,11 @@ public class ComparatorFactory {
propertyNameComparator = new Comparator<PropertyWrapper>() {
@Override
public int compare(PropertyWrapper o1, PropertyWrapper o2) {
public int compare(PropertyWrapper o1, PropertyWrapper o2) {
if (o1.isReadOnly() && !o2.isReadOnly())
return 1;
if (!o1.isReadOnly() && o2.isReadOnly())
return -1;
int comp = new Integer(o1.getSortOrder()).compareTo(o2.getSortOrder());
if (comp != 0)
return comp;
@@ -151,7 +151,7 @@ public class ComponentProcessor {
List<PropertyWrapper> properties = new ArrayList<PropertyWrapper>();
for (Method getter : clazz.getMethods()) {
if (getter.getName().startsWith("get")) {
try {
if (getter.isAnnotationPresent(EditableProperty.class) && !getter.isAnnotationPresent(Deprecated.class)
// since Java 8 in generic classes we get properties of both the generic type and Object
// added this condition to skip Object property that we do not need
@@ -163,16 +163,20 @@ public class ComponentProcessor {
} else {
name = annotation.name();
}
IPropertyValidator validator = getPropertyValidator(annotation.validatorClass());
Method setter = clazz.getMethod("set" + getter.getName().substring(3), getter.getReturnType());
IPropertyValidator validator = getPropertyValidator(annotation.validatorClass());
String setterName = null;
try {
Method setter = clazz.getMethod("set" + getter.getName().substring(3), getter.getReturnType());
setterName = setter.getName();
} catch (NoSuchMethodException e) {
LOG.debug("No matching setter found for \"" + getter.getName() + "\". Skipping...");
}
PropertyWrapper property =
new PropertyWrapper(name, getter.getReturnType(), getter.getName(), setter.getName(),
new PropertyWrapper(name, getter.getReturnType(), getter.getName(), setterName,
annotation.defaultable(), validator, annotation.sortOrder());
properties.add(property);
}
} catch (NoSuchMethodException e) {
LOG.debug("No matching setter found for \"" + getter.getName() + "\". Skipping...");
}
}
}
}
@@ -2726,6 +2726,10 @@
<changeType>NEW_FEATURE</changeType>
<description>Added ability to collapse and expand the component tree panel to the left edge of the screen</description>
</org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change>
<changeType>NEW_FEATURE</changeType>
<description>Added read-only "Length" property to curved components (i.e. "Hookup Wire") that calculates total length of the curve</description>
</org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change>
<changeType>NEW_FEATURE</changeType>
<description>Added "Renumber On Paste" option in the "Config" menu</description>