public override IEnumerable <Selection> Select(IStructure structure) { List <Selection> results = new List <Selection>(); for (int chainIndex = 0; chainIndex < structure.Count; chainIndex++) { if (chainIndex == ChainIndex) { continue; } IChain chain = structure[chainIndex]; List <SSBlock> chainSelections = SecondaryStructure.GetPhiPsiSSBlocks(chain, MinLength); if (IncludeAdjacentLoops) { // Extend the SSBlock ranges to include everything up to the neighboring blocks List <SSBlock> extendedChainSelections = new List <SSBlock>(); for (int selectionIndex = 0; selectionIndex < chainSelections.Count; selectionIndex++) { int start = selectionIndex == 0 ? 0 : chainSelections[selectionIndex - 1].End + 1; int end = selectionIndex == chainSelections.Count - 1 ? chain.Count - 1 : chainSelections[selectionIndex + 1].Start - 1; extendedChainSelections.Add(new SSBlock(chainSelections[selectionIndex].SS, start, end)); } chainSelections = extendedChainSelections; } if (SkipCountC != null && SkipCountC > 0) { int firstSkipIndex = Math.Max(0, chainSelections.Count - (int)SkipCountC); chainSelections.RemoveRange(firstSkipIndex, chainSelections.Count - firstSkipIndex); } if (SkipCountN != null && SkipCountN > 0) { int skipCount = Math.Min((int)SkipCountN, chainSelections.Count); chainSelections.RemoveRange(0, skipCount); } // Convert the computed SS block ranges to an AA selection and add that to list results.AddRange(chainSelections.Select(block => new Selection(chain[block.Start, block.End]))); } return(results); }
public void Initialise(int id, PrimaryStructure primaryStructure, MoleculeRenderSettings renderSettings) { if (primaryStructure == null) { return; } this.ID = id; this.PrimaryStructure = primaryStructure; this.renderSettings = renderSettings; this.frameNumber = null; try { secondaryStructure = SecondaryStructure.CreateFromPrimaryStructure(primaryStructure, Settings.StrideExecutablePath, Settings.TmpFilePath); } catch (Exception ex) { Debug.Log("Error Parsing Secondary Structure from Structure File: " + ex.Message); buildSecondaryStructureTrajectory = false; } moleculeBox.gameObject.SetActive(renderSettings.ShowSimulationBox); boundingBox = new BoundingBox(primaryStructure, true); moleculeRender.transform.position = new Vector3(-1 * boundingBox.Centre.x, -1 * boundingBox.Centre.y, -1 * boundingBox.Centre.z); this.transform.position = new Vector3(boundingBox.Centre.x, boundingBox.Centre.y, boundingBox.Centre.z); if (renderSettings.ShowSimulationBox) { moleculeBox.Build(boundingBox); } primaryStructureRenderer.Initialise(primaryStructure); secondaryStructureRenderer.Initialise(primaryStructure); moleculeInput.enabled = false; autoRotateEnabled = false; AutoRotateSpeed = 0f; }
public void ParseFile() { topY = -99999; bottomY = 99999; leftX = 99999; rightX = -99999; frontZ = 99999; backZ = -99999; startTime = Time.realtimeSinceStartup; ConsoleText.text += string.Format(" Reading in DSSP file..."); DSSPfile = GetComponent <HttpTest>().outputfile; string pattern = @"([0-9]+)\s+(\S+)\s+([A-Z]+)\s+([A-Z]+)..(.)...........(....)(...)(...)(............)(...........)(...........)(...........)(........)(......)(......)(......)(......)\s+(\S+)\s+(\S+)\s+(\S+..)"; string getnumAA = @"([0-9]+)\s+[0-9]+\s+[0-9]+\s+[0-9]+\s+[0-9]+\s+TOTAL NUMBER OF RESIDUES"; string newmolpattern = @"!* 0 0 0 0, 0.0 0, 0.0 0, 0.0 0, 0.0 0.000 360.0 360.0 360.0 360.0 0.0 0.0 0.0"; string header = @"# RESIDUE AA STRUCTURE BP1 BP2 ACC N-H-->O O-->H-N N-H-->O O-->H-N TCO KAPPA ALPHA PHI PSI X-CA Y-CA Z-CA CHAIN AUTHCHAIN"; // get total num of amino acids in the protein complex Regex getnumAAr = new Regex(getnumAA); int numaa = Convert.ToInt32(getnumAAr.Match(DSSPfile).Groups[1].ToString()); ConsoleText.text += string.Format("\n Total number of amino acids: {0}", numaa); if (Regex.Split(Regex.Split(DSSPfile, header)[1], newmolpattern) == null) { ConsoleText.text += string.Format("\n string[] molecules is null."); } string[] molecules = Regex.Split(Regex.Split(DSSPfile, header)[1], newmolpattern); int totmolnum = molecules.Length; // index of molecule. total num of molecules in a protein complex List <SecondaryStructure[]> MoleculesSecondaryAssignments = new List <SecondaryStructure[]>(); // We want to make lists of the above vectors per molecule List <Vector3[]> MoleculesCAPoints = new List <Vector3[]>(); foreach (string molecule in molecules) { int te = 0; // temp SecondaryStructure[] structure = new SecondaryStructure[Regex.Matches(molecule, pattern).Count]; Vector3[] points = new Vector3[Regex.Matches(molecule, pattern).Count]; if (Regex.Matches(molecule, pattern) == null) { ConsoleText.text += string.Format("\n Error reading DSSP file. Regex pattern returned no matches. Matches is null."); } foreach (Match matches in Regex.Matches(molecule, pattern)) { structure[te].structure = matches.Groups[5].ToString(); points[te] = new Vector3(float.Parse(matches.Groups[18].ToString()), float.Parse(matches.Groups[19].ToString()), float.Parse(matches.Groups[20].ToString())); te++; } MoleculesSecondaryAssignments.Add(structure); MoleculesCAPoints.Add(points); } GameObject ThisFile = new GameObject(); ThisFile.name = string.Format("File {0}", GetComponent <Load>().FileNumber); ThisFile.transform.parent = GameObject.Find("MoleculeCollection").transform; ThisFile.transform.localPosition = Vector3.zero; ThisFile.transform.localScale = Vector3.one; GameObject RibbonCollection = new GameObject(); RibbonCollection.name = "RibbonCollection"; RibbonCollection.transform.parent = ThisFile.transform; RibbonCollection.transform.localPosition = Vector3.zero; RibbonCollection.transform.localScale = Vector3.one; // TODO : Put this in script Ribbon.cs as "DrawRibbon(Vector3 points)" GameObject ThisPDB = new GameObject(); ThisPDB.name = string.Format("PDB{0}", GetComponent <Load>().FileNumber); ThisPDB.transform.parent = RibbonCollection.transform; ThisPDB.transform.localScale = new Vector3(0.3f, 0.3f, 0.3f); //ThisPDB.transform.localPosition = new Vector3(0.75f, 0, 0) * (numPDB - 1); GameObject MoleculeHolder = new GameObject(); MoleculeHolder.transform.parent = ThisPDB.transform; MeshFilter[] meshFilters = new MeshFilter[totmolnum]; ConsoleText.text += string.Format("\n Total number of molecules: {0}.", totmolnum); Vector3 offset = new Vector3(0, 0f, 0f); GameObject parent = GameObject.Find("Hologram Collection"); // TODO: Remove find for (int tem = 0; tem < totmolnum; tem++) { // Make a new vector that has more points in it so it is smoother // The higher the second number, the more points and thus smoother lines. Changes smoothness exponentially relative to number of amino acids. Vector3[] newPoints = LineSmoother.SmoothLine(MoleculesCAPoints[tem], 0.8f * (float)Math.Exp(-10f / (float)numaa)); if (newPoints == null) { ConsoleText.text += string.Format("\n Error initializing smoothing array. NewPoints is null."); } // Second argument adjusts the smoothness. Smaller = smoother // TODO: Second argument can be adjusted for changing quality using slider // TODO: These three parameters can be adjustable with sliders float lineWidth = 0.006f; float rescale = 100f; int numofsides = 12; int[] triangles = new int[6 * numofsides * newPoints.Length]; Vector3[] quad = new Vector3[newPoints.Length * numofsides]; Color[] colors = new Color[quad.Length]; float a = lineWidth; float b = lineWidth / 2.5f; ConsoleText.text += string.Format("\n Initialized arrays and variables for molecule {0}...", tem); //foreach (Vector3 point in newPoints) foreach (Vector3 point in newPoints) { tiltFactor = 30; int i = Array.IndexOf(newPoints, point); int totnumofsides = i * numofsides; int totnumofvertices = totnumofsides * 6; int div = Convert.ToInt32(Math.Floor(i / ((float)newPoints.Length / (float)MoleculesCAPoints[tem].Length))); // Adds color based on secondary structure assignment for (int z = 0; z < numofsides; z++) { colors[totnumofsides + z] = Colors(MoleculesSecondaryAssignments[tem][div].structure); } } Parallel.ForEach(newPoints, point => { tiltFactor = 30; int i = Array.IndexOf(newPoints, point); int totnumofsides = i * numofsides; int totnumofvertices = totnumofsides * 6; int div = Convert.ToInt32(Math.Floor(i / ((float)newPoints.Length / (float)MoleculesCAPoints[tem].Length))); // for padding on the z axis: if (totnumofsides < (newPoints.Length - 2) * 6 && Mathf.Abs(point.z - newPoints[i + 1].z) > Mathf.Abs(point.x - newPoints[i + 1].x) && Mathf.Abs(point.z - newPoints[i + 1].z) > Mathf.Abs(point.y - newPoints[i + 1].y)) { tiltFactor = 45; } // Makes an oval // TODO: Find a way to fix thinness of certain axes (the padding on z axis method right above doesn't entirely work) for (int side = 0; side < numofsides; side++) { float angle = (side * (360f / numofsides)) * Mathf.Deg2Rad; float x = ((float)a * b) / (float)Mathf.Sqrt(((float)Math.Pow(b, 2) + ((float)Math.Pow(a, 2) * (float)Math.Pow(Mathf.Tan(angle), 2)))); float y = ((float)a * b) / (float)Mathf.Sqrt((float)Mathf.Pow(a, 2) + ((float)Mathf.Pow(b, 2) / (float)Mathf.Pow(Mathf.Tan(angle), 2))); if (side * (360f / numofsides) > 90 && side * (360f / numofsides) < 270) { x = -1 * x; } if (side * (360f / numofsides) > 180 && side * (360f / numofsides) < 360) { y = -1 * y; } // Determine the max/min vertices for resizing and positioning later if ((point / rescale).y + y > topY) { topY = (point / rescale).y + y; } if ((point / rescale).y + y < bottomY) { bottomY = (point / rescale).y + y; } if ((point / rescale).x + x > rightX) { rightX = (point / rescale).x + x; } if ((point / rescale).x + x < leftX) { leftX = (point / rescale).x + x; } if ((point / rescale).z > backZ) { backZ = (point / rescale).z; } if ((point / rescale).z < frontZ) { frontZ = (point / rescale).z; } quad[totnumofsides + side] = (point / rescale) + offset + new Vector3(x, y, 0); } // Creates an array for the triangles if (i < (newPoints.Length - 1)) { for (int p = 0; p < totnumofsides; p++) { triangles[(p * 6) + 0] = p + 0; triangles[(p * 6) + 1] = p + numofsides; triangles[(p * 6) + 2] = p + 1; triangles[(p * 6) + 3] = p + 1; triangles[(p * 6) + 4] = p + numofsides; triangles[(p * 6) + 5] = p + numofsides + 1; } } } ); // Draw the molecule GameObject Protein = new GameObject(); Protein.transform.parent = MoleculeHolder.transform; // remove find Protein.name = string.Format("PDB.{0}.molecule.{1}", GetComponent <Load>().FileNumber, tem); // some sanity checks if (GameObject.Find(string.Format("PDB.{0}.molecule.{1}", GetComponent <Load>().FileNumber, tem)) == null) { ConsoleText.text += string.Format("\n Molecule {0} GameObject does not exist.", tem); } if (quad == null) { ConsoleText.text += string.Format("\nQuad is null"); } if (triangles == null) { ConsoleText.text += string.Format("\n Triangles is null."); } Protein.AddComponent <MeshFilter>(); Protein.AddComponent <MeshRenderer>(); //Protein.GetComponent<MeshRenderer>().material = new Material(Shader.Find("VertexColorLightmaps")); Protein.GetComponent <MeshFilter>().mesh.vertices = quad; Protein.GetComponent <MeshFilter>().mesh.triangles = triangles; Protein.GetComponent <MeshFilter>().mesh.colors = colors; Protein.GetComponent <MeshRenderer>().material = new Material(Shader.Find("Custom/SpecularHighlight")); Protein.GetComponent <MeshFilter>().mesh.RecalculateNormals(); //meshFilters[tem] = Protein.GetComponent<MeshFilter>(); } /* * ThisPDB.AddComponent<MeshCollider>(); * ThisPDB.AddComponent<MeshFilter>(); * CombineInstance[] combine = new CombineInstance[meshFilters.Length]; * int inde = 0; * while (inde < meshFilters.Length) * { * combine[inde].mesh = meshFilters[inde].sharedMesh; * combine[inde].transform = meshFilters[inde].transform.localToWorldMatrix; * //meshFilters[inde].gameObject.SetActive(false); * inde++; * } * ThisPDB.transform.GetComponent<MeshFilter>().mesh = new Mesh(); * ThisPDB.transform.GetComponent<MeshFilter>().mesh.CombineMeshes(combine); * ThisPDB.transform.gameObject.SetActive(true); * ThisPDB.transform.GetComponent<MeshCollider>().sharedMesh = ThisPDB.transform.GetComponent<MeshFilter>().mesh; * ThisPDB.AddComponent<MeshRenderer>().material = new Material(Shader.Find("Custom/SpecularHighlight")); */ MoleculeHolder.transform.localPosition -= new Vector3((rightX + leftX) / 2f, (topY + bottomY) / 2f, (backZ + frontZ) / 2f); ThisPDB.transform.localPosition = Vector3.zero; //ThisPDB.AddComponent<BoxCollider>().size = new Vector3(0.5f, 0.5f, 0.5f); //ThisPDB.AddComponent<MeshRenderer>().material = GameObject.Find("MoleculeCollection").GetComponent<MeshRenderer>().material; if (Math.Abs(topY - bottomY) >= Math.Abs(rightX - leftX)) { if (Math.Abs(backZ - frontZ) >= Math.Abs(topY - bottomY)) { MoleculeHolder.transform.localScale /= Math.Abs(backZ - frontZ) / .3f; // instead of .48f make this localscale of moelculecolelctin } else { MoleculeHolder.transform.localScale /= Math.Abs(topY - bottomY) / .3f; } } else { MoleculeHolder.transform.localScale /= Math.Abs(rightX - leftX) / .3f; } // change back to interpolated strings ConsoleText.text += string.Format("\n Cartoon structure drawn for PDB #{0}.", GetComponent <Load>().FileNumber); finishTime = Time.realtimeSinceStartup; ConsoleText.text += string.Format("\n Time taken to draw: {0} seconds.\n", (finishTime - startTime)); Debug.Log($"Time to draw protein: {finishTime - startTime}"); //ThisPDB.AddComponent<BoxCollider>().size = new Vector3(0.48f / ThisPDB.transform.localScale.x, 0.48f / ThisPDB.transform.localScale.x, 0.48f / ThisPDB.transform.localScale.x); //GameObject.Find("RibbonCollection").GetComponent<BoxCollider>().enabled = true; //MoleculeHolder.transform.localScale = new Vector3(3, 3, 3); RibbonCollection.AddComponent <BoundingBoxRig>().ScaleHandleMaterial = BoundingBoxHandle; RibbonCollection.GetComponent <BoundingBoxRig>().RotateHandleMaterial = BoundingBoxHandle; RibbonCollection.GetComponent <BoundingBoxRig>().InteractingMaterial = BoundingBoxHandleGrabbed; RibbonCollection.GetComponent <BoundingBoxRig>().BoundingBoxPrefab = BoundingBoxBasic; RibbonCollection.GetComponent <BoundingBoxRig>().appBarPrefab = AppBar; RibbonCollection.AddComponent <MixedRealityToolkit.InputModule.Utilities.Interations.TwoHandManipulatable>().BoundingBoxPrefab = BoundingBoxBasic; RibbonCollection.GetComponent <MixedRealityToolkit.InputModule.Utilities.Interations.TwoHandManipulatable>().SetManipulationMode(MixedRealityToolkit.InputModule.Utilities.Interations.TwoHandManipulatable.TwoHandedManipulation.MoveRotateScale); ThisPDB.AddComponent <MeshFilter>().mesh = GameObject.Find("MoleculeCollection").GetComponent <MeshFilter>().mesh; ThisPDB.AddComponent <MeshCollider>().sharedMesh = ThisPDB.GetComponent <MeshFilter>().mesh; ThisPDB.AddComponent <MeshRenderer>().material = GameObject.Find("MoleculeCollection").GetComponent <MeshRenderer>().material; ThisPDB.GetComponent <MeshRenderer>().enabled = false; GetComponent <Load>().FileNumber++; }
public IEnumerator Render(int meshQuality) { // if currently rendering, then store render request if (rendering) { awaitingMeshQuality = meshQuality; awaitingRender = true; yield break; } rendering = true; System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch(); watch.Start(); // primary structure render PrimaryStructureFrame frame = null; if (PrimaryStructureTrajectory != null && frameNumber != null) { frame = PrimaryStructureTrajectory.GetFrame((int)frameNumber); } // We use a clone of the render settings so any settings updates dont interfere with the builds MoleculeRenderSettings renderSettingsClone = renderSettings.Clone(); yield return(StartCoroutine(primaryStructureRenderer.RenderStructure(renderSettingsClone, frame, meshQuality))); // secondary structure render SecondaryStructure secondaryStructureToBuild = null; if (secondaryStructureTrajectory != null && frameNumber != null && buildSecondaryStructureTrajectory) { string loadException = null; Thread thread = new Thread(() => { try { secondaryStructureToBuild = secondaryStructureTrajectory.GetStructure((int)frameNumber); } catch (FileParseException ex) { loadException = ex.Message; } }); thread.Start(); while (thread.IsAlive) { yield return(null); } if (loadException != null) { MoleculeEvents.RaiseShowMessage(loadException + " - Aborting trajectory secondary structure builds.", true); buildSecondaryStructureTrajectory = false; } } else { secondaryStructureToBuild = secondaryStructure; } yield return(StartCoroutine(secondaryStructureRenderer.RenderStructure(renderSettingsClone, frame, secondaryStructureToBuild))); primaryStructureRenderer.ShowStructure(); secondaryStructureRenderer.ShowStructure(); // simulation box render if (renderSettingsClone.ShowSimulationBox) { moleculeBox.gameObject.SetActive(true); BoundingBox box = boundingBox; if (renderSettingsClone.CalculateBoxEveryFrame && frame != null) { box = new BoundingBox(frame, true); } moleculeBox.Build(box); } else { moleculeBox.gameObject.SetActive(false); } //Cleanup.ForeceGC(); rendering = false; watch.Stop(); if (Settings.DebugMessages) { //console.BannerBuildTime = watch.ElapsedMilliseconds.ToString(); } //UnityEngine.Debug.Log("Ending model build. Elapsed time [" + watch.ElapsedMilliseconds.ToString() + "]"); yield break; }
private IEnumerator createSecondaryStructure(MoleculeRenderSettings settings, PrimaryStructureFrame frame, SecondaryStructure secondaryStructure) { for (int i = 0; i < primaryStructure.Chains().Count; i++) { Chain chain = primaryStructure.Chains()[i]; if (chain.ResidueType != StandardResidue.AminoAcid) { // UnityEngine.Debug.Log("Skipping secondary strucure. Non protein structures not currently supported."); continue; } if (chain.MainChainResidues.Count < 2) { // UnityEngine.Debug.Log("Skipping secondary strucure. Protein structure doesn't have enough residues for mesh."); continue; } Mesh structureMesh = BuildStructureMesh(settings, chain, frame, secondaryStructure); GameObject structure = (GameObject)Instantiate(SecondaryStructurePrefab); structure.GetComponent <MeshFilter>().sharedMesh = structureMesh; structure.SetActive(false); structure.transform.SetParent(StructureParent.transform, false); yield return(null); } }
// RenderStructure and ShowStructure are separate to allow the primary and secondary structures to be prerendered and then // both turned on at the same time. Without this, the show of the structures is staggered and shows some level of flickering public IEnumerator RenderStructure(MoleculeRenderSettings settings, PrimaryStructureFrame frame, SecondaryStructure secondaryStructure) { if (!initialised) { yield break; } System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch(); watch.Start(); yield return(null); storeExistingStructure(); // create mesh if (secondaryStructure != null && settings.ShowSecondaryStructure) { yield return(StartCoroutine(createSecondaryStructure(settings, frame, secondaryStructure))); } watch.Stop(); }
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); }
// Parses sheet secondary structure object specified by the pdb-file line void ParseSheet(string pdbLine) { Chain chain; char chainId = pdbLine[21]; if (!chains.TryGetValue(chainId, out chain)) chains[chainId] = chain = new Chain() { Name = chainId.ToString() }; SecondaryStructure sheet = new SecondaryStructure(); sheet.StructureType = SecondaryStructureType.Sheet; sheet.FirstResidueSequenceNumber = int.Parse(pdbLine.Substring(22, 4), CultureInfo.InvariantCulture); sheet.LastResidueSequenceNumber = int.Parse(pdbLine.Substring(33, 4), CultureInfo.InvariantCulture); chain.SecondaryStructures.Add(sheet); }
// Parses helix secondary structure object specified by the pdb-file line void ParseHelix(string pdbLine) { Chain chain; char chainId = pdbLine[19]; if (!chains.TryGetValue(chainId, out chain)) chains[chainId] = chain = new Chain() { Name = chainId.ToString() }; SecondaryStructure helix = new SecondaryStructure(); helix.StructureType = SecondaryStructureType.Helix; helix.FirstResidueSequenceNumber = int.Parse(pdbLine.Substring(21, 4), CultureInfo.InvariantCulture); helix.LastResidueSequenceNumber = int.Parse(pdbLine.Substring(33, 4), CultureInfo.InvariantCulture); chain.SecondaryStructures.Add(helix); }