PageRenderTime 91ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 26ms

/src/main/java/grafica/GHistogram.java

https://gitlab.com/aleexkj/hoc-tsp
Java | 531 lines | 300 code | 58 blank | 173 comment | 98 complexity | b7ef5d520d28aa00f81c59f84341c2cc MD5 | raw file
  1. /**
  2. * grafica
  3. * Create simple and configurable 2D plots with Processing.
  4. * http://jagracar.com/grafica.php
  5. *
  6. * Copyright (c) 2015 Javier Gracia Carpio http://jagracar.com
  7. *
  8. * This library is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU Lesser General Public
  10. * License as published by the Free Software Foundation; either
  11. * version 2.1 of the License, or (at your option) any later version.
  12. *
  13. * This library is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * Lesser General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Lesser General
  19. * Public License along with this library; if not, write to the
  20. * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  21. * Boston, MA 02111-1307 USA
  22. *
  23. * @author Javier Gracia Carpio http://jagracar.com
  24. * @modified 09/16/2016
  25. * @version 1.7.0 (8)
  26. */
  27. package grafica;
  28. import java.util.ArrayList;
  29. import processing.core.PApplet;
  30. import processing.core.PConstants;
  31. import processing.core.PFont;
  32. /**
  33. * Histogram class.
  34. *
  35. * @author Javier Gracia Carpio http://jagracar.com
  36. */
  37. public class GHistogram implements PConstants {
  38. // The parent Processing applet
  39. protected final PApplet parent;
  40. // General properties
  41. protected int type;
  42. protected float[] dim;
  43. protected GPointsArray plotPoints;
  44. protected boolean visible;
  45. protected float[] separations;
  46. protected int[] bgColors;
  47. protected int[] lineColors;
  48. protected float[] lineWidths;
  49. protected ArrayList<Float> differences;
  50. protected ArrayList<Float> leftSides;
  51. protected ArrayList<Float> rightSides;
  52. // Labels properties
  53. protected float labelsOffset;
  54. protected boolean drawLabels;
  55. protected boolean rotateLabels;
  56. protected String fontName;
  57. protected int fontColor;
  58. protected int fontSize;
  59. protected PFont font;
  60. /**
  61. * Constructor
  62. *
  63. * @param parent the parent Processing applet
  64. * @param type the histogram type. It can be GPlot.VERTICAL or GPlot.HORIZONTAL
  65. * @param dim the plot box dimensions in pixels
  66. * @param plotPoints the points positions in the plot reference system
  67. */
  68. public GHistogram(PApplet parent, int type, float[] dim, GPointsArray plotPoints) {
  69. this.parent = parent;
  70. this.type = (type == GPlot.VERTICAL || type == GPlot.HORIZONTAL) ? type : GPlot.VERTICAL;
  71. this.dim = dim.clone();
  72. this.plotPoints = new GPointsArray(plotPoints);
  73. visible = true;
  74. separations = new float[] { 2 };
  75. bgColors = new int[] { this.parent.color(150, 150, 255) };
  76. lineColors = new int[] { this.parent.color(100, 100, 255) };
  77. lineWidths = new float[] { 1 };
  78. int nPoints = plotPoints.getNPoints();
  79. differences = new ArrayList<Float>(nPoints);
  80. leftSides = new ArrayList<Float>(nPoints);
  81. rightSides = new ArrayList<Float>(nPoints);
  82. initializeArrays(nPoints);
  83. updateArrays();
  84. labelsOffset = 8;
  85. drawLabels = false;
  86. rotateLabels = false;
  87. fontName = "SansSerif.plain";
  88. fontColor = this.parent.color(0);
  89. fontSize = 11;
  90. font = this.parent.createFont(fontName, fontSize);
  91. }
  92. /**
  93. * Fills the differences, leftSides and rightSides arrays
  94. */
  95. protected void initializeArrays(int nPoints) {
  96. if (differences.size() < nPoints) {
  97. for (int i = differences.size(); i < nPoints; i++) {
  98. differences.add(0f);
  99. leftSides.add(0f);
  100. rightSides.add(0f);
  101. }
  102. } else {
  103. differences.subList(nPoints, differences.size()).clear();
  104. }
  105. }
  106. /**
  107. * Updates the differences, leftSides and rightSides arrays
  108. */
  109. protected void updateArrays() {
  110. int nPoints = plotPoints.getNPoints();
  111. if (nPoints == 1) {
  112. leftSides.set(0, (type == GPlot.VERTICAL) ? 0.2f * dim[0] : 0.2f * dim[1]);
  113. rightSides.set(0, leftSides.get(0));
  114. } else if (nPoints > 1) {
  115. // Calculate the differences between consecutive points
  116. for (int i = 0; i < nPoints - 1; i++) {
  117. if (plotPoints.isValid(i) && plotPoints.isValid(i + 1)) {
  118. float separation = separations[i % separations.length];
  119. float diff;
  120. if (type == GPlot.VERTICAL) {
  121. diff = plotPoints.getX(i + 1) - plotPoints.getX(i);
  122. } else {
  123. diff = plotPoints.getY(i + 1) - plotPoints.getY(i);
  124. }
  125. if (diff > 0) {
  126. differences.set(i, (diff - separation) / 2f);
  127. } else {
  128. differences.set(i, (diff + separation) / 2f);
  129. }
  130. } else {
  131. differences.set(i, 0f);
  132. }
  133. }
  134. // Fill the leftSides and rightSides arrays
  135. leftSides.set(0, differences.get(0));
  136. rightSides.set(0, differences.get(0));
  137. for (int i = 1; i < nPoints - 1; i++) {
  138. leftSides.set(i, differences.get(i - 1));
  139. rightSides.set(i, differences.get(i));
  140. }
  141. leftSides.set(nPoints - 1, differences.get(nPoints - 2));
  142. rightSides.set(nPoints - 1, differences.get(nPoints - 2));
  143. }
  144. }
  145. /**
  146. * Draws the histogram
  147. *
  148. * @param plotBasePoint the histogram base point in the plot reference system
  149. */
  150. public void draw(GPoint plotBasePoint) {
  151. if (visible) {
  152. // Calculate the baseline for the histogram
  153. float baseline = 0;
  154. if (plotBasePoint.isValid()) {
  155. baseline = (type == GPlot.VERTICAL) ? plotBasePoint.getY() : plotBasePoint.getX();
  156. }
  157. // Draw the rectangles
  158. parent.pushStyle();
  159. parent.rectMode(CORNERS);
  160. parent.strokeCap(SQUARE);
  161. for (int i = 0; i < plotPoints.getNPoints(); i++) {
  162. if (plotPoints.isValid(i)) {
  163. // Obtain the corners
  164. float x1, x2, y1, y2;
  165. if (type == GPlot.VERTICAL) {
  166. x1 = plotPoints.getX(i) - leftSides.get(i);
  167. x2 = plotPoints.getX(i) + rightSides.get(i);
  168. y1 = plotPoints.getY(i);
  169. y2 = baseline;
  170. } else {
  171. x1 = baseline;
  172. x2 = plotPoints.getX(i);
  173. y1 = plotPoints.getY(i) - leftSides.get(i);
  174. y2 = plotPoints.getY(i) + rightSides.get(i);
  175. }
  176. if (x1 < 0) {
  177. x1 = 0;
  178. } else if (x1 > dim[0]) {
  179. x1 = dim[0];
  180. }
  181. if (-y1 < 0) {
  182. y1 = 0;
  183. } else if (-y1 > dim[1]) {
  184. y1 = -dim[1];
  185. }
  186. if (x2 < 0) {
  187. x2 = 0;
  188. } else if (x2 > dim[0]) {
  189. x2 = dim[0];
  190. }
  191. if (-y2 < 0) {
  192. y2 = 0;
  193. } else if (-y2 > dim[1]) {
  194. y2 = -dim[1];
  195. }
  196. // Draw the rectangle
  197. float lw = lineWidths[i % lineWidths.length];
  198. parent.fill(bgColors[i % bgColors.length]);
  199. parent.stroke(lineColors[i % lineColors.length]);
  200. parent.strokeWeight(lw);
  201. if (Math.abs(x2 - x1) > 2 * lw && Math.abs(y2 - y1) > 2 * lw) {
  202. parent.rect(x1, y1, x2, y2);
  203. } else if ((type == GPlot.VERTICAL && x2 != x1 && !(y1 == y2 && (y1 == 0 || y1 == -dim[1])))
  204. || (type == GPlot.HORIZONTAL && y2 != y1 && !(x1 == x2 && (x1 == 0 || x1 == dim[0])))) {
  205. parent.rect(x1, y1, x2, y2);
  206. parent.line(x1, y1, x1, y2);
  207. parent.line(x2, y1, x2, y2);
  208. parent.line(x1, y1, x2, y1);
  209. parent.line(x1, y2, x2, y2);
  210. }
  211. }
  212. }
  213. parent.popStyle();
  214. // Draw the labels
  215. if (drawLabels) {
  216. drawHistLabels();
  217. }
  218. }
  219. }
  220. /**
  221. * Draws the histogram labels
  222. */
  223. protected void drawHistLabels() {
  224. parent.pushStyle();
  225. parent.textFont(font);
  226. parent.textSize(fontSize);
  227. parent.fill(fontColor);
  228. parent.noStroke();
  229. if (type == GPlot.VERTICAL) {
  230. if (rotateLabels) {
  231. parent.textAlign(RIGHT, CENTER);
  232. for (int i = 0; i < plotPoints.getNPoints(); i++) {
  233. if (plotPoints.isValid(i) && plotPoints.getX(i) >= 0 && plotPoints.getX(i) <= dim[0]) {
  234. parent.pushMatrix();
  235. parent.translate(plotPoints.getX(i), labelsOffset);
  236. parent.rotate(-HALF_PI);
  237. parent.text(plotPoints.getLabel(i), 0, 0);
  238. parent.popMatrix();
  239. }
  240. }
  241. } else {
  242. parent.textAlign(CENTER, TOP);
  243. for (int i = 0; i < plotPoints.getNPoints(); i++) {
  244. if (plotPoints.isValid(i) && plotPoints.getX(i) >= 0 && plotPoints.getX(i) <= dim[0]) {
  245. parent.text(plotPoints.getLabel(i), plotPoints.getX(i), labelsOffset);
  246. }
  247. }
  248. }
  249. } else {
  250. if (rotateLabels) {
  251. parent.textAlign(CENTER, BOTTOM);
  252. for (int i = 0; i < plotPoints.getNPoints(); i++) {
  253. if (plotPoints.isValid(i) && -plotPoints.getY(i) >= 0 && -plotPoints.getY(i) <= dim[1]) {
  254. parent.pushMatrix();
  255. parent.translate(-labelsOffset, plotPoints.getY(i));
  256. parent.rotate(-HALF_PI);
  257. parent.text(plotPoints.getLabel(i), 0, 0);
  258. parent.popMatrix();
  259. }
  260. }
  261. } else {
  262. parent.textAlign(RIGHT, CENTER);
  263. for (int i = 0; i < plotPoints.getNPoints(); i++) {
  264. if (plotPoints.isValid(i) && -plotPoints.getY(i) >= 0 && -plotPoints.getY(i) <= dim[1]) {
  265. parent.text(plotPoints.getLabel(i), -labelsOffset, plotPoints.getY(i));
  266. }
  267. }
  268. }
  269. }
  270. parent.popStyle();
  271. }
  272. /**
  273. * Sets the type of histogram to display
  274. *
  275. * @param newType the new type of histogram to display
  276. */
  277. public void setType(int newType) {
  278. if (newType != type && (newType == GPlot.VERTICAL || newType == GPlot.HORIZONTAL)) {
  279. type = newType;
  280. updateArrays();
  281. }
  282. }
  283. /**
  284. * Sets the plot box dimensions information
  285. *
  286. * @param xDim the new plot box x dimension
  287. * @param yDim the new plot box y dimension
  288. */
  289. public void setDim(float xDim, float yDim) {
  290. if (xDim > 0 && yDim > 0) {
  291. dim[0] = xDim;
  292. dim[1] = yDim;
  293. updateArrays();
  294. }
  295. }
  296. /**
  297. * Sets the plot box dimensions information
  298. *
  299. * @param newDim the new plot box dimensions information
  300. */
  301. public void setDim(float[] newDim) {
  302. setDim(newDim[0], newDim[1]);
  303. }
  304. /**
  305. * Sets the histogram plot points
  306. *
  307. * @param newPlotPoints the new point positions in the plot reference system
  308. */
  309. public void setPlotPoints(GPointsArray newPlotPoints) {
  310. plotPoints.set(newPlotPoints);
  311. initializeArrays(plotPoints.getNPoints());
  312. updateArrays();
  313. }
  314. /**
  315. * Sets one of the histogram plot points
  316. *
  317. * @param index the point position
  318. * @param newPlotPoint the new point positions in the plot reference system
  319. */
  320. public void setPlotPoint(int index, GPoint newPlotPoint) {
  321. plotPoints.set(index, newPlotPoint);
  322. updateArrays();
  323. }
  324. /**
  325. * Adds a new plot point to the histogram
  326. *
  327. * @param newPlotPoint the new point position in the plot reference system
  328. */
  329. public void addPlotPoint(GPoint newPlotPoint) {
  330. plotPoints.add(newPlotPoint);
  331. initializeArrays(plotPoints.getNPoints());
  332. updateArrays();
  333. }
  334. /**
  335. * Adds a new plot point to the histogram
  336. *
  337. * @param index the position to add the point
  338. * @param newPlotPoint the new point position in the plot reference system
  339. */
  340. public void addPlotPoint(int index, GPoint newPlotPoint) {
  341. plotPoints.add(index, newPlotPoint);
  342. initializeArrays(plotPoints.getNPoints());
  343. updateArrays();
  344. }
  345. /**
  346. * Adds a new plot points to the histogram
  347. *
  348. * @param newPlotPoints the new points positions in the plot reference system
  349. */
  350. public void addPlotPoints(GPointsArray newPlotPoints) {
  351. plotPoints.add(newPlotPoints);
  352. initializeArrays(plotPoints.getNPoints());
  353. updateArrays();
  354. }
  355. /**
  356. * Removes one of the points from the histogram
  357. *
  358. * @param index the point position
  359. */
  360. public void removePlotPoint(int index) {
  361. plotPoints.remove(index);
  362. initializeArrays(plotPoints.getNPoints());
  363. updateArrays();
  364. }
  365. /**
  366. * Sets the separations between the histogram elements
  367. *
  368. * @param newSeparations the new separations between the histogram elements
  369. */
  370. public void setSeparations(float[] newSeparations) {
  371. separations = newSeparations.clone();
  372. updateArrays();
  373. }
  374. /**
  375. * Sets the background colors of the histogram elements
  376. *
  377. * @param newBgColors the new background colors of the histogram elements
  378. */
  379. public void setBgColors(int[] newBgColors) {
  380. bgColors = newBgColors.clone();
  381. }
  382. /**
  383. * Sets the line colors of the histogram elements
  384. *
  385. * @param newLineColors the new line colors of the histogram elements
  386. */
  387. public void setLineColors(int[] newLineColors) {
  388. lineColors = newLineColors.clone();
  389. }
  390. /**
  391. * Sets the line widths of the histogram elements
  392. *
  393. * @param newLineWidths the new line widths of the histogram elements
  394. */
  395. public void setLineWidths(float[] newLineWidths) {
  396. lineWidths = newLineWidths.clone();
  397. }
  398. /**
  399. * Sets if the histogram should be visible or not
  400. *
  401. * @param newVisible true if the histogram should be visible
  402. */
  403. public void setVisible(boolean newVisible) {
  404. visible = newVisible;
  405. }
  406. /**
  407. * Sets the histogram labels offset
  408. *
  409. * @param newLabelsOffset the new histogram labels offset
  410. */
  411. public void setLabelsOffset(float newLabelsOffset) {
  412. labelsOffset = newLabelsOffset;
  413. }
  414. /**
  415. * Sets if the histogram labels should be drawn or not
  416. *
  417. * @param newDrawLabels true if the histogram labels should be drawn
  418. */
  419. public void setDrawLabels(boolean newDrawLabels) {
  420. drawLabels = newDrawLabels;
  421. }
  422. /**
  423. * Sets if the histogram labels should be rotated or not
  424. *
  425. * @param newRotateLabels true if the histogram labels should be rotated
  426. */
  427. public void setRotateLabels(boolean newRotateLabels) {
  428. rotateLabels = newRotateLabels;
  429. }
  430. /**
  431. * Sets the font name
  432. *
  433. * @param newFontName the name of the new font
  434. */
  435. public void setFontName(String newFontName) {
  436. fontName = newFontName;
  437. font = parent.createFont(fontName, fontSize);
  438. }
  439. /**
  440. * Sets the font color
  441. *
  442. * @param newFontColor the new font color
  443. */
  444. public void setFontColor(int newFontColor) {
  445. fontColor = newFontColor;
  446. }
  447. /**
  448. * Sets the font size
  449. *
  450. * @param newFontSize the new font size
  451. */
  452. public void setFontSize(int newFontSize) {
  453. if (newFontSize > 0) {
  454. fontSize = newFontSize;
  455. font = parent.createFont(fontName, fontSize);
  456. }
  457. }
  458. /**
  459. * Sets all the font properties at once
  460. *
  461. * @param newFontName the name of the new font
  462. * @param newFontColor the new font color
  463. * @param newFontSize the new font size
  464. */
  465. public void setFontProperties(String newFontName, int newFontColor, int newFontSize) {
  466. if (newFontSize > 0) {
  467. fontName = newFontName;
  468. fontColor = newFontColor;
  469. fontSize = newFontSize;
  470. font = parent.createFont(fontName, fontSize);
  471. }
  472. }
  473. }