Пример #1
0
def compute_table(snowline):
    """
    Compute the table with snowline height for each day of the year.

    @param snowline: Snowline definition.
    @type  snowline: L{Snowline}

    @return: Table of 12*32 entries with snowline heights.
    @rtype:  C{str}
    """
    day_table = [None]*365 # Height at each day, starting at day 0
    for dh in snowline.date_heights:
        doy = dh.name.reduce()
        if not isinstance(doy, expression.ConstantNumeric):
            raise generic.ScriptError('Day of year is not a compile-time constant', doy.pos)
        if doy.value < 1 or doy.value > 365:
            raise generic.ScriptError('Day of the year must be between 1 and 365', doy.pos)

        height = dh.value.reduce()
        if isinstance(height, expression.ConstantNumeric) and height.value < 0:
            raise generic.ScriptError('Height must be at least 0', height.pos)
        if dh.unit is None:
            if isinstance(height, expression.ConstantNumeric) and height.value > 255:
                raise generic.ScriptError('Height must be at most 255', height.pos)
        else:
            unit = dh.unit
            if unit.type != 'snowline':
                raise generic.ScriptError('Expected a snowline percentage ("snow%")', height.pos)

            if isinstance(height, expression.ConstantNumeric) and height.value > 100:
                raise generic.ScriptError('Height must be at most 100 snow%', height.pos)


            mul, div = unit.convert, 1
            if isinstance(mul, tuple):
                mul, div = mul

            # Factor out common factors
            gcd = generic.greatest_common_divisor(mul, div)
            mul //= gcd
            div //= gcd

            if isinstance(height, (expression.ConstantNumeric, expression.ConstantFloat)):
                # Even if mul == div == 1, we have to round floats and adjust value
                height = expression.ConstantNumeric(int(float(height.value) * mul / div + 0.5), height.pos)
            elif mul != div:
                # Compute (value * mul + div/2) / div
                height = expression.BinOp(nmlop.MUL, height, expression.ConstantNumeric(mul, height.pos), height.pos)
                height = expression.BinOp(nmlop.ADD, height, expression.ConstantNumeric(int(div / 2), height.pos), height.pos)
                height = expression.BinOp(nmlop.DIV, height, expression.ConstantNumeric(div, height.pos), height.pos)

        # For 'linear' snow-line, only accept integer constants.
        if snowline.type != 'equal' and not isinstance(height, expression.ConstantNumeric):
            raise generic.ScriptError('Height is not a compile-time constant', height.pos)

        day_table[doy.value - 1] = height

    # Find first specified point.
    start = 0
    while start < 365 and day_table[start] is None:
        start = start + 1
    if start == 365:
        raise generic.ScriptError('No heights given for the snowline table', snowline.pos)

    first_point = start
    while True:
        # Find second point from start
        end = start + 1
        if end == 365:
            end = 0

        while end != first_point and day_table[end] is None:
            end = end + 1
            if end == 365:
                end = 0

        # Fill the days between start and end (exclusive both border values)
        startvalue = day_table[start]
        endvalue   = day_table[end]
        unwrapped_end = end
        if end < start: unwrapped_end += 365

        if snowline.type == 'equal':
            for day in range(start + 1, unwrapped_end):
                if day >= 365: day -= 365
                day_table[day] = startvalue
        else:
            assert snowline.type == 'linear'

            if start != end:
                dhd = float(endvalue.value - startvalue.value) / float(unwrapped_end - start)
            else:
                assert startvalue.value == endvalue.value
                dhd = 0

            for day in range(start + 1, unwrapped_end):
                uday = day
                if uday >= 365: uday -= 365
                height = startvalue.value + int(round(dhd * (day - start)))
                day_table[uday] = expression.ConstantNumeric(height)


        if end == first_point: # All days done
            break

        start = end

    table = [None] * (12*32)
    for dy in range(365):
        today = datetime.date.fromordinal(dy + 1)
        if day_table[dy]:
            expr = day_table[dy].reduce()
        else:
            expr = None
        table[(today.month - 1) * 32 + today.day - 1] = expr

    for idx, d in enumerate(table):
        if d is None:
            table[idx] = table[idx - 1]
    #Second loop is needed because we need make sure the first item is also set.
    for idx, d in enumerate(table):
        if d is None:
            table[idx] = table[idx - 1]


    return table
Пример #2
0
def parse_property_value(prop_info, value, unit=None, size_bit=None):
    """
    Parse a single property value / unit
    To determine the value that is to be used in nfo

    @param prop_info: A dictionary with property information
    @type prop_info: C{dict}

    @param value: Value of the property
    @type value: L{Expression}

    @param unit: Unit of the property value (e.g. km/h)
    @type unit: L{Unit} or C{None}

    @param size_bit: Bit that indicates the size of a multitile house
                     Set iff the item is a house
    @type size_bit: C{int} or C{None}

    @return: List of values to actually use (in nfo) for the property
    @rtype: L{Expression}
    """
    # Change value to use, except when the 'nfo' unit is used
    if unit is None or unit.type != 'nfo':
        # Save the original value to test conversion against it
        org_value = value

        # Multiply by property-specific conversion factor
        mul, div = 1, 1
        if 'unit_conversion' in prop_info:
            mul = prop_info['unit_conversion']
            if isinstance(mul, tuple):
                mul, div = mul

        # Divide by conversion factor specified by unit
        if unit is not None:
            if not 'unit_type' in prop_info or unit.type != prop_info[
                    'unit_type']:
                raise generic.ScriptError("Invalid unit for property",
                                          value.pos)
            unit_mul, unit_div = unit.convert, 1
            if isinstance(unit_mul, tuple):
                unit_mul, unit_div = unit_mul
            mul *= unit_div
            div *= unit_mul

        # Factor out common factors
        gcd = generic.greatest_common_divisor(mul, div)
        mul //= gcd
        div //= gcd

        if isinstance(value,
                      (expression.ConstantNumeric, expression.ConstantFloat)):
            # Even if mul == div == 1, we have to round floats and adjust value
            value = expression.ConstantNumeric(
                int(float(value.value) * mul / div + 0.5), value.pos)
            if unit is not None and 'adjust_value' in prop_info:
                value = adjust_value(value, org_value, unit,
                                     prop_info['adjust_value'])
        elif mul != div:
            # Compute (value * mul + div/2) / div
            value = expression.BinOp(
                nmlop.MUL, value, expression.ConstantNumeric(mul, value.pos),
                value.pos)
            value = expression.BinOp(
                nmlop.ADD, value,
                expression.ConstantNumeric(int(div / 2), value.pos), value.pos)
            value = expression.BinOp(
                nmlop.DIV, value, expression.ConstantNumeric(div, value.pos),
                value.pos)

    elif isinstance(value, expression.ConstantFloat):
        # Round floats to ints
        value = expression.ConstantNumeric(int(value.value + 0.5), value.pos)

    # Apply value_function if it exists
    if 'value_function' in prop_info:
        value = prop_info['value_function'](value)

    # Make multitile houses work
    if size_bit is not None:
        num_ids = house_sizes[size_bit]
        assert 'multitile_function' in prop_info
        ret = prop_info['multitile_function'](value, num_ids, size_bit)
        assert len(ret) == num_ids
        return ret
    else:
        return [value]