| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525 |
- using UnityEngine;
- using UnityEditor;
- using System.IO;
- using System.Collections.Generic;
- #region Image Class
- [System.Serializable]
- public sealed class ImageAtlasBase
- {
- [SerializeField]
- private Texture2D m_image;
- [SerializeField]
- private Texture2D m_rotatedImage;
- public Texture2D image
- {
- get
- {
- return m_attr.isRotated ? m_rotatedImage : m_image;
- }
- }
- [SerializeField]
- private ImageAttributes m_attr;
- public ImageAttributes attr
- {
- get
- {
- return m_attr;
- }
- }
- public ImageAtlasBase(Texture2D image, ImageAttributes attr)
- : this(image, attr, true)
- {
- }
- public void Dispose()
- {
- if (string.IsNullOrEmpty(AssetDatabase.GetAssetPath(m_image)))
- Editor.DestroyImmediate(m_image);
- if (string.IsNullOrEmpty(AssetDatabase.GetAssetPath(m_rotatedImage)))
- Editor.DestroyImmediate(m_rotatedImage);
- }
- public ImageAtlasBase(Texture2D image, ImageAttributes attr, bool startDefault)
- {
- m_attr = attr;
- if (m_attr.isRotated)
- {
- m_rotatedImage = image;
- GenerateDefaultImage();
- m_rotatedImage.name = m_image.name = m_attr.name;
- if (startDefault)
- m_attr.ChangeOrientation();
- }
- else
- {
- m_image = image;
- GenerateRotatedImage();
- m_image.name = m_rotatedImage.name = m_attr.name;
- }
- }
- public void LoadNewImage(Texture2D image)
- {
- if (m_attr.isRotated)
- {
- m_rotatedImage = image;
- GenerateDefaultImage();
- m_rotatedImage.name = m_image.name = m_attr.name;
- m_attr.ChangeOrientation();
- }
- else
- {
- m_image = image;
- GenerateRotatedImage();
- m_image.name = m_rotatedImage.name = m_attr.name;
- }
- }
- public void ChangeRotation()
- {
- m_attr.isRotated = !m_attr.isRotated;
- }
- public void SetDefaultOrientation()
- {
- if (m_attr.isRotated)
- m_attr.ChangeOrientation();
- }
- private void GenerateDefaultImage()
- {
- m_image = new Texture2D(m_rotatedImage.height, m_rotatedImage.width);
- for (int y = 0; y < m_rotatedImage.height; y++)
- for (int x = 0; x < m_rotatedImage.width; x++)
- m_image.SetPixel(y, x, m_rotatedImage.GetPixel(x, m_rotatedImage.height - y));
- m_image.Apply();
- }
- private void GenerateRotatedImage()
- {
- m_rotatedImage = new Texture2D(m_image.height, m_image.width);
- for (int y = 0; y < m_image.height; y++)
- for (int x = 0; x < m_image.width; x++)
- m_rotatedImage.SetPixel(y, x, m_image.GetPixel(m_image.width - x - 1, y));
- m_rotatedImage.Apply();
- }
- }
- #endregion
- #region ImageAttributes Class
- [System.Serializable]
- public sealed class ImageAttributes
- {
- public string name;
- public Rect position;
- public bool isRotated;
- public bool canBeRotated = true;
- private ImageAttributes()
- : this("texture", new Rect(), false)
- {
- }
- public ImageAttributes(string name, Rect position, bool isRotated)
- : this(name, position, isRotated, true)
- {
- }
- public ImageAttributes(string name, Rect position, bool isRotated, bool canBeRotated)
- {
- if (string.IsNullOrEmpty(name))
- this.name = "no_name_image";
- else
- this.name = name;
- this.position = position;
- this.isRotated = isRotated;
- this.canBeRotated = canBeRotated;
- }
- public void ChangeOrientation()
- {
- isRotated = !isRotated;
- position = new Rect(position.x, position.y, position.height, position.width);
- }
- }
- #endregion
- #region ImageAtlas Static Class
- public static class ImageAtlas
- {
- public static ImageAtlasBase[] GetParts(Texture2D atlas, TextAsset codings, TextureImporter importer, bool readFromText)
- {
- ImageAtlasBase[] parts;
- if (readFromText || importer.spritesheet.Length == 0)
- {
- string[] lines = codings.text.Split('\n');
- parts = new ImageAtlasBase[lines.Length];
- for (int i = 0; i < parts.Length; i++)
- {
- ImageAttributes attr = DecodeLine(lines[i]);
- Texture2D image = new Texture2D(
- (int)attr.position.width,
- (int)attr.position.height,
- TextureFormat.RGBA32,
- false
- );
- image.SetPixels(
- atlas.GetPixels(
- (int)attr.position.x,
- (int)atlas.height - (int)attr.position.y - (int)attr.position.height,
- (int)attr.position.width,
- (int)attr.position.height
- ));
- image.Apply();
- parts[i] = new ImageAtlasBase(image, attr);
- }
- }
- else
- {
- SpriteMetaData[] sprites = importer.spritesheet;
- parts = new ImageAtlasBase[sprites.Length];
- for (int i = 0; i < sprites.Length; i++)
- {
- ImageAttributes attr = new ImageAttributes(
- sprites[i].name,
- new Rect(
- sprites[i].rect.x,
- atlas.height - sprites[i].rect.y - sprites[i].rect.height,
- sprites[i].rect.width,
- sprites[i].rect.height),
- false
- );
- Texture2D image = new Texture2D(
- (int)attr.position.width,
- (int)attr.position.height,
- TextureFormat.RGBA32,
- false
- );
- image.SetPixels(
- atlas.GetPixels(
- (int)attr.position.x,
- (int)sprites[i].rect.y,
- (int)attr.position.width,
- (int)attr.position.height
- ));
- image.Apply();
- parts[i] = new ImageAtlasBase(image, attr);
- }
- }
- return parts;
- }
- public static string EncodeLine(ImageAttributes attr)
- {
- string[] ckBegin = new string[]
- {
- " --",
- " x-",
- " y-",
- " w-",
- " h-",
- " r-",
- " xx-",
- " yy-",
- " aa-"
- };
- string[] ckEnd = new string[]
- {
- "-- ",
- "-x ",
- "-y ",
- "-w ",
- "-h ",
- "-r ",
- "-xx ",
- "-yy ",
- "-aa "
- };
- return
- ckBegin[0] + attr.name + ckEnd[0] +
- ckBegin[1] + (int)attr.position.x + ckEnd[1] +
- ckBegin[2] + (int)attr.position.y + ckEnd[2] +
- ckBegin[3] + (int)attr.position.width + ckEnd[3] +
- ckBegin[4] + (int)attr.position.height + ckEnd[4] +
- ckBegin[5] + (attr.isRotated ? 1 : 0).ToString() + ckEnd[5];
- }
- private static ImageAttributes DecodeLine(string codings)
- {
- string[] ckBegin = new string[]
- {
- " --",
- " x-",
- " y-",
- " w-",
- " h-",
- " r-",
- " xx-",
- " yy-",
- " aa-"
- };
- string[] ckEnd = new string[]
- {
- "-- ",
- "-x ",
- "-y ",
- "-w ",
- "-h ",
- "-r ",
- "-xx ",
- "-yy ",
- "-aa "
- };
- string name = GetValue(codings, ckBegin[0], ckEnd[0]);
- Rect position = new Rect(
- float.Parse(GetValue(codings, ckBegin[1], ckEnd[1])),
- float.Parse(GetValue(codings, ckBegin[2], ckEnd[2])),
- float.Parse(GetValue(codings, ckBegin[3], ckEnd[3])),
- float.Parse(GetValue(codings, ckBegin[4], ckEnd[4]))
- );
- bool isRotated = int.Parse(GetValue(codings, ckBegin[5], ckEnd[5])) == 1;
- return new ImageAttributes(name, position, isRotated);
- }
- private static string GetValue(string codings, string begin, string end)
- {
- int startIndex = codings.IndexOf(begin) + begin.Length;
- return codings.Substring(startIndex, (codings.IndexOf(end) - startIndex));
- }
- #region Atlassing Methods
- public static void PackParts(ref List<ImageAtlasBase> parts,
- out int usedMethod, out int usedSize, int spacing, out Vector2 atlasSize)
- {
- atlasSize = Vector2.zero;
- usedMethod = 0;
- usedSize = 32;
- if (parts == null || parts.Count == 0)
- return;
- Rect[] rects;
- int[] methods =
- {
- 0,
- 1,
- 2,
- 3,
- 4,
- 5,
- 6,
- 7
- };
- int[] sizes =
- {
- 32,
- 64,
- 128,
- 256,
- 512,
- 1024,
- 2048,
- 4096
- };
- float bestMag = -1;
- Vector2 currSize;
- for (int method = 1; method < methods.Length; method++)
- {
- for (int size = 0; size < sizes.Length; size++)
- {
- parts.SetDefaultOrientation();
- rects = GetPackRects(ref parts, method, sizes[size], spacing, out currSize);
- if (rects == null)
- continue;
- float currSizeMagnitude = (currSize.x + currSize.y) * 0.5f;
- if (usedMethod == 0)
- {
- usedMethod = method;
- usedSize = size;
- bestMag = currSizeMagnitude;
- }
- else if (currSizeMagnitude < bestMag)
- {
- usedMethod = method;
- usedSize = size;
- bestMag = currSizeMagnitude;
- }
- }
- }
- parts.SetDefaultOrientation();
- usedSize = sizes[usedSize];
- rects = GetPackRects(ref parts, usedMethod, usedSize, spacing, out atlasSize);
- if (rects != null)
- for (int i = 0; i < rects.Length; i++)
- parts[i].attr.position = rects[i];
- else
- Debug.Log("Either something went wrong or textures don\'t fit in the package!");
- }
- public static void PackParts(ref List<ImageAtlasBase> parts, int method, int maxSize, int spacing, out Vector2 atlasSize)
- {
- atlasSize = Vector2.zero;
- if (parts == null || parts.Count == 0)
- return;
- Rect[] rects = null;
- if (method == 0)
- return;
- parts.SetDefaultOrientation();
- rects = GetPackRects(ref parts, method, maxSize, spacing, out atlasSize);
- if (rects != null)
- for (int i = 0; i < rects.Length; i++)
- parts[i].attr.position = rects[i];
- else
- Debug.Log("Either something went wrong or textures don\'t fit in the package!");
- }
- private static Rect[] GetPackRects(ref List<ImageAtlasBase> parts, int method, int size, int spacing, out Vector2 atlasSize)
- {
- switch (method)
- {
- case 1:
- return Pack_MethodA(GetContainedElements(parts), size, spacing, out atlasSize);
- case 2:
- return Pack_MethodB(GetContainedElements(parts), size, spacing, out atlasSize);
- default:
- return Pack_MethodC(GetContainedElements(parts), size, method - 3, spacing, out atlasSize);
- }
- }
- private static ImageAtlasBase[] GetContainedElements(List<ImageAtlasBase> parts)
- {
- List<ImageAtlasBase> containedParts = new List<ImageAtlasBase>();
- for (int i = 0; i < parts.Count; i++)
- if (parts[i].image)
- containedParts.Add(parts[i]);
- return containedParts.ToArray();
- }
- #endregion
- #region Pack Methods
- private static Rect[] Pack_MethodA(ImageAtlasBase[] parts, int size, int spacing, out Vector2 atlasSize)
- {
- int columnPosition = 0;
- int x = 0;
- int y = 0;
- List<Rect> positions = new List<Rect>();
- atlasSize = Vector2.zero;
- for (int i = 0; i < parts.Length; i++)
- {
- int width = parts[i].image.width;
- int height = parts[i].image.height;
- if (y + height + spacing <= size && x + width + spacing <= size)
- {
- positions.Add(new Rect(x, y, width, height));
- y += height + spacing;
- if (columnPosition < x + width + spacing)
- columnPosition = x + width + spacing;
- }
- else if (columnPosition + width <= size)
- {
- x = columnPosition;
- positions.Add(new Rect(x, 0, width, height));
- y = height + spacing;
- columnPosition = x + width + spacing;
- }
- else return null;
- }
- for (int i = 0; i < positions.Count; i++)
- {
- if (positions[i].xMax > atlasSize.x)
- atlasSize.x = (int)positions[i].xMax;
- if (positions[i].yMax > atlasSize.y)
- atlasSize.y = (int)positions[i].yMax;
- }
- return positions.ToArray();
- }
- private static Rect[] Pack_MethodB(ImageAtlasBase[] parts, int size, int spacing, out Vector2 atlasSize)
- {
- CygonRectanglePacker packer = new CygonRectanglePacker(size, size);
- Rect[] positions = new Rect[parts.Length];
- atlasSize = Vector2.zero;
- for (int i = 0; i < parts.Length; i++)
- {
- Vector2 point;
- if (!packer.TryPack(parts[i].image.width + spacing, parts[i].image.height + spacing, out point))
- return null;
- else
- positions[i] = new Rect(point.x, point.y, parts[i].image.width, parts[i].image.height);
- }
- for (int i = 0; i < positions.Length; i++)
- {
- if (positions[i].xMax > atlasSize.x)
- atlasSize.x = (int)positions[i].xMax;
- if (positions[i].yMax > atlasSize.y)
- atlasSize.y = (int)positions[i].yMax;
- }
- return positions;
- }
- private static Rect[] Pack_MethodC(ImageAtlasBase[] parts, int size, int method, int spacing, out Vector2 atlasSize)
- {
- Rect[] positions = new Rect[parts.Length];
- atlasSize = Vector2.zero;
- MaximalRectanglesBinPack bin = new MaximalRectanglesBinPack();
- bin.Init(size, size);
- for (int i = 0; i < parts.Length; i++)
- {
- int texWidth = parts[i].image.width;
- int texHeight = parts[i].image.height;
- MaximalRectanglesBinPack.FreeRectChoiceHeuristic heuristic;
- switch (method)
- {
- case 0:
- heuristic = MaximalRectanglesBinPack.FreeRectChoiceHeuristic.RectBottomLeftRule;
- break;
- case 1:
- heuristic = MaximalRectanglesBinPack.FreeRectChoiceHeuristic.RectBestShortSideFit;
- break;
- case 2:
- heuristic = MaximalRectanglesBinPack.FreeRectChoiceHeuristic.RectBestLongSideFit;
- break;
- case 3:
- heuristic = MaximalRectanglesBinPack.FreeRectChoiceHeuristic.RectBestAreaFit;
- break;
- default:
- heuristic = MaximalRectanglesBinPack.FreeRectChoiceHeuristic.RectContactPointRule;
- break;
- }
- positions[i] = bin.Insert(texWidth + spacing, texHeight + spacing, heuristic, parts[i].attr.canBeRotated);
- positions[i].width -= spacing;
- positions[i].height -= spacing;
- if (positions[i].height <= 0)
- return null;
- if (texWidth != texHeight &&
- positions[i].width == texHeight &&
- positions[i].height == texWidth)
- parts[i].ChangeRotation();
- }
- for (int i = 0; i < positions.Length; i++)
- {
- if (positions[i].xMax > atlasSize.x)
- atlasSize.x = (int)positions[i].xMax;
- if (positions[i].yMax > atlasSize.y)
- atlasSize.y = (int)positions[i].yMax;
- }
- return positions;
- }
- #region Maximal Rectangles Bin Pack
- private class MaximalRectanglesBinPack
- {
- #region Variables
- private int binWidth;
- private int binHeight;
- private List<Rect> usedRectangles = new List<Rect>();
- private List<Rect> freeRectangles = new List<Rect>();
- #endregion
- #region Constructors
- public MaximalRectanglesBinPack() : this(0, 0) { }
- public MaximalRectanglesBinPack(int width, int height)
- {
- Init(width, height);
- }
- #endregion
- public void Init(int width, int height)
- {
- binWidth = width;
- binHeight = height;
- Rect n = new Rect(0, 0, width, height);
- usedRectangles.Clear();
- freeRectangles.Clear();
- freeRectangles.Add(n);
- }
- public enum FreeRectChoiceHeuristic
- {
- RectBestShortSideFit,
- RectBestLongSideFit,
- RectBestAreaFit,
- RectBottomLeftRule,
- RectContactPointRule
- };
- #region Insert
- public void Insert(List<Rect> rects, out List<Rect> dst, FreeRectChoiceHeuristic method, bool canBeRotated)
- {
- dst = new List<Rect>();
- while (rects.Count > 0)
- {
- int bestScore1 = int.MaxValue;
- int bestScore2 = int.MaxValue;
- int bestRectIndex = -1;
- Rect bestNode = new Rect();
- for (int index = 0; index < rects.Count; index++)
- {
- int score1;
- int score2;
- Rect newNode = ScoreRect((int)rects[index].width, (int)rects[index].height, method, out score1, out score2, canBeRotated);
- if (score1 < bestScore1 || (score1 == bestScore1 && score2 < bestScore2))
- {
- bestScore1 = score1;
- bestScore2 = score2;
- bestNode = newNode;
- bestRectIndex = index;
- }
- }
- if (bestRectIndex == -1)
- return;
- PlaceRect(bestNode);
- rects.Remove(rects[bestRectIndex]);
- }
- }
- public Rect Insert(int width, int height, FreeRectChoiceHeuristic method, bool canBeRotated)
- {
- Rect newNode = new Rect();
- int score1;
- int score2;
- switch (method)
- {
- case FreeRectChoiceHeuristic.RectBestShortSideFit:
- newNode = FindPositionForNewNodeBestShortSideFit(width, height, out score1, out score2, canBeRotated);
- break;
- case FreeRectChoiceHeuristic.RectBottomLeftRule:
- newNode = FindPositionForNewNodeBottomLeft(width, height, out score2, out score1, canBeRotated);
- break;
- case FreeRectChoiceHeuristic.RectContactPointRule:
- newNode = FindPositionForNewNodeContactPoint(width, height, out score1, canBeRotated);
- break;
- case FreeRectChoiceHeuristic.RectBestLongSideFit:
- newNode = FindPositionForNewNodeBestLongSideFit(width, height, out score1, out score2, canBeRotated);
- break;
- case FreeRectChoiceHeuristic.RectBestAreaFit:
- newNode = FindPositionForNewNodeBestAreaFit(width, height, out score1, out score2, canBeRotated);
- break;
- }
- if (newNode.height == 0)
- return newNode;
- int numRectanglesToProcess = freeRectangles.Count;
- for (int index = 0; index < numRectanglesToProcess; index++)
- if (SplitFreeNode(freeRectangles[index], newNode))
- {
- freeRectangles.Remove(freeRectangles[index]);
- index--;
- numRectanglesToProcess--;
- }
- PruneFreeList();
- usedRectangles.Add(newNode);
- return newNode;
- }
- #endregion
- public float Occupancy()
- {
- ulong usedSurfaceArea = 0;
- for (int index = 0; index < usedRectangles.Count; index++)
- usedSurfaceArea += (ulong)(usedRectangles[index].width * usedRectangles[index].height);
- return (float)usedSurfaceArea / (binWidth * binHeight);
- }
- private Rect ScoreRect(int width, int height, FreeRectChoiceHeuristic method, out int score1, out int score2, bool canBeRotated)
- {
- Rect newNode = new Rect();
- score1 = int.MaxValue;
- score2 = int.MaxValue;
- switch (method)
- {
- case FreeRectChoiceHeuristic.RectBestShortSideFit:
- newNode = FindPositionForNewNodeBestShortSideFit(width, height, out score1, out score2, canBeRotated);
- break;
- case FreeRectChoiceHeuristic.RectBottomLeftRule:
- newNode = FindPositionForNewNodeBottomLeft(width, height, out score2, out score1, canBeRotated);
- break;
- case FreeRectChoiceHeuristic.RectContactPointRule:
- newNode = FindPositionForNewNodeContactPoint(width, height, out score1, canBeRotated);
- score1 = -score1;
- break;
- case FreeRectChoiceHeuristic.RectBestLongSideFit:
- newNode = FindPositionForNewNodeBestLongSideFit(width, height, out score2, out score1, canBeRotated);
- break;
- case FreeRectChoiceHeuristic.RectBestAreaFit:
- newNode = FindPositionForNewNodeBestAreaFit(width, height, out score1, out score2, canBeRotated);
- break;
- }
- if (newNode.height == 0)
- {
- score1 = int.MaxValue;
- score2 = int.MaxValue;
- }
- return newNode;
- }
- private void PlaceRect(Rect node)
- {
- int numRectanglesToProcess = freeRectangles.Count;
- for (int index = 0; index < numRectanglesToProcess; index++)
- if (SplitFreeNode(freeRectangles[index], node))
- {
- freeRectangles.Remove(freeRectangles[index]);
- index--;
- numRectanglesToProcess--;
- }
- PruneFreeList();
- usedRectangles.Add(node);
- }
- private int CommonIntervalLength(int i1start, int i1end, int i2start, int i2end)
- {
- if (i1end < i2start || i2end < i1start)
- return 0;
- return Mathf.Min(i1end, i2end) - Mathf.Max(i1start, i2start);
- }
- private int ContactPointScoreNode(int x, int y, int width, int height)
- {
- int score = 0;
- if (x == 0 || x + width == binWidth)
- score += height;
- if (y == 0 || y + height == binHeight)
- score += width;
- for (int index = 0; index < usedRectangles.Count; index++)
- {
- if (usedRectangles[index].x == x + width || usedRectangles[index].x + usedRectangles[index].width == x)
- score += CommonIntervalLength((int)usedRectangles[index].y, (int)(usedRectangles[index].y + usedRectangles[index].height), y, y + height);
- if (usedRectangles[index].y == y + height || usedRectangles[index].y + usedRectangles[index].height == y)
- score += CommonIntervalLength((int)usedRectangles[index].x, (int)(usedRectangles[index].x + usedRectangles[index].width), x, x + width);
- }
- return score;
- }
- #region FindPositionForNewNode Methods
- private Rect FindPositionForNewNodeBottomLeft(int width, int height, out int bestX, out int bestY, bool canBeRotated)
- {
- Rect bestNode = new Rect();
- bestY = int.MaxValue;
- bestX = int.MaxValue; // Not sure
- for (int index = 0; index < freeRectangles.Count; index++)
- {
- if (freeRectangles[index].width >= width && freeRectangles[index].height >= height)
- {
- int topSideY = (int)freeRectangles[index].y + height;
- if (topSideY < bestY || (topSideY == bestY && freeRectangles[index].x < bestX))
- {
- bestNode.x = freeRectangles[index].x;
- bestNode.y = freeRectangles[index].y;
- bestNode.width = width;
- bestNode.height = height;
- bestY = topSideY;
- bestX = (int)freeRectangles[index].x;
- }
- }
- if (canBeRotated)
- if (freeRectangles[index].width >= height && freeRectangles[index].height >= width)
- {
- int topSideY = (int)freeRectangles[index].y + width;
- if (topSideY < bestY || (topSideY == bestY && freeRectangles[index].x < bestX))
- {
- bestNode.x = freeRectangles[index].x;
- bestNode.y = freeRectangles[index].y;
- bestNode.width = height;
- bestNode.height = width;
- bestY = topSideY;
- bestX = (int)freeRectangles[index].x;
- }
- }
- }
- return bestNode;
- }
- private Rect FindPositionForNewNodeBestShortSideFit(int width, int height, out int bestShortSideFit, out int bestLongSideFit, bool canBeRotated)
- {
- Rect bestNode = new Rect();
- bestShortSideFit = int.MaxValue;
- bestLongSideFit = int.MaxValue; // Not sure
- for (int index = 0; index < freeRectangles.Count; index++)
- {
- if (freeRectangles[index].width >= width && freeRectangles[index].height >= height)
- {
- int leftoverHoriz = Mathf.Abs((int)freeRectangles[index].width - width);
- int leftoverVert = Mathf.Abs((int)freeRectangles[index].height - height);
- int shortSideFit = Mathf.Min(leftoverHoriz, leftoverVert);
- int longSideFit = Mathf.Max(leftoverHoriz, leftoverVert);
- if (shortSideFit < bestShortSideFit || (shortSideFit == bestShortSideFit && longSideFit < bestLongSideFit))
- {
- bestNode.x = freeRectangles[index].x;
- bestNode.y = freeRectangles[index].y;
- bestNode.width = width;
- bestNode.height = height;
- bestShortSideFit = shortSideFit;
- bestLongSideFit = longSideFit;
- }
- }
- if (canBeRotated)
- if (freeRectangles[index].width >= height && freeRectangles[index].height >= width)
- {
- int flippedLeftoverHoriz = Mathf.Abs((int)freeRectangles[index].width - height);
- int flippedLeftoverVert = Mathf.Abs((int)freeRectangles[index].height - width);
- int flippedShortSideFit = Mathf.Min(flippedLeftoverHoriz, flippedLeftoverVert);
- int flippedLongSideFit = Mathf.Max(flippedLeftoverHoriz, flippedLeftoverVert);
- if (flippedShortSideFit < bestShortSideFit || (flippedShortSideFit == bestShortSideFit && flippedLongSideFit < bestLongSideFit))
- {
- bestNode.x = freeRectangles[index].x;
- bestNode.y = freeRectangles[index].y;
- bestNode.width = height;
- bestNode.height = width;
- bestShortSideFit = flippedShortSideFit;
- bestLongSideFit = flippedLongSideFit;
- }
- }
- }
- return bestNode;
- }
- private Rect FindPositionForNewNodeBestLongSideFit(int width, int height, out int bestShortSideFit, out int bestLongSideFit, bool canBeRotated)
- {
- Rect bestNode = new Rect();
- bestLongSideFit = int.MaxValue;
- bestShortSideFit = int.MaxValue; // Not sure
- for (int index = 0; index < freeRectangles.Count; index++)
- {
- if (freeRectangles[index].width >= width && freeRectangles[index].height >= height)
- {
- int leftoverHoriz = Mathf.Abs((int)freeRectangles[index].width - width);
- int leftoverVert = Mathf.Abs((int)freeRectangles[index].height - height);
- int shortSideFit = Mathf.Min(leftoverHoriz, leftoverVert);
- int longSideFit = Mathf.Max(leftoverHoriz, leftoverVert);
- if (longSideFit < bestLongSideFit || (longSideFit == bestLongSideFit && shortSideFit < bestShortSideFit))
- {
- bestNode.x = freeRectangles[index].x;
- bestNode.y = freeRectangles[index].y;
- bestNode.width = width;
- bestNode.height = height;
- bestShortSideFit = shortSideFit;
- bestLongSideFit = longSideFit;
- }
- }
- if (canBeRotated)
- if (freeRectangles[index].width >= height && freeRectangles[index].height >= width)
- {
- int leftoverHoriz = Mathf.Abs((int)freeRectangles[index].width - height);
- int leftoverVert = Mathf.Abs((int)freeRectangles[index].height - width);
- int shortSideFit = Mathf.Min(leftoverHoriz, leftoverVert);
- int longSideFit = Mathf.Max(leftoverHoriz, leftoverVert);
- if (longSideFit < bestLongSideFit || (longSideFit == bestLongSideFit && shortSideFit < bestShortSideFit))
- {
- bestNode.x = freeRectangles[index].x;
- bestNode.y = freeRectangles[index].y;
- bestNode.width = height;
- bestNode.height = width;
- bestShortSideFit = shortSideFit;
- bestLongSideFit = longSideFit;
- }
- }
- }
- return bestNode;
- }
- private Rect FindPositionForNewNodeBestAreaFit(int width, int height, out int bestAreaFit, out int bestShortSideFit, bool canBeRotated)
- {
- Rect bestNode = new Rect();
- bestAreaFit = int.MaxValue;
- bestShortSideFit = int.MaxValue; // Not sure
- for (int index = 0; index < freeRectangles.Count; index++)
- {
- int areaFit = (int)freeRectangles[index].width * (int)freeRectangles[index].height - width * height;
- if (freeRectangles[index].width >= width && freeRectangles[index].height >= height)
- {
- int leftoverHoriz = Mathf.Abs((int)freeRectangles[index].width - width);
- int leftoverVert = Mathf.Abs((int)freeRectangles[index].height - height);
- int shortSideFit = Mathf.Min(leftoverHoriz, leftoverVert);
- if (areaFit < bestAreaFit || (areaFit == bestAreaFit && shortSideFit < bestShortSideFit))
- {
- bestNode.x = freeRectangles[index].x;
- bestNode.y = freeRectangles[index].y;
- bestNode.width = width;
- bestNode.height = height;
- bestShortSideFit = shortSideFit;
- bestAreaFit = areaFit;
- }
- }
- if (canBeRotated)
- if (freeRectangles[index].width >= height && freeRectangles[index].height >= width)
- {
- int leftoverHoriz = Mathf.Abs((int)freeRectangles[index].width - height);
- int leftoverVert = Mathf.Abs((int)freeRectangles[index].height - width);
- int shortSideFit = Mathf.Min(leftoverHoriz, leftoverVert);
- if (areaFit < bestAreaFit || (areaFit == bestAreaFit && shortSideFit < bestShortSideFit))
- {
- bestNode.x = freeRectangles[index].x;
- bestNode.y = freeRectangles[index].y;
- bestNode.width = height;
- bestNode.height = width;
- bestShortSideFit = shortSideFit;
- bestAreaFit = areaFit;
- }
- }
- }
- return bestNode;
- }
- private Rect FindPositionForNewNodeContactPoint(int width, int height, out int bestContactScore, bool canBeRotated)
- {
- Rect bestNode = new Rect();
- bestContactScore = -1;
- for (int index = 0; index < freeRectangles.Count; index++)
- {
- if (freeRectangles[index].width >= width && freeRectangles[index].height >= height)
- {
- int score = ContactPointScoreNode((int)freeRectangles[index].x, (int)freeRectangles[index].y, width, height);
- if (score > bestContactScore)
- {
- bestNode.x = freeRectangles[index].x;
- bestNode.y = freeRectangles[index].y;
- bestNode.width = width;
- bestNode.height = height;
- bestContactScore = score;
- }
- }
- if (canBeRotated)
- if (freeRectangles[index].width >= height && freeRectangles[index].height >= width)
- {
- int score = ContactPointScoreNode((int)freeRectangles[index].x, (int)freeRectangles[index].y, height, width);
- if (score > bestContactScore)
- {
- bestNode.x = freeRectangles[index].x;
- bestNode.y = freeRectangles[index].y;
- bestNode.width = height;
- bestNode.height = width;
- bestContactScore = score;
- }
- }
- }
- return bestNode;
- }
- #endregion
- private bool SplitFreeNode(Rect freeNode, Rect usedNode)
- {
- if (usedNode.x >= freeNode.x + freeNode.width || usedNode.x + usedNode.width <= freeNode.x ||
- usedNode.y >= freeNode.y + freeNode.height || usedNode.y + usedNode.height <= freeNode.y)
- return false;
- if (usedNode.x < freeNode.x + freeNode.width && usedNode.x + usedNode.width > freeNode.x)
- {
- if (usedNode.y > freeNode.y && usedNode.y < freeNode.y + freeNode.height)
- {
- Rect newNode = freeNode;
- newNode.height = usedNode.y - newNode.y;
- freeRectangles.Add(newNode);
- }
- if (usedNode.y + usedNode.height < freeNode.y + freeNode.height)
- {
- Rect newNode = freeNode;
- newNode.y = usedNode.y + usedNode.height;
- newNode.height = freeNode.y + freeNode.height - (usedNode.y + usedNode.height);
- freeRectangles.Add(newNode);
- }
- }
- if (usedNode.y < freeNode.y + freeNode.height && usedNode.y + usedNode.height > freeNode.y)
- {
- if (usedNode.x > freeNode.x && usedNode.x < freeNode.x + freeNode.width)
- {
- Rect newNode = freeNode;
- newNode.width = usedNode.x - newNode.x;
- freeRectangles.Add(newNode);
- }
- if (usedNode.x + usedNode.width < freeNode.x + freeNode.width)
- {
- Rect newNode = freeNode;
- newNode.x = usedNode.x + usedNode.width;
- newNode.width = freeNode.x + freeNode.width - (usedNode.x + usedNode.width);
- freeRectangles.Add(newNode);
- }
- }
- return true;
- }
- private bool IsContainedIn(Rect a, Rect b)
- {
- return a.x >= b.x && a.y >= b.y &&
- a.x + a.width <= b.x + b.width &&
- a.y + a.height <= b.y + b.height;
- }
- private void PruneFreeList()
- {
- for (int index = 0; index < freeRectangles.Count; index++)
- for (int i = index + 1; i < freeRectangles.Count; i++)
- {
- if (IsContainedIn(freeRectangles[index], freeRectangles[i]))
- {
- freeRectangles.Remove(freeRectangles[index]);
- index--;
- break;
- }
- if (IsContainedIn(freeRectangles[i], freeRectangles[index]))
- {
- freeRectangles.Remove(freeRectangles[i]);
- i--;
- }
- }
- }
- }
- #endregion
- #region OutOfSpaceException
- #if !NO_SERIALIZATION
- [System.Serializable]
- #endif
- public class OutOfSpaceException : System.Exception
- {
- /// <summary>Initializes the exception</summary>
- public OutOfSpaceException() { }
- /// <summary>Initializes the exception with an error message</summary>
- /// <param name="message">Error message describing the cause of the exception</param>
- public OutOfSpaceException(string message) : base(message) { }
- /// <summary>Initializes the exception as a followup exception</summary>
- /// <param name="message">Error message describing the cause of the exception</param>
- /// <param name="inner">Preceding exception that has caused this exception</param>
- public OutOfSpaceException(string message, System.Exception inner) : base(message, inner) { }
- #if !NO_SERIALIZATION
- /// <summary>Initializes the exception from its serialized state</summary>
- /// <param name="info">Contains the serialized fields of the exception</param>
- /// <param name="context">Additional environmental informations</param>
- protected OutOfSpaceException(
- System.Runtime.Serialization.SerializationInfo info,
- System.Runtime.Serialization.StreamingContext context
- ) :
- base(info, context) { }
- #endif
- }
- #endregion
- #region RectanglePacker
- public abstract class RectanglePacker
- {
- /// <summary>Initializes a new rectangle packer</summary>
- /// <param name="packingAreaWidth">Width of the packing area</param>
- /// <param name="packingAreaHeight">Height of the packing area</param>
- protected RectanglePacker(int packingAreaWidth, int packingAreaHeight)
- {
- this.packingAreaWidth = packingAreaWidth;
- this.packingAreaHeight = packingAreaHeight;
- }
- /// <summary>Allocates space for a rectangle in the packing area</summary>
- /// <param name="rectangleWidth">Width of the rectangle to allocate</param>
- /// <param name="rectangleHeight">Height of the rectangle to allocate</param>
- /// <returns>The location at which the rectangle has been placed</returns>
- public virtual Vector2 Pack(int rectangleWidth, int rectangleHeight)
- {
- Vector2 point;
- if (!TryPack(rectangleWidth, rectangleHeight, out point))
- throw new OutOfSpaceException("Rectangle does not fit in packing area");
- return point;
- }
- /// <summary>Tries to allocate space for a rectangle in the packing area</summary>
- /// <param name="rectangleWidth">Width of the rectangle to allocate</param>
- /// <param name="rectangleHeight">Height of the rectangle to allocate</param>
- /// <param name="placement">Output parameter receiving the rectangle's placement</param>
- /// <returns>True if space for the rectangle could be allocated</returns>
- public abstract bool TryPack(
- int rectangleWidth, int rectangleHeight, out Vector2 placement
- );
- /// <summary>Maximum width the packing area is allowed to have</summary>
- protected int PackingAreaWidth
- {
- get { return this.packingAreaWidth; }
- }
- /// <summary>Maximum height the packing area is allowed to have</summary>
- protected int PackingAreaHeight
- {
- get { return this.packingAreaHeight; }
- }
- /// <summary>Maximum allowed width of the packing area</summary>
- private int packingAreaWidth;
- /// <summary>Maximum allowed height of the packing area</summary>
- private int packingAreaHeight;
- }
- #endregion
- #region Cygon Packer
- public class CygonRectanglePacker : RectanglePacker
- {
- #region class SliceStartComparer
- /// <summary>Compares the starting position of height slices</summary>
- private class SliceStartComparer : IComparer<Vector2>
- {
- /// <summary>Provides a default instance for the anchor rank comparer</summary>
- public static SliceStartComparer Default = new SliceStartComparer();
- /// <summary>Compares the starting position of two height slices</summary>
- /// <param name="left">Left slice start that will be compared</param>
- /// <param name="right">Right slice start that will be compared</param>
- /// <returns>The relation of the two slice starts ranks to each other</returns>
- public int Compare(Vector2 left, Vector2 right)
- {
- return (int)left.x - (int)right.x;
- }
- }
- #endregion
- /// <summary>Initializes a new rectangle packer</summary>
- /// <param name="packingAreaWidth">Maximum width of the packing area</param>
- /// <param name="packingAreaHeight">Maximum height of the packing area</param>
- public CygonRectanglePacker(int packingAreaWidth, int packingAreaHeight) :
- base(packingAreaWidth, packingAreaHeight)
- {
- this.heightSlices = new List<Vector2>();
- // At the beginning, the packing area is a single slice of height 0
- this.heightSlices.Add(new Vector2(0, 0));
- }
- /// <summary>Tries to allocate space for a rectangle in the packing area</summary>
- /// <param name="rectangleWidth">Width of the rectangle to allocate</param>
- /// <param name="rectangleHeight">Height of the rectangle to allocate</param>
- /// <param name="placement">Output parameter receiving the rectangle's placement</param>
- /// <returns>True if space for the rectangle could be allocated</returns>
- public override bool TryPack(
- int rectangleWidth, int rectangleHeight, out Vector2 placement
- )
- {
- // If the rectangle is larger than the packing area in any dimension,
- // it will never fit!
- if (
- (rectangleWidth > PackingAreaWidth) || (rectangleHeight > PackingAreaHeight)
- )
- {
- placement = Vector2.zero;
- return false;
- }
- // Determine the placement for the new rectangle
- bool fits = tryFindBestPlacement(rectangleWidth, rectangleHeight, out placement);
- // If a place for the rectangle could be found, update the height slice table to
- // mark the region of the rectangle as being taken.
- if (fits)
- integrateRectangle((int)placement.x, rectangleWidth, (int)placement.y + rectangleHeight);
- return fits;
- }
- /// <summary>Finds the best position for a rectangle of the given dimensions</summary>
- /// <param name="rectangleWidth">Width of the rectangle to find a position for</param>
- /// <param name="rectangleHeight">Height of the rectangle to find a position for</param>
- /// <param name="placement">Receives the best placement found for the rectangle</param>
- /// <returns>True if a valid placement for the rectangle could be found</returns>
- private bool tryFindBestPlacement(
- int rectangleWidth, int rectangleHeight, out Vector2 placement
- )
- {
- int bestSliceIndex = -1; // Slice index where the best placement was found
- int bestSliceY = 0; // Y position of the best placement found
- int bestScore = PackingAreaHeight; // lower == better!
- // This is the counter for the currently checked position. The search works by
- // skipping from slice to slice, determining the suitability of the location for the
- // placement of the rectangle.
- int leftSliceIndex = 0;
- // Determine the slice in which the right end of the rectangle is located when
- // the rectangle is placed at the far left of the packing area.
- int rightSliceIndex = this.heightSlices.BinarySearch(
- new Vector2(rectangleWidth, 0), SliceStartComparer.Default
- );
- if (rightSliceIndex < 0)
- rightSliceIndex = ~rightSliceIndex;
- while (rightSliceIndex <= this.heightSlices.Count)
- {
- // Determine the highest slice within the slices covered by the rectangle at
- // its current placement. We cannot put the rectangle any lower than this without
- // overlapping the other rectangles.
- int highest = (int)this.heightSlices[leftSliceIndex].y;
- for (int index = leftSliceIndex + 1; index < rightSliceIndex; ++index)
- if (this.heightSlices[index].y > highest)
- highest = (int)this.heightSlices[index].y;
- // Only process this position if it doesn't leave the packing area
- if ((highest + rectangleHeight <= PackingAreaHeight))
- {
- int score = highest;
- if (score < bestScore)
- {
- bestSliceIndex = leftSliceIndex;
- bestSliceY = highest;
- bestScore = score;
- }
- }
- // Advance the starting slice to the next slice start
- ++leftSliceIndex;
- if (leftSliceIndex >= this.heightSlices.Count)
- break;
- // Advance the ending slice until we're on the proper slice again, given the new
- // starting position of the rectangle.
- int rightRectangleEnd = (int)this.heightSlices[leftSliceIndex].x + rectangleWidth;
- for (; rightSliceIndex <= this.heightSlices.Count; ++rightSliceIndex)
- {
- int rightSliceStart;
- if (rightSliceIndex == this.heightSlices.Count)
- rightSliceStart = PackingAreaWidth;
- else
- rightSliceStart = (int)this.heightSlices[rightSliceIndex].x;
- // Is this the slice we're looking for?
- if (rightSliceStart > rightRectangleEnd)
- break;
- }
- // If we crossed the end of the slice array, the rectangle's right end has left
- // the packing area, and thus, our search ends.
- if (rightSliceIndex > this.heightSlices.Count)
- break;
- } // while rightSliceIndex <= this.heightSlices.Count
- // Return the best placement we found for this rectangle. If the rectangle
- // didn't fit anywhere, the slice index will still have its initialization value
- // of -1 and we can report that no placement could be found.
- if (bestSliceIndex == -1)
- {
- placement = Vector2.zero;
- return false;
- }
- else
- {
- placement = new Vector2(this.heightSlices[bestSliceIndex].x, bestSliceY);
- return true;
- }
- }
- /// <summary>Integrates a new rectangle into the height slice table</summary>
- /// <param name="left">Position of the rectangle's left side</param>
- /// <param name="width">Width of the rectangle</param>
- /// <param name="bottom">Position of the rectangle's lower side</param>
- private void integrateRectangle(int left, int width, int bottom)
- {
- // Find the first slice that is touched by the rectangle
- int startSlice = this.heightSlices.BinarySearch(
- new Vector2(left, 0), SliceStartComparer.Default
- );
- int firstSliceOriginalHeight;
- // Since the placement algorithm always places rectangles on the slices,
- // the binary search should never some up with a miss!
- //if (startSlice >= 0)
- // Debug.Log("Slice starts within another slice");
- //Debug.Assert(
- // startSlice >= 0, "Slice starts within another slice"
- //);
- // We scored a direct hit, so we can replace the slice we have hit
- firstSliceOriginalHeight = (int)this.heightSlices[startSlice].y;
- this.heightSlices[startSlice] = new Vector2(left, bottom);
- int right = left + width;
- ++startSlice;
- // Special case, the rectangle started on the last slice, so we cannot
- // use the start slice + 1 for the binary search and the possibly already
- // modified start slice height now only remains in our temporary
- // firstSliceOriginalHeight variable
- if (startSlice >= this.heightSlices.Count)
- {
- // If the slice ends within the last slice (usual case, unless it has the
- // exact same width the packing area has), add another slice to return to
- // the original height at the end of the rectangle.
- if (right < PackingAreaWidth)
- this.heightSlices.Add(new Vector2(right, firstSliceOriginalHeight));
- }
- else
- { // The rectangle doesn't start on the last slice
- int endSlice = this.heightSlices.BinarySearch(
- startSlice, this.heightSlices.Count - startSlice,
- new Vector2(right, 0), SliceStartComparer.Default
- );
- // Another direct hit on the final slice's end?
- if (endSlice > 0)
- {
- this.heightSlices.RemoveRange(startSlice, endSlice - startSlice);
- }
- else
- { // No direct hit, rectangle ends inside another slice
- // Make index from negative BinarySearch() result
- endSlice = ~endSlice;
- // Find out to which height we need to return at the right end of
- // the rectangle
- int returnHeight;
- if (endSlice == startSlice)
- returnHeight = firstSliceOriginalHeight;
- else
- returnHeight = (int)this.heightSlices[endSlice - 1].y;
- // Remove all slices covered by the rectangle and begin a new slice at its end
- // to return back to the height of the slice on which the rectangle ends.
- this.heightSlices.RemoveRange(startSlice, endSlice - startSlice);
- if (right < PackingAreaWidth)
- this.heightSlices.Insert(startSlice, new Vector2(right, returnHeight));
- } // if endSlice > 0
- } // if startSlice >= this.heightSlices.Count
- }
- /// <summary>Stores the height silhouette of the rectangles</summary>
- private List<Vector2> heightSlices;
- }
- #endregion
- #endregion
- #region Alphanumeric Comparator Fast
- public class AlphanumComparatorFast : IComparer<FileInfo>
- {
- //public int Compare(object x, object y)
- public int Compare(FileInfo x, FileInfo y)
- {
- //string s1 = x as string;
- string s1 = x.Name;
- if (s1 == null)
- {
- return 0;
- }
- //string s2 = y as string;
- string s2 = y.Name;
- if (s2 == null)
- {
- return 0;
- }
- int len1 = s1.Length;
- int len2 = s2.Length;
- int marker1 = 0;
- int marker2 = 0;
- // Walk through two the strings with two markers.
- while (marker1 < len1 && marker2 < len2)
- {
- char ch1 = s1[marker1];
- char ch2 = s2[marker2];
- // Some buffers we can build up characters in for each chunk.
- char[] space1 = new char[len1];
- int loc1 = 0;
- char[] space2 = new char[len2];
- int loc2 = 0;
- // Walk through all following characters that are digits or
- // characters in BOTH strings starting at the appropriate marker.
- // Collect char arrays.
- do
- {
- space1[loc1++] = ch1;
- marker1++;
- if (marker1 < len1)
- {
- ch1 = s1[marker1];
- }
- else
- {
- break;
- }
- } while (char.IsDigit(ch1) == char.IsDigit(space1[0]));
- do
- {
- space2[loc2++] = ch2;
- marker2++;
- if (marker2 < len2)
- {
- ch2 = s2[marker2];
- }
- else
- {
- break;
- }
- } while (char.IsDigit(ch2) == char.IsDigit(space2[0]));
- // If we have collected numbers, compare them numerically.
- // Otherwise, if we have strings, compare them alphabetically.
- string str1 = new string(space1);
- string str2 = new string(space2);
- int result;
- if (char.IsDigit(space1[0]) && char.IsDigit(space2[0]))
- {
- int thisNumericChunk = int.Parse(str1);
- int thatNumericChunk = int.Parse(str2);
- result = thisNumericChunk.CompareTo(thatNumericChunk);
- }
- else
- {
- result = str1.CompareTo(str2);
- }
- if (result != 0)
- {
- return result;
- }
- }
- return len1 - len2;
- }
- }
- #endregion
- }
- #endregion
- public static class ImageAtlasBaseExtensions
- {
- public static void Dispose(this List<ImageAtlasBase> images)
- {
- for (int i = 0; i < images.Count; i++)
- images[i].Dispose();
- images.Clear();
- }
- public static void SetDefaultOrientation(this List<ImageAtlasBase> images)
- {
- for (int i = 0; i < images.Count; i++)
- images[i].SetDefaultOrientation();
- }
- }
|