Changeset e2bbd0c in subsurface


Ignore:
Timestamp:
Feb 9, 2017, 9:30:49 PM (7 weeks ago)
Author:
Dirk Hohndel <dirk@…>
Branches:
master
Children:
0e7d899
Parents:
8f97c4a8
git-author:
Linus Torvalds <torvalds@…> (02/08/17 11:36:08)
git-committer:
Dirk Hohndel <dirk@…> (02/09/17 21:30:49)
Message:

Rewrite cylinder merging code from scratch

The old cylinder merging code depended on the preferred dive having all
the cylinders, and the newly merged dive was just forced to pick from
that existing set of cylinders.

That worked ok if you have a "main" dive computer that you have all the
gases programmed for, and you download that first, and then you download
any secondary data later.

But it completely messed up if the second dive computer had gases that
the first one didn't know about, and just basically ended up doing
random things.

This rewrites the whole thing to actually try to create a union of the
two sets of cylinders when merging, with sane matching so that if the
cylinders match you won't get duplicates.

Miika Turkia hit this when he only used one gas, but had several gases
defined in his OSTC that he downloaded after his Vyper (with had just
the single gas defined).

This should fix that case (at least it does for my xml merging test-case
that showed the same problem after some munging).

Reported-by: Miika Turkia <miika.turkia@…>
Signed-off-by: Linus Torvalds <torvalds@…>

File:
1 edited

Legend:

