parseCml function

StructurePage? parseCml(
  1. String xml
)

Implementation

StructurePage? parseCml(String xml) {
  var document = XmlDocument.parse(xml);
  var fragments = <Fragment>[];
  for (var mol in document.findAllElements('molecule')) {
    var atoms = mol.findElements('atomArray').firstOrNull?.childElements ?? [];
    var bonds =
        mol.findAllElements('bondArray').firstOrNull?.childElements ?? [];

    var atomList = <Atom>[];
    var bondList = <Bond>[];

    for (var atom in atoms) {
      String? textId = atom.getAttribute('id');
      if (textId == null) return null;
      int id = int.tryParse(textId.substring(1)) ?? 0;
      double x = join(double.tryParse, atom.getAttribute('x2')) ?? 0.0;
      double y = -(join(double.tryParse, atom.getAttribute('y2')) ?? 0.0);
      String atomLabel = atom.getAttribute('elementType') ?? "None";

      Atom a = Atom(atomLabel, id, x, y, fontSize: 1);

      a.numHgens = join(int.tryParse, atom.getAttribute('hydrogenCount')) ?? 0;

      atomList.add(a);
    }
    double xmin = atomList
        .map((e) => e.x)
        .reduce((value, element) => value < element ? value : element);
    double ymin = atomList
        .map((e) => e.y)
        .reduce((value, element) => value < element ? value : element);
    double xmax = atomList
        .map((e) => e.x)
        .reduce((value, element) => value > element ? value : element);
    double ymax = atomList
        .map((e) => e.y)
        .reduce((value, element) => value > element ? value : element);
    var molBoundingBox = BoundingBox(xmin, ymin, xmax - xmin, ymax - ymin);
    // print(molBoundingBox);
    for (var bond in bonds) {
      var atoms = bond.getAttribute('atomRefs2')?.split(' ') ?? ['a0', 'a0'];
      var beginAtom = int.tryParse(atoms[0].substring(1)) ?? 0;
      var endAtom = int.tryParse(atoms[1].substring(1)) ?? 0;
      var type = switch (bond.getAttribute('order')) {
        "1" => BondType.single,
        "2" => BondType.double,
        "3" => BondType.triple,
        _ => BondType.single
      };

      bondList.add(Bond(BondStyle(bondType: type), beginAtom, endAtom));
    }
    fragments.add(Fragment(
        name: mol.getAttribute('title') ?? "None",
        atoms: atomList.toSet(),
        bonds: bondList.toSet(),
        boundingBox: molBoundingBox));

    for (var bond in bondList) {
      if (bond.bondStyle.bondPosition == BondPosition.unknown) {
        bond.fixDoubleBondPosision(atomList.toSet(), bondList.toSet());
      }
    }
  }

  var pageBoundingBox = fragments
      .map((e) => e.boundingBox)
      .reduce((value, element) => value + element);

  var margin = 2.0;
  pageBoundingBox
    ..x -= margin
    ..y -= margin
    ..width += margin * 2
    ..height += margin * 2;

  //why copy? because if it is not copied, original x and y will be 0 when for loop.
  final pageBoundingBoxCopy = pageBoundingBox.copyWith();
  //move all as pageBoundingBox x and y are 0
  for (int i = 0; i < fragments.length; i++) {
    fragments[i].boundingBox.x -= pageBoundingBoxCopy.x;
    fragments[i].boundingBox.y -= pageBoundingBoxCopy.y;
    for (var atom in fragments[i].atoms) {
      atom.x -= pageBoundingBoxCopy.x;
      atom.y -= pageBoundingBoxCopy.y;
    }
  }

  pageBoundingBox
    ..x = 0.0
    ..y = 0.0;

  return StructurePage(
      name: "CML", fragments: fragments.toSet(), boundingBox: pageBoundingBox);
}