diff --git a/interface/slice_diagram.cpp b/interface/slice_diagram.cpp index 17fb193b..36375feb 100644 --- a/interface/slice_diagram.cpp +++ b/interface/slice_diagram.cpp @@ -1,19 +1,15 @@ /********************************************************************** Copyright 2014-2016 The RIVET Developers. See the COPYRIGHT file at the top-level directory of this distribution. - This file is part of RIVET. - This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - This program 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 Public License for more details. - You should have received a copy of the GNU General Public License along with this program. If not, see . **********************************************************************/ @@ -122,6 +118,24 @@ void SliceDiagram::create_diagram(const QString x_text, const QString y_text, do x_label_text = x_text; y_label_text = y_text; + //xgrades text and line items + for (unsigned int i = 0; i < x_grades.size(); i++) { + QGraphicsSimpleTextItem* text = new QGraphicsSimpleTextItem; + textlistx.push_back(text); + QGraphicsLineItem* line = new QGraphicsLineItem; + linelistx.push_back(line); + + } + + //ygrades text and line items + for (unsigned int i = 0; i < y_grades.size(); i++) { + QGraphicsSimpleTextItem* text = new QGraphicsSimpleTextItem; + textlisty.push_back(text); + QGraphicsLineItem* line = new QGraphicsLineItem; + linelisty.push_back(line); + + } + //pens and brushes QPen blackPen(Qt::black); blackPen.setWidth(2); @@ -171,20 +185,7 @@ void SliceDiagram::create_diagram(const QString x_text, const QString y_text, do y_label->setTransform(QTransform(0, 1, 1, 0, 0, 0)); y_label->setFont(config_params->diagramFont); - rect1 = addRect(0, 0, 0, 0, Qt::NoPen, QBrush(QColor(255, 255, 255))); - rect2 = addRect(0, 0, 0, 0, Qt::NoPen, QBrush(QColor(255, 255, 255))); - rect3 = addRect(0, 0, 0, 0, Qt::NoPen, QBrush(QColor(255, 255, 255))); - rect4 = addRect(0, 0, 0, 0, Qt::NoPen, QBrush(QColor(255, 255, 255))); - rect5 = addRect(0, 0, 0, 0, Qt::NoPen, QBrush(QColor(255, 255, 255))); - rect6 = addRect(0, 0, 0, 0, Qt::NoPen, QBrush(QColor(255, 255, 255))); - int BigZValue = 1000; //probably not the best way to do this... - rect1->setZValue(BigZValue); - rect2->setZValue(BigZValue); - rect3->setZValue(BigZValue); - rect4->setZValue(BigZValue); - rect5->setZValue(BigZValue); - rect6->setZValue(BigZValue); data_xmin_text->setZValue(BigZValue + 1); data_ymin_text->setZValue(BigZValue + 1); @@ -193,6 +194,29 @@ void SliceDiagram::create_diagram(const QString x_text, const QString y_text, do x_label->setZValue(BigZValue + 1); y_label->setZValue(BigZValue + 1); + //Draw labels for the labels in between min and max + std::ostringstream stream; + + for (unsigned int i = 0; i < x_grades.size(); i++) { // for x_grade labels + stream.precision(4); + + stream << x_grades[i]; + textlistx[i] = addSimpleText(QString(stream.str().data())); + textlistx[i]->setFlag(QGraphicsItem::ItemIgnoresTransformations); + textlistx[i]->setFont(config_params->diagramFont); + textlistx[i]->setZValue(BigZValue); + } + + for (unsigned int i = 0; i < y_grades.size(); i++) { // for y_grade labels + stream.precision(4); + + stream << y_grades[i]; + textlisty[i] = addSimpleText(QString(stream.str().data())); + textlisty[i]->setFlag(QGraphicsItem::ItemIgnoresTransformations); + textlisty[i]->setFont(config_params->diagramFont); + textlisty[i]->setZValue(BigZValue); + } + //create rectangles for visualizing homology dimensions //first, find max dimension unsigned max_hom_dim = 0; @@ -219,6 +243,21 @@ void SliceDiagram::create_diagram(const QString x_text, const QString y_text, do } } + //draw tick marks + // first define tick marks for the maxes and mins + xmintick = addLine(QLineF(), blackPen); + xmaxtick = addLine(QLineF(), blackPen); + ymintick = addLine(QLineF(), blackPen); + ymaxtick = addLine(QLineF(), blackPen); + + // define tick marks for the rest of the axis labels + for (unsigned int i = 0; i < x_grades.size(); i++) { + linelistx[i] = addLine(QLineF(), blackPen); + } + for (unsigned int i = 0; i < y_grades.size(); i++) { + linelisty[i] = addLine(QLineF(), blackPen); + } + //draw bounds gray_line_vertical = addLine(QLineF(), grayPen); //(diagram_width, 0, diagram_width, diagram_height, grayPen); gray_line_horizontal = addLine(QLineF(), grayPen); //0, diagram_height, diagram_width, diagram_height, grayPen); @@ -349,9 +388,9 @@ void SliceDiagram::resize_diagram() //determine scale double left_text_width = std::max(data_ymin_text->boundingRect().width(), data_ymax_text->boundingRect().width()); - double diagram_max_width = view_width - padding - 2 * scene_padding - text_padding - left_text_width; + double diagram_max_width = view_width - padding - 2 * scene_padding - text_padding - left_text_width - y_label->boundingRect().height(); double lower_text_height = std::max(data_xmin_text->boundingRect().height(), data_xmax_text->boundingRect().height()); - double diagram_max_height = view_height - padding - 2 * scene_padding - text_padding - lower_text_height; + double diagram_max_height = view_height - padding - 2 * scene_padding - text_padding - lower_text_height - x_label->boundingRect().height(); if (data_xmax > data_xmin) scale_x = diagram_max_width / (data_xmax - data_xmin); @@ -436,6 +475,14 @@ void SliceDiagram::resize_diagram() //redraw labels redraw_labels(); + //reposition tick marks + xmintick->setLine((data_xmin_text->pos().x()) + (data_xmin_text->boundingRect().width() / 2), 0, (data_xmin_text->pos().x()) + (data_xmin_text->boundingRect().width() / 2), (-1 * padding + 13)); + xmaxtick->setLine((data_xmax_text->pos().x()) + (data_xmax_text->boundingRect().width() / 2), 0, (data_xmax_text->pos().x()) + (data_xmax_text->boundingRect().width() / 2), (-1 * padding + 13)); + ymintick->setLine(0, (data_ymin_text->pos().y()) - (data_ymin_text->boundingRect().height() / 2), (-1 * padding + 13), (data_ymin_text->pos().y()) - (data_ymin_text->boundingRect().height() / 2)); + ymaxtick->setLine(0, (data_ymax_text->pos().y()) - (data_ymin_text->boundingRect().height() / 2), (-1 * padding + 13), (data_ymax_text->pos().y()) - (data_ymin_text->boundingRect().height() / 2)); + + redraw_tickmarks(); + //clear selection (because resizing window might combine or split dots in the upper strip of the persistence diagram) clear_selection(); highlight_line->hide(); @@ -444,10 +491,10 @@ void SliceDiagram::resize_diagram() if (primary_selected.size() > 0) update_highlight(); //set scene rectangle (necessary to prevent auto-scrolling) - double scene_rect_x = -left_text_width - text_padding; - double scene_rect_y = -lower_text_height - text_padding; - double scene_rect_w = diagram_width + padding + text_padding + left_text_width; - double scene_rect_h = diagram_height + padding + text_padding + lower_text_height; + double scene_rect_x = -left_text_width - text_padding - y_label->boundingRect().height(); + double scene_rect_y = -lower_text_height - text_padding - x_label->boundingRect().height(); + double scene_rect_w = diagram_width + padding + text_padding + left_text_width + y_label->boundingRect().height() + data_xmax_text->boundingRect().width(); + double scene_rect_h = diagram_height + padding + text_padding + lower_text_height + x_label->boundingRect().height(); redraw_labels(); setSceneRect(scene_rect_x, scene_rect_y, scene_rect_w, scene_rect_h); @@ -601,6 +648,14 @@ void SliceDiagram::zoom_diagram(double angle, double offset, double distance_to_ //draw the labels redraw_labels(); + //reposition tick marks + xmintick->setLine((data_xmin_text->pos().x()) + (data_xmin_text->boundingRect().width() / 2), 0, (data_xmin_text->pos().x()) + (data_xmin_text->boundingRect().width() / 2), (-1 * padding + 13)); + xmaxtick->setLine((data_xmax_text->pos().x()) + (data_xmax_text->boundingRect().width() / 2), 0, (data_xmax_text->pos().x()) + (data_xmax_text->boundingRect().width() / 2), (-1 * padding + 13)); + ymintick->setLine(0, (data_ymin_text->pos().y()) - (data_ymin_text->boundingRect().height() / 2), (-1 * padding + 13), (data_ymin_text->pos().y()) - (data_ymin_text->boundingRect().height() / 2)); + ymaxtick->setLine(0, (data_ymax_text->pos().y()) - (data_ymin_text->boundingRect().height() / 2), (-1 * padding + 13), (data_ymax_text->pos().y()) - (data_ymin_text->boundingRect().height() / 2)); + + redraw_tickmarks(); + //clear selection (because resizing window might combine or split dots in the upper strip of the persistence diagram) clear_selection(); highlight_line->hide(); @@ -693,6 +748,14 @@ void SliceDiagram::receive_parameter_change() x_label->setFont(config_params->diagramFont); y_label->setFont(config_params->diagramFont); + //update fonts for axis labels between max and min + for (unsigned int i = 0; i < x_grades.size(); i++) { + textlistx[i]->setFont(config_params->diagramFont); + } + for (unsigned int i = 0; i < y_grades.size(); i++) { + textlisty[i]->setFont(config_params->diagramFont); + } + //update diagram resize_diagram(); } //end receive_parameter_change() @@ -1152,18 +1215,109 @@ double SliceDiagram::get_pd_scale() return scale_x * scale_y / denominator; } +//redraws the tick marks on the axis diagram +void SliceDiagram::redraw_tickmarks() +{ + int tickmarksize; + tickmarksize = 8; + + //reposition tick marks + for (unsigned int i = 0; i < x_grades.size(); i++) { + double left = (x_grades[i] - data_xmin) * scale_x; + left = fmin(fmax(0, left), diagram_width + padding); + if (textlistx[i]->isVisible() == false) { + linelistx[i]->setPos(left, 0); + linelistx[i]->setLine(0, 0, 0, -tickmarksize/2); + } else { + linelistx[i]->setPos(left, 0); + linelistx[i]->setLine(0, 0, 0, -tickmarksize); + linelistx[i]->show(); + } + } + + for (unsigned int i = 0; i < y_grades.size(); i++) { + double bottom = (y_grades[i] - data_ymin) * scale_y; + bottom = fmin(fmax(0, bottom), diagram_height + padding); + if (textlisty[i]->isVisible() == false) { + linelisty[i]->setPos(0, bottom); + linelisty[i]->setLine(0, 0, -tickmarksize/2, 0); + } else { + linelisty[i]->setPos(0, bottom); + linelisty[i]->setLine(0, 0, -tickmarksize, 0); + linelisty[i]->show(); + } + } +} + //draws labels on top of white rectangles, so they don't get obscured by other graphics void SliceDiagram::redraw_labels() { - + int mindistbetweenlables = 10; //the minimum number of pixels that should be between the axis label numbers int text_padding = 15; //pixels data_xmin_text->setPos(data_xmin_text->boundingRect().width() / (-2), -1 * text_padding); data_xmax_text->setPos(diagram_width - data_xmax_text->boundingRect().width() / 2, -1 * text_padding); data_ymin_text->setPos(-1 * text_padding - data_ymin_text->boundingRect().width(), data_ymin_text->boundingRect().height() / 2); data_ymax_text->setPos(-1 * text_padding - data_ymax_text->boundingRect().width(), diagram_height + data_ymax_text->boundingRect().height() / 2); - x_label->setPos((diagram_width - x_label->boundingRect().width()) / 2, -1 * text_padding); - y_label->setPos(-1 * text_padding - y_label->boundingRect().height(), (diagram_height - y_label->boundingRect().width()) / 2); + x_label->setPos((diagram_width - x_label->boundingRect().width()) / 2, -1 * text_padding - 5 - (data_xmin_text->boundingRect().height())); + y_label->setPos(-1 * text_padding - (data_ymax_text->boundingRect().width()) - y_label->boundingRect().height()-10, (diagram_height - y_label->boundingRect().width()) / 2); + + //setting position for x_grades axis label + for (unsigned i = 0; i < x_grades.size(); i++) { + double left = (x_grades[i] - data_xmin) * scale_x; + + left = fmin(fmax(0, left), diagram_width + padding); + + textlistx[i]->setPos((left - (textlistx[i]->boundingRect().width() / 2)), -1 * text_padding); + + std::ostringstream stream1; + stream1.clear(); + stream1.precision(4); + stream1 << (x_grades[i] == 0 ? 0 : x_grades[i] * xrev_sign); + textlistx[i]->setText(QString(stream1.str().data())); + + } + + //setting position for y_grades axis labels + for (unsigned i = 0; i < y_grades.size(); i++) { + double bottom = (y_grades[i] - data_ymin) * scale_y; + + bottom = fmin(fmax(0, bottom), diagram_height + padding); + + textlisty[i]->setPos(-1 * text_padding - textlisty[i]->boundingRect().width(), (bottom + (textlisty[i]->boundingRect().height() / 2))); + + std::ostringstream stream2; + stream2.clear(); + stream2.precision(4); + stream2 << (y_grades[i] == 0 ? 0 : y_grades[i] * yrev_sign); + textlisty[i]->setText(QString(stream2.str().data())); + } + + double currentdistx = (data_xmin_text->pos().x() + data_xmin_text->boundingRect().width()) + mindistbetweenlables; + double currentdisty = data_ymin_text->pos().y(); + + //checking for space on the axis for the labels to fit + for (unsigned int i = 0; i < x_grades.size(); i++) { + if (textlistx[i]->pos().x() > currentdistx && (textlistx[i]->pos().x() + textlistx[i]->boundingRect().width()) < data_xmax_text->pos().x()) { + + currentdistx = textlistx[i]->pos().x() + textlistx[i]->boundingRect().width() + mindistbetweenlables; + textlistx[i]->show(); + } else { + textlistx[i]->hide(); + } + } + + for (unsigned int i = 0; i < y_grades.size(); i++) { + if ((textlisty[i]->pos().y() - textlisty[i]->boundingRect().height()) > currentdisty && textlisty[i]->pos().y() < (data_ymax_text->pos().y() - data_ymax_text->boundingRect().height())) { + + currentdisty = textlisty[i]->pos().y(); + + textlisty[i]->show(); + + } else { + textlisty[i]->hide(); + } + } std::ostringstream s_xmin; s_xmin.precision(4); @@ -1171,36 +1325,19 @@ void SliceDiagram::redraw_labels() s_xmin << (data_xmin == 0 ? 0 : data_xmin * xrev_sign); data_xmin_text->setText(QString(s_xmin.str().data())); - rect1->setRect(0, 0, data_xmin_text->sceneBoundingRect().width(), data_xmin_text->sceneBoundingRect().height()); - rect1->setPos(data_xmin_text->pos().x(), data_xmin_text->pos().y() - data_xmin_text->boundingRect().height()); - std::ostringstream s_ymin; s_ymin.precision(4); s_ymin << (data_ymin == 0 ? 0 : data_ymin * yrev_sign); data_ymin_text->setText(QString(s_ymin.str().data())); - rect2->setRect(0, 0, data_ymin_text->sceneBoundingRect().width(), data_ymin_text->sceneBoundingRect().height()); - rect2->setPos(data_ymin_text->pos().x(), data_ymin_text->pos().y() - data_ymin_text->boundingRect().height()); - std::ostringstream s_xmax; s_xmax.precision(4); s_xmax << (data_xmax == 0 ? 0 : data_xmax * xrev_sign); data_xmax_text->setText(QString(s_xmax.str().data())); - rect3->setRect(0, 0, data_xmax_text->sceneBoundingRect().width(), data_xmax_text->sceneBoundingRect().height()); - rect3->setPos(data_xmax_text->pos().x(), data_xmax_text->pos().y() - data_xmax_text->boundingRect().height()); - std::ostringstream s_ymax; s_ymax.precision(4); s_ymax << (data_ymax == 0 ? 0 : data_ymax * yrev_sign); data_ymax_text->setText(QString(s_ymax.str().data())); - rect4->setRect(0, 0, data_ymax_text->sceneBoundingRect().width(), data_ymax_text->sceneBoundingRect().height()); - rect4->setPos(data_ymax_text->pos().x(), data_ymax_text->pos().y() - data_ymax_text->boundingRect().height()); - - rect5->setRect(0, 0, x_label->boundingRect().width(), x_label->boundingRect().height()); - rect5->setPos(x_label->pos().x(), x_label->pos().y() - x_label->boundingRect().height()); - - rect6->setRect(0, 0, y_label->boundingRect().height(), y_label->boundingRect().width()); - rect6->setPos(y_label->pos().x(), y_label->pos().y()); -} +} \ No newline at end of file diff --git a/interface/slice_diagram.h b/interface/slice_diagram.h index 1a84440c..efdf56b4 100644 --- a/interface/slice_diagram.h +++ b/interface/slice_diagram.h @@ -1,19 +1,15 @@ /********************************************************************** Copyright 2014-2016 The RIVET Developers. See the COPYRIGHT file at the top-level directory of this distribution. - This file is part of RIVET. - This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - This program 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 Public License for more details. - You should have received a copy of the GNU General Public License along with this program. If not, see . **********************************************************************/ @@ -57,6 +53,7 @@ class SliceDiagram : public QGraphicsScene { void redraw_dim_rects(); //redraws the rectangles for the homology dimension visualization void redraw_dots(); //redraws the support points of the multigraded Betti numbers void redraw_labels(); //redraws axis labels in same position on top of rectangles + void redraw_tickmarks(); //redraws tick marks on the axis labels void zoom_diagram(double angle, double offset, double distance_to_origin); //redraws diagram in response to a change in bounds @@ -121,6 +118,14 @@ public slots: //parameters ConfigParameters* config_params; + std::vector datalistx; // contains the data from x_grades + std::vector datalisty; // contains the data from y_grades + + std::vector textlistx; // text items for x_grades labels + std::vector textlisty; // text items for y_grades labels + std::vector linelistx; //tick marks for x_grade labels + std::vector linelisty; //tick marks for y_grade labels + //graphics items QGraphicsSimpleTextItem* data_xmin_text; QGraphicsSimpleTextItem* data_xmax_text; @@ -135,6 +140,12 @@ public slots: QGraphicsLineItem* gray_line_vertical_left; //vertical gray line at the left of the grading rectangle QGraphicsLineItem* gray_line_horizontal_bottom; //horizontal gray line at the bottom of the grading rectangle + //max and min tick marks + QGraphicsLineItem* xmintick; + QGraphicsLineItem* xmaxtick; + QGraphicsLineItem* ymintick; + QGraphicsLineItem* ymaxtick; + QGraphicsRectItem* rect1; QGraphicsRectItem* rect2; QGraphicsRectItem* rect3; @@ -218,4 +229,4 @@ public slots: std::pair compute_endpoint(double coordinate, unsigned offset); //computes an endpoint of a bar in the barcode }; -#endif // SLICE_DIAGRAM_H +#endif // SLICE_DIAGRAM_H \ No newline at end of file