MeshGeometry3D ExtractMeshGeometry3D(Primitive surface)
 {
     if (surface == null) UpdateVisualModel();
     if (surface == null) return new MeshGeometry3D();
     if (surface.Geometry == null) return new MeshGeometry3D();
     return surface.Geometry as MeshGeometry3D;
 }
        void UpdateVisualModel()
        {
            if (style == null || Data == null) return;

            this.primitive = null;
            this.upperCap = null;
            this.lowerCap = null;
            this.Children.Clear();

            if (this.chain == null) return;

            Point3D[] points;
            Vector3D[] normals;
            Vector3D[] torsions;
            this.chain.Ribbon.GetResidueBackbone(this, out points, out torsions, out normals);

            bool isStructureEnd = this.chain.Ribbon.IsStructureEnd(this);
            bool isStructureBegin = this.chain.Ribbon.IsStructureBegin(this);

            switch (this.Data.GetStructureType())
            {
                case NuGenBioChem.Data.SecondaryStructureType.Sheet:
                    this.primitive = CreateSheet(points, normals, torsions, isStructureEnd);
                    if (isStructureEnd || isStructureBegin) this.lowerCap = this.primitive.CreateLowerCap();
                    break;
                case NuGenBioChem.Data.SecondaryStructureType.Helix:
                    this.primitive = CreateHelix(points, normals, torsions);
                    if (isStructureEnd) this.upperCap = this.primitive.CreateUpperCap();
                    if (isStructureBegin) this.lowerCap = this.primitive.CreateLowerCap();
                    break;
                case NuGenBioChem.Data.SecondaryStructureType.NotDefined:
                    this.primitive = CreateTurn(points, normals, torsions);
                    if (isStructureEnd) this.upperCap = this.primitive.CreateUpperCap();
                    if (isStructureBegin) this.lowerCap = this.primitive.CreateLowerCap();
                    break;
            };

            if (this.lowerCap != null)
            {
                this.lowerCap.Material = this.material ?? this.Data.Material;
                this.Children.Add(this.lowerCap);
            }
            if (this.upperCap != null)
            {
                this.upperCap.Material = this.material ?? this.Data.Material;
                this.Children.Add(this.upperCap);
            }
            if (this.primitive != null)
            {
                this.primitive.Material = this.material ?? this.Data.Material;
                this.Children.Add(this.primitive);
            }
        }
        void AddMeshData(Primitive surface, float[] vertices, short[] indices, int verticesOffset, int indicesOffset, out int verticesAdded, out int indicesAdded)
        {
            MeshGeometry3D mesh = ExtractMeshGeometry3D(surface);
            verticesAdded = mesh.Positions.Count;
            indicesAdded = mesh.TriangleIndices.Count;

            for (int i = 0; i < verticesAdded; i++)
            {
                int offset = i * 8 + verticesOffset * 8;
                vertices[offset + 0] = (float)mesh.Positions[i].X;
                vertices[offset + 1] = (float)mesh.Positions[i].Y;
                vertices[offset + 2] = (float)mesh.Positions[i].Z;
                vertices[offset + 3] = (float)mesh.Normals[i].X;
                vertices[offset + 4] = (float)mesh.Normals[i].Y;
                vertices[offset + 5] = (float)mesh.Normals[i].Z;
                vertices[offset + 6] = mesh.TextureCoordinates.Count == 0 ? 0.0f : (float)mesh.TextureCoordinates[i].X;
                vertices[offset + 7] = mesh.TextureCoordinates.Count == 0 ? 0.0f : (float)mesh.TextureCoordinates[i].Y;
            }

            for (int i = 0; i < indicesAdded; i++)
            {
                indices[i + indicesOffset + 0] = (short)mesh.TriangleIndices[i];
            }
        }