Source code for mathmaker.lib.document.content.geometry.intercept_theorem_triangle

# -*- coding: utf-8 -*-

# Mathmaker creates automatically maths exercises sheets
# with their answers
# Copyright 2006-2017 Nicolas Hainaux <nh.techn@gmail.com>

# This file is part of Mathmaker.

# Mathmaker 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
# any later version.

# Mathmaker 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 Mathmaker; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

import random

from mathmaker.lib import shared
from mathmaker.lib.tools.wording import setup_wording_format_of
from mathmaker.lib.core.root_calculus import Value
from mathmaker.lib.core.base_calculus import Item, Sum
from mathmaker.lib.core.calculus import Equality, Equation
from mathmaker.lib.document.content import component

ALL_LENGTHS_TO_CALCULATE = ['oneside', 'onechunk', 'twosides', 'twochunks',
                            'onesideonechunk']


[docs]class sub_object(component.structure): def __init__(self, build_data, picture='true', **options): super().setup("minimal", **options) if build_data[0] < 11: raise ValueError('build_data[0] == {} whereas it should be ' '>= 11'.format(str(build_data[0]))) build_data = (build_data[0] / 10, ) + build_data[1:] super().setup("numbers", nb=build_data, shuffle_nbs=False, **options) super().setup("length_units", **options) super().setup("intercept_theorem_figure", **options) if self.variant == 'default': variant = ['oneside', 'random', 'false'] else: if self.variant.count('_') != 2: raise ValueError('XMLFileFormatError: the variant for ' 'intercept_theorem_triangle ' 'shoud contain two _') variant = self.variant.split(sep='_') valid_variant = [['onerandom', 'tworandom', 'random', 'oneside', 'onechunk', 'twosides', 'twochunks', 'onesideonechunk'], ['random', 'all', 'twocouples'], ['random', 'true', 'false']] for v, valid, n in zip(variant, valid_variant, ['first', 'second', 'third']): if v not in valid: raise ValueError('XMLFileFormatError: invalid {} part of the ' 'variant. It should be in: {}' .format(n, str(valid))) if variant[0] == 'onerandom': variant[0] = random.choice(['oneside', 'onechunk']) elif variant[0] == 'tworandom': if variant[1] == 'twocouples': raise ValueError('XMLFileFormatError: the ' 'tworandom_twocouples_* ' 'variants are impossible.') if variant[2] == 'random': variant[2] = random.choice(['true', 'false']) if variant[2] == 'false': variant[0] = random.choice(['twosides', 'twochunks', 'onesideonechunk']) elif variant[2] == 'true': variant[0] = random.choice(['twosides', 'onesideonechunk']) else: raise ValueError('XMLFileFormatError: the third part of the ' 'variant should be "true" or "false".') # The order is: # small[0] small[1] small[2] side[0] side[1] side[2] chunk[0] chunk[1] # 'hid' means 'hidden', e.g. the length won't be displayed but can be # easily calculated before using the intercept theorem. labels_configurations = { 'oneside_all_false': [ ['?', True, True, True, True, True, False, False], [True, '?', True, True, True, True, False, False], [True, True, '?', True, True, True, False, False], [True, True, True, '?', True, True, False, False], [True, True, True, True, '?', True, False, False], [True, True, True, True, True, '?', False, False] ], 'oneside_all_true': [ ['?', True, True, True, True, 'hid', False, True], [True, '?', True, 'hid', True, 'hid', True, True], [True, '?', True, 'hid', True, True, True, False], [True, '?', True, True, True, 'hid', False, True], [True, True, '?', 'hid', True, True, True, False], [True, True, True, '?', True, 'hid', False, True], [True, True, True, True, '?', 'hid', False, True], [True, True, True, 'hid', '?', 'hid', True, True], [True, True, True, 'hid', '?', True, True, False], [True, True, True, 'hid', True, '?', True, False], ], 'onechunk_all_false': [ [True, True, True, False, True, True, '?', False], [True, True, True, True, True, False, False, '?'] ], 'onechunk_all_true': [ [True, True, True, False, True, 'hid', '?', True], [True, True, True, 'hid', True, False, True, '?'] ], 'twosides_all_false': [ ['?', '?', True, True, True, True, False, False], ['?', True, '?', True, True, True, False, False], [True, '?', '?', True, True, True, False, False], ['?', True, True, True, '?', True, False, False], ['?', True, True, True, True, '?', False, False], [True, '?', True, '?', True, True, False, False], [True, '?', True, True, True, '?', False, False], [True, True, '?', True, '?', True, False, False], [True, True, '?', '?', True, True, False, False], [True, True, True, '?', '?', True, False, False], [True, True, True, '?', True, '?', False, False], [True, True, True, True, '?', '?', False, False], ], 'twosides_all_true': [ ['?', '?', True, True, True, 'hid', False, True], [True, '?', '?', 'hid', True, True, True, False], ['?', True, True, True, '?', 'hid', False, True], [True, '?', True, '?', True, 'hid', False, True], [True, '?', True, False, True, '?', True, False], [True, True, '?', False, '?', True, True, False], [True, True, True, '?', '?', 'hid', False, True], [True, True, True, 'hid', '?', '?', True, False], ], 'twochunks_all_false': [ [False, True, False, True, True, True, '?', '?'], [True, True, False, False, True, True, '?', '?'], [False, True, True, True, True, False, '?', '?'], [True, True, True, False, True, False, '?', '?'], ], 'onesideonechunk_all_false': [ [False, '?', True, True, True, True, '?', False], [True, '?', False, True, True, True, False, '?'], [True, '?', True, False, True, True, '?', False], [True, '?', True, True, True, False, False, '?'], [False, True, '?', True, True, True, '?', False], ['?', True, False, True, True, True, False, '?'], [True, True, '?', False, True, True, '?', False], ['?', True, True, True, True, False, False, '?'], [True, True, True, False, True, '?', '?', False], [True, True, True, '?', True, False, False, '?'], [False, True, True, True, True, '?', '?', False], [True, True, False, '?', True, True, False, '?'], [False, True, True, True, '?', True, '?', False], [True, True, False, True, '?', True, False, '?'], [True, True, True, False, '?', True, '?', False], [True, True, True, True, '?', False, False, '?'], ], 'onesideonechunk_all_true': [ [True, '?', True, False, True, 'hid', '?', True], [True, '?', True, 'hid', True, False, True, '?'], [False, '?', True, True, True, 'hid', '?', True], [True, '?', False, 'hid', True, True, True, '?'], [True, True, True, False, '?', 'hid', '?', True], [True, True, True, 'hid', '?', False, True, '?'], [False, True, True, True, '?', 'hid', '?', True], [True, True, False, 'hid', '?', True, True, '?'], ], 'oneside_twocouples_false': [ ['?', True, False, True, True, False, False, False], [False, True, '?', False, True, True, False, False], [True, True, False, True, '?', False, False, False], [False, True, True, False, '?', True, False, False], ['?', False, True, True, False, True, False, False], [True, False, '?', True, False, True, False, False], [True, '?', False, True, True, False, False, False], [False, '?', True, False, True, True, False, False], [False, True, True, False, True, '?', False, False], [True, True, False, '?', True, False, False, False], [True, False, True, True, False, '?', False, False], [True, False, True, '?', False, True, False, False], ], 'oneside_twocouples_true': [ ['?', False, True, True, False, 'hid', False, True], [True, False, '?', 'hid', False, True, True, False], [True, '?', False, 'hid', True, False, True, False], [False, '?', True, False, True, 'hid', False, True], [True, True, False, 'hid', '?', False, True, False], [False, True, True, False, '?', 'hid', False, True], [True, False, True, '?', False, 'hid', False, True], [True, False, True, 'hid', False, '?', True, False], ], 'onechunk_twocouples_false': [ [True, True, False, False, True, False, '?', False], [False, True, True, False, True, False, False, '?'], [True, False, True, False, False, True, '?', False], [True, False, True, True, False, False, False, '?'], ], 'onechunk_twocouples_true': [ [True, False, True, False, False, 'hid', '?', True], [True, False, True, 'hid', False, False, True, '?'], ] } random_nb = variant.count('random') if random_nb == 3: variant = random.choice( list(labels_configurations.keys())).split(sep='_') elif random_nb == 2: if variant[0] == 'random' and variant[1] == 'random': if variant[2] == 'false': variant[0] = random.choice(ALL_LENGTHS_TO_CALCULATE) if variant[0] in ['twosides', 'twochunks', 'onesideonechunk']: variant[1] = 'all' else: variant[1] = random.choice(['all', 'twocouples']) elif variant[2] == 'true': variant[0] = random.choice(['oneside', 'onechunk', 'twosides', 'onesideonechunk']) if variant[0] in ['oneside', 'onechunk']: variant[1] = random.choice(['all', 'twocouples']) else: variant[1] = 'all' elif variant[0] == 'random' and variant[2] == 'random': if variant[1] == 'all': variant[0] = random.choice(ALL_LENGTHS_TO_CALCULATE) if variant[0] == 'twochunks': variant[2] = 'false' else: variant[2] = random.choice(['true', 'false']) elif variant[1] == 'twocouples': variant[0] = random.choice(['oneside', 'onechunk']) variant[2] = random.choice(['true', 'false']) elif variant[1] == 'random' and variant[2] == 'random': if variant[0] in ['oneside', 'onechunk']: variant[1] = random.choice(['all', 'twocouples']) variant[2] = random.choice(['true', 'false']) elif variant[0] in ['twosides', 'onesideonechunk']: variant[1] = 'all' variant[2] = random.choice(['true', 'false']) elif variant[0] == 'twochunks': variant[1] = 'all' variant[2] = 'false' elif random_nb == 1: if variant[0] == 'random': if variant[1] == 'twocouples': variant[0] = random.choice(['oneside', 'onechunk']) elif variant[1] == 'all': if variant[2] == 'true': variant[0] = random.choice(['oneside', 'onechunk', 'twosides', 'onesideonechunk']) elif variant[2] == 'false': variant[0] = random.choice(ALL_LENGTHS_TO_CALCULATE) elif variant[1] == 'random': if variant[0] in ['oneside', 'onechunk']: variant[1] = random.choice(['all', 'twocouples']) elif variant[0] in ['twosides', 'onesideonechunk']: variant[1] = 'all' elif variant[0] == 'twochunks': if variant[2] == 'false': variant[1] = 'all' else: raise ValueError('XMLFileFormatError: invalid' 'variants: "twochunks_*_true".') elif variant[2] == 'random': if variant[0] in ['oneside', 'onechunk']: variant[2] = random.choice(['true', 'false']) elif variant[1] == 'twocouples': raise ValueError('XMLFileFormatError: invalid variants: ' '"two..._twocouples_*".') else: if variant[0] == 'twochunks': variant[2] = 'false' else: variant[2] = random.choice(['true', 'false']) variant_key = '_'.join(variant) labels_conf = random.choice(labels_configurations[variant_key]) self.figure.setup_labels(labels_conf, segments_list=self.figure.small + [self.figure.u, self.figure.side[1], self.figure.v] + self.figure.chunk) self.figure.setup_labels([labels_conf[3], labels_conf[5]], segments_list=[self.figure.side[0], self.figure.side[2]]) lengths_to_calculate = [s.length_name for s in self.figure.small + self.figure.side if s.label == Value('?')] chunks_to_calculate = [] chunks_infos = [] if 'chunk' in variant_key: if len(lengths_to_calculate) == 1: chunks_to_calculate = [None] chunks_infos = [None] if labels_conf[6] == '?': # This matches chunk0 chunks_to_calculate += [self.figure.chunk[0].length_name] chunks_infos += [(self.figure.side[0].length_name, self.figure.small[0].length_name, self.figure.side[0].length, self.figure.small[0].length)] if not labels_conf[0]: lengths_to_calculate += [self.figure.small[0].length_name] else: lengths_to_calculate += [self.figure.side[0].length_name] if labels_conf[7] == '?': # This matches chunk1 chunks_to_calculate += [self.figure.chunk[1].length_name] chunks_infos += [(self.figure.side[2].length_name, self.figure.small[2].length_name, self.figure.side[2].length, self.figure.small[2].length)] if not labels_conf[2]: lengths_to_calculate += [self.figure.small[2].length_name] else: lengths_to_calculate += [self.figure.side[2].length_name] self.line1 = self.figure.small[1].length_name self.line2 = self.figure.side[1].length_name lengths_asked_for = [s.length_name for s in self.figure.small + self.figure.side + self.figure.chunk if s.label == Value('?')] self.length1_name = lengths_asked_for[0] if len(lengths_asked_for) == 2: self.length2_name = lengths_asked_for[1] if len(lengths_asked_for) == 1: self.wording = _('The drawn figure is out of shape. {newline} ' 'The lengths are given in {length_unit}. ' '{newline} ' 'The {line1} is parallel to {line2}. {newline} ' '{newline} ' 'Determine the length of {length1_name}.') else: self.wording = _('The drawn figure is out of shape. {newline} ' 'The lengths are given in {length_unit}. ' '{newline} ' 'The {line1} is parallel to {line2}. {newline} ' '{newline} ' 'Determine the lengths of {length1_name} ' 'and {length2_name}.') setup_wording_format_of(self) preamble = '' if variant_key.endswith('true'): self.pre_reso0 = self.pre_reso1 = '' if labels_conf[6] is True: pre_equality0 = Equality( [Item(self.side0_length_name), Sum([Item(self.small0_length_name), Item(self.chunk0_length_name) ])], subst_dict={Value(self.small0_length_name): Value(self.figure.small[0].length), Value(self.chunk0_length_name): Value(self.figure.chunk[0].length)} ) pre_equality0_str = pre_equality0.into_str() pre_equation0 = Equation(pre_equality0.substitute()) self.pre_reso0 = shared.machine.write_math_style1( pre_equality0_str) \ + pre_equation0.auto_resolution( dont_display_equations_name=True, decimal_result=2, unit=self.length_unit, underline_result=True) if labels_conf[7] is True: pre_equality1 = Equality( [Item(self.side1_length_name), Sum([Item(self.small1_length_name), Item(self.chunk1_length_name) ])], subst_dict={Value(self.small1_length_name): Value(self.figure.small[2].length), Value(self.chunk1_length_name): Value(self.figure.chunk[1].length)} ) pre_equality1_str = pre_equality1.into_str() pre_equation1 = Equation(pre_equality1.substitute()) self.pre_reso1 = shared.machine.write_math_style1( pre_equality1_str) \ + pre_equation1.auto_resolution( dont_display_equations_name=True, decimal_result=2, unit=self.length_unit, underline_result=True) if labels_conf[6] is True and labels_conf[7] is True: preamble = _('Note: {pre_reso0} {newline} and: {pre_reso1} ' '{newline} ') elif labels_conf[6] is True: preamble = _('Note: {pre_reso0} {newline} ') elif labels_conf[7] is True: preamble = _('Note: {pre_reso1} {newline} ') self.ratios = shared.machine.write_math_style1( self.figure.ratios_equalities().into_str()) self.ratios_substituted = shared.machine.write_math_style1( self.figure.ratios_equalities_substituted().into_str()) self.resolution0 = self.figure.ratios_equalities_substituted()\ .into_crossproduct_equation(Item(lengths_to_calculate[0]))\ .auto_resolution(dont_display_equations_name=True, skip_first_step=True, skip_fraction_simplification=True, decimal_result=2, unit=self.length_unit, underline_result=True) lengths_resolutions_part = _('hence: {resolution0} ') if len(lengths_to_calculate) == 2: self.resolution1 = self.figure.ratios_equalities_substituted()\ .into_crossproduct_equation(Item(lengths_to_calculate[1]))\ .auto_resolution(dont_display_equations_name=True, skip_first_step=True, skip_fraction_simplification=True, decimal_result=2, unit=self.length_unit, underline_result=True) lengths_resolutions_part = shared.machine.write( lengths_resolutions_part + _('and: {resolution1} '), multicolumns=2) chunks_part = '' if len(chunks_to_calculate): if chunks_to_calculate[0] is not None: chunk_equality0 = Equality( [Item(chunks_to_calculate[0]), Sum([Item(chunks_infos[0][0]), Item(('-', chunks_infos[0][1])) ])], subst_dict={Value(chunks_infos[0][0]): Value(chunks_infos[0][2]), Value(chunks_infos[0][1]): Value(chunks_infos[0][3])}) chunk_equality0_str = chunk_equality0.into_str() chunk_equation0 = Equation(chunk_equality0.substitute()) self.chunk_reso0 = shared.machine.write_math_style1( chunk_equality0_str) \ + chunk_equation0.auto_resolution( dont_display_equations_name=True, decimal_result=2, unit=self.length_unit, underline_result=True) chunks_part += _('so: {chunk_reso0} ') else: chunks_part += '~\n\n\\newline\\newline\\newline\\newline\n\n' if len(chunks_to_calculate) == 2: chunk_equality1 = Equality( [Item(chunks_to_calculate[1]), Sum([Item(chunks_infos[1][0]), Item(('-', chunks_infos[1][1])) ])], {Value(chunks_infos[1][0]): Value(chunks_infos[1][2]), Value(chunks_infos[1][1]): Value(chunks_infos[1][3])}) chunk_equality1_str = chunk_equality1.into_str() chunk_equation1 = Equation(chunk_equality1.substitute()) self.chunk_reso1 = shared.machine.write_math_style1( chunk_equality1_str) \ + chunk_equation1.auto_resolution( dont_display_equations_name=True, decimal_result=2, unit=self.length_unit, underline_result=True) chunks_part = shared.machine.write( chunks_part + _('so: {chunk_reso1} '), multicolumns=2) ans_variant = options.get('ans_variant', 'default') ans_texts = { 'default': _('As: {line1} {parallel_to} {line2}, ' '{point0_name} {belongs_to} {side0_length_name} and ' '{point1_name} {belongs_to} {side1_length_name}, ' 'then by the intercept theorem: {newline} ' '{ratios} ' 'thus: {ratios_substituted} '), 'alternative1': _('As {line1} is parallel to {line2}, ' 'and as the line {chunk0_length_name} cuts ' 'the line {chunk1_length_name} at point ' '{main_vertex_name}, ' 'then by the intercept theorem: {newline} ' '{ratios} ' 'thus: {ratios_substituted} '), 'alternative2': _('As: {line1} is parallel to {line2}, ' 'and as {vertex1_name}, {point0_name} and ' '{main_vertex_name} on one hand, ' '{vertex2_name}, {point1_name} and ' '{main_vertex_name} on the other hand,' 'are aligned in the same order, ' 'then by the intercept theorem: {newline} ' '{ratios} ' 'thus: {ratios_substituted} ') } self.answer_wording = preamble \ + ans_texts[ans_variant] \ + lengths_resolutions_part \ + chunks_part setup_wording_format_of(self, w_prefix='answer_')
[docs] def q(self, **options): return shared.machine.write_layout( (1, 2), [10, 10], [self.wording.format(**self.wording_format), shared.machine.insert_picture(self.figure, scale=0.7, top_aligned_in_a_tabular=True)])
[docs] def a(self, **options): return self.answer_wording.format(**self.answer_wording_format)
# TODO: create the "js" answer (for interactive pdf) # def js_a(self, **kwargs): # return [self......jsprinted]