Пример #1
0
        /// <summary>
        /// Implementation of Marching Cubes based on http://paulbourke.net/geometry/polygonise/
        /// </summary>
        /// <param name="volume">Volume intensity values</param>
        /// <param name="dims">Volume dimensions</param>
        /// <param name="angpix">Angstrom per pixel</param>
        /// <param name="threshold">Isosurface threshold</param>
        /// <returns></returns>
        public static Mesh FromVolume(float[] volume, int3 dims, float angpix, float threshold)
        {
            Triangle[][] CellTriangles = new Triangle[volume.Length][];

            unsafe
            {
                fixed (float* volumePtr = volume)
                    for (int z = 0; z < dims.Z - 1; z++)
                    {
                        float zz = (z - dims.Z / 2) * angpix;
                        for (int y = 0; y < dims.Y - 1; y++)
                        {
                            float yy = (y - dims.Y / 2) * angpix;
                            for (int x = 0; x < dims.X - 1; x++)
                            {
                                float xx = (x - dims.X / 2) * angpix;

                                Vector3[] p = new Vector3[8];
                                float[] val = new float[8];

                                p[0] = new Vector3(xx, yy, zz);
                                p[1] = new Vector3(xx + angpix, yy, zz);
                                p[2] = new Vector3(xx + angpix, yy + angpix, zz);
                                p[3] = new Vector3(xx, yy + angpix, zz);
                                p[4] = new Vector3(xx, yy, zz + angpix);
                                p[5] = new Vector3(xx + angpix, yy, zz + angpix);
                                p[6] = new Vector3(xx + angpix, yy + angpix, zz + angpix);
                                p[7] = new Vector3(xx, yy + angpix, zz + angpix);

                                val[0] = volumePtr[((z + 0) * dims.Y + (y + 0)) * dims.X + (x + 0)];
                                val[1] = volumePtr[((z + 0) * dims.Y + (y + 0)) * dims.X + (x + 1)];
                                val[2] = volumePtr[((z + 0) * dims.Y + (y + 1)) * dims.X + (x + 1)];
                                val[3] = volumePtr[((z + 0) * dims.Y + (y + 1)) * dims.X + (x + 0)];
                                val[4] = volumePtr[((z + 1) * dims.Y + (y + 0)) * dims.X + (x + 0)];
                                val[5] = volumePtr[((z + 1) * dims.Y + (y + 0)) * dims.X + (x + 1)];
                                val[6] = volumePtr[((z + 1) * dims.Y + (y + 1)) * dims.X + (x + 1)];
                                val[7] = volumePtr[((z + 1) * dims.Y + (y + 1)) * dims.X + (x + 0)];

                                CellTriangles[(z * dims.Y + y) * dims.X + x] = Polygonize(p, val, threshold);
                            }
                        }
                    }
            }

            Mesh NewMesh = new Mesh();

            for (int i = 0; i < CellTriangles.Length; i++)
            {
                if (CellTriangles[i] == null)
                    continue;

                foreach (var tri in CellTriangles[i])
                {
                    NewMesh.Vertices.Add(tri.V0);
                    NewMesh.Vertices.Add(tri.V1);
                    NewMesh.Vertices.Add(tri.V2);

                    tri.ID = NewMesh.Triangles.Count;
                    NewMesh.Triangles.Add(tri);
                }
            }

            NewMesh.UpdateGraph();
            NewMesh.UpdateVertexIDs();

            return NewMesh;
        }
Пример #2
0
 public void CenterOn(Mesh model)
 {
     Vector3 MeshMin = model.GetMin();
     Vector3 MeshMax = model.GetMax();
     Vector3 MeshCenter = (MeshMin + MeshMax) / 2f;
     Move(MeshCenter - Target);
     float MaxExtent = Math.Max(Math.Max(MeshMax.X - MeshMin.X, MeshMax.Y - MeshMin.Y), MeshMax.Z - MeshMin.Z);
     if (!IsOrthogonal)
         Distance = MaxExtent * 1.5f;
     else
         OrthogonalSize = MaxExtent;
 }
