/**
* Copyright 2010-2014 Jingjing Li.
*
* This file is part of jplot2d.
*
* jplot2d is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or any later version.
*
* jplot2d 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 Lesser Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with jplot2d. If not, see .
*/
package org.jplot2d.element.impl;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.jplot2d.axtype.AxisType;
import org.jplot2d.element.AxisRangeLockGroup;
import org.jplot2d.notice.Notice;
import org.jplot2d.notice.RangeAdjustedToValueBoundsNotice;
import org.jplot2d.notice.RangeSelectionNotice;
import org.jplot2d.transform.NormalTransform;
import org.jplot2d.transform.TransformType;
import org.jplot2d.util.Range;
public class AxisTransformImpl extends ElementImpl implements AxisTransformEx {
/** The default margin factor (used for both lower and upper margins) */
public static final double DEFAULT_MARGIN_FACTOR = 1.0 / 32; // 0.03125
private AxisType type;
private TransformType txfType;
private boolean autoMargin = true;
private double marginFactor = DEFAULT_MARGIN_FACTOR;
private Range coreRange;
private NormalTransform ntf;
private AxisRangeLockGroupEx group;
private final List tickManagers = new ArrayList();
private final List layers = new ArrayList();
public AxisTransformImpl() {
super();
type = AxisType.NUMBER;
txfType = type.getDefaultTransformType();
ntf = txfType.createNormalTransform(type.getDefaultWorldRange(txfType));
}
public String getId() {
StringBuilder sb = new StringBuilder();
sb.append("AxisTransform");
for (AxisTickManagerEx tick : tickManagers) {
sb.append("(");
for (AxisEx axis : tick.getAxes()) {
sb.append(axis.getShortId()).append(',');
}
sb.replace(sb.length() - 1, sb.length(), ")");
}
sb.deleteCharAt(sb.length() - 1);
sb.append(")(");
for (LayerEx layer : layers) {
sb.append(layer.getShortId()).append(',');
}
sb.deleteCharAt(sb.length() - 1);
sb.append(")");
return sb.toString();
}
public String getFullId() {
if (group != null) {
int xidx = group.indexOfRangeManager(this);
return "AxisTransform" + xidx + "." + group.getFullId();
} else {
return "AxisTransform@" + Integer.toHexString(System.identityHashCode(this));
}
}
public InvokeStep getInvokeStepFormParent() {
if (tickManagers.size() == 0) {
return null;
}
Method method;
try {
method = AxisTickManagerEx.class.getMethod("getAxisTransform");
} catch (NoSuchMethodException e) {
throw new Error(e);
}
return new InvokeStep(method);
}
public AxisTickManagerEx getParent() {
return (AxisTickManagerEx) super.getParent();
}
public ElementEx getPrim() {
if (tickManagers.size() == 0) {
return null;
} else {
return tickManagers.get(0);
}
}
public void notify(Notice msg) {
if (getPrim() != null) {
getPrim().notify(msg);
}
}
public boolean isInverted() {
return ntf.isInverted();
}
public void setInverted(boolean flag) {
if (ntf.isInverted() != flag) {
setNormalTransfrom(ntf.invert());
}
}
public boolean isAutoMargin() {
return autoMargin;
}
public void setAutoMargin(boolean autoMargin) {
this.autoMargin = autoMargin;
if (group.isAutoRange() && group.getPrimaryAxis() == this) {
group.reAutoRange();
} else if (coreRange != null) {
Range irng = coreRange.copy();
setRange(coreRange, true);
coreRange = irng;
}
}
public double getMarginFactor() {
return marginFactor;
}
public void setMarginFactor(double factor) {
marginFactor = factor;
if (group.isAutoRange() && group.getPrimaryAxis() == this) {
group.reAutoRange();
} else if (coreRange != null) {
Range irng = coreRange.copy();
setRange(coreRange, true);
coreRange = irng;
}
}
public AxisType getType() {
return type;
}
public void setType(AxisType type) {
if (group.getRangeManagers().length > 1) {
throw new IllegalStateException(
"The axis type can only be changed when the axis doses not lock with other axes.");
}
this.type = type;
if (!type.canSupport(txfType)) {
txfType = type.getDefaultTransformType();
}
for (AxisTickManagerEx atm : tickManagers) {
atm.transformTypeChanged();
}
group.validateAxesRange();
}
public TransformType getTransform() {
return txfType;
}
public void setTransform(TransformType txfType) {
if (group.getRangeManagers().length > 1) {
throw new IllegalStateException(
"The axis type can only be changed when the axis doses not lock with other axes.");
}
this.txfType = txfType;
for (AxisTickManagerEx atm : tickManagers) {
atm.transformTypeChanged();
}
group.validateAxesRange();
}
public void changeTransformType(TransformType txfType) {
this.txfType = txfType;
for (AxisTickManagerEx atm : tickManagers) {
atm.transformTypeChanged();
}
}
public AxisRangeLockGroupEx getLockGroup() {
return group;
}
public void setLockGroup(AxisRangeLockGroup group) {
if (this.group != null) {
this.group.removeRangeManager(this);
}
this.group = (AxisRangeLockGroupEx) group;
if (this.group != null) {
this.group.addRangeManager(this);
}
}
public NormalTransform getNormalTransform() {
return ntf;
}
public void setNormalTransfrom(NormalTransform ntf) {
if (this.ntf.equals(ntf)) {
return;
}
boolean sameRange = this.ntf.equals(ntf.invert());
this.ntf = ntf;
if (!sameRange) {
for (LayerEx layer : layers) {
if (layer.getXAxisTransform() == this) {
AxisRangeLockGroupEx orth = layer.getYAxisTransform().getLockGroup();
if (orth != null && orth.isAutoRange()) {
orth.reAutoRange();
}
} else if (layer.getYAxisTransform() == this) {
AxisRangeLockGroupEx orth = layer.getXAxisTransform().getLockGroup();
if (orth != null && orth.isAutoRange()) {
orth.reAutoRange();
}
}
}
}
for (LayerEx layer : layers) {
layer.transformChanged();
}
}
public AxisTickManagerEx[] getTickManagers() {
return tickManagers.toArray(new AxisTickManagerEx[tickManagers.size()]);
}
public void addTickManager(AxisTickManagerEx tickManager) {
tickManagers.add(tickManager);
if (tickManagers.size() == 1) {
parent = tickManagers.get(0);
} else {
parent = null;
}
}
public void removeTickManager(AxisTickManagerEx tickManager) {
tickManagers.remove(tickManager);
if (tickManagers.size() == 1) {
parent = tickManagers.get(0);
} else {
parent = null;
}
}
public int indexOfTickManager(AxisTickManagerEx tickManager) {
return tickManagers.indexOf(tickManager);
}
public LayerEx[] getLayers() {
return layers.toArray(new LayerEx[layers.size()]);
}
public void addLayer(LayerEx layer) {
layers.add(layer);
if (group.isAutoRange()) {
for (GraphEx graph : ((LayerEx) layer).getGraphs()) {
if (graph.isVisible()) {
group.reAutoRange();
break;
}
}
}
}
public void removeLayer(LayerEx layer) {
layers.remove(layer);
if (group.isAutoRange()) {
for (GraphEx graph : ((LayerEx) layer).getGraphs()) {
if (graph.isVisible()) {
group.reAutoRange();
break;
}
}
}
}
public void linkLayer(LayerEx layer) {
layers.add(layer);
}
public Range getCoreRange() {
return coreRange;
}
public void setCoreRange(Range crange) {
if (crange == null) {
coreRange = null;
} else {
if (crange.isInverted() != ntf.isInverted()) {
crange = crange.invert();
}
if (!crange.equals(coreRange)) {
coreRange = crange;
setRange(coreRange, true);
}
}
}
public Range getRange() {
return ntf.getValueRange();
}
public void setRange(Range urange) {
if (urange.isInverted() != ntf.isInverted()) {
urange = urange.invert();
}
if (!urange.equals(getRange())) {
setRange(urange, false);
}
}
/**
* Notice after this method, the _coreRange will be reset to null
*
* @param urange
* the range to be set
* @param appendMargin
* true to indicate a margin should be appended to the given range, to derive a actual range.
*/
private void setRange(Range urange, boolean appendMargin) {
if (Double.isNaN(urange.getStart()) || Double.isNaN(urange.getEnd())) {
throw new IllegalArgumentException("Range cannot start or end at NaN.");
}
Map vtMap = AxisRangeUtils.createVirtualTransformMap(Arrays.asList(group
.getRangeManagers()));
NormalTransform vnt = vtMap.get(this);
Range pr = vnt.convToNR(urange);
if (appendMargin) {
double span = pr.getSpan();
double mpStart = pr.getStart() - span * getMarginFactor();
double mpEnd = pr.getEnd() + span * getMarginFactor();
pr = new Range.Double(mpStart, mpEnd);
}
Range pRange = AxisRangeUtils.validateNormalRange(pr, vtMap, false);
if (pRange == null) {
// no intersect at all
throw new IllegalArgumentException(getFullId() + ": The given range is not valid.");
}
double pLo = pRange.getMin();
double pHi = pRange.getMax();
if (!pRange.equals(pr)) {
notify(new RangeAdjustedToValueBoundsNotice(getFullId()
+ ": the given range contains invalid value, range adjusted to [" + ntf.convFromNR(pLo) + ", "
+ ntf.convFromNR(pHi) + "]"));
}
/* ensurePrecision */
RangeStatus rs = AxisRangeUtils.ensurePrecision(pRange, vtMap);
if (rs.getStatus() != null) {
notify(new RangeSelectionNotice(rs.getStatus().getMessage()));
}
/* extend range to tick */
Range extRange;
if (appendMargin && isAutoMargin()) {
Range ur = vnt.convFromNR(rs);
Range exur = expandRangeToTick(ur);
extRange = vnt.convToNR(exur);
} else {
extRange = rs;
}
RangeStatus xrs = AxisRangeUtils.ensureCircleSpan(extRange, vtMap);
if (xrs.getStatus() != null) {
notify(new RangeSelectionNotice(xrs.getStatus().getMessage()));
}
group.zoomVirtualRange(xrs, vtMap);
}
public Range expandRangeToTick(Range ur) {
if (tickManagers.size() > 0) {
return tickManagers.get(0).expandRangeToTick(getTransform(), ur);
}
return null;
}
@Override
public AxisTransformEx copyStructure(Map orig2copyMap) {
AxisTransformImpl result = new AxisTransformImpl();
if (orig2copyMap != null) {
orig2copyMap.put(this, result);
}
// copy or link lock group
AxisRangeLockGroupEx algCopy = (AxisRangeLockGroupEx) orig2copyMap.get(group);
if (algCopy == null) {
algCopy = (AxisRangeLockGroupEx) group.copyStructure(orig2copyMap);
}
result.group = algCopy;
algCopy.addRangeManager(result);
return result;
}
@Override
public void copyFrom(ElementEx src) {
super.copyFrom(src);
AxisTransformImpl arm = (AxisTransformImpl) src;
this.type = arm.type;
this.txfType = arm.txfType;
this.autoMargin = arm.autoMargin;
this.marginFactor = arm.marginFactor;
this.coreRange = arm.coreRange;
this.ntf = arm.ntf;
}
}
Ads help maintain this website.