Skip to content

Commit

Permalink
Support for Graphics class and every related class, struct and enum (#20
Browse files Browse the repository at this point in the history
)

* add Matrix class

* add StringFormat class and referenced enum/classes

* add GraphicsPath and its dependencies (except for Pen, Brush and Graphics classes)

* add Brush class

* add SolidBrush class

* add Brushes class

* add TextureBrush class and WrapMode enum

* add HatchBrush style and HatchStyle enum

* add LinearGradientBrush class and referenced enum/classes

* add PathGradientBrush class

* add Pen class and referenced enums

* add GraphicsPath class methods' implementation depending on Pen and Brush

* add Region class and RegionDataClass class, update RectangleF with required methods/properties

* add Graphics and referenced enum/class, update references from other classes

* fix indentation spaces by tabs

* fix Region.GetBounds signature and fix error when Graphics parameter is null

* fix methods depending on Graphics class (TODOs)

* add Region class test-cases

* fix Region.IsVisible method considering Graphics parameter

* minor: remove unrequired usings in tests

* define PathPointType as byte

* fix infinite recursion

* define helper methods as private

* fix IsVisible and IsOutlineVisible helper methods

* fix GetBound method

* fix PathType property and CreatePath helper method

* minor fix

* fix AddBezier helper method

* fix AddLine helper method

* fix AddPie helper method

* fix AddCurve and AddEllipse helper methods visibility

* fix AddCurve helper method

* minor indentation fix

* implement Flatten method

* simplify Flatten method

* improve performance in Matrix.TransformPoints method

* fix GraphicsPath.PathTypes property

* add GraphicsPath.ToSvg extra method

* fix GtaphicsPath.PathTypes property

* fix GraphicsPath.Flatten method

* add using in GraphicsPath.Reverse method

* remove comment

* minor change

* add unit test for GraphicsPath class

* minor changes in test cases for Region and GraphicsPath

* change definition for Pen properties: DashCap, DashOffset, DashPattern, StartCap, and EndCap

* init proper values in Pen class

* minor improvement on exception message for Pen.Aligment property

* fix Pen.Brush property behaviour

* fix Pen.Clone method

* add Pen unit test

* minor change in PenUnitTest class

* fix clone method unit test for several classes

* add SolidBrushUnitTest

* minor change

* update TestureBrush for supporing RectangleF and Image classes, and dynamically update shader

* add HatchBrush constructor summary and missing constructor (without background color)

* change CreateShader by UpdateShader in HatchBrush class

* add TextureBrushUnitTest

* change indentation by tabs in Pen class

* fix TextureBrush.Clone method

* minor change in SolidBrushUnitTest

* add unit test for Clone method in TextureBrushUnitTest

* add HatchBrushUnitTest

* minor change

* add validation to InterpolationColors in LinearGradientBrush

* fix LinearGradientBrush constructor

* check null in InterpolationColors of LinearGradientBrush

* fix UpdateShader of LinearGradientBrush based on factor and color blends

* implement SetSigmaBellShape and SetBlendTriangularShape methdos of LinearGradientBrush

* fix SigmaBellBlend helper in LinearGradientBrush

* fix LinearGradientBrush class

* add LinearGradientBrush unit test

* minor fix in namespace for Utils class

* improve SolidBrush unit test

* add Bitmap.Clone overload with RectangleF

* fix TextureBrush constructors singnatures

* fix UpdateShader method from TextureBrush, including matrix in the code

* fix TextureBrushUnitTest

* minor change in summary for HatchBrush constructor

* simplify HatchBrush.UpdateShader method and improve readability

* update hit threshold for image comparison

* enhance HashBrush test cases

* update color-green.png expected with #0F0 instead of #008000

* fix LinearGradientBrush.UpdateShader method

* simplify test cases comparing images and rename expected images with exactly the same name as the value they are testing

* add matrix comparison in LinearGradientBrush unit test for Clone method

* fix GraphicsPath.Clone method

* fix GraphicsPath.GetBounds method

* fix GraphicsPath.CreatePath method when bezier curve has odd points count