Пример #3
0
        /// <summary>
        /// Creates a Mesh object based on a Wavefront OBJ file.
        /// </summary>
        /// <param name="path">Path to the file</param>
        /// <returns></returns>
        public static Mesh FromOBJ(string path, bool center = false)
        {
            Mesh NewMesh = new Mesh();

            // Parse vertices
            using (TextReader Reader = new StreamReader(File.OpenRead(path)))
            {
                string Line = Reader.ReadLine();
                while (Line != null)
                {
                    string[] Parts = Line.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                    if (Parts.Length > 0 && Parts[0] == "v")
                        NewMesh.Vertices.Add(new Vertex(new Vector3(float.Parse(Parts[1]), float.Parse(Parts[2]), float.Parse(Parts[3])), new Vector3(1, 0, 0)));

                    Line = Reader.ReadLine();
                }
            }

            if (center)
            {
                Vector3 Center = Vector3.Zero;
                Vector3 CenterVolume = Vector3.Zero;
                foreach (var v in NewMesh.Vertices)
                {
                    Center += v.Position;
                    CenterVolume += v.VolumePosition;
                }

                Center /= NewMesh.Vertices.Count;
                CenterVolume /= NewMesh.Vertices.Count;

                foreach (var v in NewMesh.Vertices)
                {
                    v.Position -= Center;
                    v.VolumePosition -= CenterVolume;
                }
            }

            // Parse faces
            using (TextReader Reader = new StreamReader(File.OpenRead(path)))
            {
                string Line = Reader.ReadLine();
                while (Line != null)
                {
                    string[] Parts = Line.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                    if (Parts.Length > 0 && Parts[0] == "f")
                    {
                        string[] FaceParts0 = Parts[1].Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
                        string[] FaceParts1 = Parts[2].Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
                        string[] FaceParts2 = Parts[3].Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
                        NewMesh.Triangles.Add(new Triangle(NewMesh.Triangles.Count,
                                                           NewMesh.Vertices[int.Parse(FaceParts0[0]) - 1],
                                                           NewMesh.Vertices[int.Parse(FaceParts1[0]) - 1],
                                                           NewMesh.Vertices[int.Parse(FaceParts2[0]) - 1]));
                    }
                    Line = Reader.ReadLine();
                }
            }

            // Amira likes to put unused vertices into the OBJ
            NewMesh.Vertices.RemoveAll(v => v.Triangles.Count == 0);

            NewMesh.UpdateGraph();
            NewMesh.UpdateVertexIDs();

            return NewMesh;
        }
