static unsafe int GetPixel(int penWidth, int *penData, float x, float y) { var left = (int)x; var right = x.Ceiling(); var top = (int)y; var bottom = y.Ceiling(); var i = left + top * penWidth; if (left - x == 0 && y - top == 0) { return(penData[i]); } var j = i + 1; var k = i + penWidth; var l = i + 1 + penWidth; var lt = penData[i]; var rt = penData[j]; var lb = penData[k]; var rb = penData[l]; return(Colours.Blend(lt, rt, lb, rb, x - left, y - top)); }
public unsafe override void RenderPixel(IBuffer target, int index, int color, bool blend, float? delta = null) { if (IsDisposed) throw new System.Exception("Object is disposed!"); if (index < 0 || index >= target.Length) return; target.XYOf(index, out int x, out int y); int i = index; if (blend && FillMode != FillMode.Erase) { if (delta != null) target[i] = Colours.Blend(target[i], color, delta.Value); else target[i] = Colours.Blend(target[i], color); } else target[i] = color; NotifyDrawPoint(x, y); }
/* The MIT License(MIT) * Copyright(c) 2009-2015 Rene Schulte * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files(the "Software"), to deal * the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE.*/ public static unsafe IGraphics RotatedCopy(this IGraphics surface, Angle angle, bool crop = false) { bool isAngle = angle.Valid; // rotating clockwise, so it's negative relative to Cartesian quadrants float cnAngle = -Geometry.Radian * angle.Degree; // general iterators int i, j; // calculated indices Cartesian coordinates int x, y; float fDistance, fPolarAngle; // for use neighboring indices Cartesian coordinates int iFloorX, iCeilingX, iFloorY, iCeilingY; // calculated indices Cartesian coordinates with trailing decimals float fTrueX, fTrueY; // for interpolation float fDeltaX, fDeltaY; int iCentreX, iCentreY; int iDestCentreX, iDestCentreY; int iWidth, iHeight, newWidth, newHeight; iWidth = surface.Width; iHeight = surface.Height; if (crop) { newWidth = iWidth; newHeight = iHeight; } else { var rad = angle.Degree / Geometry.RadianInv; var nAngle = new Angle(rad); newWidth = (int)Math.Ceiling(Math.Abs(nAngle.Sin * iHeight) + Math.Abs(nAngle.Cos * iWidth)); newHeight = (int)Math.Ceiling(Math.Abs(nAngle.Sin * iWidth) + Math.Abs(nAngle.Cos * iHeight)); } iCentreX = iWidth / 2; iCentreY = iHeight / 2; iDestCentreX = newWidth / 2; iDestCentreY = newHeight / 2; var result = surface.ToPen(newWidth, newHeight) as IGraphics; if (!angle.Valid) { return(result); } var newp = (int *)result.Pixels; var oldp = (int *)surface.Pixels; var oldw = surface.Width; // assigning pixels of destination image from source image // with bilinear interpolation for (i = 0; i < newHeight; ++i) { for (j = 0; j < newWidth; ++j) { // convert raster to Cartesian x = j - iDestCentreX; y = iDestCentreY - i; // convert Cartesian to polar fDistance = (float)Math.Sqrt(x * x + y * y); if (x == 0) { if (y == 0) { // center of image, no rotation needed newp[i * newWidth + j] = oldp[iCentreY * oldw + iCentreX]; continue; } fPolarAngle = Geometry.PI; fPolarAngle *= y < 0 ? 1.5f : .5f; } else { fPolarAngle = (float)Math.Atan2(y, x); } // the crucial rotation part // "reverse" rotate, so minus instead of plus fPolarAngle -= cnAngle; // convert polar to Cartesian fTrueX = (float)(fDistance * Math.Cos(fPolarAngle)); fTrueY = (float)(fDistance * Math.Sin(fPolarAngle)); // convert Cartesian to raster fTrueX = fTrueX + iCentreX; fTrueY = iCentreY - fTrueY; iFloorX = (int)(Math.Floor(fTrueX)); iFloorY = (int)(Math.Floor(fTrueY)); iCeilingX = (int)(Math.Ceiling(fTrueX)); iCeilingY = (int)(Math.Ceiling(fTrueY)); // check bounds if (iFloorX < 0 || iCeilingX < 0 || iFloorX >= iWidth || iCeilingX >= iWidth || iFloorY < 0 || iCeilingY < 0 || iFloorY >= iHeight || iCeilingY >= iHeight) { continue; } fDeltaX = fTrueX - iFloorX; fDeltaY = fTrueY - iFloorY; var clrTopLeft = oldp[iFloorY * oldw + iFloorX]; var clrTopRight = oldp[iFloorY * oldw + iCeilingX]; var clrBottomLeft = oldp[iCeilingY * oldw + iFloorX]; var clrBottomRight = oldp[iCeilingY * oldw + iCeilingX]; newp[i * newWidth + j] = Colours.Blend(clrTopLeft, clrTopRight, clrBottomLeft, clrBottomRight, fDeltaX, fDeltaY); } } return(result); }
public unsafe override void RenderLine(IBuffer target, IBufferPen reader, int destVal, int destAxis, int start, int end, int axis, bool horizontal, float? delta = null) { if (!GetAxisLineInfo(target, ref destVal, ref destAxis, ref start, ref end, horizontal, out int destIndex, out int length)) return; ReadLine(reader, start, (start + length), axis, horizontal, out IntPtr source, out int sIndex, out length); if (length == 0) return; int* src = (int*)source; float? alpha; if (FillMode == FillMode.Erase) alpha = null; else alpha = delta; if (IsRotated(Entity.Buffer)) { var j = sIndex; if (length < 2) return; var last = destVal + length - 1; for (float i = destVal; i <= last; i++) { bool blend = i == start || i == last; target.WritePixel(i, destAxis, horizontal, src[j], blend); j++; } return; } int* dest = (int*)target.Pixels; if (horizontal) { if (alpha != null) Colours.Blend(src, sIndex, length, dest, destIndex, alpha); else CopyMemory(src, sIndex, dest, destIndex, length); NotifyAxisLine(destVal, destAxis, horizontal, length); } else { if (alpha != null) { for (int i = sIndex; i < sIndex + length; i++) { dest[destIndex] = Colours.Blend(dest[destIndex], src[i], alpha.Value); destIndex += target.Width; } } else { for (int i = sIndex; i < sIndex + length; i++) { dest[destIndex] = src[i]; destIndex += target.Width; } } NotifyAxisLine(destVal, destAxis, horizontal, length); } }