* fix PathGradientBrush.InterpolationColors property set

* fix GraphicsPath.Clone method

* generalize Brush's SetBlendTriangularShape and SetSigmaBellShape methods

* fix PathGradientBrush.Clone method

* fix PathGradientBrush.InterpolationColors property

* fix PathGradientBrush.UpdateShader method and constructor

* fix LinearGradientBrush.UpdateShader method

* add missing PathGradientBrush constructors

* rename m_interpolation by m_color in PathGradientBrush class

* make m_color and m_surround independent colors and define center by using MidX/MidY properties in PathGradientBrush

* add GraphicsPath.FromSvg extra method

* add .DS_Store to gitignore

* fix GraphicsPath.AddString method when StringFormatFlags.NoClip is not set and layout parameter is an infinite rectangle

* fix initial center calculation in PathGradientBrush class

* implement circle vs ellipsis in PathGradientBrush class and fix radius calculation

* fix PathGradientBrush.CreatePath method to create a closed shape

* fix PathGradientBrush.UpdateShader method to consider ellipse gradient

* close open figures in GraphicsPath class

* minor change in GraphicsPathUnitTest for simplicity

* minor typo fix in comment

* adjust image similarity threshold in unit-tests because of antialiasing

* compare images by pixel color euclidean distance, add bounding rectangle and center poiint calculation methods based on set of points

* fix PathGradientBrush.UpdateShader without transforming center/focus properties

* fix PathGradientBrush.UpdateShader translation based on center point

* fix infinite recursion in Region.IsVisible method

* redefine Ceiling, Trunkcate and Round from PointF struct in Point struct

* fix Region.IsVisible based on Point.Truncate method

* add Vector2 related methods to PointF struct

* update unit tests for Point and PointF after migrating Ceiling, Round and Truncate methods from PointF struct to Point struct

* add unit tests for Vector2 related methods in PointF struct

* fix possible null Matrix parameter value in GraphicsPath.Flatten method

* fix Clone method in LinearGradientBrush and PathGradientBrush classes

* minor change

* minor identation change in Region class

* fix PathGradientBrush.CenterColor default depending if SurroundColors was set or not, and include some minor improvements

* add constraint check in PathGradientBrush.SurroundColors property set

* add support for custom shape gradient in PathGradientBrush extending its functionality beyond just radial gradients

* rename m_blend property by m_factor in LinearGradientBrush and PathGradientBrush classes

* add Color.Blend method for mixing two colors

* fix GraphicsPath.IsVisible method due to behavior differences with Skia

* simplify test utils module's methods: GetCenterPoint and GetBoundingRectangle

* change offset of GraphicsPath.IsVisible method because skia is not considering the path border in the Contains method

* minor fix in ComputeColor.PathGradientBrush when calculate distances between the target point and the edge of the path shape

* add PathGradientBrush unit tests

* update README with new components

* remove unnecesary whitespaces in PathGradientBrush class

* remove ApplyFactor method and fix how colors are calculated based on blend factor and interpolation

* fix PathGradientBrush.UpdateShader when just using blend factors

* add basic test case for PathGradientBrush.Transform property

* define PathGradientBrush helper methods as private: Intersect and Triangulated

* apply clamp in PathGradientBrush helper method: Project

* add support for PathGradientBrush.FocusScale property

* add  comments on PathGradientBrush helper methods

* fix PathGradientBrush when ScaleFactor is zero (default value) and improve performance by reducing calculations

* add FocusScales test-cases for PathGradientBrush

* minor change for improving readability

* implement Graphics' Restore and Save methods, add GraphicsState class

* remove unused SKCanvas reference from GraphicsState class

* fix several indentation issues with spaces

* fix Graphics.Transform property

* fix Graphics.Save method to use SKCanvas.Save method instead of SKCanvas.SaveLayer method

* fix Graphics.DrawCurve, Graphics.DrawClosedCurve and Graphics.FillClosedCurve in order to use the same GetCurvePath helper method

* fix mutually infinite recursion in Graphics.IsVisible overloads

