示例#1
0
        /// <summary>
        /// <see cref="InvalidateStroke"/>
        /// </summary>
        /// <param name="iStroke">The Ink stroke to invalidate</param>
        /// <param name="padding">Number of pixels to pad invalidation
        /// rectangle in Ink space pixels</param>
        public void InvalidateStroke(Microsoft.Ink.Stroke iStroke, int padding)
        {
            using (Graphics g = InkPicture.CreateGraphics())
            {
                Rectangle            bb         = iStroke.GetBoundingBox();
                System.Drawing.Point upperLeft  = new System.Drawing.Point(bb.X - padding, bb.Y - padding);
                System.Drawing.Point lowerRight = new System.Drawing.Point(bb.Right + padding, bb.Bottom + padding);
                InkPicture.Renderer.InkSpaceToPixel(g, ref upperLeft);
                InkPicture.Renderer.InkSpaceToPixel(g, ref lowerRight);

                InkPicture.Invalidate(new Rectangle(upperLeft.X, upperLeft.Y, lowerRight.X, lowerRight.Y));
            }
        }
        /// <summary>
        /// Returns the bounding box for the given shape in ink space coordinates.  Optionall colors the strokes
        /// the default color for non-wire symbols.
        /// <see cref="UIConstants.TextFeedbackMechanismSymbolColor"/>
        /// </summary>
        /// <param name="shape">the shape for which the bounding box will be calculated</param>
        /// <param name="substroke2InkTable">A hashtable mapping Ink Stroke IDs to Sketch Substroke IDs.
        /// This hashtable allows the Feedback Mechanism to assocate Ink Strokes drawn to screen
        /// with their corresponding (labeled) Sketch substrokes.</param>
        /// <param name="colorStrokes">True iff the microsoft ink strokes should be colored while calculating
        /// the bounding box (for efficiency's sake).</param>
        /// <returns>A System.Drawing.Rectangle representing the bounding box
        /// for the given shape (in ink space coordinates)</returns>
        private Rectangle calculateBoundingBox(Sketch.Shape shape, Hashtable substroke2InkTable, bool colorStrokes)
        {
            // Compute the bounding box of all the ink strokes
            // associated with this shape
            Rectangle boundingBox = Rectangle.Empty;

            foreach (Sketch.Substroke substroke in shape.Substrokes)
            {
                if (!substroke2InkTable.Contains(substroke.XmlAttrs.Id))
                {
                    // If, for some reason, there is no ink stroke
                    // that corresponds to this substroke, skip it
                    continue;
                }

                Microsoft.Ink.Stroke iStroke = (Microsoft.Ink.Stroke)substroke2InkTable[substroke.XmlAttrs.Id];

                if (colorStrokes)
                {
                    iStroke.DrawingAttributes.Color = UIConstants.TextFeedbackMechanismSymbolColor;
                }

                Rectangle strokeBox = iStroke.GetBoundingBox();

                if (boundingBox.IsEmpty)
                {
                    boundingBox = strokeBox;
                }
                else
                {
                    if (strokeBox.X < boundingBox.X)
                    {
                        boundingBox.X = strokeBox.X;
                    }
                    if (strokeBox.Y < boundingBox.Y)
                    {
                        boundingBox.Y = strokeBox.Y;
                    }
                    if (strokeBox.Bottom > boundingBox.Bottom)
                    {
                        boundingBox.Height = strokeBox.Bottom - boundingBox.Y;
                    }
                    if (strokeBox.Right > boundingBox.Right)
                    {
                        boundingBox.Width = strokeBox.Right - boundingBox.X;
                    }
                }
            }

            return(boundingBox);
        }
