From 20a981ad9f89630ecf430ab2a9fdfafa0740a521 Mon Sep 17 00:00:00 2001 From: Your Name Date: Sat, 7 Feb 2026 16:16:00 +0100 Subject: [PATCH] antes de drift --- assets/formulas/formulas.d4rt | 32 ++-- assets/units/elasticity.d4rt.units | 19 +++ assets/units/electricity.d4rt.units | 53 +++++++ assets/units/frequency.d4rt.units | 25 +++ lib/ai/formula_screen.dart | 9 ++ pubspec.lock | 88 ++++++++++ pubspec.yaml | 1 + test/physics_trigonometry_formulas_test.dart | 159 +++++++++++++++++++ 8 files changed, 370 insertions(+), 16 deletions(-) create mode 100644 assets/units/elasticity.d4rt.units create mode 100644 assets/units/electricity.d4rt.units create mode 100644 assets/units/frequency.d4rt.units create mode 100644 test/physics_trigonometry_formulas_test.dart diff --git a/assets/formulas/formulas.d4rt b/assets/formulas/formulas.d4rt index 63ff344..e8e6c37 100644 --- a/assets/formulas/formulas.d4rt +++ b/assets/formulas/formulas.d4rt @@ -16,10 +16,10 @@ "description": r""" Calculates vertical displacement under constant gravity -$$h = \\frac{1}{2}gt^2$$ +$$h = \frac{1}{2}gt^2$$ Where: -- $g$: Gravitational acceleration ($9.81\\ \\mathrm{m/s^2}$ on Earth) +- $g$: Gravitational acceleration $9.81\ \mathrm{m/s^2}$ on Earth - $t$: Time in free fall (seconds) ![Free Fall Diagram](https://altcalculator.com/wp-content/uploads/2023/08/Free-Fall.png)""", @@ -38,10 +38,10 @@ Where: "description": r''' Newton's law of universal gravitation -\(F = G\\frac{m_1m_2}{r^2}\) +\(F = G\frac{m_1m_2}{r^2}\) Where: -- $G$: Gravitational constant ($6.674\\times 10^{-11}\\ \\mathrm{N\\cdot m^2/kg^2}$) +- $G$: Gravitational constant ($6.674\times 10^{-11}\ \mathrm{N\cdot m^2/kg^2}$) - $m_1, m_2$: Masses of two objects - $r$: Distance between centers of masses @@ -62,7 +62,7 @@ Where: "description": r''' Energy possessed by a moving object -$$KE = \\frac{1}{2}mv^2$$ +$$KE = \frac{1}{2}mv^2$$ Where: - $m$: Mass of object @@ -82,10 +82,10 @@ Where: { "name": "Projectile Range", "description": r"""Calculates horizontal distance of projectile motion - $$R = \\frac{v^2 \\sin(2\\theta)}{g}$$ + $$R = \frac{v^2 \sin(2\theta)}{g}$$ Where: - $v$: Initial velocity - - $\\theta$: Launch angle + - $\theta$: Launch angle - $g$: Gravitational acceleration ![Projectile Motion](https://upload.wikimedia.org/wikipedia/commons/thumb/5/52/Projectile_motion_diagram.png/800px-Projectile_motion_diagram.png)""", "input": [ @@ -105,11 +105,11 @@ Where: "description": r''' Force equals mass times acceleration -$$F = m \\cdot a$$ +$$F = m \cdot a$$ Where: -- $m$: Mass of object ($\\mathrm{kg}$) -- $a$: Acceleration ($\\mathrm{m/s^2}$) +- $m$: Mass of object ($\mathrm{kg}$) +- $a$: Acceleration ($\mathrm{m/s^2}$) ![Newton's Second Law](https://upload.wikimedia.org/wikipedia/commons/thumb/7/73/Newtonslawsofmotion.jpg/800px-Newtonslawsofmotion.jpg)''', "input": [ @@ -186,7 +186,7 @@ $$E = mc^2$$ Where: - $E$: Energy (Joules) - $m$: Mass (kilograms) -- $c$: Speed of light ($299,792,458\\ \\mathrm{m/s}$) +- $c$: Speed of light $299,792,458$ $\mathrm{m/s}$ This equation shows that mass can be converted to energy and vice versa.''', "input": [ @@ -249,7 +249,7 @@ The negative sign indicates the force opposes the displacement.''', "description": r''' Force required to keep an object moving in circular motion -$$F = \\frac{mv^2}{r}$$ +$$F = \frac{mv^2}{r}$$ Where: - $F$: Centripetal force (Newtons) @@ -274,7 +274,7 @@ This force acts toward the center of the circle.''', "description": r''' Relationship between wave speed, frequency, and wavelength -$$v = f\\lambda$$ +$$v = f\lambda$$ Where: - $v$: Wave speed (m/s) @@ -319,7 +319,7 @@ The square of the hypotenuse is equal to the sum of squares of the other two sid "description": r''' Relationship between the sides and angles of any triangle -$$\\frac{a}{\\sin A} = \\frac{b}{\\sin B} = \\frac{c}{\\sin C}$$ +$$\frac{a}{\sin A} = \frac{b}{\sin B} = \frac{c}{\sin C}$$ Where: - $a$, $b$, $c$: Sides of the triangle @@ -346,7 +346,7 @@ This rule is useful for solving triangles when certain combinations of angles an "description": r''' Generalization of the Pythagorean theorem for any triangle -$$c^2 = a^2 + b^2 - 2ab\\cos(C)$$ +$$c^2 = a^2 + b^2 - 2ab\cos(C)$$ Where: - $a$, $b$, $c$: Sides of the triangle @@ -372,7 +372,7 @@ This rule relates all three sides of a triangle to one of its angles.''', "description": r''' Fundamental Pythagorean identity in trigonometry -$$\\sin^2(\\theta) + \\cos^2(\\theta) = 1$$ +$$\sin^2(\theta) + \cos^2(\theta) = 1$$ Where: - $\theta$: Any angle in radians or degrees diff --git a/assets/units/elasticity.d4rt.units b/assets/units/elasticity.d4rt.units new file mode 100644 index 0000000..8f735c1 --- /dev/null +++ b/assets/units/elasticity.d4rt.units @@ -0,0 +1,19 @@ +[ + { + "name": "newton per meter", + "symbol": "N/m", + "isBase": true + }, + { + "name": "newton per centimeter", + "symbol": "N/cm", + "baseUnit": "newton per meter", + "factor": 100 + }, + { + "name": "kilonewton per meter", + "symbol": "kN/m", + "baseUnit": "newton per meter", + "factor": 1000 + } +] \ No newline at end of file diff --git a/assets/units/electricity.d4rt.units b/assets/units/electricity.d4rt.units new file mode 100644 index 0000000..a347fa3 --- /dev/null +++ b/assets/units/electricity.d4rt.units @@ -0,0 +1,53 @@ +[ + { + "name": "ampere", + "symbol": "A", + "isBase": true + }, + { + "name": "milliampere", + "symbol": "mA", + "baseUnit": "ampere", + "factor": 0.001 + }, + { + "name": "microampere", + "symbol": "µA", + "baseUnit": "ampere", + "factor": 0.000001 + }, + { + "name": "ohm", + "symbol": "Ω", + "isBase": true + }, + { + "name": "kiloohm", + "symbol": "kΩ", + "baseUnit": "ohm", + "factor": 1000 + }, + { + "name": "megaohm", + "symbol": "MΩ", + "baseUnit": "ohm", + "factor": 1000000 + }, + { + "name": "volt", + "symbol": "V", + "isBase": true + }, + { + "name": "millivolt", + "symbol": "mV", + "baseUnit": "volt", + "factor": 0.001 + }, + { + "name": "kilovolt", + "symbol": "kV", + "baseUnit": "volt", + "factor": 1000 + } +] \ No newline at end of file diff --git a/assets/units/frequency.d4rt.units b/assets/units/frequency.d4rt.units new file mode 100644 index 0000000..03acc41 --- /dev/null +++ b/assets/units/frequency.d4rt.units @@ -0,0 +1,25 @@ +[ + { + "name": "hertz", + "symbol": "Hz", + "isBase": true + }, + { + "name": "kilohertz", + "symbol": "kHz", + "baseUnit": "hertz", + "factor": 1000 + }, + { + "name": "megahertz", + "symbol": "MHz", + "baseUnit": "hertz", + "factor": 1000000 + }, + { + "name": "gigahertz", + "symbol": "GHz", + "baseUnit": "hertz", + "factor": 1000000000 + } +] \ No newline at end of file diff --git a/lib/ai/formula_screen.dart b/lib/ai/formula_screen.dart index f155039..17361f3 100644 --- a/lib/ai/formula_screen.dart +++ b/lib/ai/formula_screen.dart @@ -1,6 +1,8 @@ // dart import 'package:flutter/material.dart'; import 'package:flutter_markdown/flutter_markdown.dart'; +import 'package:flutter_markdown_latex/flutter_markdown_latex.dart'; +import 'package:markdown/markdown.dart' as markdown; import '../formula_models.dart'; import '../formula_evaluator.dart'; import '../corpus.dart'; @@ -215,6 +217,13 @@ class _FormulaScreenState extends State { child: MarkdownBody( data: widget.formula.description!, shrinkWrap: true, + builders: { + 'latex': LatexElementBuilder(), + }, + extensionSet: markdown.ExtensionSet( + [LatexBlockSyntax()], + [LatexInlineSyntax()], + ), ), ), const SizedBox(height: 24), diff --git a/pubspec.lock b/pubspec.lock index 9621524..82ade9b 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -198,6 +198,30 @@ packages: url: "https://pub.dev" source: hosted version: "0.7.7+1" + flutter_markdown_latex: + dependency: "direct main" + description: + name: flutter_markdown_latex + sha256: "839e76a84abb3632ffcebbd450cf93c7e9894af65622527d23f0084cee1bfd04" + url: "https://pub.dev" + source: hosted + version: "0.3.4" + flutter_math_fork: + dependency: transitive + description: + name: flutter_math_fork + sha256: "6d5f2f1aa57ae539ffb0a04bb39d2da67af74601d685a161aff7ce5bda5fa407" + url: "https://pub.dev" + source: hosted + version: "0.7.4" + flutter_svg: + dependency: transitive + description: + name: flutter_svg + sha256: "87fbd7c534435b6c5d9d98b01e1fd527812b82e68ddd8bd35fc45ed0fa8f0a95" + url: "https://pub.dev" + source: hosted + version: "2.2.3" flutter_test: dependency: "direct dev" description: flutter @@ -376,6 +400,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.4" + nested: + dependency: transitive + description: + name: nested + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" + source: hosted + version: "1.0.0" node_preamble: dependency: transitive description: @@ -400,6 +432,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.9.1" + path_parsing: + dependency: transitive + description: + name: path_parsing + sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: "1a97266a94f7350d30ae522c0af07890c70b8e62c71e8e3920d1db4d23c057d1" + url: "https://pub.dev" + source: hosted + version: "7.0.1" plugin_platform_interface: dependency: transitive description: @@ -416,6 +464,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.5.2" + provider: + dependency: transitive + description: + name: provider + sha256: "4e82183fa20e5ca25703ead7e05de9e4cceed1fbd1eadc1ac3cb6f565a09f272" + url: "https://pub.dev" + source: hosted + version: "6.1.5+1" pub_semver: dependency: transitive description: @@ -637,6 +693,30 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.5" + vector_graphics: + dependency: transitive + description: + name: vector_graphics + sha256: a4f059dc26fc8295b5921376600a194c4ec7d55e72f2fe4c7d2831e103d461e6 + url: "https://pub.dev" + source: hosted + version: "1.1.19" + vector_graphics_codec: + dependency: transitive + description: + name: vector_graphics_codec + sha256: "99fd9fbd34d9f9a32efd7b6a6aae14125d8237b10403b422a6a6dfeac2806146" + url: "https://pub.dev" + source: hosted + version: "1.1.13" + vector_graphics_compiler: + dependency: transitive + description: + name: vector_graphics_compiler + sha256: "201e876b5d52753626af64b6359cd13ac6011b80728731428fd34bc840f71c9b" + url: "https://pub.dev" + source: hosted + version: "1.1.20" vector_math: dependency: transitive description: @@ -693,6 +773,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.1" + xml: + dependency: transitive + description: + name: xml + sha256: "971043b3a0d3da28727e40ed3e0b5d18b742fa5a68665cca88e74b7876d5e025" + url: "https://pub.dev" + source: hosted + version: "6.6.1" yaml: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 25fab72..530b4ea 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -38,6 +38,7 @@ dependencies: d4rt: flutter_d4rt: flutter_markdown: + flutter_markdown_latex: flutter_code_editor: collection: any diff --git a/test/physics_trigonometry_formulas_test.dart b/test/physics_trigonometry_formulas_test.dart new file mode 100644 index 0000000..2b606f8 --- /dev/null +++ b/test/physics_trigonometry_formulas_test.dart @@ -0,0 +1,159 @@ +import 'package:d4rt_formulas/corpus.dart'; +import 'package:d4rt_formulas/defaults/default_corpus.dart'; +import 'package:d4rt_formulas/formula_evaluator.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:d4rt_formulas/formula_models.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + Future createTestCorpus() async { + return createDefaultCorpus(); + } + + Future testCorpus = createTestCorpus(); + + group('Physics Formulas Tests', () { + test('evaluates Mass-Energy Equivalence formula (E=mc²)', () async { + final corpus = await testCorpus; + final formula = corpus.getFormula("Mass-Energy Equivalence")!; + final evaluator = FormulaEvaluator(); + + // Test with 1 kg of mass + final result = evaluator.evaluate(formula, { + 'm': 1.0, // 1 kg + }); + + // E = mc² = 1 * (299792458)² ≈ 8.98755179 × 10^16 Joules + expect(result, closeTo(8.98755179e16, 1e12)); + }); + + test('evaluates Ohm\'s Law formula (V=IR)', () async { + final corpus = await testCorpus; + final formula = corpus.getFormula("Ohm's Law")!; + final evaluator = FormulaEvaluator(); + + // Test with 2 amperes and 5 ohms + final result = evaluator.evaluate(formula, { + 'I': 2.0, // 2 Amperes + 'R': 5.0, // 5 Ohms + }); + + // V = I * R = 2 * 5 = 10 Volts + expect(result, 10.0); + }); + + test('evaluates Hooke\'s Law formula (F=-kx)', () async { + final corpus = await testCorpus; + final formula = corpus.getFormula("Hooke's Law")!; + final evaluator = FormulaEvaluator(); + + // Test with spring constant k=100 N/m and displacement x=0.5 m + final result = evaluator.evaluate(formula, { + 'k': 100.0, // 100 N/m + 'x': 0.5, // 0.5 m + }); + + // F = -k * x = -100 * 0.5 = -50 N + expect(result, -50.0); + }); + + test('evaluates Centripetal Force formula (F=mv²/r)', () async { + final corpus = await testCorpus; + final formula = corpus.getFormula("Centripetal Force")!; + final evaluator = FormulaEvaluator(); + + // Test with m=10 kg, v=5 m/s, r=2 m + final result = evaluator.evaluate(formula, { + 'm': 10.0, // 10 kg + 'v': 5.0, // 5 m/s + 'r': 2.0, // 2 m + }); + + // F = (m * v²) / r = (10 * 25) / 2 = 250 / 2 = 125 N + expect(result, 125.0); + }); + + test('evaluates Wave Equation formula (v=fλ)', () async { + final corpus = await testCorpus; + final formula = corpus.getFormula("Wave Equation")!; + final evaluator = FormulaEvaluator(); + + // Test with frequency f=50 Hz and wavelength λ=2 m + final result = evaluator.evaluate(formula, { + 'f': 50.0, // 50 Hz + 'lambda': 2.0, // 2 m + }); + + // v = f * λ = 50 * 2 = 100 m/s + expect(result, 100.0); + }); + }); + + group('Trigonometry Formulas Tests', () { + test('evaluates Pythagorean Theorem formula (a²+b²=c²)', () async { + final corpus = await testCorpus; + final formula = corpus.getFormula("Pythagorean Theorem")!; + final evaluator = FormulaEvaluator(); + + // Test with a=3, b=4 (classic 3-4-5 triangle) + final result = evaluator.evaluate(formula, { + 'a': 3.0, // 3 m + 'b': 4.0, // 4 m + }); + + // c = √(a² + b²) = √(9 + 16) = √25 = 5 + expect(result, 5.0); + }); + + test('evaluates Sine Rule formula (a/sin A = b/sin B)', () async { + final corpus = await testCorpus; + final formula = corpus.getFormula("Sine Rule")!; + final evaluator = FormulaEvaluator(); + + // Test with a=5, angle A=30°, angle B=60° + final result = evaluator.evaluate(formula, { + 'a': 5.0, // Side a = 5 m + 'A': 30.0, // Angle A = 30 degrees + 'B': 60.0, // Angle B = 60 degrees + }); + + // b = (a * sin(B)) / sin(A) = (5 * sin(60°)) / sin(30°) + // b = (5 * 0.866) / 0.5 = 4.33 / 0.5 = 8.66 + expect(result, closeTo(8.66, 0.01)); + }); + + test('evaluates Cosine Rule formula (c²=a²+b²-2ab cos C)', () async { + final corpus = await testCorpus; + final formula = corpus.getFormula("Cosine Rule")!; + final evaluator = FormulaEvaluator(); + + // Test with a=5, b=7, angle C=60° + final result = evaluator.evaluate(formula, { + 'a': 5.0, // Side a = 5 m + 'b': 7.0, // Side b = 7 m + 'C': 60.0, // Angle C = 60 degrees + }); + + // c = √(a² + b² - 2ab*cos(C)) + // c = √(25 + 49 - 2*5*7*cos(60°)) + // c = √(74 - 70*0.5) = √(74 - 35) = √39 ≈ 6.24 + expect(result, closeTo(6.24, 0.01)); + }); + + test('evaluates Trigonometric Identity formula (sin²θ + cos²θ = 1)', () async { + final corpus = await testCorpus; + final formula = corpus.getFormula("Trigonometric Identity")!; + final evaluator = FormulaEvaluator(); + + // Test with θ=45° + final result = evaluator.evaluate(formula, { + 'theta': 45.0, // 45 degrees + }); + + // sin²(45°) + cos²(45°) should equal 1 + // (≈0.707)² + (≈0.707)² = 0.5 + 0.5 = 1 + expect(result, closeTo(1.0, 0.001)); + }); + }); +} \ No newline at end of file