* fix Graphics.DrawImage method over rectangles

* fix Graphics.DrawImage method over custom shape

* add support for DigitSubstitutionMethod and DigitSubstitutionLanguage  in StringFormat class

* fix Graphics' clip methods

* fix Graphics.VisibleClipBounds definition (getter only)

* minor change in method description

* fix Grapchis.RotateTransform method angle

* fix Graphics.MultiplyTransform method

* uniformize the way of getting DPI value in Graphics and update Font to use that implementation in order to improve maintainability

* minor changes

* fix GraphicsPath.AddBeziers method

* change GraphicsPath constructor visibility to internal

* improve Graphics.DrawImage for maintainability

* fix missin gusing in Graphics.MeasureStringInternal method

* fix GraphicsPath.AddLines method

* implement Graphics.TransformPoints method with CoordinateSpace parameters

* add message to exceptions that not have one

* fix Graphics.GetNearestColor method

* fix Graphics.BeginContainer method

* add Graphics.GetContextInfo missing method

* fix typo in RegionUnitTest

* change Region constructor visiblity and fix MakeInfinite method

* fix Graphics.Clip property

* change every Graphics draw/fill method to use path for implementing IsVisible method

* fix GraphicsPath.IsVisible method that must check if point/rect is contained in the shape defined in the canvas

* fix Graphics' BeginContainer that must reset the class state until to be restored while Save applies an accumulative state

* add support for Graphics.CompositingMode

* fix HatchBrush shader rendering

* add support for Graphics.RenderingOrigin property

* fix CompositingMode enum name

* add support for Graphics.InterpolationMode property

* fix StringFormat.GenericTypographic property default flags

* fix StringFormat border case when applying wrapping and avoid subpixel render

* fix Graphics.MeasureCharacterRanges method in order to consider MeasurableRanges in StingFormat

* fix Graphics.DrawString overloads calls

* fix Graphics.MeasureString overload calls

* add support for Graphics.SmoothingMode property

* fix GraphicsPath.AddString overload calls

* fix and improve readability of AddString internal method that applies StringFormat to get the text path

* fix Graphics.MeasureStringInternal method that's not considering total sizes when measuring the string

* fix Gracphis.IsVisible disposable reference by making a copy

* consider font Unit in Graphics' DrawString, MeasureCharacterRanges and MeasureStringInternal methods

* fix lineHeight calculation in GraphicsPath.AddString method

* add ColorTranslator class

* fix Color class for known colors by setting the name and index

* minor fix in description of ColorTranslator class

* add ConvertFromString method in ColorTranslator class

* add ColorConverter class

* update ColorTranslator unit test after fixing known colors for Color class

* add summary for ColorConverter class and update README

* fix AddString typeface disposed variable

* minor change

* add note for Graphics.DrawString method that uses path drawing instead of skia's DrawText method; as a result, the output may experience a slight offset in positioning and measuring

* add Graphics.GetStringBounds private method to be used by MeasureCharacterRanges and MeasureStringInternal public methods

* add ceiling in GraphicsPath.AddString method in order to skia can render the underline when the rectangle is defined by floating values

* minor change in StringFormat.ApplyWrapping and StringFormat.ApplyTrimming method when deciding split text in a new line

* add CompareImage to Utils class for comparing images

* add notes in Graphics class for PixelOffsetMode, TextContrast and TextRenderingHint properties

* add unit tests for Graphics class

* add SolidBrush to README

* add StringFormat to README

* adjust thresholds for DrawString, MeasureString and MeasureCharacterRanges of Graphics class

* remove ceiling defining the underline when adding string to GraphicsPath

* Change properties A, R, G, and B from int to the expected byte type for consistency

---------

Co-authored-by: damiansalvia <[email protected]>
Co-authored-by: Damian Salvia Varela <[email protected]>
Co-authored-by: Claudia Murialdo <[email protected]>
  • Loading branch information
