Ejemplo n.º 1
0
 /// <summary>
 /// Constructor.  Mostly pass-through, but we want to set the overlay image.
 /// </summary>
 public VisWireframeAnimation(string tag, string visGenIdent,
                              ReadOnlyDictionary <string, object> visGenParams, Visualization oldObj,
                              WireframeObject wireObj)
     : base(tag, visGenIdent, visGenParams, oldObj)
 {
     // wireObj may be null when loading from project file
     mWireObj     = wireObj;
     OverlayImage = ANIM_OVERLAY_IMAGE;
 }
Ejemplo n.º 2
0
        /// <summary>
        /// Generates WPF Path geometry from IVisualizationWireframe data.  Line widths get
        /// scaled if the output area is larger or smaller than the path bounds, so this scales
        /// coordinates so they fit within the box.
        /// </summary>
        /// <param name="visWire">Visualization data.</param>
        /// <param name="dim">Width/height to use for path area.</param>
        /// <param name="parms">Visualization parameters.</param>
        public static GeometryGroup GenerateWireframePath(WireframeObject wireObj,
                                                          double dim, ReadOnlyDictionary <string, object> parms)
        {
            int  eulerX  = Util.GetFromObjDict(parms, VisWireframeAnimation.P_EULER_ROT_X, 0);
            int  eulerY  = Util.GetFromObjDict(parms, VisWireframeAnimation.P_EULER_ROT_Y, 0);
            int  eulerZ  = Util.GetFromObjDict(parms, VisWireframeAnimation.P_EULER_ROT_Z, 0);
            bool doPersp = Util.GetFromObjDict(parms, VisWireframe.P_IS_PERSPECTIVE, true);
            bool doBfc   = Util.GetFromObjDict(parms, VisWireframe.P_IS_BFC_ENABLED, false);

            return(GenerateWireframePath(wireObj, dim, eulerX, eulerY, eulerZ, doPersp, doBfc));
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Generates a BitmapSource from IVisualizationWireframe data.  Useful for thumbnails
        /// and GIF exports.
        /// </summary>
        /// <param name="visWire">Visualization data.</param>
        /// <param name="dim">Output bitmap dimension (width and height).</param>
        /// <param name="parms">Parameter set, for rotations and render options.</param>
        /// <returns>Rendered bitmap.</returns>
        public static BitmapSource GenerateWireframeImage(WireframeObject wireObj,
                                                          double dim, ReadOnlyDictionary <string, object> parms)
        {
            int  eulerX     = Util.GetFromObjDict(parms, VisWireframeAnimation.P_EULER_ROT_X, 0);
            int  eulerY     = Util.GetFromObjDict(parms, VisWireframeAnimation.P_EULER_ROT_Y, 0);
            int  eulerZ     = Util.GetFromObjDict(parms, VisWireframeAnimation.P_EULER_ROT_Z, 0);
            bool doPersp    = Util.GetFromObjDict(parms, VisWireframe.P_IS_PERSPECTIVE, true);
            bool doBfc      = Util.GetFromObjDict(parms, VisWireframe.P_IS_BFC_ENABLED, false);
            bool doRecenter = Util.GetFromObjDict(parms, VisWireframe.P_IS_RECENTERED, true);

            return(GenerateWireframeImage(wireObj, dim, eulerX, eulerY, eulerZ, doPersp, doBfc,
                                          doRecenter));
        }
Ejemplo n.º 4
0
 /// <summary>
 /// Updates the thumbnail.
 /// </summary>
 /// <remarks>
 /// We override it because this is our first opportunity to capture the
 /// wireframe object reference if the object was created during project
 /// file loading.
 /// </remarks>
 /// <param name="visWire">Reference to wireframe data generated by plugin.</param>
 /// <param name="parms">Render parameters.</param>
 public override void SetThumbnail(IVisualizationWireframe visWire,
                                   ReadOnlyDictionary <string, object> parms)
 {
     base.SetThumbnail(visWire, parms);
     if (visWire == null)
     {
         // Thumbnail cache is being cleared.  Throw out the wireframe object too.
         mWireObj = null;
     }
     else
     {
         mWireObj = WireframeObject.Create(visWire);
     }
 }
Ejemplo n.º 5
0
 /// <summary>
 /// Updates the cached thumbnail image.
 /// </summary>
 /// <param name="visWire">Visualization object, or null to clear the thumbnail.</param>
 /// <param name="parms">Visualization parameters.</param>
 public virtual void SetThumbnail(IVisualizationWireframe visWire,
                                  ReadOnlyDictionary <string, object> parms)
 {
     if (visWire == null)
     {
         CachedImage = BROKEN_IMAGE;
     }
     else
     {
         Debug.Assert(parms != null);
         WireframeObject wireObj = WireframeObject.Create(visWire);
         CachedImage = GenerateWireframeImage(wireObj, THUMBNAIL_DIM, parms);
     }
     Debug.Assert(CachedImage.IsFrozen);
 }
Ejemplo n.º 6
0
        /// <summary>
        /// Generates WPF Path geometry from IVisualizationWireframe data.  Line widths get
        /// scaled if the output area is larger or smaller than the path bounds, so this scales
        /// coordinates so they fit within the box.
        /// </summary>
        public static GeometryGroup GenerateWireframePath(WireframeObject wireObj,
                                                          double dim, int eulerX, int eulerY, int eulerZ, bool doPersp, bool doBfc,
                                                          bool doRecenter)
        {
            // WPF path drawing is based on a system where a pixel is drawn at the center
            // of its coordinates, and integer coordinates start at the top left edge of
            // the drawing area.  If you draw a pixel at (0,0), 3/4ths of the pixel will be
            // outside the window (visible or not based on ClipToBounds).
            //
            // If you draw a line from (1,1 to 4,1), the line's length will appear to
            // be (4 - 1) = 3.  It touches four pixels -- the end point is not exclusive --
            // but the filled area is only three, because the thickness doesn't extend the
            // line's length, and the line stops at the coordinate at the center of the pixel.
            // You're not drawing N pixels, you're drawing from one coordinate point to another.
            // If you have a window of size 8x8, and you draw from 0,0 to 7,0, the line will
            // extend for half a line-thickness off the top, but will not go past the right/left
            // edges.  (This becomes very obvious when you're working with an up-scaled 8x8 path.)
            //
            // Similarly, drawing a horizontal line two units long results in a square, and
            // drawing a line that starts and ends at the same point doesn't appear to
            // produce anything.
            //
            // It's possible to clean up the edges by adding 0.5 to all coordinate values.
            // This turns out to be important for another reason: a line from (1,1) to (9,1)
            // shows up as a double-wide half-bright line, while a line from (1.5,1.5) to
            // (9.5,1.5) is drawn as a single-wide full-brightness line.  This is because of
            // the anti-aliasing.  Anti-aliasing can be disabled, but the lines look much
            // nicer with it enabled.
            //
            // The path has an axis-aligned bounding box that covers the pixel centers.  If we
            // want a path-drawn mesh to animate smoothly we want to ensure that the bounds
            // are constant across all renderings of a shape (which could get thinner or wider
            // as it rotates), so we plot an invisible point in our desired bottom-right corner.
            //
            // If we want an 8x8 bitmap, we draw a line from (8,8) to (8,8) to establish the
            // bounds, then draw lines with coordinates from 0.5 to 7.5.

            GeometryGroup geo = new GeometryGroup();

            // Draw invisible line segments to establish Path bounds.
            Point topLeft  = new Point(0, 0);
            Point botRight = new Point(dim, dim);

            geo.Children.Add(new LineGeometry(topLeft, topLeft));
            geo.Children.Add(new LineGeometry(botRight, botRight));

            // Generate a list of clip-space line segments.  Coordinate values are in the
            // range [-1,1], with +X to the right and +Y upward.
            List <WireframeObject.LineSeg> segs = wireObj.Generate(eulerX, eulerY, eulerZ,
                                                                   doPersp, doBfc, doRecenter);

            // Convert clip-space coords to screen.  We need to translate to [0,2] with +Y
            // toward the bottom of the screen, scale up, round to the nearest whole pixel,
            // and add +0.5 to make thumbnail-size bitmaps look crisp.
            double scale = (dim - 0.5) / 2;
            double adj   = 0.5;

            foreach (WireframeObject.LineSeg seg in segs)
            {
                Point start = new Point(Math.Round((seg.X0 + 1) * scale) + adj,
                                        Math.Round((1 - seg.Y0) * scale) + adj);
                Point end = new Point(Math.Round((seg.X1 + 1) * scale) + adj,
                                      Math.Round((1 - seg.Y1) * scale) + adj);
                geo.Children.Add(new LineGeometry(start, end));
            }

            return(geo);
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Generates a BitmapSource from IVisualizationWireframe data.  Useful for thumbnails
        /// and GIF exports.
        /// </summary>
        public static BitmapSource GenerateWireframeImage(WireframeObject wireObj,
                                                          double dim, int eulerX, int eulerY, int eulerZ, bool doPersp, bool doBfc,
                                                          bool doRecenter)
        {
            if (wireObj == null)
            {
                // Can happen if the visualization generator is failing on stuff loaded from
                // the project file.
                return(BROKEN_IMAGE);
            }

            // Generate the path geometry.
            GeometryGroup geo = GenerateWireframePath(wireObj, dim, eulerX, eulerY, eulerZ,
                                                      doPersp, doBfc, doRecenter);

            // Render geometry to bitmap -- https://stackoverflow.com/a/869767/294248
            Rect bounds = geo.GetRenderBounds(null);

            //Debug.WriteLine("RenderWF dim=" + dim + " bounds=" + bounds + ": " + wireObj);

            // Create bitmap.
            RenderTargetBitmap bitmap = new RenderTargetBitmap(
                (int)dim,
                (int)dim,
                96,
                96,
                PixelFormats.Pbgra32);
            //RenderOptions.SetEdgeMode(bitmap, EdgeMode.Aliased);  <-- no apparent effect

            DrawingVisual dv = new DrawingVisual();

            using (DrawingContext dc = dv.RenderOpen()) {
                dc.DrawRectangle(Brushes.Black, null, new Rect(0, 0, bounds.Width, bounds.Height));
                Pen pen = new Pen(Brushes.White, 1.0);
                dc.DrawGeometry(null, pen, geo);
            }
            bitmap.Render(dv);

#if false
            // Old way: render Path to bitmap -- https://stackoverflow.com/a/23582564/294248

            // Clear the bitmap to black.  (Is there an easier way?)
            GeometryGroup bkgnd = new GeometryGroup();
            bkgnd.Children.Add(new RectangleGeometry(new Rect(0, 0, bounds.Width, bounds.Height)));
            Path path = new Path();
            path.Data   = bkgnd;
            path.Stroke = path.Fill = Brushes.Black;
            path.Measure(bounds.Size);
            path.Arrange(bounds);
            bitmap.Render(path);

            path        = new Path();
            path.Data   = geo;
            path.Stroke = Brushes.White;
            path.Measure(bounds.Size);
            path.Arrange(bounds);
            bitmap.Render(path);
#endif

            bitmap.Freeze();
            return(bitmap);
        }
Ejemplo n.º 8
0
        /// <summary>
        /// Creates a new object from a wireframe visualization.
        /// </summary>
        /// <param name="visWire">Visualization object.</param>
        /// <returns>New object, or null if visualization data fails validation.</returns>
        public static WireframeObject Create(IVisualizationWireframe visWire)
        {
            if (!visWire.Validate(out string msg))
            {
                // Should not be here -- visualizer should have checked validation and
                // reported an error.
                Debug.WriteLine("Wireframe validation failed: " + msg);
                return(null);
            }

            WireframeObject wireObj = new WireframeObject();

            wireObj.mIs2d = visWire.Is2d;

            //
            // Start by extracting data from the visualization object.  Everything stored
            // there is loaded into this object.  The VisWireframe validator will have
            // ensured that all the indices are in range.
            //
            // IMPORTANT: do not retain "visWire", as it may be a proxy for an object with a
            // limited lifespan.
            //

            float[] normalsX = visWire.GetNormalsX();
            if (normalsX.Length > 0)
            {
                float[] normalsY = visWire.GetNormalsY();
                float[] normalsZ = visWire.GetNormalsZ();

                for (int i = 0; i < normalsX.Length; i++)
                {
                    wireObj.mFaces.Add(new Face(normalsX[i], normalsY[i], normalsZ[i]));
                }
            }

            float[] verticesX        = visWire.GetVerticesX();
            float[] verticesY        = visWire.GetVerticesY();
            float[] verticesZ        = visWire.GetVerticesZ();
            int[]   excludedVertices = visWire.GetExcludedVertices();

            // Compute min/max for X/Y for 2d re-centering.  The trick is that we only want
            // to use vertices that are visible.  If the shape starts with a huge move off to
            // the left, we don't want to include (0,0).
            double xmin, xmax, ymin, ymax;

            xmin = ymin = 10e9;
            xmax = ymax = -10e9;

            for (int i = 0; i < verticesX.Length; i++)
            {
                wireObj.mVertices.Add(new Vertex(verticesX[i], verticesY[i], verticesZ[i],
                                                 HasIndex(excludedVertices, i)));
            }

            int[] points = visWire.GetPoints();
            for (int i = 0; i < points.Length; i++)
            {
                Vertex vert = wireObj.mVertices[points[i]];
                wireObj.mPoints.Add(vert);
                UpdateMinMax(vert, ref xmin, ref xmax, ref ymin, ref ymax);
            }

            IntPair[] edges         = visWire.GetEdges();
            int[]     excludedEdges = visWire.GetExcludedEdges();
            for (int i = 0; i < edges.Length; i++)
            {
                int v0index = edges[i].Val0;
                int v1index = edges[i].Val1;

                //if (v0index < 0 || v0index >= wireObj.mVertices.Count ||
                //        v1index < 0 || v1index >= wireObj.mVertices.Count) {
                //    Debug.Assert(false);
                //    return null;
                //}

                Vertex vert0 = wireObj.mVertices[v0index];
                Vertex vert1 = wireObj.mVertices[v1index];
                wireObj.mEdges.Add(new Edge(vert0, vert1, HasIndex(excludedEdges, i)));

                UpdateMinMax(vert0, ref xmin, ref xmax, ref ymin, ref ymax);
                UpdateMinMax(vert1, ref xmin, ref xmax, ref ymin, ref ymax);
            }

            IntPair[] vfaces = visWire.GetVertexFaces();
            for (int i = 0; i < vfaces.Length; i++)
            {
                int vindex = vfaces[i].Val0;
                int findex = vfaces[i].Val1;

                //if (vindex < 0 || vindex >= wireObj.mVertices.Count ||
                //        findex < 0 || findex >= wireObj.mFaces.Count) {
                //    Debug.Assert(false);
                //    return null;
                //}

                Face face = wireObj.mFaces[findex];
                wireObj.mVertices[vindex].Faces.Add(face);
                if (face.Vert == null)
                {
                    face.Vert = wireObj.mVertices[vindex];
                }
            }

            IntPair[] efaces = visWire.GetEdgeFaces();
            for (int i = 0; i < efaces.Length; i++)
            {
                int eindex = efaces[i].Val0;
                int findex = efaces[i].Val1;

                //if (eindex < 0 || eindex >= wireObj.mEdges.Count ||
                //        findex < 0 || findex >= wireObj.mFaces.Count) {
                //    Debug.Assert(false);
                //    return null;
                //}

                Face face = wireObj.mFaces[findex];
                wireObj.mEdges[eindex].Faces.Add(face);
                if (face.Vert == null)
                {
                    face.Vert = wireObj.mEdges[eindex].Vertex0;
                }
            }

            //
            // All data has been loaded into friendly classes.
            //

            // Compute center of visible vertices.
            wireObj.mCenterAdjX = -(xmin + xmax) / 2;
            wireObj.mCenterAdjY = -(ymin + ymax / 2);

            // Compute the magnitude of the largest vertex, for scaling.
            double bigMag   = -1.0;
            double bigMagRc = -1.0;

            for (int i = 0; i < wireObj.mVertices.Count; i++)
            {
                Vector3 vec = wireObj.mVertices[i].Vec;
                double  mag = vec.Magnitude();
                if (bigMag < mag)
                {
                    bigMag = mag;
                }

                // Repeat the operation with recentering.  This isn't quite right as we're
                // including all vertices, not just the visible ones.
                mag = new Vector3(vec.X + wireObj.mCenterAdjX,
                                  vec.Y + wireObj.mCenterAdjY, vec.Z).Magnitude();
                if (bigMagRc < mag)
                {
                    bigMagRc = mag;
                }
            }

            // Avoid divide-by-zero.
            if (bigMag == 0)
            {
                Debug.WriteLine("NOTE: wireframe magnitude was zero");
                bigMag = 1;
            }
            if (bigMagRc == 0)
            {
                bigMagRc = 1;
            }
            wireObj.mBigMag   = bigMag;
            wireObj.mBigMagRc = bigMagRc;

            return(wireObj);
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Creates a new object from a wireframe visualization.
        /// </summary>
        /// <param name="visWire">Visualization object.</param>
        /// <returns>New object.</returns>
        public static WireframeObject Create(IVisualizationWireframe visWire)
        {
            WireframeObject wireObj = new WireframeObject();

            //
            // Start by extracting data from the visualization object.  Everything stored
            // there is loaded into this object.
            //

            float[] normalsX = visWire.GetNormalsX();
            if (normalsX.Length > 0)
            {
                float[] normalsY = visWire.GetNormalsY();
                float[] normalsZ = visWire.GetNormalsZ();

                if (normalsX.Length != normalsY.Length || normalsX.Length != normalsZ.Length)
                {
                    Debug.Assert(false);
                    return(null);
                }

                for (int i = 0; i < normalsX.Length; i++)
                {
                    wireObj.mFaces.Add(new Face(normalsX[i], normalsY[i], normalsZ[i]));
                }
            }

            float[] verticesX        = visWire.GetVerticesX();
            float[] verticesY        = visWire.GetVerticesY();
            float[] verticesZ        = visWire.GetVerticesZ();
            int[]   excludedVertices = visWire.GetExcludedVertices();
            if (verticesX.Length == 0)
            {
                Debug.Assert(false);
                return(null);
            }
            if (verticesX.Length != verticesY.Length || verticesX.Length != verticesZ.Length)
            {
                Debug.Assert(false);
                return(null);
            }

            for (int i = 0; i < verticesX.Length; i++)
            {
                wireObj.mVertices.Add(new Vertex(verticesX[i], verticesY[i], verticesZ[i],
                                                 HasIndex(excludedVertices, i)));
            }

            IntPair[] edges         = visWire.GetEdges();
            int[]     excludedEdges = visWire.GetExcludedEdges();
            for (int i = 0; i < edges.Length; i++)
            {
                int v0index = edges[i].Val0;
                int v1index = edges[i].Val1;

                if (v0index < 0 || v0index >= wireObj.mVertices.Count ||
                    v1index < 0 || v1index >= wireObj.mVertices.Count)
                {
                    Debug.Assert(false);
                    return(null);
                }

                wireObj.mEdges.Add(new Edge(wireObj.mVertices[v0index],
                                            wireObj.mVertices[v1index], HasIndex(excludedEdges, i)));
            }

            IntPair[] vfaces = visWire.GetVertexFaces();
            for (int i = 0; i < vfaces.Length; i++)
            {
                int vindex = vfaces[i].Val0;
                int findex = vfaces[i].Val1;

                if (vindex < 0 || vindex >= wireObj.mVertices.Count ||
                    findex < 0 || findex >= wireObj.mFaces.Count)
                {
                    Debug.Assert(false);
                    return(null);
                }

                Face face = wireObj.mFaces[findex];
                wireObj.mVertices[vindex].Faces.Add(face);
                if (face.Vert == null)
                {
                    face.Vert = wireObj.mVertices[vindex];
                }
            }

            IntPair[] efaces = visWire.GetEdgeFaces();
            for (int i = 0; i < efaces.Length; i++)
            {
                int eindex = efaces[i].Val0;
                int findex = efaces[i].Val1;

                if (eindex < 0 || eindex >= wireObj.mEdges.Count ||
                    findex < 0 || findex >= wireObj.mFaces.Count)
                {
                    Debug.Assert(false);
                    return(null);
                }

                Face face = wireObj.mFaces[findex];
                wireObj.mEdges[eindex].Faces.Add(face);
                if (face.Vert == null)
                {
                    face.Vert = wireObj.mEdges[eindex].Vertex0;
                }
            }

            //
            // All data has been loaded into friendly classes.
            //

            // Compute the magnitude of the largest vertex, for scaling.
            double bigMag = -1.0;

            for (int i = 0; i < wireObj.mVertices.Count; i++)
            {
                double mag = wireObj.mVertices[i].Vec.Magnitude();
                if (bigMag < mag)
                {
                    bigMag = mag;
                }
            }
            wireObj.mBigMag = bigMag;

            return(wireObj);
        }