示例#3
0
        /// <summary>
        /// Takes an Ink.Stroke and outputs an internal representation that can
        /// then be output to an XML file
        /// </summary>
        /// <param name="inkStroke">Ink.Stroke which will have extracted from it the information necessary to store a Stroke in MIT XML.</param>
        /// <param name="transf">Transformation matrix to shift the stroke by</param>
        /// <param name="shift">Boolean for if we should shift by the transformation matrix</param>
        /// <returns>PointsAndShape object that stores the extracted information.</returns>
        public static Sketch.Stroke StripStrokeData(Microsoft.Ink.Stroke inkStroke, Matrix transf, bool shift)
        {
            int i;
            int length;

            // Get the timestamp for the function using an undocumented GUID (Microsoft.Ink.StrokeProperty.TimeID) to
            // get the time as a byte array, which we then convert to a long
            ulong theTime;

            if (inkStroke.ExtendedProperties.Contains(Microsoft.Ink.StrokeProperty.TimeID) &&
                (inkStroke.ExtendedProperties[Microsoft.Ink.StrokeProperty.TimeID] != null))
            {
                byte[] timeBits = inkStroke.ExtendedProperties[Microsoft.Ink.StrokeProperty.TimeID].Data as byte[];

                // Filetime format
                ulong fileTime = BitConverter.ToUInt64(timeBits, 0);

                // MIT time format
                theTime = (fileTime - 116444736000000000) / 10000;
                //string time = theTime.ToString();
            }
            else
            {
                //theTime = (ulong)System.DateTime.Now.Ticks;
                //theTime = ((ulong)System.DateTime.Now.Ticks - 116444736000000000) / 10000;
                theTime = ((ulong)DateTime.Now.ToFileTime() - 116444736000000000) / 10000;
            }

            // Grab X and Y
            int[] xData = inkStroke.GetPacketValuesByProperty(Microsoft.Ink.PacketProperty.X);
            int[] yData = inkStroke.GetPacketValuesByProperty(Microsoft.Ink.PacketProperty.Y);

            if (shift)
            {
                // Shift X and Y according to transformation matrix
                System.Drawing.Point[] pointData = new System.Drawing.Point[xData.Length];
                length = xData.Length;
                for (i = 0; i < length; i++)
                {
                    pointData[i] = new System.Drawing.Point(xData[i], yData[i]);
                }

                transf.TransformPoints(pointData);

                //Console.WriteLine("x: " + (pointData[0].X - xData[0]) + " y: " + (pointData[0].Y - yData[0]));

                for (i = 0; i < length; i++)
                {
                    xData[i] = pointData[i].X;
                    yData[i] = pointData[i].Y;
                }
            }

            Microsoft.Ink.DrawingAttributes drawingAttributes = inkStroke.DrawingAttributes;
            System.Drawing.Rectangle        boundingBox       = inkStroke.GetBoundingBox();

            // Grab the color
            int color = drawingAttributes.Color.ToArgb();

            // THIS IS DRAWING POINT (PENTIP) HEIGHT AND WIDTH... WE DONT HAVE ANYWHERE TO PUT IT...
            //string height = inkStroke.DrawingAttributes.Height.ToString();
            //string width = inkStroke.DrawingAttributes.Width.ToString();
            float penWidth  = drawingAttributes.Width;
            float penHeight = drawingAttributes.Height;

            // Grab height and width of total stroke
            //float height = boundingBox.Height;
            //float width = boundingBox.Width;

            // Grab penTip
            string penTip = drawingAttributes.PenTip.ToString();

            // Grab raster
            string raster = drawingAttributes.RasterOperation.ToString();


            //float x = Convert.ToSingle(boundingBox.X);
            //float y = Convert.ToSingle(boundingBox.Y);

            //float leftx = Convert.ToSingle(boundingBox.Left);
            //float topy = Convert.ToSingle(boundingBox.Top);

            // If the pressure data is included take it, otherwise set to 255/2's
            // Not all pressure data is in the range of 0 - 255. Some tablets
            // register pressure in the range 0 - 1023, while others are 0 - 32768
            int[] pressureData;
            if (ReadJnt.IsPropertyIncluded(inkStroke, Microsoft.Ink.PacketProperty.NormalPressure))
            {
                pressureData = inkStroke.GetPacketValuesByProperty(Microsoft.Ink.PacketProperty.NormalPressure);
                int max = 0;
                foreach (int p in pressureData)
                {
                    max = Math.Max(max, p);
                }

                if (max > 1024) // Tablet reading in range 0 - 32767
                {
                    double     conversion = 255.0 / 32767.0;
                    List <int> temp       = new List <int>(pressureData.Length);
                    foreach (int p in pressureData)
                    {
                        temp.Add((int)(p * conversion));
                    }

                    pressureData = temp.ToArray();
                }
                else if (max > 255) // Tablet reading in range 0 - 1023
                {
                    double     conversion = 255.0 / 1023.0;
                    List <int> temp       = new List <int>(pressureData.Length);
                    foreach (int p in pressureData)
                    {
                        temp.Add((int)(p * conversion));
                    }

                    pressureData = temp.ToArray();
                }
            }
            else
            {
                pressureData = new int[xData.Length];
                length       = pressureData.Length;
                for (i = 0; i < length; ++i)
                {
                    pressureData[i] = (255 - 0) / 2;
                }
            }

            // If the time data is included take it, otherwise set to the timestamp plus and increment
            ulong[] adjustedTime = new ulong[xData.Length];
            int[]   timerTick;
            if (ReadJnt.IsPropertyIncluded(inkStroke, Microsoft.Ink.PacketProperty.TimerTick))
            {
                timerTick = inkStroke.GetPacketValuesByProperty(Microsoft.Ink.PacketProperty.TimerTick);
                length    = timerTick.Length;
                for (i = 0; i < length; i++)
                {
                    // This may be incorrect, we never encountered this because Microsoft Journal doesn't save TimerTick data.
                    // We know that the timestamp of a stroke is made when the pen is lifted.

                    // Add the time of the stroke to each offset
                    adjustedTime[i] = theTime + (ulong)timerTick[i] * 10000;
                }
            }
            else
            {
                timerTick = new int[xData.Length];
                length    = timerTick.Length;
                for (i = 0; i < length; i++)
                {
                    // We believe this to be the standard sample rate.  The multiplication by 1,000 is to convert from
                    // seconds to milliseconds.
                    //
                    // Our time is in the form of milliseconds since Jan 1, 1970
                    //
                    // NOTE: The timestamp for the stroke is made WHEN THE PEN IS LIFTED
                    adjustedTime[i] = theTime - (ulong)((1 / SAMPLE_RATE * 1000) * (length - i));
                }
            }

            // Create the array of ID's as new Guid's
            Guid[] idData = new Guid[xData.Length];
            length = idData.Length;
            for (i = 0; i < length; i++)
            {
                idData[i] = Guid.NewGuid();
            }

            // Create the internal representation
            Sketch.Stroke converterStroke = new Sketch.Stroke();
            converterStroke.Name   = "stroke";
            converterStroke.Time   = (ulong)theTime;
            converterStroke.Source = "Converter";


            // Add all of the points to the stroke

            length = inkStroke.PacketCount;
            List <Point> pointsToAdd = new List <Point>();

            for (i = 0; i < length; i++)
            {
                float currX = Convert.ToSingle(xData[i]);
                float currY = Convert.ToSingle(yData[i]);

                XmlStructs.XmlPointAttrs attrs = new XmlStructs.XmlPointAttrs(
                    currX, currY,
                    Convert.ToUInt16(pressureData[i]),
                    Convert.ToUInt64(adjustedTime[i]),
                    "point", idData[i]);

                Sketch.Point toAdd = new Sketch.Point(attrs);
            }


            //NOTE: X, Y, WIDTH, HEIGHT done later... boundingbox seems to be off
            Sketch.Substroke substroke = new Sketch.Substroke(pointsToAdd);
            substroke.Name      = "substroke";
            substroke.Color     = color;
            substroke.PenTip    = penTip;
            substroke.PenWidth  = penWidth;
            substroke.PenHeight = penHeight;
            substroke.Raster    = raster;
            substroke.Source    = "ConverterJnt";
            substroke.Start     = idData[0];
            substroke.End       = idData[idData.Length - 1];

            converterStroke.AddSubstroke(substroke);
            return(converterStroke);
        }