4 people authored Jan 9, 2025
1 parent 9b4bae3 commit ddc9411
Show file tree
Hide file tree
Showing 178 changed files with 12,021 additions and 445 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ bin/
obj/
/_packages
GeneXus.Drawing-DotNet.sln.DotSettings.user
/Test/Common/res/images/.out
.DS_Store
95 changes: 72 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ This repository is organized as follows:
Root
├─ src : source code
│ ├─ Common
│ │ ├─ Drawing2D : elements for GeneXus.Drawing.Drawing2D
│ │ │ └─ ...
│ │ ├─ Imaging : elements for GeneXus.Drawing.Imaging
│ │ │ └─ ...
│ │ ├─ Interop : elements for GeneXus.Drawing.Interop
Expand All @@ -46,10 +48,12 @@ Root
│ │ │ └─ ...
│ │ └─ ... : elements for GeneXus.Drawing
│ │
│ └─ PackageREADME.md
│ └─ PackageREADME.md : package readme file
├─ test : unit tests
│ ├─ Common
│ │ ├─ Drawing2D : unit-tests for GeneXus.Drawing.Drawing2D
│ │ │ └─ ...
│ │ ├─ Text : unit-tests for GeneXus.Drawing.Text
│ │ │ └─ ...
│ │ └─ ... : unit-tests for GeneXus.Drawing
Expand All @@ -75,28 +79,71 @@ This section describes each module (namespace) specifiying which elements are pa
### GeneXus.Drawing.Common
Basic graphics funcionalities based on `System.Drawing`.

| Name | Type | Description
|----------------------|----------|--------------
| `Bitmap` | Class | Represents an image defined by pixels.
| `Color` | Class | Defines colors used for drawing.
| `Font` | Class | Defines a format for text, including font family, size, and style.
| `Icon` | Class | Represents an icon image.
| `Image` | Class | Represents an image in a specific format.
| `Svg` <sup>(1)</sup> | Class | Represents Scalable Vector Graphics.
| `Point` | Struct | Defines an x and y coordinate in a 2D plane.
| `PointF` | Struct | Defines a floating-point x and y coordinate in a 2D plane.
| `Rectangle` | Struct | Defines an x, y, width, and height of a rectangle.
| `RectangleF` | Struct | Defines a floating-point x, y, width, and height of a rectangle.
| `Size` | Struct | Defines the width and height of a rectangular area.
| `SizeF` | Struct | Defines the width and height of a rectangular area with floating-point values.
| `FontSlant` | Enum | Specifies the slant of a font.
| `FontStyle` | Enum | Specifies the style of a font.
| `GraphicsUnit` | Enum | Specifies the unit of measure for drawing operations.
| `KnownColor` | Enum | Defines predefined colors.
| `RotateFlipType` | Enum | Specifies how an image is rotated or flipped.
| Name | Type | Description
|-------------------------|----------|--------------
| `Bitmap` | Class | Represents an image defined by pixels.
| `Brush` | Class | Abstract class for brushes used to fill graphics shapes.
| `Color` | Class | Defines colors used for drawing.
| `ColorConverter` | Class | Converts colors from one data type to another
| `ColorTranslator` | Class | Translates colors to and from HTML, OLE and Win32 representations.
| `Font` | Class | Defines a format for text, including font family, size, and style.
| `Graphics` | Class | Provides methods for drawing on a drawing surface.
| `Icon` | Class | Represents an icon image.
| `Image` | Class | Represents an image in a specific format.
| `Pen` | Class | Defines an object used to draw lines and curves.
| `Region` | Class | Defines the area of a drawing surface.
| `SolidBrush` | Class | Defines a brush of a single color.
| `StringFormat` | Class | Defines text layout information, display manipulation and font features.
| `Svg` <sup>(1)</sup> | Class | Represents Scalable Vector Graphics.
| `TextureBrush` | Class | Defines a brush that uses an image to fill shapes.
| `Point` | Struct | Defines an x and y coordinate in a 2D plane.
| `PointF` | Struct | Defines a floating-point x and y coordinate in a 2D plane.
| `Rectangle` | Struct | Defines an x, y, width, and height of a rectangle.
| `RectangleF` | Struct | Defines a floating-point x, y, width, and height of a rectangle.
| `Size` | Struct | Defines the width and height of a rectangular area.
| `SizeF` | Struct | Defines the width and height of a rectangular area with floating-point values.
| `CopyPixelOperation` | Enum | Specifies the type of pixel copying operation.
| `FontSlant` | Enum | Specifies the slant of a font.
| `FontStyle` | Enum | Specifies the style of a font.
| `GraphicsUnit` | Enum | Specifies the unit of measure for drawing operations.
| `KnownColor` | Enum | Defines predefined colors.
| `RotateFlipType` | Enum | Specifies how an image is rotated or flipped.
| `StringAlignment` | Enum | Specifies the alignment of text within a string.
| `StringDigitSubstitute` | Enum | Specifies how digits are substituted in a string.
| `StringFormatFlags` | Enum | Specifies formatting options for strings.
| `StringTrimming` | Enum | Specifies how text is trimmed when it does not fit.

