Erdnaxela3/bioptim_gui

View on GitHub
gui/lib/models/acrobatics_data.dart

Summary

Maintainability
Test Coverage
import 'dart:convert';

import 'package:bioptim_gui/models/acrobatics_controllers.dart';
import 'package:bioptim_gui/models/acrobatics_request_maker.dart';
import 'package:bioptim_gui/models/ocp_data.dart';

class AcrobaticsData extends OCPData<SomersaultPhase> {
  int nbSomersaults;
  List<int> halfTwists = [];
  double finalTime;
  double finalTimeMargin;
  String position;
  String sportType;
  String preferredTwistSide;
  bool withVisualCriteria;
  bool collisionConstraint;
  bool withSpine;
  String dynamics;
  List<String> dofNames = [];

  AcrobaticsData.fromJson(Map<String, dynamic> data)
      : nbSomersaults = data["nb_somersaults"],
        halfTwists = List.from(data["nb_half_twists"]),
        finalTime = data["final_time"],
        finalTimeMargin = data["final_time_margin"],
        position = data["position"],
        sportType = data["sport_type"],
        preferredTwistSide = data["preferred_twist_side"],
        withVisualCriteria = data["with_visual_criteria"],
        collisionConstraint = data["collision_constraint"],
        withSpine = data["with_spine"],
        dynamics = data["dynamics"],
        dofNames = List.from(data["dof_names"]),
        super.fromJson(data, (json) => SomersaultPhase.fromJson(json),
            AcrobaticsRequestMaker());

  ///
  /// Update methods

  void updateHalfTwists(int index, int value) async {
    final response = await (requestMaker as AcrobaticsRequestMaker)
        .updateHalfTwists(index, value);

    final jsonData = json.decode(response.body);

    final newPhases = SomersaultPhase.convertDynamicList(jsonData);

    phasesInfo = newPhases;
    halfTwists[index] = value;
    notifyListeners();
  }

  @override
  void updateField(String name, dynamic value) async {
    final response = await requestMaker.updateField(name, value);

    if (response.statusCode != 200) throw Exception('Failed to update $name');

    final jsonData = json.decode(response.body);

    switch (name) {
      case "nb_somersaults":
      case "position":
        nbSomersaults = jsonData["nb_somersaults"];
        halfTwists = List.from(jsonData["nb_half_twists"]);
        position = jsonData["position"];
        dofNames = List.from(jsonData["dof_names"]);
        phasesInfo =
            SomersaultPhase.convertDynamicList(jsonData["phases_info"]);
        break;
      case "final_time":
        finalTime = jsonData["final_time"];
        for (var i = 0; i < phasesInfo.length; i++) {
          phasesInfo[i].duration = jsonData["new_phase_duration"];
        }
        break;
      case "final_time_margin":
        finalTimeMargin = jsonData["final_time_margin"];
        break;
      case "sport_type":
        sportType = jsonData["sport_type"];
        break;
      case "preferred_twist_side":
        preferredTwistSide = jsonData["preferred_twist_side"];
        break;
      case "with_visual_criteria":
        withVisualCriteria = jsonData["with_visual_criteria"];
        dofNames = List.from(jsonData["dof_names"]);
        phasesInfo =
            SomersaultPhase.convertDynamicList(jsonData["phases_info"]);
        break;
      case "collision_constraint":
        collisionConstraint = jsonData["collision_constraint"];
        phasesInfo =
            SomersaultPhase.convertDynamicList(jsonData["phases_info"]);
        break;
      case "with_spine":
        withSpine = jsonData["with_spine"];
        dynamics = jsonData["dynamics"];
        dofNames = List.from(jsonData["dof_names"]);
        phasesInfo =
            SomersaultPhase.convertDynamicList(jsonData["phases_info"]);
        break;
      case "dynamics":
        dynamics = jsonData["dynamics"];
        phasesInfo =
            SomersaultPhase.convertDynamicList(jsonData["phases_info"]);
        break;
      // model_path is not updated here because it is a special case, it has to
      // be send as a multipart file request
      // It is currently updated using updateBioModel
      case "model_path":
        break;
      default:
        break;
    }
    notifyListeners();
  }

  @override
  void updatePhaseField(
      int phaseIndex, String fieldName, dynamic newValue) async {
    final response =
        await requestMaker.updatePhaseField(phaseIndex, fieldName, newValue);
    final jsonData = json.decode(response.body);

    switch (fieldName) {
      case "duration":
        phasesInfo[phaseIndex].duration = jsonData["duration"];
        finalTime = jsonData["new_final_time"];
        break;
      case "nb_shooting_points":
        phasesInfo[phaseIndex].nbShootingPoints =
            jsonData["nb_shooting_points"];
        break;
      default:
        break;
    }
    notifyListeners();
  }

  @override
  void notifyListeners() {
    AcrobaticsControllers.instance.notifyListeners();
    super.notifyListeners();
  }
}

class SomersaultPhase extends Phase {
  SomersaultPhase.fromJson(super.somersaultData) : super.fromJson();

  static List<SomersaultPhase> convertDynamicList(List<dynamic> list) {
    return list.map((item) => SomersaultPhase.fromJson(item)).toList();
  }
}

class AcrobaticsAvailableValues extends OCPAvailableValues {
  List<String> positions;
  List<String> sportTypes;
  List<String> preferredTwistSides;

  AcrobaticsAvailableValues(
    super.nodeValues,
    super.integrationRules,
    super.objectiveMin,
    super.objectiveMax,
    super.constraints,
    super.interpolationTypes,
    super.dynamics,
    this.positions,
    this.sportTypes,
    this.preferredTwistSides,
  );
}