private IEnumerator createMainChains(PrimaryStructureFrame frame) { int interpolation = 5; int resolution = 5; // should be in config float radius = 0.015f; int currentIndex = 0; foreach (Chain chain in primaryStructure.Chains()) { if (chain.ResidueType != StandardResidue.AminoAcid) { // UnityEngine.Debug.Log("Skipping main chain build. Non protein main chain not currently supported."); continue; } List <Vector3> nodePositions = new List <Vector3>(); foreach (Atom atom in chain.MainChainAtoms) { // if no frame number use the base structure coordinates. Vector3 position; if (frame == null) { if (atom == null) { UnityEngine.Debug.Log("Main chain atom is null"); } position = new Vector3(atom.Position.x, atom.Position.y, atom.Position.z); } else { position = new Vector3(frame.Coords[atom.Index * 3], frame.Coords[(atom.Index * 3) + 1], frame.Coords[(atom.Index * 3) + 2]); } // flip coord system for Unity position.z *= -1; nodePositions.Add(position); } List <DynamicMeshNode> nodes = new List <DynamicMeshNode>(); IEnumerable splinePoints = Interpolate.NewCatmullRom(nodePositions.ToArray(), interpolation, false); Color32 chainColour = ChainColors[currentIndex % ChainColors.Length]; foreach (Vector3 position in splinePoints) { DynamicMeshNode node = new DynamicMeshNode(); node.Position = position; node.VertexColor = chainColour; nodes.Add(node); } DynamicMesh mesh = new DynamicMesh(nodes, radius, resolution, interpolation + 1); Mesh chainMesh = mesh.Build(Settings.DebugFlag); GameObject chainStructure = (GameObject)Instantiate(ChainPrefab); chainStructure.GetComponent <MeshFilter>().sharedMesh = chainMesh; chainStructure.SetActive(false); chainStructure.transform.SetParent(ChainParent.transform, false); currentIndex++; yield return(null); } }
private Mesh BuildStructureMesh(MoleculeRenderSettings renderSettings, Chain chain, PrimaryStructureFrame frame, SecondaryStructure secondaryStructure) { Mesh structureMesh = null; int interpolation = 20; int resolution = 6; // should be in config float radius = 0.015f; List <DynamicMeshNode> nodes = new List <DynamicMeshNode>(); Vector3 lastPosition = Vector3.zero; Vector3 lastNormal = Vector3.zero; Vector3 averagedNormal = Vector3.zero; SecondaryStructureType lastType = SecondaryStructureType.Coil; for (int i = 0; i < chain.MainChainResidues.Count; i++) { DynamicMeshNode node = new DynamicMeshNode(); Residue residue = chain.MainChainResidues[i]; // check if residue mainchain information is complete. Ignore if not if (residue.AlphaCarbon == null || residue.CarbonylCarbon == null || residue.CarbonylOxygen == null) { continue; } // set position Atom atom = residue.AlphaCarbon; // if no frame number use the base structure coordinates. Vector3 position; if (frame == null) { position = new Vector3(atom.Position.x, atom.Position.y, atom.Position.z); } else { position = new Vector3(frame.Coords[atom.Index * 3], frame.Coords[(atom.Index * 3) + 1], frame.Coords[(atom.Index * 3) + 2]); } // flip coord system for Unity position.z *= -1; node.Position = position; SecondaryStructureInfomation structureInformation = secondaryStructure.GetStructureInformation(residue.Index); Residue nextResidue = null; if (i + 1 < chain.MainChainResidues.Count) { nextResidue = chain.MainChainResidues[i + 1]; } SecondaryStructureInfomation nextResidueStructureInfo = null; if (nextResidue != null) { nextResidueStructureInfo = secondaryStructure.GetStructureInformation(nextResidue.Index); } // store the node type if (structureInformation != null) { if (renderSettings.ShowHelices && (structureInformation.type == SecondaryStructureType.ThreeHelix || structureInformation.type == SecondaryStructureType.AlphaHelix || structureInformation.type == SecondaryStructureType.FiveHelix)) { node.Type = DynamicMeshNodeType.SpiralRibbon; } else if (renderSettings.ShowSheets && structureInformation.type == SecondaryStructureType.BetaSheet) { if (nextResidue == null || (nextResidueStructureInfo != null && nextResidueStructureInfo.type != SecondaryStructureType.BetaSheet)) { node.Type = DynamicMeshNodeType.RibbonHead; } else { node.Type = DynamicMeshNodeType.Ribbon; } } else if (renderSettings.ShowTurns && structureInformation.type == SecondaryStructureType.Turn) { node.Type = DynamicMeshNodeType.LargeTube; } else { node.Type = DynamicMeshNodeType.Tube; } // calculate and store the node color bool foundColour = false; if (renderSettings.CustomResidueRenderSettings != null && renderSettings.CustomResidueRenderSettings.ContainsKey(residue.ID)) { ResidueRenderSettings residueRenderSettings = renderSettings.CustomResidueRenderSettings[residue.ID]; if (residueRenderSettings != null && residueRenderSettings.ColourSecondaryStructure) { node.VertexColor = residueRenderSettings.ResidueColour; foundColour = true; } } if (foundColour == false) { switch (structureInformation.type) { case SecondaryStructureType.ThreeHelix: node.VertexColor = Settings.ThreeHelixColour; break; case SecondaryStructureType.AlphaHelix: node.VertexColor = Settings.AlphaHelixColour; break; case SecondaryStructureType.FiveHelix: node.VertexColor = Settings.FiveHelixColour; break; case SecondaryStructureType.Turn: node.VertexColor = Settings.TurnColour; break; case SecondaryStructureType.BetaSheet: node.VertexColor = Settings.BetaSheetColour; break; case SecondaryStructureType.BetaBridge: node.VertexColor = Settings.BetaBridgeColour; break; case SecondaryStructureType.Bend: node.VertexColor = Settings.BendColour; break; case SecondaryStructureType.Coil: node.VertexColor = Settings.CoilColour; break; default: node.VertexColor = ErrorColor; break; } } } else { Debug.Log("*** Structure info null: assigning defaults"); node.Type = DynamicMeshNodeType.Tube; node.VertexColor = ErrorColor; } // determine the node rotation // calculate the normal from the peptide plane and store as the node rotation Vector3 vertexA = residue.AlphaCarbon.Position; Vector3 vertexB = residue.CarbonylCarbon.Position; Vector3 vertexC = residue.CarbonylOxygen.Position; // flip coord system for Unity vertexA.z *= -1; vertexB.z *= -1; vertexC.z *= -1; //// create a triangle to show the peptide plane on the model for debugging purposes //GameObject residuePlane = createTriangle(vertexA, vertexB, vertexC); //residuePlane.name = "ResiduePlane"; //AddMeshToModel(residuePlane, StructureParent); Vector3 direction = Vector3.Cross(vertexB - vertexA, vertexC - vertexA); Vector3 normal = Vector3.Normalize(direction); if (structureInformation != null && structureInformation.type == SecondaryStructureType.BetaSheet || lastType == SecondaryStructureType.BetaSheet) { if (Vector3.Dot(normal, lastNormal) < 0) { normal *= -1; } if (lastType != SecondaryStructureType.BetaSheet) { averagedNormal = normal; } else { averagedNormal += normal; averagedNormal.Normalize(); normal = averagedNormal; } } node.Rotation = normal; lastNormal = normal; if (structureInformation != null) { lastType = structureInformation.type; } else { lastType = SecondaryStructureType.Coil; } nodes.Add(node); } if (renderSettings.SmoothNodes) { nodes = smoothMeshNodes(nodes); } //// draw debug line from node points along rotation vector //for (int q = 0; q < nodePositions.Count; q++) { // Vector3 fromPosition = nodePositions[q]; // Vector3 toPosition = fromPosition + nodeRotations[q] * 0.3f; // GameObject line = createLine(fromPosition, toPosition, Color.white, Color.red); // AddMeshToModel(line, StructureParent); //} List <Vector3> nodePositions = new List <Vector3>(); foreach (DynamicMeshNode node in nodes) { nodePositions.Add(node.Position); } List <DynamicMeshNode> splineNodes = new List <DynamicMeshNode>(); IEnumerable splinePoints = Interpolate.NewCatmullRom(nodePositions.ToArray(), interpolation, false); int j = 0; foreach (Vector3 position in splinePoints) { int nodeIndex = j / (interpolation + 1); int splinePointsSinceLastNode = j % (interpolation + 1); DynamicMeshNode node = new DynamicMeshNode(); node.Position = position; //int colorIndex = nodeIndex % DebugColors.Count; //node.VertexColor = DebugColors[colorIndex]; node.VertexColor = nodes[nodeIndex].VertexColor; node.Type = nodes[nodeIndex].Type; // set the mesh rotations for the node // dont do rotations on tube structures switch (node.Type) { case DynamicMeshNodeType.Ribbon: case DynamicMeshNodeType.RibbonHead: case DynamicMeshNodeType.SpiralRibbon: if (nodeIndex < nodes.Count - 1) { float percentThroughNode = (float)splinePointsSinceLastNode / ((float)interpolation + 1f); node.Rotation = Vector3.Lerp((Vector3)nodes[nodeIndex].Rotation, (Vector3)nodes[nodeIndex + 1].Rotation, percentThroughNode); } else // last node { node.Rotation = (Vector3)nodes[nodeIndex].Rotation; } break; } splineNodes.Add(node); j++; } DynamicMesh dynamicMesh = new DynamicMesh(splineNodes, radius, resolution, interpolation + 1); structureMesh = dynamicMesh.Build(Settings.DebugFlag); return(structureMesh); }