<small><sup>(1)</sup> New element (does not belogs to `System.Drawing` library).</small>

### GeneXus.Drawing.Drawing2D
Advanced 2D graphics functionalities based on `System.Drawing.Drawing2D` for complex vector graphics and rendering tasks.

| Name | Type | Description
|-----------------------|----------|--------------
| `Blend` | Class | Defines a blend of colors along a gradient.
| `ColorBlend` | Class | Defines a blend of colors for a gradient.
| `GraphicsPath` | Class | Represents a series of connected lines and curves.
| `HatchBrush` | Class | Defines a brush with a hatching pattern.
| `PathGradientBrush` | Class | Defines a brush that fills an area with a gradient of colors.
| `LinearGradientBrush` | Class | Defines a brush that fills an area with a linear gradient of colors.
| `Matrix` | Struct | Defines a transformation matrix for graphics operations.
| `PathData` | Struct | Contains data associated with a GraphicsPath object.
| `CombineMode` | Enum | Specifies how two graphics objects are combined.
| `CompositingQuality` | Enum | Specifies the quality of compositing operations.
| `CoordinateSpace` | Enum | Specifies the coordinate space for transformations.
| `DashCap` | Enum | Specifies the cap style for dashed lines.
| `FillMode` | Enum | Specifies the fill mode for filling shapes.
| `InterpolationMode` | Enum | Specifies the interpolation mode for scaling and resizing.
| `LineCap` | Enum | Specifies the shape of the end of a line.
| `LineJoin` | Enum | Specifies the shape used to join two connected lines.
| `MatrixOrder` | Enum | Specifies the order of matrix transformations.
| `PenAlignment` | Enum | Specifies the alignment of a pen's stroke.
| `PenType` | Enum | Specifies the type of pen used for drawing.
| `PixelOffsetMode` | Enum | Specifies how to offset pixels when drawing.
| `SmoothingMode` | Enum | Specifies the level of smoothing applied to graphics.
| `WarpMode` | Enum | Specifies how text is warped.
| `WrapMode` | Enum | Specifies how text wraps within its container.

### GeneXus.Drawing.Imaging
Advanced image processing based on `System.Drawing.Imaging` to support sophisticated image manipulation and format handling.

Expand All @@ -114,9 +161,11 @@ Advanced typographic features based on `System.Drawing.Text` for managing and re
| Name | Type | Description
|---------------------------|----------|--------------
| `FontCollection` | Class | Represents a collection of fonts.
| `InstalledFontCollection` | Class | Represents a collection of installed fonts.
| `PrivateFontCollection` | Class | Represents a collection of private fonts.
| `GenericFontFamilies` | Enum | Specifies generic font families.
| `InstalledFontCollection` | Class | Represents a collection of installed fonts.
| `PrivateFontCollection` | Class | Represents a collection of private fonts.
| `GenericFontFamilies` | Enum | Specifies generic font families.
| `HotkeyPrefix` | Enum | Specifies how hotkey prefixes are rendered.
| `TextRenderingHint` | Enum | Specifies the level of text rendering quality.