Пример #4
0
        public void UpdateDepiction()
        {
            if (DepictionMesh != null)
            {
                DepictionMesh.Dispose();
                DepictionMesh = null;
            }
            foreach (var point in Points)
                point.DropDepictionMesh();

            //if (Points.Count == 0)
                //return;

            if (Depiction == PointDepiction.Mesh && File.Exists(DepictionMeshPath))
            {
                FileInfo Info = new FileInfo(DepictionMeshPath);
                if (Info.Extension.ToLower().Contains("mrc"))
                {
                    HeaderMRC VolumeHeader = (HeaderMRC)MapHeader.ReadFromFile(DepictionMeshPath);
                    float[] VolumeData = IOHelper.ReadSmallMapFloat(DepictionMeshPath, new int2(1, 1), 0, typeof(float));

                    Mesh NewMesh = Mesh.FromVolume(VolumeData, VolumeHeader.Dimensions, VolumeHeader.Pixelsize.X, (float)DepictionMeshLevel);
                    NewMesh.UsedComponents = MeshVertexComponents.Position | MeshVertexComponents.Normal;
                    NewMesh.GLContext = MainWindow.Options.Viewport.GetControl();
                    NewMesh.UpdateBuffers();

                    _DepictionMesh = NewMesh;
                }
                else if (Info.Extension.ToLower().Contains("obj"))
                {
                    Mesh NewMesh = Mesh.FromOBJ(DepictionMeshPath, true);
                    NewMesh.UsedComponents = MeshVertexComponents.Position | MeshVertexComponents.Normal;
                    NewMesh.GLContext = MainWindow.Options.Viewport.GetControl();
                    NewMesh.UpdateBuffers();

                    _DepictionMesh = NewMesh;
                }
            }
            else if (Depiction == PointDepiction.LocalSurface && MainWindow.Options.Membrane.TomogramTexture != null)
            {
                int3 DimsExtract = new int3((int)Size + 2, (int)Size + 2, (int)Size + 2);

                Parallel.ForEach(Points, point =>
                {
                    Vector3 TomoPos = (point.Position - MainWindow.Options.Membrane.TomogramTexture.Offset) / MainWindow.Options.PixelScale.X;
                    int3 TomoPosInt = new int3((int)Math.Round(TomoPos.X), (int)Math.Round(TomoPos.Y), (int)Math.Round(TomoPos.Z));

                    float[] LocalVol = Helper.Extract(MainWindow.Options.Membrane.TomogramTexture.OriginalData,
                                                      MainWindow.Options.Membrane.TomogramTexture.Size,
                                                      TomoPosInt,
                                                      DimsExtract);

                    if (DepictionLocalSurfaceInvert)
                        for (int i = 0; i < LocalVol.Length; i++)
                            LocalVol[i] = -LocalVol[i];

                    for (int z = 0; z < DimsExtract.Z; z++)
                        for (int y = 0; y < DimsExtract.Y; y++)
                            for (int x = 0; x < DimsExtract.X; x++)
                                if (z == 0 || y == 0 || x == 0 || z == DimsExtract.Z - 1 || y == DimsExtract.Y - 1 || x == DimsExtract.X - 1)
                                    LocalVol[(z * DimsExtract.Y + y) * DimsExtract.X + x] = -99999;

                    bool[] Mask = new bool[LocalVol.Length];
                    float Threshold = (float)DepictionLocalSurfaceLevel;
                    if (DepictionLocalSurfaceOnlyCenter)
                    {
                        int MostCentralID = -1;
                        float MostCentralDist = DimsExtract.X * DimsExtract.X;

                        // Find most central valid pixel in the local window to start mask expansion from there.
                        for (int z = 1; z < DimsExtract.Z - 1; z++)
                        {
                            int zz = z - DimsExtract.Z / 2;
                            zz *= zz;
                            for (int y = 1; y < DimsExtract.Y - 1; y++)
                            {
                                int yy = y - DimsExtract.Y / 2;
                                yy *= yy;
                                for (int x = 1; x < DimsExtract.X - 1; x++)
                                {
                                    if (LocalVol[(z * DimsExtract.Y + y) * DimsExtract.X + x] >= Threshold)
                                    {
                                        int xx = x - DimsExtract.X / 2;
                                        xx *= xx;
                                        float r = xx + yy + zz;
                                        if (r < MostCentralDist)
                                        {
                                            MostCentralDist = r;
                                            MostCentralID = (z * DimsExtract.Y + y) * DimsExtract.X + x;
                                        }
                                    }
                                }
                            }
                        }
                        if (MostCentralID < 0) // Volume doesn't contain voxels above threshold
                            return;

                        Mask[MostCentralID] = true;

                        for (int mi = 0; mi < Size / 2; mi++)
                        {
                            bool[] NextMask = new bool[Mask.Length];

                            for (int z = 1; z < DimsExtract.Z - 1; z++)
                                for (int y = 1; y < DimsExtract.Y - 1; y++)
                                    for (int x = 1; x < DimsExtract.X - 1; x++)
                                    {
                                        int ID = (z * DimsExtract.Y + y) * DimsExtract.X + x;
                                        if (LocalVol[ID] >= Threshold)
                                            if (Mask[ID] ||
                                                Mask[ID + 1] ||
                                                Mask[ID - 1] ||
                                                Mask[ID + DimsExtract.X] ||
                                                Mask[ID - DimsExtract.X] ||
                                                Mask[ID + DimsExtract.Y * DimsExtract.X] ||
                                                Mask[ID - DimsExtract.Y * DimsExtract.X])
                                                NextMask[ID] = true;
                                    }

                            Mask = NextMask;
                        }
                    }
                    else
                        for (int i = 0; i < Mask.Length; i++)
                            Mask[i] = true;

                    // Apply spherical mask
                    int Size2 = (int)(Size * Size / 4);
                    for (int z = 1; z < DimsExtract.Z - 1; z++)
                    {
                        int zz = z - DimsExtract.Z / 2;
                        zz *= zz;
                        for (int y = 1; y < DimsExtract.Y - 1; y++)
                        {
                            int yy = y - DimsExtract.Y / 2;
                            yy *= yy;
                            for (int x = 1; x < DimsExtract.X - 1; x++)
                            {
                                int xx = x - DimsExtract.X / 2;
                                xx *= xx;
                                int r2 = xx + yy + zz;

                                Mask[(z * DimsExtract.Y + y) * DimsExtract.X + x] &= r2 < Size2;
                            }
                        }
                    }

                    for (int i = 0; i < Mask.Length; i++)
                        if (!Mask[i])
                            LocalVol[i] = Math.Min(LocalVol[i], Threshold - 1e-5f);

                    //IOHelper.WriteMapFloat("d_extract.mrc", HeaderMRC.ReadFromFile("test_extract.mrc"), LocalVol);
                    //IOHelper.WriteMapFloat("d_original.mrc", HeaderMRC.ReadFromFile("Tomo1L1_bin4.mrc"), MainWindow.Options.Membrane.TomogramTexture.OriginalData);

                    point.DepictionMesh = Mesh.FromVolume(LocalVol,
                                                          DimsExtract,
                                                          MainWindow.Options.PixelScale.X,
                                                          (float)DepictionLocalSurfaceLevel);
                    point.DepictionMesh.UsedComponents = MeshVertexComponents.Position | MeshVertexComponents.Normal;
                });

                foreach (var point in Points)
                {
                    if (point.DepictionMesh == null)
                        continue;
                    point.DepictionMesh.GLContext = MainWindow.Options.Viewport.GetControl();
                    point.DepictionMesh.UpdateBuffers();
                }
            }

            MainWindow.Options.Viewport.Redraw();
        }
