Skip to content

Commit

Permalink
- Fixed error in calculation marker position after window resize
Browse files Browse the repository at this point in the history
  • Loading branch information
likhachev committed May 16, 2016
1 parent 00da21c commit e7f499b
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 24 deletions.
126 changes: 106 additions & 20 deletions src/main/java/com/ivli/roim/controls/CurvePanel.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
import java.awt.event.MouseEvent;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
Expand All @@ -31,6 +34,7 @@
import org.jfree.chart.event.MarkerChangeListener;
import org.jfree.chart.plot.ValueMarker;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYSplineRenderer;
import org.jfree.data.xy.XYDataItem;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
Expand All @@ -53,6 +57,7 @@ class MENUIITEM {
static enum MENUS {
NOP( "NOP", "NOP"),
ADD( "MARKER_CMD_MARKER_ADD", java.util.ResourceBundle.getBundle("com/ivli/roim/controls/Bundle").getString("MARKER_COMMAND.MARKER_ADD")),
EXPORT_CSV( "MARKER_CMD_EXPORT_CSV", java.util.ResourceBundle.getBundle("com/ivli/roim/controls/Bundle").getString("MARKER_COMMAND.MARKER_EXPORT_CSV")),
DELETE( "MARKER_CMD_MARKER_DELETE", java.util.ResourceBundle.getBundle("com/ivli/roim/controls/Bundle").getString("MARKER_COMMAND.MARKER_DELETE")),
DELETE_ALL( "MARKER_CMD_DELETE_ALL", java.util.ResourceBundle.getBundle("com/ivli/roim/controls/Bundle").getString("MARKER_COMMAND.MARKER_DELETE_ALL")),
MOVE_TO_MIN( "MARKER_CMD_MOVE_TO_MIN", java.util.ResourceBundle.getBundle("com/ivli/roim/controls/Bundle").getString("MARKER_COMMAND.MOVE_TO_MIN")),
Expand Down Expand Up @@ -170,7 +175,25 @@ public void actionPerformed(ActionEvent e) {
case ADD:
if (null != iSeries && iSeries instanceof XYSeries) {
addMarker(new DomainMarker(iDataItem.getXValue(), iSeries));
} break;
} break;
case EXPORT_CSV:
if (null != iSeries && iSeries instanceof XYSeries) {
try (Writer pwr = new PrintWriter("export.csv")){

for (int i=0;i<iSeries.getItemCount(); ++i) {
XYDataItem xy = iSeries.getDataItem(i);
pwr.append(String.format("%f\t%f\n", xy.getXValue(), xy.getYValue()));
}
pwr.flush();
pwr.close();
} catch (IOException ex) {

} finally {


}
} break;

case MOVE_TO_MAX:
((DomainMarker)iMarker).moveToMaximum(DomainMarker.MOVETO.GLOBAL); break;
case MOVE_TO_MAX_LEFT:
Expand Down Expand Up @@ -201,23 +224,23 @@ public void actionPerformed(ActionEvent e) {
return;
}

Collections.sort(list, (DomainMarker o1, DomainMarker o2) -> {
if (o1.equals(o2))
return 0;
if (o1.getValue() > o2.getValue())
return 1;
else
return -1;
});

Collections.sort(list, (DomainMarker aLhs, DomainMarker aRhs) -> {
if (aLhs == aRhs || aLhs.equals(aRhs))
return 0;
if (aLhs.getValue() > aRhs.getValue())
return 1;
else
return -1;
}
);

DomainMarker mark2 = null;

for(int i = 0; i < list.size(); ++i) {
if (list.get(i) == iMarker) {
int ndx = fit_left ? i-1 : i+1;
if (ndx >= 0 && ndx < list.size())
mark2 = list.get(ndx);

mark2 = list.get(ndx);
break;
}
}
Expand All @@ -239,7 +262,7 @@ public void actionPerformed(ActionEvent e) {
}

List<Interpolation> iPol = null;
static int iId = 0;
static int iInterpolationID = 0;

final class Interpolation implements MarkerChangeListener {
DomainMarker iLhs;
Expand All @@ -249,22 +272,84 @@ final class Interpolation implements MarkerChangeListener {
Interpolation(DomainMarker aLhs, DomainMarker aRhs) {
iLhs = aLhs;
iRhs = aRhs;
iSrc = new XYSeries(String.format("INTERPOLATION%d", iId++));
iSrc = new XYSeries(String.format("INTERPOLATION%d", iInterpolationID++));
fillIn();
((XYSeriesCollection)(getChart().getXYPlot().getDataset())).addSeries(iSrc);
//((XYSeriesCollection)(getChart().getXYPlot().getDataset())).addSeries(iSrc);
XYSeriesCollection ds = new XYSeriesCollection();
ds.addSeries(iSrc);
getChart().getXYPlot().setDataset(1, ds);

aLhs.addChangeListener(this);
aRhs.addChangeListener(this);
aRhs.addChangeListener(this);
//int ndx = ((XYSeriesCollection)(getChart().getXYPlot().getDataset())).getSeriesIndex(iSrc.getKey());
getChart().getXYPlot().setRenderer(1, new XYSplineRenderer());
}

void exponentialFit(XYSeries aS, double aFrom, double aTo) {
final double [][] v = aS.toArray();

/*
y' = log(y) = A - B * x;
slope = sum((x - mean(x)) * (y' - mean(y')) / sum((x - mean(x))^2) // -B
intercept = mean(y' - x * slope) // A
*/
int n1 = XYSeriesUtilities.getDomainIndex(v[0], Math.min(aFrom, aTo));
int n2 = XYSeriesUtilities.getDomainIndex(v[0], Math.max(aFrom, aTo));
final int length = n2-n1;

double[] x = new double [n2-n1];
double[] y = new double [n2-n1];

double meanX = .0;
double meanY = .0;

for(int i=0; i<x.length; ++i) {
x[i] = v[1][i+n1];
y[i] = Math.log(v[1][i+n1]);
meanX += x[i];
meanY += y[i];
}

meanX /= (double)length;
meanY /= (double)length;

double sum1 = .0;
double sum2 = .0;
for(int i=0; i<x.length; ++i) {
sum1 += (x[i] - meanX) * (y[i] - meanY) ;
sum2 += (x[i] - meanX) * (x[i] - meanX) ;
}

final double slope = sum1 / sum2;

double intercept = .0;
for(int i=0; i<x.length; ++i) {
intercept += y[i] - x[i] * slope;
}
intercept /= (double)length;

for(int i=0; i<x.length; ++i) {
iSrc.add(v[0][i+n1], intercept + slope*v[0][i+n1]);
}

logger.info(String.format("slope = %f; intercept = %f", slope, intercept));
}



void fillIn() {
iSrc.add(iLhs.getValue(), iLhs.getLinkedMarker().getValue());
iSrc.add((iLhs.getValue() + iRhs.getValue())/2.0, (iLhs.getLinkedMarker().getValue() + iRhs.getLinkedMarker().getValue()) /2.0);

double v = XYSeriesUtilities.getDomainValueOfMinimum(iLhs.getXYSeries(), iLhs.getValue(), iRhs.getValue());
iSrc.add(v, XYSeriesUtilities.getNearestY(iLhs.getXYSeries(), v));
//iSrc.add((iLhs.getValue() + iRhs.getValue())/2.0, (iLhs.getLinkedMarker().getValue() + iRhs.getLinkedMarker().getValue()) /2.0);

iSrc.add(iRhs.getValue(), iRhs.getLinkedMarker().getValue());
}

public void markerChanged(MarkerChangeEvent mce) {
iSrc.clear();
fillIn();
//fillIn();
exponentialFit(iLhs.getXYSeries(), iLhs.getValue(), iRhs.getValue());
}
}

Expand Down Expand Up @@ -306,7 +391,8 @@ public void mouseReleased(MouseEvent e) {
if (SwingUtilities.isRightMouseButton(e) && (iMarker instanceof DomainMarker || iSeries instanceof XYSeries)) {
JPopupMenu mnu = new JPopupMenu(java.util.ResourceBundle.getBundle("com/ivli/roim/controls/Bundle").getString("MNU_MARKER_OPERATIONS"));
if (iSeries instanceof XYSeries) {
mnu.add(MENUS.ADD.makeItem(this));
mnu.add(MENUS.ADD.makeItem(this));
mnu.add(MENUS.EXPORT_CSV.makeItem(this));
mnu.add(MENUS.DELETE_ALL.makeItem(this));
} else if (iMarker instanceof DomainMarker) {
JMenu mi1 = new JMenu(MENUS.MOVE_TO_MIN.iText);
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/com/ivli/roim/controls/DomainMarker.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public XYSeries getXYSeries() {

public void setLinkedMarker(ValueMarker aM) {
iLink = aM;
iLink.setValue(XYSeriesUtilities.getNearestY(getValue(), iSeries));
iLink.setValue(XYSeriesUtilities.getNearestY(iSeries, getValue()));
iLink.setLabelAnchor(RectangleAnchor.BOTTOM);
iLink.setLabelOffset(RectangleInsets.ZERO_INSETS);
}
Expand Down Expand Up @@ -103,7 +103,7 @@ public void setValue(double aVal) {
super.setValue(aVal);

if (null != iSeries) {
final Double newY = XYSeriesUtilities.getNearestY(aVal, iSeries);
final Double newY = XYSeriesUtilities.getNearestY(iSeries, aVal);
if (null != iLink) {
iLink.setValue(newY);
iLink.setLabel(String.format(LABEL_FORMAT, newY));
Expand Down
31 changes: 29 additions & 2 deletions src/main/java/com/ivli/roim/controls/XYSeriesUtilities.java
Original file line number Diff line number Diff line change
Expand Up @@ -125,15 +125,42 @@ static double getDomainValueOfMinimum(XYSeries aS, double aX, boolean aLookLeft)
return valX;
}


static double getDomainValueOfMinimum(XYSeries aS, double aFrom, double aTo) {
final double [][] v = aS.toArray();
double valY = Double.MAX_VALUE;
double valX = Double.NaN;

final int ndx1 = getDomainIndex(v[0], aFrom);
final int ndx2 = getDomainIndex(v[0], aTo);

if (ndx1 < 0 || ndx1 > v[0].length)
return Double.NaN;

if (ndx2 < 0|| ndx1 > v[0].length)
return Double.NaN;

int start;
int end;


for (int i = ndx1; i < ndx2; ++i) {
if (v[1][i] < valY) {
valY = v[1][i];
valX = v[0][i];
}
}

return valX;
}


/*
* computes Y = F(X) where X := [X0, X1, ... Xi, Xi+1 ... Xn]
* for the case actual 'x' value lies between samples say Xi and Xi+1
* for that neighbouring samples found using bisection method
* linear fit used to obtain 'y'
*/
static double getNearestY(final double aX, final XYSeries aS) {
static double getNearestY(final XYSeries aS, final double aX) {
int i = aS.getItemCount();

do{ // bisection
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ MARKER_COMMAND.MOVE_TO_MIN=Move to min
MARKER_COMMAND.MOVE_TO_MIN_LEFT=Left min
MARKER_COMMAND.MOVE_TO_MIN_RIGHT=Right min
MARKER_COMMAND.MARKER_ADD=Add marker
MARKER_COMMAND.MARKER_EXPORT_CSV=Export to CSV
MARKER_COMMAND.MARKER_DELETE=Delete marker
MARKER_COMMAND.MARKER_DELETE_ALL=Delete all markers
MARKER_COMMAND.FIT=Fit
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ MARKER_COMMAND.MOVE_TO_MIN=\u041d\u0430 \u043c\u0438\u043d\u0438\u043c\u0443\u04
MARKER_COMMAND.MOVE_TO_MIN_LEFT=<-\u0441\u043b\u0435\u0432\u0430
MARKER_COMMAND.MOVE_TO_MIN_RIGHT=\u0441\u043f\u0440\u0430\u0432\u0430->
MARKER_COMMAND.MARKER_ADD=\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043c\u0430\u0440\u043a\u0435\u0440
MARKER_COMMAND.MARKER_EXPORT_CSV=Export to CSV
MARKER_COMMAND.MARKER_DELETE=\u0423\u0434\u0430\u043b\u0438\u0442\u044c
MARKER_COMMAND.MARKER_DELETE_ALL=\u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0432\u0441\u0435
MARKER_COMMAND.FIT=\u0418\u043d\u0442\u0435\u0440\u043f\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c
Expand Down

0 comments on commit e7f499b

Please # to comment.