示例#4
0
        /// <summary>
        /// Takes an Ink.Stroke and outputs an internal representation that can
        /// then be output to an XML file
        /// </summary>
        /// <param name="inkStroke">Ink.Stroke which will have extracted from it the information necessary to store a Stroke in MIT XML.</param>
        /// <param name="transf">Transformation matrix to shift the stroke by</param>
        /// <param name="shift">Boolean for if we should shift by the transformation matrix</param>
        /// <returns>PointsAndShape object that stores the extracted information.</returns>
        private Sketch.Stroke StripStrokeData(Microsoft.Ink.Stroke inkStroke, Matrix transf, bool shift)
        {
            int i;
            int length;

            // Get the timestamp for the function using an undocumented GUID (Microsoft.Ink.StrokeProperty.TimeID) to
            // get the time as a byte array, which we then convert to a long
            long theTime;

            if (this.IsPropertyIncluded(inkStroke, Microsoft.Ink.StrokeProperty.TimeID))
            {
                byte[] timeBits = inkStroke.ExtendedProperties[Microsoft.Ink.StrokeProperty.TimeID].Data as byte[];
                long   fileTime = BitConverter.ToInt64(timeBits, 0);               //filetime format
                theTime = (fileTime - 116444736000000000) / 10000;                 //MIT time format
                // string time = theTime.ToString();
            }
            else
            {
                theTime = DateTime.Now.Ticks;
            }

            // Grab X and Y
            int[] xData = inkStroke.GetPacketValuesByProperty(Microsoft.Ink.PacketProperty.X);
            int[] yData = inkStroke.GetPacketValuesByProperty(Microsoft.Ink.PacketProperty.Y);

            if (shift)
            {
                // Shift X and Y according to transformation matrix
                System.Drawing.Point[] pointData = new System.Drawing.Point [xData.Length];
                length = xData.Length;
                for (i = 0; i < length; i++)
                {
                    pointData[i] = new System.Drawing.Point(xData[i], yData[i]);
                }

                transf.TransformPoints(pointData);
                //Console.WriteLine("x: " + (pointData[0].X - xData[0]) + " y: " + (pointData[0].Y - yData[0]));

                for (i = 0; i < length; i++)
                {
                    xData[i] = pointData[i].X;
                    yData[i] = pointData[i].Y;
                }
            }

            Microsoft.Ink.DrawingAttributes drawingAttributes = inkStroke.DrawingAttributes;
            System.Drawing.Rectangle        boundingBox       = inkStroke.GetBoundingBox();

            // Grab the color
            int color = drawingAttributes.Color.ToArgb();

            // THIS IS DRAWING POINT (PENTIP) HEIGHT AND WIDTH... WE DONT HAVE ANYWHERE TO PUT IT...
            //string height = inkStroke.DrawingAttributes.Height.ToString();
            //string width = inkStroke.DrawingAttributes.Width.ToString();

            // Grab height and width of total stroke
            float height = boundingBox.Height;
            float width  = boundingBox.Width;

            // Grab penTip
            string penTip = drawingAttributes.PenTip.ToString();

            // Grab raster
            string raster = drawingAttributes.RasterOperation.ToString();


            float x = Convert.ToSingle(boundingBox.X);
            float y = Convert.ToSingle(boundingBox.Y);

            float leftx = Convert.ToSingle(boundingBox.Left);
            float topy  = Convert.ToSingle(boundingBox.Top);



            // If the pressure data is included take it, otherwise set to 255/2's
            int[] pressureData;
            if (this.IsPropertyIncluded(inkStroke, Microsoft.Ink.PacketProperty.NormalPressure))
            {
                pressureData = inkStroke.GetPacketValuesByProperty(Microsoft.Ink.PacketProperty.NormalPressure);
            }
            else
            {
                pressureData = new int[xData.Length];
                length       = pressureData.Length;
                for (i = 0; i < length; ++i)
                {
                    pressureData[i] = (255 - 0) / 2;
                }
            }
            // If the time data is included take it, otherwise set to the timestamp plus and increment
            long[] adjustedTime = new long[xData.Length];
            int[]  timerTick;
            if (this.IsPropertyIncluded(inkStroke, Microsoft.Ink.PacketProperty.TimerTick))
            {
                timerTick = inkStroke.GetPacketValuesByProperty(Microsoft.Ink.PacketProperty.TimerTick);
                length    = timerTick.Length;
                for (i = 0; i < length; i++)
                {
                    // This may be incorrect, we never encountered this because Microsoft Journal doesn't save TimerTick data.
                    // We know that the timestamp of a stroke is made when the pen is lifted.
                    adjustedTime[i] = theTime + (long)timerTick[i] * 10000;                   //add the time of the stroke to each offset
                }
            }
            else
            {
                timerTick = new int[xData.Length];
                length    = timerTick.Length;
                for (i = 0; i < length; i++)
                {
                    // We believe this to be the standard sample rate.  The multiplication by 1,000 is to convert from
                    // seconds to milliseconds.
                    //
                    // Our time is in the form of milliseconds since Jan 1, 1970
                    //
                    // NOTE: The timestamp for the stroke is made WHEN THE PEN IS LIFTED
                    adjustedTime[i] = theTime - (long)((1 / SAMPLE_RATE * 1000) * (length - i));
                }
            }

            // Create the array of ID's as new Guid's
            Guid[] idData = new Guid[xData.Length];
            length = idData.Length;
            for (i = 0; i < length; i++)
            {
                idData[i] = Guid.NewGuid();
            }

            // Create the internal representation
            Sketch.Stroke converterStroke = new Sketch.Stroke();
            converterStroke.XmlAttrs.Id     = System.Guid.NewGuid();
            converterStroke.XmlAttrs.Name   = "stroke";
            converterStroke.XmlAttrs.Time   = (ulong)theTime;
            converterStroke.XmlAttrs.Type   = "stroke";
            converterStroke.XmlAttrs.Source = "Converter";

            Sketch.Substroke substroke = new Sketch.Substroke();
            substroke.XmlAttrs.Id     = System.Guid.NewGuid();
            substroke.XmlAttrs.Name   = "substroke";
            substroke.XmlAttrs.Time   = (ulong)theTime;
            substroke.XmlAttrs.Type   = "substroke";
            substroke.XmlAttrs.Color  = color;
            substroke.XmlAttrs.Height = height;
            substroke.XmlAttrs.Width  = width;
            substroke.XmlAttrs.PenTip = penTip;
            substroke.XmlAttrs.Raster = raster;
            substroke.XmlAttrs.X      = x;
            substroke.XmlAttrs.Y      = y;
            substroke.XmlAttrs.LeftX  = leftx;
            substroke.XmlAttrs.TopY   = topy;
            substroke.XmlAttrs.Source = "Converter";
            substroke.XmlAttrs.Start  = idData[0];
            substroke.XmlAttrs.End    = idData[idData.Length - 1];


            // Add all of the points to the stroke
            length = inkStroke.PacketCount;
            for (i = 0; i < length; i++)
            {
                Sketch.Point toAdd = new Sketch.Point();
                toAdd.XmlAttrs.Name     = "point";
                toAdd.XmlAttrs.X        = Convert.ToSingle(xData[i]);
                toAdd.XmlAttrs.Y        = Convert.ToSingle(yData[i]);
                toAdd.XmlAttrs.Pressure = Convert.ToUInt16(pressureData[i]);
                toAdd.XmlAttrs.Time     = Convert.ToUInt64(adjustedTime[i]);
                toAdd.XmlAttrs.Id       = idData[i];

                substroke.AddPoint(toAdd);
            }
            converterStroke.AddSubstroke(substroke);
            return(converterStroke);
        }