Пример #5
0
        public void LoadModel(string path)
        {
            if (string.IsNullOrEmpty(path))
                return;

            if (SurfaceMesh != null)
                SurfaceMesh.FreeBuffers();

            SurfaceMesh = Mesh.FromOBJ(path);
            SurfaceMesh.GLContext = Viewport.GetControl();
            SurfaceMesh.UpdateProcessedGeometry(0f);

            Viewport.GetControl().MakeCurrent();
            SurfaceMesh.UpdateBuffers();

            SurfaceOffset = 0;
            Viewport.Camera.CenterOn(SurfaceMesh);

            PathModel = path;
        }
Пример #6
0
        public SurfacePatch(Membrane membrane, string name, Color color, IEnumerable<Triangle> triangles)
        {
            Membrane = membrane;
            Name = name;
            Color = color;

            Dictionary<Vertex, Vertex> VertexToTransformed = new Dictionary<Vertex, Vertex>();
            List<Triangle> NewTriangles = new List<Triangle>(triangles.Count());

            foreach (var t in triangles)
            {
                foreach (var v in t.Vertices)
                    if (!VertexToTransformed.ContainsKey(v))
                        VertexToTransformed.Add(v, new Vertex(v.VolumePosition, v.VolumeNormal));

                Triangle NewTriangle = new Triangle(t.ID, VertexToTransformed[t.V0], VertexToTransformed[t.V1], VertexToTransformed[t.V2]);
                NewTriangles.Add(NewTriangle);
                OriginalToTransformed.Add(t, NewTriangle);
                TransformedToOriginal.Add(NewTriangle, t);
            }

            SurfaceMesh = new Mesh();
            SurfaceMesh.Vertices.AddRange(VertexToTransformed.Values);
            SurfaceMesh.Triangles.AddRange(OriginalToTransformed.Values);

            SurfaceMesh.UpdateGraph();
            SurfaceMesh.UpdateVertexIDs();

            TurnUpsideUp();
            // Don't update buffers because there is no OpenGL context yet.

            UpdateStats();
            UpdatePlanarizationStats();

            Membrane.DisplayedPatches.CollectionChanged += MembraneDisplayedPatches_CollectionChanged;
            Membrane.PointGroups.CollectionChanged += MembranePointGroups_CollectionChanged;
            MembranePointGroups_CollectionChanged(null, null);
        }
Пример #7
0
 public void DropDepictionMesh()
 {
     if (DepictionMesh != null)
     {
         DepictionMesh.Dispose();
         DepictionMesh = null;
     }
 }