unsafe private void AddTriangleStripPointsForPreviousPoint(NICSignaturePoint previous, NICSignaturePoint next) { float toTravel = this.penThickness / 2.0f; for (int i = 0; i < 2; i++) { Vector3 p = this.Perpendicular(previous, next); Vector3 p1 = next.Vertex; Vector3 pref = Vector3.Add(p1, p); float difX = p1.X - pref.X; float difY = p1.Y - pref.Y; float distance = (float)Math.Sqrt(Math.Pow(difX, 2) + Math.Pow(difY, 2) + Math.Pow(p1.Z - pref.Z, 2)); // 3d distance between p1 and reference point float ratio = -1.0f * (toTravel / distance); difX = difX * ratio; difY = difY * ratio; NICSignaturePoint stripPoint = new NICSignaturePoint(); stripPoint.Color = GLSignatureView.StrokeColor; stripPoint.Vertex = new Vector3 { X = p1.X + difX, Y = p1.Y + difY, Z = 0.0f }; fixed(uint *pvl = &vertexLength) { this.AddVertex(pvl, stripPoint); } toTravel *= -1; } }
// Calculates perpendicular vector from two other vectors to compute triangle strip around line private Vector3 Perpendicular(NICSignaturePoint p1, NICSignaturePoint p2) { Vector3 pVector = new Vector3(); pVector.X = p2.Vertex.Y - p1.Vertex.Y; pVector.Y = -1 * (p2.Vertex.X - p1.Vertex.X); pVector.Z = 0; return(pVector); }
private NICSignaturePoint ViewPointToGL(CGPoint viewPoint, CGRect bounds, Vector3 color) { NICSignaturePoint GLPoint = new NICSignaturePoint(); GLPoint.Vertex.X = (float)(viewPoint.X / bounds.Size.Width * 2.0 - 1); GLPoint.Vertex.Y = (float)(((viewPoint.Y / bounds.Size.Height) * 2.0 - 1) * (-1)); GLPoint.Vertex.Z = 0; GLPoint.Color = color; return(GLPoint); }
private byte[] SigPointBytes(NICSignaturePoint point) { // Returns raw signature point data as byte array int rawsize = Marshal.SizeOf(typeof(NICSignaturePoint)); IntPtr buffer = Marshal.AllocHGlobal(rawsize); Marshal.StructureToPtr(point, buffer, false); byte[] rawdata = new byte[rawsize]; Marshal.Copy(buffer, rawdata, 0, rawsize); Marshal.FreeHGlobal(buffer); return(rawdata); }
unsafe private void AddVertex(uint *length, NICSignaturePoint v) { if (*length >= maxLength) { return; } IntPtr data = GL.Oes.MapBuffer(All.ArrayBuffer, All.WriteOnlyOes); byte[] pointBytes = SigPointBytes(v); int offset = (int)(pointBytes.Length * (*length)); IntPtr targetAddress = IntPtr.Add(data, offset); Marshal.Copy(pointBytes, 0, targetAddress, pointBytes.Length); GL.Oes.UnmapBuffer(All.ArrayBuffer); (*length)++; }
unsafe protected void pan(UIPanGestureRecognizer sender) { if (nsvc.SigningMode) { GL.BindBuffer(BufferTarget.ArrayBuffer, vertexBuffer); CGPoint vel = sender.VelocityInView(this); CGPoint loc = sender.LocationInView(this); // currentVelocity = this.ViewPointToGL (vel, this.Frame, GLSignatureView.StrokeColor); float distance = 0.0f; if (previousPoint.X > 0) { distance = (float)Math.Sqrt(Math.Pow(loc.X - previousPoint.X, 2) + Math.Pow(loc.Y - previousPoint.Y, 2)); } float velocityMagnitude = (float)Math.Sqrt(vel.X * vel.X + vel.Y * vel.Y); float clampedVelocityMagnitude = this.Clamp(VELOCITY_CLAMP_MIN, VELOCITY_CLAMP_MAX, velocityMagnitude); float normalizedVelocity = (clampedVelocityMagnitude - VELOCITY_CLAMP_MIN) / (VELOCITY_CLAMP_MAX - VELOCITY_CLAMP_MIN); float lowPassFilterAlpha = (float)STROKE_WIDTH_SMOOTHING; float newThickness = (float)((STROKE_WIDTH_MAX - STROKE_WIDTH_MIN) * (1 - normalizedVelocity) + STROKE_WIDTH_MIN); this.penThickness = this.penThickness * lowPassFilterAlpha + newThickness * (1 - lowPassFilterAlpha); switch (sender.State) { case UIGestureRecognizerState.Began: { this.previousPoint = loc; this.previousMidPoint = loc; NICSignaturePoint startPoint = this.ViewPointToGL(loc, this.Frame, new Vector3 { X = 1, Y = 1, Z = 1 }); this.previousVertex = startPoint; this.previousThickness = penThickness; fixed(uint *pvl = &vertexLength) { this.AddVertex(pvl, startPoint); } fixed(uint *pvl = &vertexLength) { this.AddVertex(pvl, previousVertex); } this.nsvc.hasBeenSigned = true; break; } case UIGestureRecognizerState.Changed: { CGPoint mid = new CGPoint((loc.X + previousPoint.X) / 2.0f, (loc.Y + previousPoint.Y) / 2.0f); if (distance > QUADRATIC_DISTANCE_TOLERANCE) { // Plot quadratic Bezier line instead of a straight uint i; int segments = (int)(distance / 1.5f); float startPenThickness = this.previousThickness; float endPenThickness = this.penThickness; this.previousThickness = this.penThickness; for (i = 0; i < segments; i++) { this.penThickness = startPenThickness + ((endPenThickness - startPenThickness) / segments) * i; CGPoint quadPoint = QuadraticPointInCurve(previousMidPoint, mid, previousPoint, (float)i / (float)segments); NICSignaturePoint v = this.ViewPointToGL(quadPoint, this.Frame, GLSignatureView.StrokeColor); this.AddTriangleStripPointsForPreviousPoint(this.previousVertex, v); this.previousVertex = v; } } else if (distance > 1.0f) { NICSignaturePoint v = this.ViewPointToGL(loc, this.Frame, GLSignatureView.StrokeColor); this.AddTriangleStripPointsForPreviousPoint(this.previousVertex, v); this.previousVertex = v; this.previousThickness = this.penThickness; } this.previousPoint = loc; this.previousMidPoint = mid; break; } case UIGestureRecognizerState.Ended: { NICSignaturePoint v = this.ViewPointToGL(loc, this.Frame, new Vector3 { X = 1, Y = 1, Z = 1 }); fixed(uint *pvl = &vertexLength) { this.AddVertex(pvl, v); } this.previousVertex = v; fixed(uint *pvl = &vertexLength) { this.AddVertex(pvl, v); } break; } case UIGestureRecognizerState.Cancelled: { NICSignaturePoint v = this.ViewPointToGL(loc, this.Frame, new Vector3 { X = 1, Y = 1, Z = 1 }); fixed(uint *pvl = &vertexLength) { this.AddVertex(pvl, v); } this.previousVertex = v; fixed(uint *pvl = &vertexLength) { this.AddVertex(pvl, v); } break; } } this.SetNeedsDisplay(); } // end if the corresponding ciew controller is in Signing mode }
unsafe protected void tap(UITapGestureRecognizer sender) { if (nsvc.SigningMode) { CGPoint l = sender.LocationInView(this); if (sender.State == UIGestureRecognizerState.Recognized) { this.nsvc.hasBeenSigned = true; GL.BindBuffer(BufferTarget.ArrayBuffer, dotsBuffer); NICSignaturePoint touchPoint = this.ViewPointToGL(l, this.Frame, new Vector3 { X = 1.0f, Y = 1.0f, Z = 1.0f }); fixed(uint *pdl = &dotsLength) { this.AddVertex(pdl, touchPoint); } NICSignaturePoint centerPoint = touchPoint; centerPoint.Color = GLSignatureView.StrokeColor; fixed(uint *pdl = &dotsLength) { this.AddVertex(pdl, centerPoint); } const int segments = 20; Vector2 radius = new Vector2 { X = penThickness * this.GenerateRandom(0.5f, 1.0f), Y = penThickness * this.GenerateRandom(0.5f, 1.0f) }; Vector2 velocityRadius = radius; double angle = 0; // Our view height is much less than width, for them dots to be more roundy float uncompressY = (float)(this.Frame.Width / this.Frame.Height); for (int i = 0; i <= segments; i++) { NICSignaturePoint p = centerPoint; p.Vertex.X += velocityRadius.X * ((float)Math.Cos(angle)); p.Vertex.Y += velocityRadius.Y * ((float)Math.Sin(angle)) * uncompressY; fixed(uint *pdl = &dotsLength) { this.AddVertex(pdl, p); } fixed(uint *pdl = &dotsLength) { this.AddVertex(pdl, centerPoint); } angle += Math.PI * 2.0f / segments; } fixed(uint *pdl = &dotsLength) { this.AddVertex(pdl, touchPoint); } GL.BindBuffer(BufferTarget.ArrayBuffer, 0); } this.SetNeedsDisplay(); } // end if the corresponding view controller is in Signing mode }