### GeneXus.Drawing.Interop
Advanced interoperability utilities based on `System.Drawing.Interop` that includes definitions used in font management and graphics rendering.
Expand Down
19 changes: 15 additions & 4 deletions src/Common/Bitmap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,12 @@ public Bitmap(float width, float height)
/// Initializes a new instance of the <see cref='Bitmap'/> class with the specified size
/// and with the resolution of the specified <see cref='Graphics'/> object.
/// </summary>
//public Bitmap(int width, int height, object g) // TODO: Implement Graphics
// : this(width, height) => throw new NotImplementedException();
public Bitmap(int width, int height, Graphics g)
: this(width, height)
{
HorizontalResolution = g.DpiX;
VerticalResolution = g.DpiY;
}

/// <summary>
/// Initializes a new instance of the <see cref='Bitmap'/> class with the specified size and format.
Expand Down Expand Up @@ -119,13 +123,20 @@ public Bitmap(Image original, Size size)
/// Creates a copy of the section of this <see cref='Bitmap'/> defined
/// by <see cref='Rectangle'/> structure and with a specified PixelFormat enumeration.
/// </summary>
public object Clone(Rectangle rect, PixelFormat format)
public object Clone(RectangleF rect, PixelFormat format)
{
var bitmap = new Bitmap(rect.Width, rect.Height);
var portion = SKRectI.Truncate(rect.m_rect);
return m_bitmap.ExtractSubset(bitmap.m_bitmap, portion) ? bitmap : Clone();
}

/// <summary>
/// Creates a copy of the section of this <see cref='Bitmap'/> defined
/// by <see cref='Rectangle'/> structure and with a specified PixelFormat enumeration.
/// </summary>
public object Clone(Rectangle rect, PixelFormat format)
=> Clone(new RectangleF(rect.m_rect), format);

#endregion


Expand Down Expand Up @@ -253,7 +264,7 @@ protected override void RotateFlip(int degrees, float scaleX, float scaleY)
/// </summary>
public void SetPixel(int x, int y, Color color)
{
var c = new SKColor((byte)color.R, (byte)color.G, (byte)color.B, (byte)color.A);
var c = new SKColor(color.R, color.G, color.B, color.A);
m_bitmap.SetPixel(x, y, c);
}

Expand Down
192 changes: 192 additions & 0 deletions src/Common/Brush.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
using System;
using SkiaSharp;

namespace GeneXus.Drawing;

