aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--planner.c223
-rw-r--r--qt-ui/diveplanner.cpp252
-rw-r--r--qt-ui/diveplanner.h49
-rw-r--r--qt-ui/diveplanner.ui18
-rw-r--r--qt-ui/models.cpp1
5 files changed, 227 insertions, 316 deletions
diff --git a/planner.c b/planner.c
index 9df5c894c..95ac0251f 100644
--- a/planner.c
+++ b/planner.c
@@ -13,7 +13,7 @@
#include "planner.h"
#include "gettext.h"
-unsigned int decostoplevels[] = { 0, 3000, 6000, 9000, 12000, 15000, 18000, 21000, 24000, 27000,
+int decostoplevels[] = { 0, 3000, 6000, 9000, 12000, 15000, 18000, 21000, 24000, 27000,
30000, 33000, 36000, 39000, 42000, 45000, 48000, 51000, 54000, 57000,
60000, 63000, 66000, 69000, 72000, 75000, 78000, 81000, 84000, 87000,
90000, 100000, 110000, 120000, 130000, 140000, 150000, 160000, 170000,
@@ -99,6 +99,18 @@ void get_gas_string(int o2, int he, char *text, int len)
snprintf(text, len, "(%d/%d)", (o2 + 5) / 10, (he + 5) / 10);
}
+double interpolate_transition(struct dive *dive, int t0, int t1, int d0, int d1, const struct gasmix *gasmix, int ppo2)
+{
+ int j;
+ double tissue_tolerance;
+
+ for (j = t0; j < t1; j++) {
+ int depth = interpolate(d0, d1, j - t0, t1 - t0);
+ tissue_tolerance = add_segment(depth_to_mbar(depth, dive) / 1000.0, gasmix, 1, ppo2, dive);
+ }
+ return tissue_tolerance;
+}
+
/* returns the tissue tolerance at the end of this (partial) dive */
double tissue_at_end(struct dive *dive, char **cached_datap)
{
@@ -133,43 +145,13 @@ double tissue_at_end(struct dive *dive, char **cached_datap)
}
if (i > 0)
lastdepth = psample->depth.mm;
- for (j = t0; j < t1; j++) {
- int depth = interpolate(lastdepth, sample->depth.mm, j - t0, t1 - t0);
- tissue_tolerance = add_segment(depth_to_mbar(depth, dive) / 1000.0,
- &dive->cylinder[gasidx].gasmix, 1, sample->po2, dive);
- }
+ tissue_tolerance = interpolate_transition(dive, t0, t1, lastdepth, sample->depth.mm, &dive->cylinder[gasidx].gasmix, sample->po2);
psample = sample;
t0 = t1;
}
return tissue_tolerance;
}
-/* how many seconds until we can ascend to the next stop? */
-static int time_at_last_depth(struct dive *dive, int o2, int he, unsigned int next_stop, char **cached_data_p)
-{
- int depth, gasidx;
- double surface_pressure, tissue_tolerance;
- int wait = 0;
- struct sample *sample;
-
- if (!dive)
- return 0;
- surface_pressure = dive->dc.surface_pressure.mbar / 1000.0;
- tissue_tolerance = tissue_at_end(dive, cached_data_p);
- sample = &dive->dc.sample[dive->dc.samples - 1];
- depth = sample->depth.mm;
- gasidx = get_gasidx(dive, o2, he);
- if (gasidx == -1) {
- fprintf(stderr, "cannot find gas (%d/%d), using first gas\n", o2, he);
- gasidx = 0;
- }
- while (deco_allowed_depth(tissue_tolerance, surface_pressure, dive, 1) > next_stop) {
- wait++;
- tissue_tolerance = add_segment(depth_to_mbar(depth, dive) / 1000.0,
- &dive->cylinder[gasidx].gasmix, 1, sample->po2, dive);
- }
- return wait;
-}
/* if a default cylinder is set, use that */
void fill_default_cylinder(cylinder_t *cyl)
@@ -196,6 +178,7 @@ void fill_default_cylinder(cylinder_t *cyl)
if (ti->psi)
cyl->type.size.mliter = cuft_to_l(ti->cuft) * 1000 / bar_to_atm(psi_to_bar(ti->psi));
}
+ cyl->depth.mm = 1600 * 1000 / O2_IN_AIR * 10 - 10000; // MOD of air
}
static int add_gas(struct dive *dive, int o2, int he)
@@ -389,18 +372,18 @@ struct divedatapoint *plan_add_segment(struct diveplan *diveplan, int duration,
}
struct gaschanges {
- unsigned int depth;
+ int depth;
int gasidx;
};
-static struct gaschanges *analyze_gaslist(struct diveplan *diveplan, struct dive *dive, int *gaschangenr)
+static struct gaschanges *analyze_gaslist(struct diveplan *diveplan, struct dive *dive, int *gaschangenr, int depth)
{
int nr = 0;
struct gaschanges *gaschanges = NULL;
struct divedatapoint *dp = diveplan->dp;
while (dp) {
- if (dp->time == 0) {
+ if (dp->time == 0 && dp->depth <= depth) {
int i = 0, j = 0;
nr++;
gaschanges = realloc(gaschanges, nr * sizeof(struct gaschanges));
@@ -436,15 +419,15 @@ static struct gaschanges *analyze_gaslist(struct diveplan *diveplan, struct dive
}
/* sort all the stops into one ordered list */
-static unsigned int *sort_stops(unsigned int *dstops, int dnr, struct gaschanges *gstops, int gnr)
+static unsigned int *sort_stops(int *dstops, int dnr, struct gaschanges *gstops, int gnr)
{
int i, gi, di;
int total = dnr + gnr;
- unsigned int *stoplevels = malloc(total * sizeof(unsigned int));
+ int *stoplevels = malloc(total * sizeof(int));
/* no gaschanges */
if (gnr == 0) {
- memcpy(stoplevels, dstops, dnr * sizeof(unsigned int));
+ memcpy(stoplevels, dstops, dnr * sizeof(int));
return stoplevels;
}
i = total - 1;
@@ -586,17 +569,29 @@ static void add_plan_to_notes(struct diveplan *diveplan, struct dive *dive)
}
#endif
+int ascend_velocity(int depth)
+{
+ /* We need to make this configurable */
+ return 10000/60;
+}
+
void plan(struct diveplan *diveplan, char **cached_datap, struct dive **divep, bool add_deco)
{
struct dive *dive;
struct sample *sample;
int wait_time, o2, he, po2;
int transitiontime, gi;
- unsigned int stopidx, depth, ceiling;
+ int current_cylinder;
+ unsigned int stopidx;
+ int depth, ceiling;
double tissue_tolerance;
struct gaschanges *gaschanges = NULL;
int gaschangenr;
- unsigned int *stoplevels = NULL;
+ int *stoplevels = NULL;
+ char *trial_cache = NULL;
+ bool stopping = false;
+ bool clear_to_ascend;
+ int clock, previous_point_time;
set_gf(diveplan->gflow, diveplan->gfhigh, default_prefs.gf_low_at_maxdepth);
if (!diveplan->surface_pressure)
@@ -614,6 +609,10 @@ void plan(struct diveplan *diveplan, char **cached_datap, struct dive **divep, b
he = dive->cylinder[0].gasmix.he.permille;
get_gas_from_events(&dive->dc, sample->time.seconds, &o2, &he);
po2 = dive->dc.sample[dive->dc.samples - 1].po2;
+ if ((current_cylinder = get_gasidx(dive, o2, he)) == -1) {
+ report_error(translate("gettextFromC", "Can't find gas %d/%d"), (o2 + 5) / 10, (he + 5) / 10);
+ current_cylinder = 0;
+ }
depth = dive->dc.sample[dive->dc.samples - 1].depth.mm;
/* if all we wanted was the dive just get us back to the surface */
@@ -629,90 +628,102 @@ void plan(struct diveplan *diveplan, char **cached_datap, struct dive **divep, b
}
tissue_tolerance = tissue_at_end(dive, cached_datap);
- ceiling = deco_allowed_depth(tissue_tolerance, diveplan->surface_pressure / 1000.0, dive, 1);
+
#if DEBUG_PLAN & 4
printf("gas %d/%d\n", o2, he);
printf("depth %5.2lfm ceiling %5.2lfm\n", depth / 1000.0, ceiling / 1000.0);
#endif
- if (depth < ceiling) /* that's not good... */
- depth = ceiling;
- if (depth == 0 && ceiling == 0) /* we are done here */
- goto done;
+
+ gaschanges = analyze_gaslist(diveplan, dive, &gaschangenr, depth);
for (stopidx = 0; stopidx < sizeof(decostoplevels) / sizeof(int); stopidx++)
- if (decostoplevels[stopidx] >= ceiling)
+ if (decostoplevels[stopidx] >= depth)
break;
if (stopidx > 0)
stopidx--;
-
- /* so now we know the first decostop level above us
- * NOTE, this could be the surface or a long list of potential stops
- * we do NOT start only at the ceiling, as the ceiling may come down
- * further during the ascent.
- * Next we need to figure out if there are better gases available
- * and at which depths we are supposed to switch to them */
- gaschanges = analyze_gaslist(diveplan, dive, &gaschangenr);
stoplevels = sort_stops(decostoplevels, stopidx + 1, gaschanges, gaschangenr);
+ stopidx += gaschangenr;
+ clock = previous_point_time = dive->dc.sample[dive->dc.samples - 1].time.seconds;
gi = gaschangenr - 1;
- stopidx += gaschangenr;
- if (depth > stoplevels[stopidx]) {
- /* right now all the transitions are at 30ft/min - this needs to be configurable */
- transitiontime = (depth - stoplevels[stopidx]) / 150;
-#if DEBUG_PLAN & 2
- printf("transitiontime %d:%02d to depth %5.2lfm\n", FRACTION(transitiontime, 60), stoplevels[stopidx] / 1000.0);
-#endif
- plan_add_segment(diveplan, transitiontime, stoplevels[stopidx], o2, he, po2, false);
- /* re-create the dive */
- delete_single_dive(dive_table.nr - 1);
- *divep = dive = create_dive_from_plan(diveplan);
- if (!dive)
- goto error_exit;
- record_dive(dive);
- }
- while (stopidx > 0) { /* this indicates that we aren't surfacing directly */
- /* if we are in a double-step, eg, when 3m/10ft stop is disabled,
- * just skip the first stop at that depth */
- if (stoplevels[stopidx] == stoplevels[stopidx - 1]) {
- stopidx--;
- continue;
- }
+
+ while (1) {
+ /* We will break out when we hit the surface */
+ do {
+ /* Ascend in one second steps to next stop depth */
+ int deltad = ascend_velocity(depth);
+ if (depth - deltad < stoplevels[stopidx])
+ deltad = depth - stoplevels[stopidx];
+
+ tissue_tolerance = add_segment(depth_to_mbar(depth, dive) / 1000.0, &dive->cylinder[current_cylinder].gasmix, 1, po2, dive);
+ ++clock;
+ depth -= deltad;
+ } while (depth > stoplevels[stopidx]);
+
+ if (depth <= 0)
+ break; /* We are at the surface */
+
+
if (gi >= 0 && stoplevels[stopidx] == gaschanges[gi].depth) {
- o2 = dive->cylinder[gaschanges[gi].gasidx].gasmix.o2.permille;
- he = dive->cylinder[gaschanges[gi].gasidx].gasmix.he.permille;
+ plan_add_segment(diveplan, clock - previous_point_time, depth, o2, he, po2, false);
+ previous_point_time = clock;
+ stopping = true;
+
+ current_cylinder = gaschanges[gi].gasidx;
+ o2 = dive->cylinder[current_cylinder].gasmix.o2.permille;
+ he = dive->cylinder[current_cylinder].gasmix.he.permille;
#if DEBUG_PLAN & 16
printf("switch to gas %d (%d/%d) @ %5.2lfm\n", gaschanges[gi].gasidx,
- (o2 + 5) / 10, (he + 5) / 10, gaschanges[gi].depth / 1000.0);
+ (o2 + 5) / 10, (he + 5) / 10, gaschanges[gi].depth / 1000.0);
#endif
gi--;
}
- wait_time = time_at_last_depth(dive, o2, he, stoplevels[stopidx - 1], cached_datap);
- /* typically deco plans are done in one minute increments; we may want to
- * make this configurable at some point */
- wait_time = ((wait_time + 59) / 60) * 60;
-#if DEBUG_PLAN & 2
- tissue_tolerance = tissue_at_end(dive, cached_datap);
- ceiling = deco_allowed_depth(tissue_tolerance, diveplan->surface_pressure / 1000.0, dive, 1);
- printf("waittime %d:%02d at depth %5.2lfm; ceiling %5.2lfm\n", FRACTION(wait_time, 60),
- stoplevels[stopidx] / 1000.0, ceiling / 1000.0);
-#endif
- if (wait_time)
- plan_add_segment(diveplan, wait_time, stoplevels[stopidx], o2, he, po2, false);
- /* right now all the transitions are at 30ft/min - this needs to be configurable */
- transitiontime = (stoplevels[stopidx] - stoplevels[stopidx - 1]) / 150;
-#if DEBUG_PLAN & 2
- printf("transitiontime %d:%02d to depth %5.2lfm\n", FRACTION(transitiontime, 60), stoplevels[stopidx - 1] / 1000.0);
-#endif
- plan_add_segment(diveplan, transitiontime, stoplevels[stopidx - 1], o2, he, po2, false);
- /* re-create the dive */
- delete_single_dive(dive_table.nr - 1);
- *divep = dive = create_dive_from_plan(diveplan);
- if (!dive)
- goto error_exit;
- record_dive(dive);
- stopidx--;
- }
-done:
+ /* trial ascend */
+ --stopidx;
+ int trial_depth = depth;
+ cache_deco_state(tissue_tolerance, &trial_cache);
+ while(1) {
+ /* Try to ascend to next stop, go back and wait if we hit the ceiling on the way */
+ clear_to_ascend = true;
+ while (trial_depth > stoplevels[stopidx]) {
+ int deltad = ascend_velocity(trial_depth);
+ tissue_tolerance = add_segment(depth_to_mbar(trial_depth, dive) / 1000.0, &dive->cylinder[current_cylinder].gasmix, 1, po2, dive);
+ if (deco_allowed_depth(tissue_tolerance, diveplan->surface_pressure / 1000.0, dive, 1) > trial_depth - deltad){
+ /* We should have stopped */
+ clear_to_ascend = false;
+ break;
+ }
+ trial_depth -= deltad;
+ }
+ restore_deco_state(trial_cache);
+ /* The next stop is clear */
+ if(clear_to_ascend)
+ break;
+
+ /* Wait a minute */
+ if (!stopping) {
+ plan_add_segment(diveplan, clock - previous_point_time, depth, o2, he, po2, false);
+ previous_point_time = clock;
+ stopping = true;
+ }
+ tissue_tolerance = add_segment(depth_to_mbar(depth, dive) / 1000.0, &dive->cylinder[current_cylinder].gasmix, 60, po2, dive);
+ cache_deco_state(tissue_tolerance, &trial_cache);
+ clock += 60;
+ trial_depth = depth;
+ }
+ if (stopping) {
+ plan_add_segment(diveplan, clock - previous_point_time, depth, o2, he, po2, false);
+ previous_point_time = clock;
+ stopping = false;
+ }
+
+ }
+ plan_add_segment(diveplan, clock - previous_point_time, 0, o2, he, po2, false);
+ delete_single_dive(dive_table.nr - 1);
+ *divep = dive = create_dive_from_plan(diveplan);
+ if (!dive)
+ goto error_exit;
+ record_dive(dive);
#if DO_WE_WANT_THIS_IN_QT
add_plan_to_notes(diveplan, dive);
diff --git a/qt-ui/diveplanner.cpp b/qt-ui/diveplanner.cpp
index 5c8973224..cc4565e1a 100644
--- a/qt-ui/diveplanner.cpp
+++ b/qt-ui/diveplanner.cpp
@@ -41,135 +41,6 @@ QString dpGasToStr(const divedatapoint &p)
return gasToStr(p.o2, p.he);
}
-static DivePlannerDisplay *plannerDisplay = DivePlannerDisplay::instance();
-
-DivePlannerDisplay::DivePlannerDisplay(QObject *parent) : QAbstractTableModel(parent)
-{
-}
-
-DivePlannerDisplay *DivePlannerDisplay::instance()
-{
- static QScopedPointer<DivePlannerDisplay> self(new DivePlannerDisplay());
- return self.data();
-}
-
-int DivePlannerDisplay::size()
-{
- return computedPoints.size();
-}
-
-int DivePlannerDisplay::columnCount(const QModelIndex &parent) const
-{
- return COLUMNS;
-}
-
-QVariant DivePlannerDisplay::data(const QModelIndex &index, int role) const
-{
- if (role == Qt::DisplayRole) {
- computedPoint p = computedPoints.at(index.row());
- switch (index.column()) {
- case COMPUTED_DEPTH:
- return rint(get_depth_units(p.computedDepth, NULL, NULL));
- case COMPUTED_DURATION:
- return p.computedTime / 60;
- }
- } else if (role == Qt::DecorationRole) {
- switch (index.column()) {
- case REMOVE:
- return QIcon(":trash");
- }
- } else if (role == Qt::FontRole) {
- return defaultModelFont();
- }
- return QVariant();
-}
-
-bool DivePlannerDisplay::setData(const QModelIndex &index, const QVariant &value, int role)
-{
- if (role == Qt::EditRole) {
- computedPoint &p = computedPoints[index.row()];
- switch (index.column()) {
- case COMPUTED_DEPTH:
- p.computedDepth = units_to_depth(value.toInt());
- break;
- case COMPUTED_DURATION:
- p.computedTime = value.toInt() * 60;
- break;
- }
- }
- return QAbstractItemModel::setData(index, value, role);
-}
-
-QVariant DivePlannerDisplay::headerData(int section, Qt::Orientation orientation, int role) const
-{
- if (role == Qt::DisplayRole && orientation == Qt::Horizontal) {
- switch (section) {
- case COMPUTED_DEPTH:
- return tr("Comp. Depth");
- case COMPUTED_DURATION:
- return tr("Comp. Duration");
- }
- } else if (role == Qt::FontRole) {
- return defaultModelFont();
- }
- return QVariant();
-}
-
-Qt::ItemFlags DivePlannerDisplay::flags(const QModelIndex &index) const
-{
- return QAbstractItemModel::flags(index);
-}
-
-int DivePlannerDisplay::rowCount(const QModelIndex &parent) const
-{
- return computedPoints.size();
-}
-
-struct computedPoint DivePlannerDisplay::at(int row)
-{
- return computedPoints.at(row);
-}
-
-void DivePlannerDisplay::clear()
-{
- if (rowCount() > 0) {
- beginRemoveRows(QModelIndex(), 0, rowCount() - 1);
- computedPoints.clear();
- endRemoveRows();
- }
-}
-
-void DivePlannerDisplay::removeStops()
-{
- if (rowCount() > 0) {
- beginRemoveRows(QModelIndex(), 0, rowCount() - 1);
- endRemoveRows();
- }
-}
-
-void DivePlannerDisplay::addStops()
-{
- int rows = computedPoints.size();
- if (rows > 0) {
- beginInsertRows(QModelIndex(), 0, rows - 1);
- endInsertRows();
- }
-}
-
-void DivePlannerDisplay::insertPoint(const struct computedPoint &p)
-{
- computedPoints.append(p);
-}
-
-void DivePlannerDisplay::remove(const QModelIndex &index)
-{
- if (index.column() != REMOVE)
- return;
-
- beginRemoveRows(QModelIndex(), index.row(), index.row());
- endRemoveRows();
-}
-
static DivePlannerPointsModel *plannerModel = DivePlannerPointsModel::instance();
DivePlannerGraphics::DivePlannerGraphics(QWidget *parent) : QGraphicsView(parent),
@@ -311,7 +182,8 @@ void DivePlannerGraphics::pointInserted(const QModelIndex &parent, int start, in
gasChooseBtn->setZValue(10);
gasChooseBtn->setFlag(QGraphicsItem::ItemIgnoresTransformations);
gases << gasChooseBtn;
- drawProfile();
+ if(plannerModel->recalcQ())
+ drawProfile();
}
void DivePlannerGraphics::keyDownAction()
@@ -585,6 +457,8 @@ QStringList &DivePlannerPointsModel::getGasList()
void DivePlannerGraphics::drawProfile()
{
+ if(!plannerModel->recalcQ())
+ return;
qDeleteAll(lines);
lines.clear();
@@ -598,7 +472,7 @@ void DivePlannerGraphics::drawProfile()
return;
}
while (dp->next) {
- if (dp->depth > max_depth)
+ if (dp->time && dp->depth > max_depth)
max_depth = dp->depth;
dp = dp->next;
}
@@ -639,7 +513,16 @@ void DivePlannerGraphics::drawProfile()
QPolygonF poly;
poly.append(QPointF(lastx, lasty));
- plannerDisplay->clear();
+ bool oldRecalc = plannerModel->setRecalc(false);
+ QVector<int> computedPoints;
+ for (int i = 0; i < plannerModel->rowCount(); i++)
+ if (!plannerModel->at(i).entered)
+ computedPoints.push_back(i);
+ plannerModel->removeSelectedPoints(computedPoints);
+
+ int lastdepth = 0;
+ int lasto2 = 0;
+ int lasthe = 0;
for (dp = diveplan.dp; dp != NULL; dp = dp->next) {
if (dp->time == 0) // magic entry for available tank
continue;
@@ -648,21 +531,22 @@ void DivePlannerGraphics::drawProfile()
if (!dp->entered) {
QGraphicsLineItem *item = new QGraphicsLineItem(lastx, lasty, xpos, ypos);
item->setPen(QPen(QBrush(Qt::red), 0));
+
scene()->addItem(item);
lines << item;
if (dp->depth) {
- qDebug() << "Time: " << dp->time / 60 << " depth: " << dp->depth / 1000;
- computedPoint p(dp->time, dp->depth);
- plannerDisplay->insertPoint(p);
+ if (dp->depth == lastdepth || dp->o2 != dp->next->o2 || dp->he != dp->next->he)
+ plannerModel->addStop(dp->depth, dp->time, dp->o2, dp->he, 0, false);
+ lastdepth = dp->depth;
+ lasto2 = dp->o2;
+ lasthe = dp->he;
}
}
lastx = xpos;
lasty = ypos;
poly.append(QPointF(lastx, lasty));
}
-
- qDebug() << " ";
- plannerDisplay->addStops();
+ plannerModel->setRecalc(oldRecalc);
diveBg->setPolygon(poly);
QRectF b = poly.boundingRect();
@@ -1069,9 +953,8 @@ DivePlannerWidget::DivePlannerWidget(QWidget *parent, Qt::WindowFlags f) : QWidg
ui.setupUi(this);
ui.tableWidget->setTitle(tr("Dive Planner Points"));
ui.tableWidget->setModel(DivePlannerPointsModel::instance());
+ DivePlannerPointsModel::instance()->setRecalc(true);
ui.tableWidget->view()->setItemDelegateForColumn(DivePlannerPointsModel::GAS, new AirTypesDelegate(this));
- ui.tableWidgetComp->setTitle(tr("Computed Waypoints"));
- ui.tableWidgetComp->setModel(DivePlannerDisplay::instance());
ui.cylinderTableWidget->setTitle(tr("Available Gases"));
ui.cylinderTableWidget->setModel(CylindersModel::instance());
QTableView *view = ui.cylinderTableWidget->view();
@@ -1090,9 +973,14 @@ DivePlannerWidget::DivePlannerWidget(QWidget *parent, Qt::WindowFlags f) : QWidg
GasSelectionModel::instance(), SLOT(repopulate()));
connect(CylindersModel::instance(), SIGNAL(rowsRemoved(QModelIndex, int, int)),
GasSelectionModel::instance(), SLOT(repopulate()));
+ connect(CylindersModel::instance(), SIGNAL(dataChanged(QModelIndex, int, int)),
+ plannerModel, SLOT(drawProfile()));
+ connect(CylindersModel::instance(), SIGNAL(rowsInserted(QModelIndex, int, int)),
+ plannerModel, SLOT(drawProfile()));
+ connect(CylindersModel::instance(), SIGNAL(rowsRemoved(QModelIndex, int, int)),
+ plannerModel, SLOT(drawProfile()));
ui.tableWidget->setBtnToolTip(tr("add dive data point"));
- ui.tableWidgetComp->setBtnToolTip(tr("This does nothing, and should be removed"));
connect(ui.startTime, SIGNAL(timeChanged(QTime)), plannerModel, SLOT(setStartTime(QTime)));
connect(ui.ATMPressure, SIGNAL(textChanged(QString)), this, SLOT(atmPressureChanged(QString)));
connect(ui.bottomSAC, SIGNAL(textChanged(QString)), this, SLOT(bottomSacChanged(QString)));
@@ -1156,6 +1044,18 @@ bool DivePlannerPointsModel::isPlanner()
return mode == PLAN;
}
+bool DivePlannerPointsModel::setRecalc(bool rec)
+{
+ bool old = recalc;
+ recalc = rec;
+ return old;
+}
+
+bool DivePlannerPointsModel::recalcQ()
+{
+ return recalc;
+}
+
int DivePlannerPointsModel::columnCount(const QModelIndex &parent) const
{
return COLUMNS;
@@ -1170,9 +1070,15 @@ QVariant DivePlannerPointsModel::data(const QModelIndex &index, int role) const
return (double)p.po2 / 1000;
case DEPTH:
return rint(get_depth_units(p.depth, NULL, NULL));
- case DURATION:
+ case RUNTIME:
return p.time / 60;
+ case DURATION:
+ if (index.row())
+ return (p.time - divepoints.at(index.row() -1).time) / 60;
+ else
+ return p.time / 60;
case GAS:
+
return dpGasToStr(p);
}
} else if (role == Qt::DecorationRole) {
@@ -1181,7 +1087,13 @@ QVariant DivePlannerPointsModel::data(const QModelIndex &index, int role) const
return QIcon(":trash");
}
} else if (role == Qt::FontRole) {
- return defaultModelFont();
+ if (divepoints.at(index.row()).entered) {
+ return defaultModelFont();
+ } else {
+ QFont font = defaultModelFont();
+ font.setBold(true);
+ return font;
+ }
}
return QVariant();
}
@@ -1196,9 +1108,15 @@ bool DivePlannerPointsModel::setData(const QModelIndex &index, const QVariant &v
case DEPTH:
p.depth = units_to_depth(value.toInt());
break;
- case DURATION:
+ case RUNTIME:
p.time = value.toInt() * 60;
break;
+ case DURATION:
+ if (index.row())
+ p.time = value.toInt() * 60 + divepoints[index.row() - 1].time;
+ else
+ p.time = value.toInt() * 60;
+ break;
case CCSETPOINT: {
int po2 = 0;
QByteArray gasv = value.toByteArray();
@@ -1224,6 +1142,8 @@ QVariant DivePlannerPointsModel::headerData(int section, Qt::Orientation orienta
switch (section) {
case DEPTH:
return tr("Final Depth");
+ case RUNTIME:
+ return tr("Run time");
case DURATION:
return tr("Duration");
case GAS:
@@ -1239,7 +1159,10 @@ QVariant DivePlannerPointsModel::headerData(int section, Qt::Orientation orienta
Qt::ItemFlags DivePlannerPointsModel::flags(const QModelIndex &index) const
{
- return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;
+ if(index.column() != DURATION)
+ return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;
+ else
+ return QAbstractItemModel::flags(index);
}
int DivePlannerPointsModel::rowCount(const QModelIndex &parent) const
@@ -1317,6 +1240,10 @@ bool DivePlannerPointsModel::addGas(int o2, int he)
fill_default_cylinder(cyl);
cyl->gasmix.o2.permille = o2;
cyl->gasmix.he.permille = he;
+ if(!o2)
+ cyl->depth.mm = 1600 * 1000 / O2_IN_AIR * 10 - 10000;
+ else
+ cyl->depth.mm = 1600 * 1000 / o2 * 10 - 10000;
CylindersModel::instance()->setDive(stagingDive);
return true;
}
@@ -1327,12 +1254,20 @@ bool DivePlannerPointsModel::addGas(int o2, int he)
return false;
}
+int DivePlannerPointsModel::lastEnteredPoint()
+{
+ for (int i = divepoints.count()-1; i >= 0; i--)
+ if (divepoints.at(i).entered)
+ return i;
+ return -1;
+}
+
int DivePlannerPointsModel::addStop(int milimeters, int seconds, int o2, int he, int ccpoint, bool entered)
{
int row = divepoints.count();
if (seconds == 0 && milimeters == 0 && row != 0) {
/* this is only possible if the user clicked on the 'plus' sign on the DivePoints Table */
- struct divedatapoint &t = divepoints.last();
+ const divedatapoint t = divepoints.at(lastEnteredPoint());
milimeters = t.depth;
seconds = t.time + 600; // 10 minutes.
o2 = t.o2;
@@ -1386,6 +1321,15 @@ int DivePlannerPointsModel::addStop(int milimeters, int seconds, int o2, int he,
}
}
}
+ bool oldRecalc = setRecalc(false);
+ if (oldRecalc){
+ QVector<int> computedPoints;
+ for (int i = 0; i < plannerModel->rowCount(); i++)
+ if (!plannerModel->at(i).entered)
+ computedPoints.push_back(i);
+ plannerModel->removeSelectedPoints(computedPoints);
+ }
+ setRecalc(oldRecalc);
// add the new stop
beginInsertRows(QModelIndex(), row, row);
divedatapoint point;
@@ -1478,6 +1422,8 @@ bool DivePlannerPointsModel::tankInUse(int o2, int he)
divedatapoint &p = divepoints[j];
if (p.time == 0) // special entries that hold the available gases
continue;
+ if (!p.entered) // removing deco gases is ok
+ continue;
if ((p.o2 == o2 && p.he == he) ||
(is_air(p.o2, p.he) && is_air(o2, he)))
return true;
@@ -1552,8 +1498,8 @@ void DivePlannerPointsModel::createTemporaryPlan()
divedatapoint p = at(i);
int deltaT = lastIndex != -1 ? p.time - at(lastIndex).time : p.time;
lastIndex = i;
- p.entered = true;
- plan_add_segment(&diveplan, deltaT, p.depth, p.o2, p.he, p.po2, true);
+ if (p.entered)
+ plan_add_segment(&diveplan, deltaT, p.depth, p.o2, p.he, p.po2, true);
}
char *cache = NULL;
tempDive = NULL;
@@ -1626,10 +1572,14 @@ void DivePlannerPointsModel::createPlan()
// FIXME: The epic assumption that all the cylinders after the first is deco
int sac = i ? diveplan.decosac : diveplan.bottomsac;
cyl->start.mbar = cyl->type.workingpressure.mbar;
- int consumption = ((depth_to_mbar(mean[i], tempDive) * duration[i] / 60) * sac) / (cyl->type.size.mliter / 1000);
- cyl->end.mbar = cyl->start.mbar - consumption;
+ if(cyl->type.size.mliter) {
+ int consumption = ((depth_to_mbar(mean[i], tempDive) * duration[i] / 60) * sac) / (cyl->type.size.mliter / 1000);
+ cyl->end.mbar = cyl->start.mbar - consumption;
+ } else {
+ /* Cylider without a proper size are easily emptied */
+ cyl->end.mbar = 0;
+ }
}
-
mark_divelist_changed(true);
// Remove and clean the diveplan, so we don't delete
diff --git a/qt-ui/diveplanner.h b/qt-ui/diveplanner.h
index 4d3f0cbaf..8352d6a69 100644
--- a/qt-ui/diveplanner.h
+++ b/qt-ui/diveplanner.h
@@ -12,48 +12,6 @@
class QListView;
class QModelIndex;
-struct computedPoint {
- int computedTime;
- unsigned int computedDepth;
- computedPoint(int computedTime_, unsigned int computedDepth_) {
- computedTime = computedTime_;
- computedDepth = computedDepth_;
- };
- computedPoint() {};
-};
-
-class DivePlannerDisplay : public QAbstractTableModel {
- Q_OBJECT
-private:
- explicit DivePlannerDisplay(QObject *parent = 0);
- QVector<computedPoint> computedPoints;
-
-public:
- static DivePlannerDisplay *instance();
- enum Sections {
- REMOVE,
- COMPUTED_DEPTH,
- COMPUTED_DURATION,
- COLUMNS
- };
- virtual int columnCount(const QModelIndex &parent = QModelIndex()) const;
- virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
- virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
- virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
- virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
- virtual Qt::ItemFlags flags(const QModelIndex &index) const;
- void clear();
- computedPoint at(int row);
- int size();
- void removeStops();
- void addStops();
- void insertPoint(const struct computedPoint &p);
-
-public
-slots:
- void remove(const QModelIndex &index);
-};
-
class DivePlannerPointsModel : public QAbstractTableModel {
Q_OBJECT
public:
@@ -62,6 +20,7 @@ public:
REMOVE,
DEPTH,
DURATION,
+ RUNTIME,
GAS,
CCSETPOINT,
COLUMNS
@@ -83,6 +42,8 @@ public:
void createSimpleDive();
void clear();
Mode currentMode() const;
+ bool setRecalc(bool recalc);
+ bool recalcQ();
void tanksUpdated();
void rememberTanks();
bool tankInUse(int o2, int he);
@@ -96,6 +57,8 @@ public:
struct diveplan getDiveplan();
QStringList &getGasList();
QVector<QPair<int, int> > collectGases(dive *d);
+ int lastEnteredPoint();
+ static bool addingDeco;
public
slots:
@@ -115,6 +78,7 @@ slots:
void deleteTemporaryPlan();
void loadFromDive(dive *d);
void restoreBackupDive();
+
signals:
void planCreated();
void planCanceled();
@@ -124,6 +88,7 @@ private:
bool addGas(int o2, int he);
struct diveplan diveplan;
Mode mode;
+ bool recalc;
QVector<divedatapoint> divepoints;
struct dive *tempDive;
struct dive backupDive;
diff --git a/qt-ui/diveplanner.ui b/qt-ui/diveplanner.ui
index 986f1b9d5..558be069d 100644
--- a/qt-ui/diveplanner.ui
+++ b/qt-ui/diveplanner.ui
@@ -142,7 +142,7 @@
</property>
</widget>
</item>
- <item row="8" column="0" colspan="1">
+ <item row="8" column="0" colspan="2">
<widget class="TableView" name="tableWidget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
@@ -158,22 +158,6 @@
</property>
</widget>
</item>
- <item row="8" column="1" colspan="1">
- <widget class="TableView" name="tableWidgetComp" native="true">
- <property name="sizePolicy">
- <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="minimumSize">
- <size>
- <width>0</width>
- <height>50</height>
- </size>
- </property>
- </widget>
- </item>
<item row="9" column="0" colspan="2">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
diff --git a/qt-ui/models.cpp b/qt-ui/models.cpp
index 5b011d747..6d64da44b 100644
--- a/qt-ui/models.cpp
+++ b/qt-ui/models.cpp
@@ -253,6 +253,7 @@ bool CylindersModel::setData(const QModelIndex &index, const QVariant &value, in
case O2:
if (CHANGED()) {
cyl->gasmix.o2 = string_to_fraction(vString.toUtf8().data());
+ cyl->depth.mm = 1600 * 1000 / cyl->gasmix.o2.permille * 10 - 10000;
changed = true;
}
break;