Unmodified
Added
Removed
  • core/dive.c

    r0277d5a re2bbd0c  
    19791979                int sensor;
    19801980
    1981                 if (!s->cylinderpressure.mbar)
    1982                         continue;
    19831981                sensor = mapping[s->sensor];
    19841982                if (sensor >= 0)
     
    20112009}
    20122010
     2011static int same_gasmix(struct gasmix *a, struct gasmix *b)
     2012{
     2013        if (gasmix_is_air(a) && gasmix_is_air(b))
     2014                return 1;
     2015        return a->o2.permille == b->o2.permille && a->he.permille == b->he.permille;
     2016}
     2017
     2018/*
     2019 * Can we find an exact match for a cylinder in another dive?
     2020 * Take the "already matched" map into account, so that we
     2021 * don't match multiple similar cylinders to one target.
     2022 */
     2023static int match_cylinder(cylinder_t *cyl, struct dive *dive, unsigned int available)
     2024{
     2025        int i;
     2026
     2027        for (i = 0; i < MAX_CYLINDERS; i++) {
     2028                cylinder_t *target;
     2029
     2030                if (!(available & (1u << i)))
     2031                        continue;
     2032                target = dive->cylinder + i;
     2033                if (!same_gasmix(&cyl->gasmix, &target->gasmix))
     2034                        continue;
     2035
     2036                /* FIXME! Should we check sizes too? */
     2037                return i;
     2038        }
     2039        return -1;
     2040}
     2041
     2042/*
     2043 * Note: we only allocate from the end, not in holes in the middle.
     2044 * So we don't look for empty bits, we look for "no more bits set".
     2045 * We could use some "find last bit set" math function, but let's
     2046 * not be fancy.
     2047 */
     2048static int find_unused_cylinder(unsigned int used_map)
     2049{
     2050        int i;
     2051
     2052        for (i = 0; i < MAX_CYLINDERS; i++) {
     2053                if (!used_map)
     2054                        return i;
     2055                used_map >>= 1;
     2056        }
     2057        return -1;
     2058}
     2059
    20132060/*
    20142061 * Merging cylinder information is non-trivial, because the two dive computers
     
    20212068static void merge_cylinders(struct dive *res, struct dive *a, struct dive *b)
    20222069{
    2023         int i, renumber = 0;
     2070        int i, last, renumber = 0;
    20242071        int mapping[MAX_CYLINDERS];
    2025         unsigned int used = 0;
    2026 
    2027         /* Copy the cylinder info raw from 'a' */
     2072        unsigned int used_in_a = 0, used_in_b = 0, matched = 0;
     2073
     2074        /* Calculate usage map of cylinders */
     2075        for (i = 0; i < MAX_CYLINDERS; i++) {
     2076                if (!cylinder_none(a->cylinder+i) || is_cylinder_used(a, i))
     2077                        used_in_a |= 1u << i;
     2078                if (!cylinder_none(b->cylinder+i) || is_cylinder_used(b, i))
     2079                        used_in_b |= 1u << i;
     2080        }
     2081
     2082        /* For each cylinder in 'b', try to match up things */
     2083        for (i = 0; i < MAX_CYLINDERS; i++) {
     2084                int j;
     2085
     2086                mapping[i] = -1;
     2087                if (!(used_in_b & (1u << i)))
     2088                        continue;
     2089
     2090                j = match_cylinder(b->cylinder+i, a, used_in_a & ~matched);
     2091                if (j < 0)
     2092                        continue;
     2093
     2094                /*
     2095                 * If we had a successful match, we:
     2096                 *
     2097                 *  - save that in the mapping table
     2098                 *
     2099                 *  - mark it as matched so that another cylinder in 'b'
     2100                 *    will no longer match
     2101                 *
     2102                 *  - mark 'b' as needing renumbering if the index changed
     2103                 */
     2104                mapping[i] = j;
     2105                matched |= 1u << j;
     2106                if (j != i)
     2107                        renumber = 1;
     2108        }
     2109
     2110        /*
     2111         * Consider all the cylinders we matched as used, whether they
     2112         * originally were or not (either in 'a' or 'b').
     2113         */
     2114        used_in_a |= matched;
     2115
     2116        /* Now copy all the cylinder info raw from 'a' (whether used/matched or not) */
    20282117        memcpy(res->cylinder, a->cylinder, sizeof(res->cylinder));
    20292118        memset(a->cylinder, 0, sizeof(a->cylinder));
    20302119
    2031         if (strcmp(b->dc.model, "planned dive")) {
    2032                 // We merge two actual dive
    2033                 for (i = 0; i < MAX_CYLINDERS; i++) {
    2034                         int j;
    2035                         cylinder_t *cyl = b->cylinder + i;
    2036 
    2037                         j = find_cylinder_match(cyl, res->cylinder, used);
    2038                         mapping[i] = j;
    2039                         if (j < 0)
    2040                                 continue;
    2041                         used |= 1 << j;
    2042                         merge_cylinder_info(cyl, res->cylinder + j);
    2043 
    2044                         /* If that renumbered the cylinders, fix it up! */
    2045                         if (i != j)
    2046                                 renumber = 1;
    2047                 }
    2048                 if (renumber)
    2049                         cylinder_renumber(b, mapping);
    2050         } else {
    2051                 int j=0;
    2052                 for (i = 0; i < MAX_CYLINDERS && j < MAX_CYLINDERS; i++) {
    2053                         if (is_cylinder_used(res, i))
    2054                                 continue;
    2055 
    2056                         while (!is_cylinder_used(b, j) && j < MAX_CYLINDERS - 1) {
    2057                                 mapping[j] = 0;
    2058                                 ++j;
    2059                         }
    2060                         memcpy(&res->cylinder[i], &b->cylinder[j], sizeof (b->cylinder[j]));
    2061                         mapping[j] = i;
    2062                         ++j;
    2063                 }
    2064                 bool warn = false;
    2065                 while (j < MAX_CYLINDERS) {
    2066                         if (is_cylinder_used(b, j))
    2067                                 warn = true;
    2068                         mapping[j++] = 0;
    2069                 }
    2070                 if (warn) {
    2071                         report_error("Could not merge all cylinders as number exceeds %d", MAX_CYLINDERS);
    2072                 }
     2120        /*
     2121         * Go back to 'b' and remap any remaining cylinders that didn't
     2122         * match completely.
     2123         */
     2124        for (i = 0; i < MAX_CYLINDERS; i++) {
     2125                int j;
     2126
     2127                /* Already remapped, or not interesting? */
     2128                if (mapping[i] >= 0)
     2129                        continue;
     2130                if (!(used_in_b & (1u << i)))
     2131                        continue;
     2132
     2133                j = find_unused_cylinder(used_in_a);
     2134                if (j < 0)
     2135                        continue;
     2136
     2137                res->cylinder[j] = b->cylinder[i];
     2138                memset(b->cylinder+i, 0, sizeof(cylinder_t));
     2139                mapping[i] = j;
     2140                used_in_a |= 1u << j;
     2141                if (i != j)
     2142                        renumber = 1;
     2143        }
     2144
     2145        if (renumber)
    20732146                cylinder_renumber(b, mapping);
    2074         }
    20752147}
    20762148
Note: See TracChangeset for help on using the changeset viewer.