public abstract class Brush : IDisposable, ICloneable
{
internal readonly SKPaint m_paint;

internal Brush(SKPaint paint)
{
m_paint = paint ?? throw new ArgumentNullException(nameof(paint));
m_paint.Style = SKPaintStyle.Fill;
}

/// <summary>
/// Cleans up resources for this <see cref='Brush'/>.
/// </summary>
~Brush() => Dispose(false);


#region IDisposable

/// <summary>
/// Cleans up resources for this <see cref='Brush'/>.
/// </summary>
public void Dispose()
{
GC.SuppressFinalize(this);
Dispose(true);
}

protected virtual void Dispose(bool disposing) => m_paint.Dispose();

#endregion


#region IClonable

/// <summary>
/// Creates an exact copy of this <see cref='Pen'/>.
/// </summary>
public abstract object Clone();

#endregion


#region Operators

/// <summary>
/// Creates a <see cref='SKPaint'/> with the coordinates of the specified <see cref='Brush'/>.
/// </summary>
public static explicit operator SKPaint(Brush brush) => brush.m_paint;

#endregion


#region Utilities

protected static Drawing2D.Blend GetBlendTriangularShape(float focus, float scale)
{
if (focus < 0 || focus > 1)
throw new ArgumentException("Invalid focus value", nameof(focus));
if (scale < 0 || scale > 1)
throw new ArgumentException("Invalid scale value", nameof(scale));

int count = focus == 0 || focus == 1 ? 2 : 3;
Drawing2D.Blend blend = new(count);

if (focus == 0)
{
blend.Positions[0] = 0;
blend.Factors[1] = scale;
blend.Positions[1] = 1;
blend.Factors[1] = 0;
}
else if (focus == 1)
{
blend.Positions[0] = 0;
blend.Factors[1] = 0;
blend.Positions[1] = 1;
blend.Factors[1] = scale;
}
else
{
blend.Positions[0] = 0;
blend.Factors[0] = 0;
blend.Positions[1] = focus;
blend.Factors[1] = scale;
blend.Positions[2] = 1;
blend.Factors[2] = 0;
}
return blend;
}

protected static Drawing2D.Blend GetSigmaBellShape(float focus, float scale = 1.0f)
{
if (focus < 0 || focus > 1)
throw new ArgumentException("Invalid focus value", nameof(focus));
if (scale < 0 || scale > 1)
throw new ArgumentException("Invalid scale value", nameof(scale));

int count = focus == 0 || focus == 1 ? 256 : 511;
Drawing2D.Blend m_blend = new(count);

// TODO: clear preset colors

float fallOffLenght = 2.0f;
if (focus == 0)
{
m_blend.Positions[0] = focus;
m_blend.Factors[0] = scale;

SigmaBellBlend(ref m_blend, focus, scale, 1 / fallOffLenght, 1f / 2, 1f / 255, 1, count - 1, true);

m_blend.Positions[count - 1] = 1f;
m_blend.Factors[count - 1] = 0f;
}
else if (focus == 1)
{
m_blend.Positions[0] = 0f;
m_blend.Factors[0] = 0f;

SigmaBellBlend(ref m_blend, focus, scale, 1 / fallOffLenght, 1f / 2, 1f / 255, 1, count - 1, false);

m_blend.Positions[count - 1] = focus;
m_blend.Factors[count - 1] = scale;
}
else
{
int middle = count / 2;

// left part of the sigma bell
m_blend.Positions[0] = 0f;
m_blend.Factors[0] = 0f;

SigmaBellBlend(ref m_blend, focus, scale, focus / (2 * fallOffLenght), focus / 2, focus / 255, 1, middle, false);

// middle part of the sigma bell
m_blend.Positions[middle] = focus;
m_blend.Factors[middle] = scale;

// right part of the sigma bell
SigmaBellBlend(ref m_blend, focus, scale, (1 - focus) / (2 * fallOffLenght), (1 + focus) / 2, (1 - focus) / 255, middle + 1, count - 1, true);

m_blend.Positions[count - 1] = 1f;
m_blend.Factors[count - 1] = 0f;
}
return m_blend;

static void SigmaBellBlend(ref Drawing2D.Blend blend, float focus, float scale, float sigma, float mean, float delta, int startIndex, int endIndex, bool invert)
{
float sg = invert ? -1 : 1;
float x0 = invert ? 1f : 0f;

float cb = (1 + sg * Erf(x0, sigma, mean)) / 2;
float ct = (1 + sg * Erf(focus, sigma, mean)) / 2;
float ch = ct - cb;

float offset = invert ? focus : 0;
float pos = delta + offset;

for (int index = startIndex; index < endIndex; index++, pos += delta)
{
blend.Positions[index] = pos;
blend.Factors[index] = scale / ch * ((1 + sg * Erf(pos, sigma, mean)) / 2 - cb);
}
}

static float Erf(float x, float sigma, float mean, int terms = 6)
{
/*
* Error function (Erf) for Gaussian distribution by Maclaurin series:
* erf (z) = (2 / sqrt (pi)) * infinite sum of [(pow (-1, n) * pow (z, 2n+1))/(n! * (2n+1))]
*/
float constant = 2 / (float)Math.Sqrt(Math.PI);
float z = (x - mean) / (sigma * (float)Math.Sqrt(2));

float series = z;
for (int n = 1, fact = 1; n < terms; n++, fact *= n)
{
int sign = (int)Math.Pow(-1, n);
int step = 2 * n + 1;
series += sign * (float)Math.Pow(z, step) / (fact * step);
}

return constant * series;
}
}

#endregion
}
Loading

0 comments on commit ddc9411

Please sign in to comment.