+ final String command = "~display #*; ~ribbon #*; ribbon :"
+ + cmd.toString();
+ return Arrays.asList(new StructureCommand(command));
+ }
+
+ @Override
+ public List<StructureCommandI> superposeStructures(AtomSpecModel ref,
+ AtomSpecModel spec)
+ {
+ /*
+ * Form Chimera match command to match spec to ref
+ * (the first set of atoms are moved on to the second)
+ *
+ * match #1:1-30.B,81-100.B@CA #0:21-40.A,61-90.A@CA
+ *
+ * @see https://www.cgl.ucsf.edu/chimera/docs/UsersGuide/midas/match.html
+ */
+ StringBuilder cmd = new StringBuilder();
+ String atomSpecAlphaOnly = getAtomSpec(spec, true);
+ String refSpecAlphaOnly = getAtomSpec(ref, true);
+ cmd.append("match ").append(atomSpecAlphaOnly).append(" ").append(refSpecAlphaOnly);
+
+ /*
+ * show superposed residues as ribbon
+ */
+ String atomSpec = getAtomSpec(spec, false);
+ String refSpec = getAtomSpec(ref, false);
+ cmd.append("; ribbon ");
+ cmd.append(atomSpec).append("|").append(refSpec).append("; focus");
+
+ return Arrays.asList(new StructureCommand(cmd.toString()));
+ }
+
+ @Override
+ public StructureCommandI openCommandFile(String path)
+ {
+ // https://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/filetypes.html
+ return new StructureCommand("open cmd:" + path);
+ }
+
+ @Override
+ public StructureCommandI saveSession(String filepath)
+ {
+ // https://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/midas/save.html
+ return new StructureCommand("save " + filepath);
+ }
+
+ /**
+ * Returns the range(s) modelled by {@code atomSpec} formatted as a Chimera
+ * atomspec string, e.g.
+ *
+ * <pre>
+ * #0:15.A,28.A,54.A,70-72.A|#1:2.A,6.A,11.A,13-14.A
+ * </pre>
+ *
+ * where
+ * <ul>
+ * <li>#0 is a model number</li>
+ * <li>15 or 70-72 is a residue number, or range of residue numbers</li>
+ * <li>.A is a chain identifier</li>
+ * <li>residue ranges are separated by comma</li>
+ * <li>atomspecs for distinct models are separated by | (or)</li>
+ * </ul>
+ *
+ * <pre>
+ *
+ * @param model
+ * @param alphaOnly
+ * @return
+ * @see https://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/midas/frameatom_spec.html
+ */
+ @Override
+ public String getAtomSpec(AtomSpecModel atomSpec, boolean alphaOnly)
+ {
+ StringBuilder sb = new StringBuilder(128);
+ boolean firstModel = true;
+ for (String model : atomSpec.getModels())
+ {
+ if (!firstModel)
+ {
+ sb.append("|");
+ }
+ firstModel = false;
+ appendModel(sb, model, atomSpec, alphaOnly);
+ }
+ return sb.toString();
+ }
+
+ /**
+ * A helper method to append an atomSpec string for atoms in the given model
+ *
+ * @param sb
+ * @param model
+ * @param atomSpec
+ * @param alphaOnly
+ */
+ protected void appendModel(StringBuilder sb, String model,
+ AtomSpecModel atomSpec, boolean alphaOnly)
+ {
+ sb.append("#").append(model).append(":");
+
+ boolean firstPositionForModel = true;
+
+ for (String chain : atomSpec.getChains(model))
+ {
+ chain = " ".equals(chain) ? chain : chain.trim();
+
+ List<int[]> rangeList = atomSpec.getRanges(model, chain);
+ for (int[] range : rangeList)
+ {
+ appendRange(sb, range[0], range[1], chain, firstPositionForModel,
+ false);
+ firstPositionForModel = false;
+ }
+ }
+ if (alphaOnly)
+ {
+ /*
+ * restrict to alpha carbon, no alternative locations
+ * (needed to ensuring matching atom counts for superposition)
+ */
+ // TODO @P instead if RNA - add nucleotide flag to AtomSpecModel?
+ sb.append("@CA").append(NO_ALTLOCS);
+ }
+ }
+
+ @Override
+ public List<StructureCommandI> showBackbone()
+ {
+ return Arrays.asList(SHOW_BACKBONE);
+ }
+
+ @Override
+ public StructureCommandI loadFile(String file)
+ {
+ return new StructureCommand("open " + file);
+ }
+
+ /**
+ * Overrides the default method to concatenate colour commands into one
+ */
+ @Override
+ public List<StructureCommandI> colourBySequence(
+ Map<Object, AtomSpecModel> colourMap)
+ {
+ List<StructureCommandI> commands = new ArrayList<>();
+ StringBuilder sb = new StringBuilder(colourMap.size() * 20);
+ boolean first = true;
+ for (Object key : colourMap.keySet())
+ {
+ Color colour = (Color) key;
+ final AtomSpecModel colourData = colourMap.get(colour);
+ StructureCommandI command = getColourCommand(colourData, colour);
+ if (!first)
+ {
+ sb.append(getCommandSeparator());
+ }
+ first = false;
+ sb.append(command.getCommand());
+ }
+
+ commands.add(new StructureCommand(sb.toString()));
+ return commands;