Calendar
Mo | Tu | We | Th | Fr | Sa | Su |
---|
28 | 29 | 30 | 31 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
Archive
- 2002
- 2003
- 2004
- 2005
- 2006
- 2007
- 2008
- 2009
- 2010
- 2011
- 2012
- 2013
- 2014
- 2015
- 2016
- 2019
- 2020
|
Website may be up and down over next few months. I'm currently doing a complete overhaul of everything.
Going back to simple individual .htm pages, new overall site theme, sanitizing and cleaning up html of all
pages and blog posts, attempting to implement a new tooling and publishing system etc etc.
This code uses a Point type that contains X/Y as integers similar to System.Drawing.Point. This class is used to calculate vertical scan lines for a polygon. It has been tested with 3 points but beyond that I am unsure if it will work. using System;
/// <summary>
/// Helper class used to calculate scan lines of a triangle
/// </summary>
public class TriangleScanLineCalculator
{
/// <summary>
/// Provides a high low type for storing min & max values for scan lines.
/// </summary>
public struct HiLoTYPE
{
public int High;
public int Low;
}
/// <summary>
/// Holds scan line information.
/// </summary>
protected internal HiLoTYPE[] scanLines;
/// <summary>
/// Holds the calculated scan line count.
/// </summary>
protected internal int scanLineCount;
/// <summary>
/// Gets the right most side of the triangle.
/// </summary>
public int MaximumX { get; private set; }
/// <summary>
/// Gets the left most side of the triangle.
/// </summary>
public int MinimumX { get; private set; }
/// <summary>
/// Gets the number of scan lines.
/// </summary>
public int Count
{
get { return scanLineCount; }
}
/// <summary>
/// Calculates the min & max y values for each scan line.
/// </summary>
/// <param name="points">The points that make up the triangle</param>
public void Calculate(Point[] points)
{
var xMax = 0;
var xMin = 0;
float XDelta = 0;
float YDelta = 0;
// X/Y distance between 2 vertexes
float YPos = 0;
float YSlope = 0;
var VertIndex1 = 0;
var VertIndex2 = 0;
var tempIndex = 0;
// Step 1: Find the min and max 'X' dimensions of the polygon
xMax = int.MinValue;
xMin = int.MaxValue;
for (var i = 0; i <= points.Length - 1; i++)
{
if (xMax < points[i].X)
{
xMax = points[i].X;
}
if (xMin > points[i].X)
{
xMin = points[i].X;
}
}
this.MinimumX = xMin;
this.MaximumX = xMax;
this.scanLineCount = xMax - xMin;
// Step 2: Resize scan line array to hold all the high and low x values
if (this.scanLines == null || this.scanLines.Length < xMax - xMin)
{
// allocate
Array.Resize(ref this.scanLines, (xMax - xMin) + 100);
}
// Step3: Set the height value of all scan lines to there min or max value(s)
for (var i = 0; i <= this.scanLines.Length - 1; i++)
{
this.scanLines[i].High = int.MinValue;
this.scanLines[i].Low = int.MaxValue;
}
// Step 4: Set up the Y highs and lows for each X scan line between the min X and Max X points
for (var i = 0; i < points.Length; i++)
{
// Step4a: Determine witch sides of the polygon we will be setting up
VertIndex1 = i;
VertIndex2 = i + 1;
if (VertIndex2 == points.Length) VertIndex2 = 0;
// Step4b: check if the first vertex if farther right then the second vertex
// and if so swap vertex indexes
if (points[VertIndex1].X > points[VertIndex2].X)
{
tempIndex = VertIndex1;
VertIndex1 = VertIndex2;
VertIndex2 = tempIndex;
}
// Step4c: Find the X/Y dist between vert1 and vert2
XDelta = points[VertIndex2].X - points[VertIndex1].X;
YDelta = points[VertIndex2].Y - points[VertIndex1].Y;
// Step4d: Determine the Y slope to use.
// YSlope determines how much to move down for every move we make to the right
if (XDelta != 0)
{
YSlope = YDelta / XDelta;
}
else
{
YSlope = 0;
}
// Save the starting y position in YPos
YPos = points[VertIndex1].Y;
// Step4e: Process all of scan lines between vert1 and vert2
for (var idy = points[VertIndex1].X; idy < points[VertIndex2].X; idy++)
{
// If the scan lines higher value has already been set then set the lower value
// we use the formula 'idy - XMin' to determine what index into the scan line
// array to use. (ScanLineIndex = AnyPositionBetweenVert1AndVert2 - LeftMostPartOfPoly)
// Store the scan line index in the TmpIndex variable so we don't
// have the overhead of doing 5 subtractions
tempIndex = idy - xMin;
var item = this.scanLines[tempIndex];
// Check if Scan(TmpIndex).High has been set already
if (item.High == int.MinValue)
{
// High has not been set yet
item.High = (int)YPos;
}
else
{
// High has been set yet so we set the low point
item.Low = (int)YPos;
// Ensure that the High is actually a higher value then low
if (item.High < item.Low)
{
var tempValue = item.High;
item.High = item.Low;
item.Low = tempValue;
}
}
this.scanLines[tempIndex] = item;
// update the Y position
YPos += YSlope;
}
}
}
/// <summary>
/// Retrieves a scan line.
/// </summary>
/// <param name="index">The index of the scan line.</param>
/// <returns>Returns information about the scan line.</returns>
public HiLoTYPE ScanLine(int index)
{
return this.scanLines[index];
}
/// <summary>
/// Gets all the scan lines.
/// </summary>
/// <returns>Returns all the scan line information.</returns>
public HiLoTYPE[] GetScanLines()
{
// if there are no scan lines return null.
if (this.scanLineCount == 0)
{
return null;
}
// resize the array
Array.Resize(ref this.scanLines, this.scanLineCount);
return this.scanLines;
}
/// <summary>
/// Calculates the scan lines for a triangle.
/// </summary>
/// <param name="points">The triangle points.</param>
/// <param name="minXValue">Will return the minimum x value that the triangle starts at.</param>
/// <returns>Returns the min max y values of the scanline.</returns>
public static HiLoTYPE[] Calculate(Point[] points, out int minXValue)
{
// create scan line calculator and get values from it
var scanner = new TriangleScanLineCalculator();
scanner.Calculate(points);
var items = scanner.GetScanLines();
minXValue = scanner.MinimumX;
return items;
}
}
e850ed73-bcdb-4eff-88fc-5d7f2450dc0e|0|.0
Source - http://stackoverflow.com/questions/11518935/mvc-redirect-to-default-route/11520787#11520787 Redirect route handler public class RedirectRouteHandler : IRouteHandler
{
private string _redirectUrl;
public RedirectRouteHandler(string redirectUrl)
{
_redirectUrl = redirectUrl;
}
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
if (_redirectUrl.StartsWith("~/"))
{
string virtualPath = _redirectUrl.Substring(2);
Route route = new Route(virtualPath, null);
var vpd = route.GetVirtualPath(requestContext,
requestContext.RouteData.Values);
if (vpd != null)
{
_redirectUrl = "~/" + vpd.VirtualPath;
}
}
return new RedirectHandler(_redirectUrl, false);
}
}
Redirect http handler
public class RedirectHandler : IHttpHandler
{
private readonly string _redirectUrl;
public RedirectHandler(string redirectUrl, bool isReusable)
{
_redirectUrl = redirectUrl;
IsReusable = isReusable;
}
public bool IsReusable { get; private set; }
public void ProcessRequest(HttpContext context)
{
context.Response.Status = "301 Moved Permanently";
context.Response.StatusCode = 301;
context.Response.AddHeader("Location", _redirectUrl);
}
}
Extension methods
public static class RouteExtensions
{
public static void Redirect(this RouteCollection routes, string url, string redirectUrl)
{
routes.Add(new Route(url, new RedirectRouteHandler(redirectUrl)));
}
}
b1e3898b-54a1-4d4a-9d4f-5920a7330fed|0|.0
The code below allows you to copy a directory structure with or without sub folders including files. Also includes a callback that can be used to filter out files or folders and reports the copy progress. /// <summary>
/// Copies a directory structure to the destination.
/// </summary>
/// <param name="source">The directory structure to be copied.</param>
/// <param name="destination">The destination where the directory structure will be copied to.</param>
/// <param name="copySubDirectories">true to copy all subdirectories.</param>
/// <param name="overwriteFiles">true if the destination files can be overwritten; otherwise, false.</param>
/// <param name="callback">Provides a callback function for reporting progress. </param>
/// <remarks><p>The callback invoked just before a file copy occurs providing a way of being notified.</p>
/// <p>The callback parameter order is source file, destination file, progress.</p>
/// <p>If the callback is specified it should return true to allow the file copy to occur.</p>
/// <p>The progress parameter reports progress from 0 to 100. Values to the left of the decimal represent folder copy progress and values to the
/// right of the decimal from 0.000 to 0.99 represent the current file copy progress for the folder that is being copied.</p>
/// <p>To get the current file copy progress as a value from 0 to 100 use the formula fileProgress = progress - 100 * 100.</p></remarks>
public static void CopyDirectories(string source, string destination, bool copySubDirectories, bool overwriteFiles, Func<string, string, float, bool> callback)
{
// ensure source folder exists
if (!Directory.Exists(source))
{
throw new DirectoryNotFoundException("The path specified in source is invalid (for example, it is on an unmapped drive).");
}
// create destination folder
Directory.CreateDirectory(destination);
// get all files in source and copy them to destination folder
var files = Directory.GetFiles(source);
var progress = 0f; // used to report the progress from 0 to 100
// set up action to copy files
var fileProcessor = new Action<float, string[], string>((folderProgress, filesToCopy, folder) =>
{
// copy files
for (var i = 0; i < filesToCopy.Length; i++)
{
// get file
var file = filesToCopy[i];
// set default result
var result = true;
// build destination filename
var fileName = Path.GetFileName(file);
if (fileName == null) // should never happen
{
return;
}
fileName = Path.Combine(folder, fileName);
// check if callback specified
if (callback != null)
{
// store result from callback
result = callback(file, fileName, progress);
}
// if result is true we are allowed to copy the file
if (result)
{
File.Copy(file, fileName, overwriteFiles);
}
// (folder progress * 100) + file progress
progress = folderProgress + ((float)i / filesToCopy.Length);
}
});
// copy initial files
fileProcessor(0, files, destination);
// check to copy sub directories
if (!copySubDirectories)
{
return;
}
// get the folder tree for the source folder
var folders = Directory.GetDirectories(source, "*.*", SearchOption.AllDirectories);
// process each sub folder
for (var index = 0; index < folders.Length; index++)
{
// get folder and increment index
var folder = folders[index];
// get files
files = Directory.GetFiles(folder);
// crop source root from destination and build destination folder path
folder = folder.Remove(0, source.Length);
folder = Path.Combine(destination, folder);
// create destination folder
Directory.CreateDirectory(folder);
// process file copying
fileProcessor((index / folders.Length) * 100, files, folder);
}
}
4f1e1d71-ba07-4a45-b0e8-c3fff3afe535|0|.0
Some .net/mono frameworks do not support the IsNullOrWhiteSpace method. The code below provides a simple replacement. /// <summary>
/// Indicates whether a specified string is null, empty, or consists only of white-space characters.
/// </summary>
/// <param name="value">value: The string to test.</param>
/// <returns>true if the value parameter is null or System.String.Empty, or if value consists exclusively of white-space characters.</returns>
public static bool IsNullOrWhiteSpace(this string value)
{
if (value == null)
{
return true;
}
var index = 0;
while (index < value.Length)
{
if (char.IsWhiteSpace(value[index]))
{
index++;
}
else
{
return false;
}
}
return true;
}
232f867b-1708-435c-b8c6-e46cae4b37e3|1|5.0
Some .net/mono frameworks do not support the 3 argument GetDirectories method. The code below provides a simple replacement. /// <summary>
/// Builds an array of folders & sub folders.
/// </summary>
/// <param name="path">The path to search.</param>
/// <param name="pattern">The search string to match against the names of files in path. The parameter cannot end in two periods
/// ("..") or contain two periods ("..") followed by System.IO.Path.DirectorySeparatorChar or System.IO.Path.AltDirectorySeparatorChar,
/// nor can it contain any of the characters in System.IO.Path.InvalidPathChars.
///</param>
/// <param name="searchOptions">One of the System.IO.SearchOption values that specifies whether the search operation should include
/// all subdirectories or only the current directory.
///</param>
/// <returns>A String array of directories that match the search pattern.</returns>
public static string[] GetDirectories(string path, string pattern, SearchOption searchOptions)
{
// check if searching for all directories
if (searchOptions == SearchOption.AllDirectories)
{
// add start paths to list
var list = Directory.GetDirectories(path, pattern);
var index = 0;
var count = list.Length;
// process list and add folders to end of list
while (index < count)
{
var directories = Directory.GetDirectories(list[index++], pattern);
if (directories.Length > 0)
{
// check if we need more space to store the directories
if (count + directories.Length > list.Length - 1)
{
Array.Resize(ref list, list.Length + directories.Length + 1000);
}
// add directories to end of the list
foreach (var directory in directories)
{
list[count++] = directory;
}
}
// trim unused index from end of the array
if (list.Length > count)
{
Array.Resize(ref list, count);
}
}
return list;
}
// just return initial list of folder with no sub folders
return Directory.GetDirectories(path, pattern);
}
8c908bd4-0488-4e96-bd3d-1f3d057e612b|0|.0
/// <summary>
/// Provides a game object that automatically self terminates.
/// </summary>
[ExecuteInEditMode]
public class SelfTerminatingObject : MonoBehaviour
{
/// <summary>
/// Holds a reference to a callback that will be called just before termination.
/// </summary>
public Action Callback;
/// <summary>
/// Holds the time delay in seconds before object self terminates.
/// </summary>
public float Delay;
/// <summary>
/// Holds a time value used to determine whether it's time to self terminate.
/// </summary>
private DateTime lastTime;
/// <summary>
/// Called by Unity to update the object.
/// </summary>
public void Update()
{
this.PerformCheck();
}
/// <summary>
/// Called by Unity to draw the object's GUI.
/// </summary>
public void OnGui()
{
this.PerformCheck();
}
/// <summary>
/// Determines whether it's time to terminate.
/// </summary>
private void PerformCheck()
{
// check if specified time span has elapsed
if (DateTime.Now > this.lastTime + TimeSpan.FromSeconds(this.Delay))
{
// run callback is specified
if (this.Callback != null)
{
this.Callback();
}
// destroy object
#if UNITY_EDITOR
DestroyImmediate(this.gameObject, true);
#else
Destroy(this.gameObject);
#endif
}
}
/// <summary>
/// Creates a self terminating game object.
/// </summary>
/// <param name="callback">The method to be called before the object terminates.</param>
/// <returns>Returns a reference to the game object that will self terminate.</returns>
public static GameObject CreateUpdateCallback(Action callback)
{
return CreateUpdateCallback(callback, 0);
}
/// <summary>
/// Creates a self terminating game object.
/// </summary>
/// <param name="callback">The method to be called before the object terminates.</param>
/// <param name="delay">Specifies a delay value in seconds before the object will self terminate.</param>
/// <returns>Returns a reference to the game object that will self terminate.</returns>
public static GameObject CreateUpdateCallback(Action callback, float delay)
{
var obj = new GameObject();
var com = obj.AddComponent<SelfTerminatingObject>();
com.lastTime = DateTime.Now;
com.Delay = delay;
com.Callback = callback;
return obj;
}
}
fac90666-3035-4d9e-8e38-b3533a7b83bb|0|.0
This code is designed to hook into unity’s EditorApplication.update delegate. IRun.cs namespace CBX.CoreProjectCode.Interfaces
{
using CBX.CoreProjectCode.Models;
/// <summary>
/// Provides a interface for running a <see cref="CallbackModel{T}"/> type.
/// </summary>
public interface IRun
{
/// <summary>
/// Runs the <see cref="CallbackModel{T}"/> type.
/// </summary>
void Run();
}
}
CallbackModel.cs
namespace CBX.CoreProjectCode.Models
{
using System;
using CBX.CoreProjectCode.Interfaces;
/// <summary>
/// Provides a modal for callbacks.
/// </summary>
/// <typeparam name="T">The generic type used to represent the data type.</typeparam>
public class CallbackModel<T> : IRun
{
/// <summary>
/// A reference to a callback method.
/// </summary>
public Action<T> Callback;
/// <summary>
/// A reference to some data that will be passed to the callback method.
/// </summary>
public T Data;
/// <summary>
/// Implements <see cref="IRun.Run"/> to run the callback.
/// </summary>
public void Run()
{
this.Callback(this.Data);
}
}
}
EditorCallbackService.cs
namespace CBX.CoreProjectCode.Services
{
using System;
using System.Collections.Generic;
using CBX.CoreProjectCode.Interfaces;
using CBX.CoreProjectCode.Models;
/// <summary>
/// The editor callback service.
/// </summary>
public class EditorCallbackService
{
/// <summary>
/// Holds a singleton instance of the <see cref="EditorCallbackService"/> type.
/// </summary>
private static EditorCallbackService service;
/// <summary>
/// Holds a list of <see cref="CallbackModel{T}"/> types that implement <see cref="IRun"/>.
/// </summary>
private readonly Stack<IRun> callbacks;
/// <summary>
/// Initializes a new instance of the <see cref="EditorCallbackService"/> class.
/// </summary>
public EditorCallbackService()
{
this.callbacks = new Stack<IRun>();
}
/// <summary>
/// Returns a singleton instance of the <see cref="EditorCallbackService"/> type.
/// </summary>
public static EditorCallbackService Instance
{
get
{
// if no service yet exists create one
return service ?? (service = new EditorCallbackService());
}
}
/// <summary>
/// Runs any callbacks that have been registered.
/// </summary>
public void Run()
{
while (this.callbacks.Count > 0)
{
var cb = this.callbacks.Pop();
cb.Run();
}
}
/// <summary>
/// Registers a <see cref="Action{T}"/> callback.
/// </summary>
/// <typeparam name="T">The type of data that the <see cref="callback"/> takes as a parameter.</typeparam>
/// <param name="callback">A reference to a callback.</param>
public void Register<T>(Action<T> callback)
{
this.Register(callback, default(T));
}
/// <summary>
/// Registers a <see cref="Action{T}"/> callback.
/// </summary>
/// <typeparam name="T">
/// The type of data that the <see cref="callback"/> takes as a parameter.
/// </typeparam>
/// <param name="callback">
/// A reference to a callback.
/// </param>
/// <param name="data">
/// The data that will be passed as a parameter when the <see cref="callback"/> is invoked.
/// </param>
public void Register<T>(Action<T> callback, T data)
{
if (callback == null)
{
throw new ArgumentNullException("callback");
}
var modal = new CallbackModel<T> { Callback = callback, Data = data };
this.callbacks.Push(modal);
}
/// <summary>
/// Registers a <see cref="Action"/> callback.
/// </summary>
/// <param name="callback">A reference to a callback.</param>
public void Register(Action callback)
{
this.Register<object>(x => callback(), null);
}
}
}
Usage scenario …
[InitializeOnLoad]
public class EditorInitialization
{
/// <summary>
/// Holds a value indicating whether the RunCallbacks method has been called at least once before.
/// </summary>
private static bool ranOnce;
/// <summary>
/// Initializes static members of the <see cref="EditorInitialization"/> class.
/// </summary>
static EditorInitialization()
{
EditorApplication.update += RunCallbacks;
}
private static void RunCallbacks()
{
if (!ranOnce)
{
// setup the settings system
SetupSettings();
// load localization strings
LoadLocalizationData();
ranOnce = true;
return;
}
// invoke callbacks from editor callback service
EditorCallbackService.Instance.Run();
}
}
c10ab460-a05d-4911-8056-432495226416|0|.0
Source –> https://gist.github.com/chkn/4748252
using System;
using System.Linq;
public static class JSON
{
public static string Stringify (object obj)
{
string str;
if (obj == null) return "null";
if (obj is ValueType) return obj.ToString ().ToLowerInvariant ();
if ((str = obj as string) != null) return System.Text.RegularExpressions.Regex.Escape (str);
// assume it's a POCO
return "{" + string.Join (",",
from p in obj.GetType ().GetProperties ()
let json = (JSONAttribute) p.GetCustomAttributes (typeof (JSONAttribute), true).FirstOrDefault ()
where json != null
select "\"" + (json.Key ?? p.Name) + "\":" + Stringify (p.GetValue (obj, null))
) + "}";
}
}
public class JSONAttribute : Attribute
{
public string Key { get; set; }
public JSONAttribute () {}
public JSONAttribute (string key) { Key = key; }
}
481a00a4-49ee-4b07-a9ed-bc17792e0620|0|.0
/// <summary>
/// Determines if this rectangle intersects with rect.
/// </summary>
/// <param name="rect">
/// The rectangle to test.
/// </param>
/// <returns>
/// This method returns true if there is any intersection, otherwise false.
/// </returns>
public bool Intersects(RectangleF rect)
{
return !((this.X > rect.Right) || (this.Right < rect.Left) || (this.Y > rect.Bottom) || (this.Bottom < rect.Top));
}
/// <summary>
/// Replaces this RectangleF with the intersection of itself and the specified RectangleF.
/// </summary>
/// <param name="rect">
/// The RectangleF with which to intersect.
/// </param>
public void Intersect(RectangleF rect)
{
this.X = Math.Max(this.Left, rect.Left);
this.Y = Math.Max(this.Top, rect.Top);
this.Width = Math.Min(this.Right, rect.Right) - this.X;
this.Height = Math.Min(this.Bottom, rect.Bottom) - this.Y;
}
/// <summary>
/// Returns a third RectangleF structure that represents the intersection of two other RectangleF structures.
/// If there is no intersection, an empty RectangleF is returned.
/// </summary>
/// <param name="a">
/// A rectangle to intersect.
/// </param>
/// <param name="b">
/// B rectangle to intersect.
/// </param>
/// <returns>
/// A RectangleF that represents the intersection of a and b.
/// </returns>
public static RectangleF Intersect(RectangleF a, RectangleF b)
{
float x = Math.Max((sbyte)a.X, (sbyte)b.X);
float num2 = Math.Min(a.X + a.Width, b.X + b.Width);
float y = Math.Max((sbyte)a.Y, (sbyte)b.Y);
float num4 = Math.Min(a.Y + a.Height, b.Y + b.Height);
if ((num2 >= x) && (num4 >= y))
{
return new RectangleF(x, y, num2 - x, num4 - y);
}
return Empty;
}
05946fd4-7017-4962-94da-f20f0e53ca87|0|.0
/// <summary>
/// Blends two colors together.
/// </summary>
/// <param name="color">
/// The source color.
/// </param>
/// <param name="src">
/// The blend color.
/// </param>
/// <returns>
/// Returns the result as a <see cref="Color"/> type.
/// </returns>
/// <remarks>
/// From Wikipedia https://en.wikipedia.org/wiki/Alpha_compositing -> "Alpha blending"
/// </remarks>
public static Color Blend(this Color color, Color src)
{
float sr = src.R / 255f;
float sg = src.G / 255f;
float sb = src.B / 255f;
float sa = src.A / 255f;
float dr = color.R / 255f;
float dg = color.G / 255f;
float db = color.B / 255f;
float da = color.A / 255f;
float oa = sa + (da * (1 - sa));
float r = ((sr * sa) + ((dr * da) * (1 - sa))) / oa;
float g = ((sg * sa) + ((dg * da) * (1 - sa))) / oa;
float b = ((sb * sa) + ((db * da) * (1 - sa))) / oa;
float a = oa;
return new Color((byte)(r * 255), (byte)(g * 255), (byte)(b * 255), (byte)(a * 255));
}
9bbf3709-4044-433c-a98f-3f1cf8767be4|0|.0
|
|