parseCml function
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);
}