sysperfana/perfinvestigator/com.nokia.carbide.cpp.pi/src/com/nokia/carbide/cpp/internal/pi/visual/GenericTraceGraph.java
/*
* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description: GenericTraceGraph.java
*
*/
package com.nokia.carbide.cpp.internal.pi.visual;
import java.awt.Component;
import java.awt.Dimension;
import java.util.Enumeration;
import java.util.Vector;
import org.eclipse.draw2d.FigureCanvas;
import org.eclipse.draw2d.Graphics;
import org.eclipse.draw2d.Panel;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.PointList;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.swt.SWTError;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.widgets.Display;
import com.nokia.carbide.cpp.internal.pi.model.GenericTrace;
import com.nokia.carbide.cpp.internal.pi.model.ProfiledGeneric;
import com.nokia.carbide.cpp.pi.util.ColorPalette;
public abstract class GenericTraceGraph
{
protected int graphIndex = 0;
private static final int ALPHA_UNSELECTED = 175;
private static final int SELECTION_BAR_WIDTH = 2;
// amount of space at left of graph to contain y-axis units
public static final int yLegendWidth = 50;
// fill selection flags
private double timeOffset = 0;
protected boolean debug = false;
// PI time scale multiplier
private float piTimeScale = 1;
private boolean timescalingEnabled = false;
private int visibleAreaIdentifier = 0; //is used to detect changes in drawing area
private boolean updatePolylinesIsNeeded = true;
public boolean updateCumulativeThreadTableIsNeeded = true;
public boolean fillFlag = false; //fill items is selected, all or selected?
public boolean fillSelected = false; //fill selected items
private int visibleRightBorder; //these are updated when the visible area changes / polylines need to be updated
private int visibleLeftBorder;
private int sizeX = 0;
private int sizeY = 0;
private int visualSizeX = 0;
private int visualSizeY = 0;
private int preferredSizeX = 0;
private int preferredSizeY = 0;
private double selectionStart = -1;
private double selectionEnd = -1;
// private double scaleX = 10; //default when creating a new analysis
private double scaleY = 100; //default for percentages
private double scale = 0;
private boolean highResolution = true;
public PICompositePanel parentComponent;
private GenericTrace myTrace;
private Vector<GenericTraceGraph> graphSubComponents;
private Image graphImage = null;
private boolean graphImageChanged = true;
public GenericTraceGraph(GenericTrace data)
{
this.graphSubComponents = new Vector<GenericTraceGraph>();
this.myTrace = data;
}
public GenericTrace getTrace()
{
return this.myTrace;
}
public void setTimeOffset(double offset)
{
this.timeOffset = offset;
}
public double getTimeOffset()
{
return this.timeOffset;
}
public void addSubGraphComponent(GenericTraceGraph subGraph)
{
this.graphSubComponents.add(subGraph);
}
public Enumeration getGraphSubComponents()
{
return graphSubComponents.elements();
}
public void importParentComponent(PICompositePanel parent)
{
this.parentComponent = parent;
}
public void setCurrentInfoComponent(Component infoComponent)
{
if (parentComponent instanceof PICompositePanel)
{
((PICompositePanel)parentComponent).
setCurrentInfoComponent(infoComponent);
}
}
public PIVisualSharedData getSharedDataInstance()
{
if (parentComponent instanceof PICompositePanel)
{
return ((PICompositePanel)parentComponent).getSharedData();
}
else
return null;
}
// a rectangle that describes visible area fo the draw 2D graphics so we paint only that
public Rectangle getVisibleArea(Graphics graphics) {
return graphics.getClip(new org.eclipse.draw2d.geometry.Rectangle());
}
public abstract void paint(Panel panel, Graphics graphics);
public abstract void paintLeftLegend(FigureCanvas figureCanvas, GC gc);
// call all subcomponents' repaint methods
public abstract void repaint();
public abstract void refreshDataFromTrace();
public abstract void action(String action);
public void setSize(int x, int y)
{
this.sizeY = y;
this.sizeX = x;
}
public void setPITimeScale(float scale)
{
System.out.println(Messages.getString("GenericTraceGraph.setTimeScaleTo") + scale); //$NON-NLS-1$
this.piTimeScale = scale;
Enumeration sc = this.getGraphSubComponents();
while (sc.hasMoreElements())
{
GenericTraceGraph gtc = (GenericTraceGraph)sc.nextElement();
gtc.setPITimeScale(scale);
}
}
public void setTimescalingEnabled(boolean flag)
{
this.timescalingEnabled = flag;
Enumeration sc = this.getGraphSubComponents();
while (sc.hasMoreElements())
{
GenericTraceGraph gtc = (GenericTraceGraph)sc.nextElement();
gtc.setTimescalingEnabled(flag);
}
}
public float getPITimeScale()
{
if (this.timescalingEnabled)
return this.piTimeScale;
else
return 1f;
}
public Dimension getSize()
{
return new Dimension(this.sizeX, this.sizeY);
}
public void setVisualSize(int x, int y)
{
this.visualSizeX = x;
this.visualSizeY = y;
Enumeration sc = this.getGraphSubComponents();
while (sc.hasMoreElements())
{
GenericTraceGraph gtc = (GenericTraceGraph)sc.nextElement();
gtc.setVisualSize(x, y);
}
}
public Dimension getVisualSize()
{
return new Dimension(this.visualSizeX, this.visualSizeY);
}
public Dimension getPreferredSize()
{
return new Dimension(this.preferredSizeX, this.preferredSizeY);
}
public void setSelectionStart(double start)
{
if (highResolution)
selectionStart = start;
else
selectionStart = (int) (start / 100 + 0.5) * 100;
Enumeration sc = this.getGraphSubComponents();
while (sc.hasMoreElements())
{
GenericTraceGraph gtc = (GenericTraceGraph)sc.nextElement();
gtc.setSelectionStart(selectionStart);
}
}
public void setSelectionEnd(double end)
{
if (highResolution)
this.selectionEnd = end;
else
selectionEnd = (int) (end / 100 + 0.5) * 100;
Enumeration sc = this.getGraphSubComponents();
while (sc.hasMoreElements())
{
GenericTraceGraph gtc = (GenericTraceGraph)sc.nextElement();
gtc.setSelectionEnd(selectionEnd);
}
}
public void setHighResolution(boolean flag)
{
this.highResolution = flag;
}
public double getSelectionStart()
{
return this.selectionStart;
}
public double getSelectionEnd()
{
return this.selectionEnd;
}
public void setScale(double scaleX, double scaleY)
{
// if (scaleX > 0)
// this.scaleX = scaleX;
if (scaleY > 0)
this.scaleY = scaleY;
Enumeration sc = this.getGraphSubComponents();
while (sc.hasMoreElements())
{
GenericTraceGraph gtc = (GenericTraceGraph)sc.nextElement();
gtc.setScale(scaleX, scaleY);
}
}
public double getScale()
{
return this.scale;
}
public void setScale(double scale)
{
this.scale = scale;
Enumeration sc = this.getGraphSubComponents();
while (sc.hasMoreElements())
{
GenericTraceGraph gtc = (GenericTraceGraph)sc.nextElement();
gtc.setScale(scale);
}
}
public void setToolTipText(String text)
{
this.parentComponent.setToolTipTextForGraphComponent(this, text);
}
public PICompositePanel getCompositePanel()
{
return this.parentComponent;
}
//new generic method to draw background
public void drawDottedLineBackground(Graphics graphics, int yLegendSpace)
{
Rectangle visibleArea = getVisibleArea(graphics);
int visY = this.getVisualSize().height;
float visYfloat = visY - yLegendSpace;
// draw the dotted lines
graphics.setForegroundColor(ColorPalette.getColor(new RGB(200, 200, 200)));
// vertical lines
// float values will be slightly smaller than the actual result
// and they will be incremented by one, since rounding to int
// discards the remaining decimals
int k = 0;
for (float y = 0; k <= 10; y += visYfloat * 10000f / 100001f, k++)
{
for (int x = visibleArea.x; x <= visibleArea.x + visibleArea.width; x += 5)
{
if ((x / 5) % 2 == 0) graphics.drawLine(x, ((int)y) + 1, x + 5, ((int)y) + 1);
}
}
// horizontal lines
if (visibleArea.width > 0)
{
for (int x = visibleArea.x; x <= visibleArea.x + visibleArea.width; x += 50)
{
if (x % 100 == 0)
graphics.setForegroundColor(ColorPalette.getColor(new RGB(100, 100, 100)));
else
graphics.setForegroundColor(ColorPalette.getColor(new RGB(200, 200, 200)));
for (int y = 0; y < visY; y += 5)
{
if ((y / 5) % 2 == 0)
graphics.drawLine(x, y, x, y + 5);
}
}
}
// draw the line indices
graphics.setForegroundColor(ColorPalette.getColor(new RGB(100, 100, 100)));
graphics.setBackgroundColor(ColorPalette.getColor(new RGB(255, 255, 255)));
for (int x = visibleArea.x; x <= visibleArea.x + visibleArea.width; x += 50)
{
double time = (double) x;
time = time * this.getScale();
time += this.timeOffset;
time = time / 1000;
String stringTime = String.valueOf(time);
if (stringTime.length() > 4)
{
int i;
for (i = 0; i < stringTime.length(); i++)
if (stringTime.charAt(i) == '.')
break;
if (i + 4 < stringTime.length())
stringTime = stringTime.substring(0, i + 4);
}
graphics.drawString(stringTime + Messages.getString("GenericTraceGraph.seconds"), x + 5, visY - 13); //$NON-NLS-1$
}
}
public void drawSelectionSection(Graphics graphics, int yLegendSpace)
{
//draws the new selection
this.drawSelection(graphics, selectionStart, selectionEnd, yLegendSpace);
}
protected void drawSelection(Graphics graphics, double start, double end, int yLegendSpace)
{
if (start > end) {
double tmp = end;
end = start;
start = tmp;
}
double scale = getScale();
int savedAlpha = graphics.getAlpha();
Color savedColor = graphics.getForegroundColor();
// shade unselected area with a fixed alpha of darker gray
Color selectColor = ColorPalette.getColor(new RGB(170, 170, 170));
graphics.setBackgroundColor(selectColor);
graphics.setAlpha(ALPHA_UNSELECTED);
Point origin = this.parentComponent.getScrolledOrigin();
int visX = this.getVisualSizeX();
int visY = this.getVisualSizeY()- yLegendSpace;
if (start != -1 && end != -1)
{
// mask with alpha adjusted the unselected area before the indicators
if (origin.x < (start / scale) - SELECTION_BAR_WIDTH)
graphics.fillRectangle(origin.x, 0,
(int)(start / scale) - SELECTION_BAR_WIDTH - origin.x, visY);
// mask with alpha adjusted the unselected area after the indicators
if ((int)(end/scale + SELECTION_BAR_WIDTH) < origin.x + visX)
graphics.fillRectangle((int)(end / scale + SELECTION_BAR_WIDTH), 0,
origin.x + visX - (int)(end / scale + SELECTION_BAR_WIDTH), visY);
// draw two indicators
graphics.setForegroundColor(ColorPalette.getColor(new RGB(255, 255, 0)));
for (int i = 0; i < SELECTION_BAR_WIDTH; i++) {
graphics.drawLine((int)(start/scale) - i, 0, (int)(start/scale) - i, visY);
graphics.drawLine((int)(end/scale) + i, 0, (int)(end/scale) + i, visY);
}
}
else
{
// mask the entire visible area with alpha adjusted
graphics.fillRectangle(origin.x, 0, visX, visY);
}
//restore proper alpha
graphics.setBackgroundColor(savedColor);
graphics.setAlpha(savedAlpha);
}
protected void drawThreadMarks(ProfiledGeneric pg, int visY, Graphics graphics)
{
Rectangle visibleArea = getVisibleArea(graphics);
int firstSample = (int)(pg.getFirstSample() / this.getScale());
int lastSample = (int)(pg.getLastSample() / this.getScale());
// Thread start mark
if (firstSample >= visibleArea.x && firstSample <= visibleArea.x + visibleArea.width) {
graphics.drawLine(firstSample, (visY - 50), firstSample, (visY - 40));
graphics.drawLine(firstSample + 1, (visY - 50), firstSample + 1, (visY - 40));
graphics.drawLine(firstSample - 1, (visY - 50), firstSample - 1, (visY - 40));
graphics.drawLine(firstSample,(visY - 40), firstSample + 10, (visY - 40));
graphics.drawLine(firstSample,(visY - 41), firstSample + 10, (visY - 41));
graphics.drawLine(firstSample,(visY - 39), firstSample + 10, (visY - 39));
}
// Thread end mark
if (lastSample >= visibleArea.x && lastSample <= visibleArea.x + visibleArea.width) {
graphics.drawLine(lastSample, (visY - 50), lastSample, (visY - 40));
graphics.drawLine(lastSample + 1, (visY - 50), lastSample + 1, (visY - 40));
graphics.drawLine(lastSample - 1, (visY - 50), lastSample - 1, (visY - 40));
graphics.drawLine(lastSample, (visY - 40), lastSample - 10, (visY - 40));
graphics.drawLine(lastSample, (visY - 41), lastSample - 10, (visY - 41));
graphics.drawLine(lastSample, (visY - 39), lastSample - 10, (visY - 39));
}
}
public void updateVisibleBorders()
{
SashForm rect = this.parentComponent.getSashForm();
int scale = (int) this.getScale();
int correctionValue = 10;
// calculate display overscan to remove graphical glitches
if (scale >= 10)
correctionValue = 10;
else if (scale < 10 && scale > 1)
correctionValue = 100 - (scale * 10);
else if ( scale <= 1 && scale > 0.3)
correctionValue = 200;
else if ( scale <= 0.3)
correctionValue = 800;
Point origin = this.parentComponent.getScrolledOrigin();
visibleLeftBorder = origin.x - (int)(correctionValue * 1.2);
visibleRightBorder = origin.x + rect.getBounds().width + (int)(correctionValue * 1.1);
}
public void genericRefreshCumulativeThreadTable()
{
updateCumulativeThreadTableIsNeeded = true;
}
protected void genericRefreshCumulativeThreadTable(Enumeration<ProfiledGeneric> threads)
{
int[] cumulativePerc = null;
while (threads.hasMoreElements())
{
ProfiledGeneric pg = threads.nextElement();
// go through all samples
if (pg.isEnabled(graphIndex))
{
// zero this profiled generic's cumulative values
pg.setupCumulativeList(graphIndex);
// Note: getSampleList() and getActivityList() create the lists
int[] samples = pg.getSampleList();
int[] values = pg.getActivityList();
if (samples == null || values == null || samples.length == 0)
return;
if (cumulativePerc == null)
{
// create a zeroed array of cumulative values
cumulativePerc = new int[samples.length];
}
for (int sampIndx = 0; sampIndx < samples.length; sampIndx++)
{
// get this profiled generic's sample count in each chunk of samples
int thisValue = values[sampIndx];
int oldCumValue = cumulativePerc[sampIndx];
// add the percentage to the current cumulative value
cumulativePerc[sampIndx] += thisValue;
// set the profiled generic's cumulative value for this bucket
pg.setCumulativeValue(graphIndex, sampIndx, oldCumValue);
}
}
}
updatePolylinesIsNeeded = true;
updateCumulativeThreadTableIsNeeded = false;
}
private void updatePolyLinesGeneric(Enumeration enumer)
{
// updatePolylinesIsNeeded will be true if refreshCumulativeThreadTable has been invoked
/******************************************************************/
if (!updatePolylinesIsNeeded)
{
int visY = this.getVisualSize().height;
int newVisibleAreaIdentifier;
SashForm rect = this.parentComponent.getSashForm();
Point point = this.parentComponent.getScrolledOrigin();
int scale = (int) this.getScale();
int visibleLeft = point.x;
int visibleRight = point.x + rect.getBounds().width;
newVisibleAreaIdentifier = scale * 13 + visibleLeft + visibleRight * 2 + visY * 3;
if (!(visibleAreaIdentifier == newVisibleAreaIdentifier))
updatePolylinesIsNeeded = true;
visibleAreaIdentifier = newVisibleAreaIdentifier;
}
/**********************************************************/
if (updatePolylinesIsNeeded)
this.updatePolyLinesGeneric(enumer, (int) this.scaleY);
}
private void updatePolyLinesGeneric(Enumeration enumer, int heightDivider)
{
if (!updatePolylinesIsNeeded)
return;
this.updateVisibleBorders();
int visY = this.getVisualSize().height;
float xscale;
if (this.timescalingEnabled)
xscale = this.piTimeScale;
else
xscale = 1;
// draw one thread/binary/function at a time
ProfiledGeneric pg = null;
while (enumer.hasMoreElements())
{
pg = (ProfiledGeneric ) enumer.nextElement();
if (pg.isEnabled(graphIndex)) //is visualised
{
if (debug)
System.out.println(Messages.getString("GenericTraceGraph.debug")+pg.getNameString()); //$NON-NLS-1$
// get samples and their corresponding values
int[] samples = pg.getSampleList(); //time stamps
int[] values = pg.getActivityList(); //percentage values
// if a ProfiledGeneric has a null cumulative list, give
// it a list of zeros
if (pg.getCumulativeList(graphIndex) == null) {
pg.setupCumulativeList(graphIndex);
}
int[] cumulatives = pg.getCumulativeList(graphIndex);
pg.resetPolyline(graphIndex);
double tmpScale = this.getScale();
// go through all samples
int thisSample, x, cumValue, thisValue;
int y = visY - 50;
for (int sampIndx = 0; sampIndx < samples.length; sampIndx++)
{
// the x value in thisSample is the timestamp
thisSample = samples[sampIndx];
x = (int)(thisSample / tmpScale / xscale);
// the y value is the percentage
thisValue = values[sampIndx];
cumValue = cumulatives[sampIndx];
y = ((thisValue + cumValue) * (visY - 50)) / heightDivider;
pg.addPointToPolyline(graphIndex, x, (visY - 50) - y);
} // for
} //if (pg.isenabled)
}//while (enum.hasmoreElements)
updatePolylinesIsNeeded = false;
}
public void drawGraphsGeneric(Vector<ProfiledGeneric> profiledGenerics, Graphics graphics, Object[] selection)
{
if (profiledGenerics.elements() == null)
return;
// update cumulative thread table
if (this.updateCumulativeThreadTableIsNeeded)
this.genericRefreshCumulativeThreadTable(profiledGenerics.elements());
// update polylines based on cumulative thread table
this.updatePolyLinesGeneric(profiledGenerics.elements());
boolean threadIsSelected = false;
int visY = this.getVisualSize().height;
ProfiledGeneric pg;
GC gc = null;
boolean useImage = false;
int width = sizeX;
int height= sizeY;
// if image < 16KB and image can be allocated, use a pre drawn image instead of
// painting on draw2D graphics, scrolling and repaint from coming into focus
// are faster
if (width * height * 4 <= 16777216){ // 16KB image under 32bit color
if (getGraphImageChanged()) {
if (graphImage != null) {
graphImage.dispose();
}
try {
graphImage = new Image(Display.getDefault(), width, height);
gc = new GC(this.graphImage);
useImage = true;
} catch (SWTError e) {
// we cannot allocate any more image, stick to slow draw2D
}
} else {
useImage = true;
}
} else {
if (graphImage != null) {
graphImage.dispose(); // don't need this anymore, use draw2D
}
}
if (useImage == false || getGraphImageChanged() == true) { // using graphics for paint or image needs update
// draw one thread/binary/function at a time
for (int i = profiledGenerics.size() - 1; i >= 0; i--)
{
pg = profiledGenerics.get(i);
if (pg.isEnabled(this.graphIndex)) //is visualised
{
// get samples and their corresponding values
int[] samples = pg.getSampleList(); //time stamps
int[] values = pg.getActivityList(); //percentage values
int[] cumulatives = pg.getCumulativeList(this.graphIndex);
if (this.fillSelected) //selected items are filled, not all of them
{
threadIsSelected = selection.length > 0;
}
if (gc != null) {
gc.setForeground(pg.getColor());
gc.setBackground(pg.getColor());
} else {
graphics.setForegroundColor(pg.getColor());
graphics.setBackgroundColor(pg.getColor());
}
drawGraph(pg, threadIsSelected, visY, graphics, gc, cumulatives, samples, values);
} //if (pg.isenabled)
}//while (enum.hasmoreElements)
}
if (gc != null) {
gc.dispose();
}
if (useImage) {
graphics.drawImage(this.graphImage, 0, 0);
setGraphImageChanged(false);
}
for (int i = profiledGenerics.size() - 1; i >= 0; i--) {
pg = profiledGenerics.get(i);
if (pg.isEnabled(this.graphIndex)) //is visualised
{
graphics.setForegroundColor(pg.getColor());
graphics.setBackgroundColor(pg.getColor());
drawThreadMarks(pg, visY, graphics);
}
}
}
public boolean getGraphImageChanged() {
return graphImageChanged;
}
public void setGraphImageChanged(boolean status) {
graphImageChanged = status;
}
private int searchSortedPointListForX(PointList list, int xValue, boolean firstLowerIfNoMatch) {
// bin search for now
if (list.getFirstPoint().x == xValue) {
return 0;
}
if (list.getLastPoint().x == xValue) {
return list.size() - 1;
}
int start = 0;
int end = list.size() - 1;
int match = 0;
while (match == 0) {
// no match
if (start + 1 == end) {
if (firstLowerIfNoMatch) {
return start;
} else {
return end;
}
}
int middle = (start + end) / 2;
int middleX = list.getPoint(middle).x;
if (middleX == xValue) {
match = middle;
} else {
if (middleX < xValue) {
start = middle;
} else {
end = middle;
}
}
}
return match;
}
/*
* this method draws a polyline or a polygon in the graph
*
* Note: it assumes all polylines have the same number of points
*/
private void drawGraph(ProfiledGeneric pg, boolean threadIsSelected, int visY, Graphics graphics, GC gc,
int[] cumulatives, int[] samples, int[] values)
{
int pointCount = pg.getPointList(this.graphIndex).size();
Rectangle drawArea;
if (gc != null) {
// draw one big picture including non-visible when drawing on image
drawArea = new Rectangle(0, 0, sizeX, this.getVisibleArea(graphics).height);
} else {
drawArea = this.getVisibleArea(graphics);
}
if (pointCount < 2) // these lusers really want to see a two pixel wide chart? what's wrong with them
return;
PointList allPointList = pg.getPointList(graphIndex);
int xIndex = searchSortedPointListForX(allPointList, drawArea.x, true);
PointList visiblePointList = new PointList();
Point currentPoint = allPointList.getPoint(xIndex++);
visiblePointList.addPoint(currentPoint);
currentPoint = allPointList.getPoint(xIndex++);
visiblePointList.addPoint(currentPoint);
Point peakPointInVertical = null;
Point troughPointInVertical = null;
Point lastPointInVertical = null;
while (xIndex < allPointList.size()) {
// only draw visible area
if (currentPoint.x >= drawArea.x + drawArea.width) {
break;
}
int lastX = currentPoint.x;
currentPoint = allPointList.getPoint(xIndex++);
//optimized polyline and draw slighly inaccurate graph for those pixel fine movement,
//only account for peak/valley if x doesn't move(e.g. vertical lines)
if (lastX == currentPoint.x) {
if (lastPointInVertical == null) {
// seen first point in the vertical line
peakPointInVertical = troughPointInVertical = visiblePointList.getLastPoint();
}
if (troughPointInVertical.y > currentPoint.y) {
troughPointInVertical = currentPoint;
} else if (peakPointInVertical.y < currentPoint.y) {
peakPointInVertical = currentPoint;
}
lastPointInVertical = currentPoint;
}
else {
// we just write two points of peak and trough of the vertical line if needed and the last
// if we seen peak and trough, this way we can render the conceptually inaccurate graph
// we less point, but still show the same vertical line on screen
if (lastPointInVertical != null) {
boolean seenPeakOrTrough = false;
if (lastPointInVertical.y != peakPointInVertical.y) {
visiblePointList.addPoint(peakPointInVertical);
seenPeakOrTrough = true;
}
if (lastPointInVertical.y != troughPointInVertical.y) {
visiblePointList.addPoint(troughPointInVertical);
seenPeakOrTrough = true;
}
if (seenPeakOrTrough) {
visiblePointList.addPoint(lastPointInVertical);
}
peakPointInVertical = null;
troughPointInVertical = null;
lastPointInVertical = null;
}
visiblePointList.addPoint(currentPoint);
}
}
if (fillFlag)
{
// close the bottom parameter
visiblePointList.addPoint(new Point(visiblePointList.getLastPoint().x, visY - 50));
visiblePointList.addPoint(new Point(visiblePointList.getFirstPoint().x, visY - 50));
if (gc != null) {
gc.fillPolygon(visiblePointList.toIntArray());
} else {
graphics.fillPolygon(visiblePointList.toIntArray());
}
}
else
{
if (gc != null) {
gc.drawPolyline(visiblePointList.toIntArray());
} else {
graphics.drawPolyline(visiblePointList.toIntArray());
}
}
//creates the first polyListX and polyListY
if (fillFlag && (!threadIsSelected && this.fillSelected))
{
this.resetPolyList(pg, visY, samples, values, cumulatives);
}
}
//this method is used to reset the list of points
private void resetPolyList(ProfiledGeneric pg, int visY, int[] samples, int[] values, int[] cumulatives)
{
pg.resetPolyline(graphIndex);
int thisValue, cumValue, thisSample, x;
int y = (visY - 50);
double tmpScale = this.getScale();
for (int sampIndx = 0; sampIndx < samples.length; sampIndx++)
{
// the x value in thisSample is the timestamp
thisSample = samples[sampIndx];
x = (int)(thisSample / tmpScale);
if (x > visibleLeftBorder && x < visibleRightBorder) //draws only visible stuff
{
// the y value is the percentage
thisValue = values[sampIndx];
cumValue = cumulatives[sampIndx];
y = ((thisValue + cumValue) * (visY - 50)) / 100;
pg.addPointToPolyline(graphIndex, x, (visY - 50) - y);
}
else if (x >= visibleRightBorder) //optimises end drawing
{
pg.addPointToPolyline(graphIndex, x, visY - 50);
sampIndx = samples.length; //breaks the for loop
}
} // for
}
public void updateIfNeeded(Vector<ProfiledGeneric> profiledGenerics)
{
// updates cumulative thread table
if (this.updateCumulativeThreadTableIsNeeded)
this.genericRefreshCumulativeThreadTable(profiledGenerics.elements());
// updates polylines based on cumulative thread table
this.updatePolyLinesGeneric(profiledGenerics.elements());
}
public int getVisibleRightBorder()
{
return this.visibleRightBorder;
}
public int getVisibleLeftBorder()
{
return this.visibleLeftBorder;
}
public int getVisualSizeX()
{
return this.visualSizeX;
}
public int getVisualSizeY()
{
return this.visualSizeY;
}
}