From 5bb47245e8e42362c0c94062bcaa7a3d6c26d3f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Gur=C3=ADn?= Date: Thu, 11 Jul 2019 15:47:31 -0300 Subject: [PATCH 1/8] bitmap --- geometrize/Util.hx | 47 +++++++---- geometrize/bitmap/Bitmap.hx | 106 ++++++++++++++++-------- geometrize/runner/ImageRunnerOptions.hx | 6 ++ 3 files changed, 105 insertions(+), 54 deletions(-) diff --git a/geometrize/Util.hx b/geometrize/Util.hx index c3398eb..46414b9 100644 --- a/geometrize/Util.hx +++ b/geometrize/Util.hx @@ -12,6 +12,17 @@ typedef Point = { var y:Int; } +/** + * Represents a rectangle in 2D space. + * @author Sam Twidale (http://samcodes.co.uk/) + */ +typedef Rect = { + > Point, + ; + w:Int; + h:Int; +} + /** * Utility functions. * @author Sam Twidale (http://samcodes.co.uk/) @@ -25,11 +36,11 @@ class Util { */ public static function getAverageImageColor(image:Bitmap, alpha:Int = 255):Rgba { Sure.sure(image != null); - + var totalRed:Int = 0; var totalGreen:Int = 0; var totalBlue:Int = 0; - + for (x in 0...image.width) { for (y in 0...image.height) { var pixel = image.getPixel(x, y); @@ -38,11 +49,11 @@ class Util { totalBlue += pixel.b; } } - + var size:Int = image.width * image.height; return Rgba.create(Std.int(totalRed / size), Std.int(totalGreen / size), Std.int(totalBlue / size), alpha); } - + /** * Clamps a value within a range. * @param value The value to clamp. @@ -54,7 +65,7 @@ class Util { Sure.sure(min <= max); return value < min ? min : value > max ? max : value; } - + /** * Compares two values and returns the smaller one. * @param first The first value. @@ -64,7 +75,7 @@ class Util { public static inline function min(first:Int, second:Int):Int { return first < second ? first : second; } - + /** * Compare two values and returns the larger one. * @param first The first value. @@ -74,7 +85,7 @@ class Util { public static inline function max(first:Int, second:Int):Int { return first > second ? first : second; } - + /** * Converts a value measured in degrees to radians. * @param degrees Degrees value to convert to radians. @@ -83,7 +94,7 @@ class Util { public static inline function toRadians(degrees:Float):Float { return degrees * Math.PI / 180; } - + /** * Converts a value measured in radians to degrees. * @param radians Radians value to convert to degrees. @@ -92,7 +103,7 @@ class Util { public static inline function toDegrees(radians:Float):Float { return radians * 180 / Math.PI; } - + /** * Returns a random integer in the range (inclusive). * @param lower The lower bound. @@ -103,7 +114,7 @@ class Util { Sure.sure(lower <= upper); return lower + Math.floor((upper - lower + 1) * Math.random()); } - + /** * Returns a random item from an array. * @param a The array to pick a random item from. @@ -113,7 +124,7 @@ class Util { Sure.sure(a != null && a.length > 0); return a[random(0, a.length - 1)]; } - + /** * Returns the smallest and largest items from an array of ints. * @param a The array of ints. @@ -121,12 +132,12 @@ class Util { */ public static inline function minMaxElements(a:Array):Point { if (a == null || a.length == 0) { - return { x : 0, y : 0 }; + return {x: 0, y: 0}; } - + var min:Int = a[0]; var max:Int = a[0]; - + for (value in a) { if (min > value) { min = value; @@ -135,10 +146,10 @@ class Util { max = value; } } - - return { x: min, y: max }; + + return {x: min, y: max}; } - + /** * Returns the absolute value of the given value. * @param value The value to abs. @@ -150,4 +161,4 @@ class Util { } return value; } -} \ No newline at end of file +} diff --git a/geometrize/bitmap/Bitmap.hx b/geometrize/bitmap/Bitmap.hx index dfcf9cd..50a9a0e 100644 --- a/geometrize/bitmap/Bitmap.hx +++ b/geometrize/bitmap/Bitmap.hx @@ -10,18 +10,58 @@ import haxe.io.Bytes; @:expose class Bitmap { /** - * The width of the bitmap. + * The width of the bitmap considering its offset, if any. */ public var width:Int; + /** - * The height of the bitmap. + * The height of the bitmap considering its offset, if any. */ public var height:Int; + + private var originalWidth:Int; + private var originalHeight:Int; + private var offsetX:Int; + private var offsetY:Int; + // private offset:Rect | null + /** + * Sets the bitmap offset, this is, a region inside relative to which pixel read and write operations are made. + * If null the whole bitmap will be read/write, this is, the region will be the entire bitmap (0x0,widthxheight) + **/ + + public setOffset(offset:Rect | null):Void { + if (offset == null) { + width = originalWidth; + height = originalHeight; + offsetX = 0; + offsetY=0; + } else { + width = offset.width; + height = offset.height; + offsetX = offset.x; + offsetY=offset.y; + } + } + + /** + * Internal method used to create a bitmap instance of given amount of pixels. + * @param length mount of pixels in the new bitmap (width * height). + **/ + private static createBitmapOfLength(w:Int, h:Int, length:Int) { + var bitmap = new Bitmap(); + bitmap.width = w; + bitmap.height = h; + butmap.originalWidth = w; + butmap.originalHeight = h; + bitmap.data = new Vector(lenght)); + return bitmap; + } + /** * The bitmap data. */ private var data:Vector; - + /** * Creates a new bitmap, filled with the given color. * @param w The width of the bitmap. @@ -30,10 +70,7 @@ class Bitmap { * @return The new bitmap. */ public static inline function create(w:Int, h:Int, color:Rgba):Bitmap { - var bitmap = new Bitmap(); - bitmap.width = w; - bitmap.height = h; - bitmap.data = new Vector(w * h); + var bitmap = createBitmapOfLength(w, h, w * h); var i:Int = 0; while (i < bitmap.data.length) { bitmap.data.set(i, color); @@ -41,7 +78,7 @@ class Bitmap { } return bitmap; } - + /** * Creates a new bitmap from the supplied byte data. * @param w The width of the bitmap. @@ -50,22 +87,15 @@ class Bitmap { * @return The new bitmap. */ public static inline function createFromBytes(w:Int, h:Int, bytes:Bytes):Bitmap { - var bitmap = new Bitmap(); Sure.sure(bytes != null); Sure.sure(bytes.length == w * h * 4); // Assume 4-byte RGBA8888 pixel format - bitmap.width = w; - bitmap.height = h; - bitmap.data = new Vector(Std.int(bytes.length / 4)); - var i:Int = 0; - var x:Int = 0; - while (i < bytes.length) { + var bitmap = createBitmapOfLength(w, h, Std.int(bytes.length / 4) var i:Int = 0; var x:Int = 0; while (i < bytes.length) { bitmap.data.set(x, Rgba.create(bytes.get(i), bytes.get(i + 1), bytes.get(i + 2), bytes.get(i + 3))); i += 4; x++; - } - return bitmap; + } return bitmap; } - + /** * Creates a new bitmap from the supplied array of bytes. Useful for target language consumers * that don't have direct access to the Bytes Haxe standard library class. @@ -83,44 +113,48 @@ class Bitmap { } return Bitmap.createFromBytes(w, h, data); } - + /** - * Gets a pixel at the given coordinate. + * Gets a pixel at the given coordinate considering its offset, if any. * @param x The x-coordinate. * @param y The y-coordinate. * @return The pixel color value. */ public inline function getPixel(x:Int, y:Int):Rgba { - return data.get(width * y + x); + // if (offs) + return data.get(width * y + x); } - + /** - * Sets a pixel at the given coordinate. + * Sets a pixel at the given coordinate considering its offset, if any. * @param x The x-coordinate. * @param y The y-coordinate. * @param color The color value to set at the given coordinate. */ public inline function setPixel(x:Int, y:Int, color:Rgba):Void { - data.set((width * y + x), color); + // if (offset != null) { + // var absoluteStart = offset.y * originalWidth + x; + // var absoluteXDiff = (originalWidth - width) * y; + // data.set(absoluteStart + width * y + x - absoluteXDiff, color); + // } else { + data.set((width * y + x), color); + // } } - + /** - * Makes a deep copy of the bitmap data. + * Makes a deep copy of the bitmap whole data (without considering its offset). * @return The deep copy of the bitmap data. */ public inline function clone():Bitmap { - var bitmap = new Bitmap(); - bitmap.width = width; - bitmap.height = height; - bitmap.data = new Vector(data.length); + var bitmap = createBitmapOfLength(originalWidth, originalHeight, data.length); for (i in 0...data.length) { bitmap.data.set(i, data.get(i)); } return bitmap; } - + /** - * Fills the bitmap with the given color. + * Fills the whole bitmap with the given color without consider its offset. * @param color The color to fill the bitmap with. */ public inline function fill(color:Rgba):Void { @@ -133,9 +167,9 @@ class Bitmap { idx += 4; } } - + /** - * Gets the raw bitmap data bytes. + * Gets the raw bitmap data bytes of the whole bitmap without considering its offset. * @return The bitmap data. */ public inline function getBytes():Bytes { @@ -151,11 +185,11 @@ class Bitmap { } return bytes; } - + /** * Private constructor. */ private function new():Void { // No implementation } -} \ No newline at end of file +} diff --git a/geometrize/runner/ImageRunnerOptions.hx b/geometrize/runner/ImageRunnerOptions.hx index 3ce265e..48871b0 100644 --- a/geometrize/runner/ImageRunnerOptions.hx +++ b/geometrize/runner/ImageRunnerOptions.hx @@ -1,6 +1,7 @@ package geometrize.runner; import geometrize.shape.ShapeType; +import geometrize.Util.Rect; /** * Encapsulates the parameters that may be passed to an image runner. @@ -27,6 +28,11 @@ typedef ImageRunnerOptions = { * The number of times to mutate each candidate shape. By default `100`. */ @:optional var shapeMutationsPerStep:Int; + + /** + * The algorithm will only consider a region of the entire bitmap. New shapes will be generated randombly but only inside this region. + **/ + @:optional var bitmapOffset:Rect; } class Default { From 61e00b3329adc5a721a5b37754e642d09f87e199 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Gur=C3=ADn?= Date: Thu, 11 Jul 2019 16:14:47 -0300 Subject: [PATCH 2/8] bitmap --- geometrize/Util.hx | 5 ++- geometrize/bitmap/Bitmap.hx | 61 ++++++++++++++++++++----------------- 2 files changed, 35 insertions(+), 31 deletions(-) diff --git a/geometrize/Util.hx b/geometrize/Util.hx index 46414b9..435177b 100644 --- a/geometrize/Util.hx +++ b/geometrize/Util.hx @@ -18,9 +18,8 @@ typedef Point = { */ typedef Rect = { > Point, - ; - w:Int; - h:Int; + w:Int, + h:Int } /** diff --git a/geometrize/bitmap/Bitmap.hx b/geometrize/bitmap/Bitmap.hx index 50a9a0e..7fd33e4 100644 --- a/geometrize/bitmap/Bitmap.hx +++ b/geometrize/bitmap/Bitmap.hx @@ -2,6 +2,7 @@ package geometrize.bitmap; import haxe.ds.Vector; import haxe.io.Bytes; +import geometrize.Util.Rect; /** * Helper class for working with bitmap data. @@ -21,25 +22,24 @@ class Bitmap { private var originalWidth:Int; private var originalHeight:Int; - private var offsetX:Int; - private var offsetY:Int; - // private offset:Rect | null - /** - * Sets the bitmap offset, this is, a region inside relative to which pixel read and write operations are made. - * If null the whole bitmap will be read/write, this is, the region will be the entire bitmap (0x0,widthxheight) - **/ + private var offsetX:Int; + private var offsetY:Int; - public setOffset(offset:Rect | null):Void { + /** + * Sets the bitmap offset, this is, a region inside relative to which pixel read and write operations are made. + * If null the whole bitmap will be read/write, this is, the region will be the entire bitmap (0x0,widthxheight) + **/ + public function setOffset(?offset:Rect):Void { if (offset == null) { width = originalWidth; height = originalHeight; offsetX = 0; - offsetY=0; + offsetY = 0; } else { - width = offset.width; - height = offset.height; - offsetX = offset.x; - offsetY=offset.y; + width = offset.w; + height = offset.h; + offsetX = offset.x; + offsetY = offset.y; } } @@ -47,13 +47,13 @@ class Bitmap { * Internal method used to create a bitmap instance of given amount of pixels. * @param length mount of pixels in the new bitmap (width * height). **/ - private static createBitmapOfLength(w:Int, h:Int, length:Int) { + static function createBitmapOfLength(w:Int, h:Int, length:Int):Bitmap { var bitmap = new Bitmap(); bitmap.width = w; bitmap.height = h; - butmap.originalWidth = w; - butmap.originalHeight = h; - bitmap.data = new Vector(lenght)); + bitmap.originalWidth = w; + bitmap.originalHeight = h; + bitmap.data = new Vector(length); return bitmap; } @@ -89,11 +89,15 @@ class Bitmap { public static inline function createFromBytes(w:Int, h:Int, bytes:Bytes):Bitmap { Sure.sure(bytes != null); Sure.sure(bytes.length == w * h * 4); // Assume 4-byte RGBA8888 pixel format - var bitmap = createBitmapOfLength(w, h, Std.int(bytes.length / 4) var i:Int = 0; var x:Int = 0; while (i < bytes.length) { + var bitmap = createBitmapOfLength(w, h, Std.int(bytes.length / 4)); + var i:Int = 0; + var x:Int = 0; + while (i < bytes.length) { bitmap.data.set(x, Rgba.create(bytes.get(i), bytes.get(i + 1), bytes.get(i + 2), bytes.get(i + 3))); i += 4; x++; - } return bitmap; + } + return bitmap; } /** @@ -121,8 +125,11 @@ class Bitmap { * @return The pixel color value. */ public inline function getPixel(x:Int, y:Int):Rgba { - // if (offs) - return data.get(width * y + x); + var absoluteStart = offsetY * originalWidth + x; + var absoluteXDiff = (originalWidth - width) * y; // TODO: maybe *(y-1) + var relativeIndex = width * y + x; + var index = absoluteStart + relativeIndex - absoluteXDiff - offsetX; + return data.get(index); } /** @@ -132,13 +139,11 @@ class Bitmap { * @param color The color value to set at the given coordinate. */ public inline function setPixel(x:Int, y:Int, color:Rgba):Void { - // if (offset != null) { - // var absoluteStart = offset.y * originalWidth + x; - // var absoluteXDiff = (originalWidth - width) * y; - // data.set(absoluteStart + width * y + x - absoluteXDiff, color); - // } else { - data.set((width * y + x), color); - // } + var absoluteStart = offsetY * originalWidth + x; + var absoluteXDiff = (originalWidth - width) * y; // TODO: maybe *(y-1) + var relativeIndex = width * y + x; + var index = absoluteStart + relativeIndex - absoluteXDiff - offsetX; + data.set(index, color); } /** From 6648ca75a3a96f2a3a34c21c6caa1766cbf838c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Gur=C3=ADn?= Date: Thu, 11 Jul 2019 16:53:05 -0300 Subject: [PATCH 3/8] bitmap --- geometrize/bitmap/Bitmap.hx | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/geometrize/bitmap/Bitmap.hx b/geometrize/bitmap/Bitmap.hx index 7fd33e4..04ac427 100644 --- a/geometrize/bitmap/Bitmap.hx +++ b/geometrize/bitmap/Bitmap.hx @@ -2,7 +2,7 @@ package geometrize.bitmap; import haxe.ds.Vector; import haxe.io.Bytes; -import geometrize.Util.Rect; +import geometrize.Util; /** * Helper class for working with bitmap data. @@ -27,17 +27,21 @@ class Bitmap { /** * Sets the bitmap offset, this is, a region inside relative to which pixel read and write operations are made. - * If null the whole bitmap will be read/write, this is, the region will be the entire bitmap (0x0,widthxheight) + * Calling this method without parameters will remove the offset and reset to default behavior. **/ - public function setOffset(?offset:Rect):Void { + public function setOffset(?offset:Util.Rect):Void { if (offset == null) { width = originalWidth; height = originalHeight; offsetX = 0; offsetY = 0; } else { - width = offset.w; - height = offset.h; + Sure.sure(offset.width>0 && offset.x+offset.width<=originalWidth); + Sure.sure(offset.height>0 && offset.y+offset.height<=originalHeight); + Sure.sure(offset.x>=0); + Sure.sure(offset.y>=0); + width = offset.width; + height = offset.height; offsetX = offset.x; offsetY = offset.y; } @@ -53,6 +57,8 @@ class Bitmap { bitmap.height = h; bitmap.originalWidth = w; bitmap.originalHeight = h; + bitmap.offsetX=0; + bitmap.offsetY=0; bitmap.data = new Vector(length); return bitmap; } @@ -125,11 +131,7 @@ class Bitmap { * @return The pixel color value. */ public inline function getPixel(x:Int, y:Int):Rgba { - var absoluteStart = offsetY * originalWidth + x; - var absoluteXDiff = (originalWidth - width) * y; // TODO: maybe *(y-1) - var relativeIndex = width * y + x; - var index = absoluteStart + relativeIndex - absoluteXDiff - offsetX; - return data.get(index); + return data.get(getCoordsIndex(x,y)); } /** @@ -139,13 +141,16 @@ class Bitmap { * @param color The color value to set at the given coordinate. */ public inline function setPixel(x:Int, y:Int, color:Rgba):Void { - var absoluteStart = offsetY * originalWidth + x; - var absoluteXDiff = (originalWidth - width) * y; // TODO: maybe *(y-1) - var relativeIndex = width * y + x; - var index = absoluteStart + relativeIndex - absoluteXDiff - offsetX; - data.set(index, color); + data.set(getCoordsIndex(x,y), color); } +private inline function getCoordsIndex(x:Int, y:Int){ + var absoluteStart = offsetY * originalWidth + offsetX; + var absoluteXDiff = (originalWidth * y) + x + offsetX;// + () (originalWidth - width) * y; // TODO: maybe *(y-1) + var relativeIndex = 0;//width * y + x; + var index = absoluteStart + relativeIndex + absoluteXDiff - offsetX; + return index; +} /** * Makes a deep copy of the bitmap whole data (without considering its offset). * @return The deep copy of the bitmap data. From 3cc9bcc947b2783548704aeb89aa8b4f2da149b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Gur=C3=ADn?= Date: Thu, 11 Jul 2019 21:10:38 -0300 Subject: [PATCH 4/8] works but too much changes --- geometrize/Model.hx | 37 +++++++++---- geometrize/Util.hx | 4 +- geometrize/bitmap/Bitmap.hx | 81 ++++++++++++++++++---------- geometrize/shape/Circle.hx | 3 +- geometrize/shape/Ellipse.hx | 3 +- geometrize/shape/Line.hx | 3 +- geometrize/shape/QuadraticBezier.hx | 3 +- geometrize/shape/Rectangle.hx | 7 +++ geometrize/shape/RotatedEllipse.hx | 3 +- geometrize/shape/RotatedRectangle.hx | 3 +- geometrize/shape/Shape.hx | 1 + geometrize/shape/Triangle.hx | 3 +- 12 files changed, 104 insertions(+), 47 deletions(-) diff --git a/geometrize/Model.hx b/geometrize/Model.hx index 8e1a475..38f0b68 100644 --- a/geometrize/Model.hx +++ b/geometrize/Model.hx @@ -27,28 +27,32 @@ class Model { * Width of the target bitmap. */ public var width(default, null):Int; + /** * Height of the target bitmap. */ public var height(default, null):Int; + /** * The target bitmap, the bitmap we aim to approximate. */ public var target(default, null):Bitmap; + /** * The current bitmap. */ public var current(default, null):Bitmap; + /** * Buffer bitmap. */ public var buffer(default, null):Bitmap; - + /** * Score derived from calculating the difference between bitmaps. */ private var score(default, null):Float; - + /** * Creates a new model. * @param target The target bitmap. @@ -56,16 +60,20 @@ class Model { */ public function new(target:Bitmap, backgroundColor:Rgba) { Sure.sure(target != null); - + this.width = target.width; this.height = target.height; this.target = target; + target.saveOffSet(true); this.current = Bitmap.create(target.width, target.height, backgroundColor); this.buffer = Bitmap.create(target.width, target.height, backgroundColor); - + target.restoreOffset(); + this.current.setOffset(target.getOffSet()); + this.buffer.setOffset(target.getOffSet()); + this.score = Core.differenceFull(target, current); } - + /** * Steps the optimization/fitting algorithm. * @param shapeType The shape types to use. @@ -79,7 +87,7 @@ class Model { var results:Array = [ addShape(state.shape, state.alpha) ]; return results; } - + /** * Adds a shape to the model. * @param shape The shape to add. @@ -88,17 +96,24 @@ class Model { */ public function addShape(shape:Shape, alpha:Int):ShapeResult { Sure.sure(shape != null); - + var before:Bitmap = current.clone(); var lines:Array = shape.rasterize(); var color:Rgba = Core.computeColor(target, current, lines, alpha); Rasterizer.drawLines(current, color, lines); - + score = Core.differencePartial(target, before, current, score, lines); - + + var currentOffset = current.getOffSet(); + if (currentOffset != null) { + shape.translate(currentOffset); + } + var result:ShapeResult = { - score: score, color: color, shape: shape + score: score, + color: color, + shape: shape }; return result; } -} \ No newline at end of file +} diff --git a/geometrize/Util.hx b/geometrize/Util.hx index 435177b..47d9ab6 100644 --- a/geometrize/Util.hx +++ b/geometrize/Util.hx @@ -18,8 +18,8 @@ typedef Point = { */ typedef Rect = { > Point, - w:Int, - h:Int + width:Int, + height:Int } /** diff --git a/geometrize/bitmap/Bitmap.hx b/geometrize/bitmap/Bitmap.hx index 04ac427..b41439f 100644 --- a/geometrize/bitmap/Bitmap.hx +++ b/geometrize/bitmap/Bitmap.hx @@ -4,12 +4,7 @@ import haxe.ds.Vector; import haxe.io.Bytes; import geometrize.Util; -/** - * Helper class for working with bitmap data. - * @author Sam Twidale (http://samcodes.co.uk/) - */ -@:expose -class Bitmap { +class OffsetArea { /** * The width of the bitmap considering its offset, if any. */ @@ -24,28 +19,64 @@ class Bitmap { private var originalHeight:Int; private var offsetX:Int; private var offsetY:Int; - + @:optional private var savedOffset:Util.Rect; /** * Sets the bitmap offset, this is, a region inside relative to which pixel read and write operations are made. * Calling this method without parameters will remove the offset and reset to default behavior. **/ - public function setOffset(?offset:Util.Rect):Void { + public inline function setOffset(?offset:Util.Rect):Void { if (offset == null) { width = originalWidth; height = originalHeight; offsetX = 0; offsetY = 0; } else { - Sure.sure(offset.width>0 && offset.x+offset.width<=originalWidth); - Sure.sure(offset.height>0 && offset.y+offset.height<=originalHeight); - Sure.sure(offset.x>=0); - Sure.sure(offset.y>=0); + trace((offset.x + offset.width)+' - '+originalWidth); + Sure.sure(offset.width>0); + Sure.sure(offset.x + offset.width <= originalWidth); + Sure.sure(offset.height > 0); + Sure.sure(offset.y + offset.height <= originalHeight); + Sure.sure(offset.x >= 0); + Sure.sure(offset.y >= 0); width = offset.width; height = offset.height; offsetX = offset.x; offsetY = offset.y; } } +public inline function getOffSet() { + if(width!=originalWidth||height!=originalHeight||offsetX!=0||offsetY!=0){ + return {x:offsetX, y: offsetY, width: width, height: height }; + } + return null; +} + +public function saveOffSet(?resetOffset: Bool) { + savedOffset=getOffSet(); + if(resetOffset){ + setOffset(); + } +} + +public function restoreOffset() { + if(savedOffset!=null){ + setOffset(savedOffset); + } +} + +} + +/** + * Helper class for working with bitmap data. + * @author Sam Twidale (http://samcodes.co.uk/) + */ +@:expose +class Bitmap extends OffsetArea { + + /** + * The bitmap data. + */ + private var data:Vector; /** * Internal method used to create a bitmap instance of given amount of pixels. @@ -57,17 +88,12 @@ class Bitmap { bitmap.height = h; bitmap.originalWidth = w; bitmap.originalHeight = h; - bitmap.offsetX=0; - bitmap.offsetY=0; + bitmap.offsetX = 0; + bitmap.offsetY = 0; bitmap.data = new Vector(length); return bitmap; } - /** - * The bitmap data. - */ - private var data:Vector; - /** * Creates a new bitmap, filled with the given color. * @param w The width of the bitmap. @@ -131,7 +157,7 @@ class Bitmap { * @return The pixel color value. */ public inline function getPixel(x:Int, y:Int):Rgba { - return data.get(getCoordsIndex(x,y)); + return data.get(getCoordsIndex(x, y)); } /** @@ -141,22 +167,23 @@ class Bitmap { * @param color The color value to set at the given coordinate. */ public inline function setPixel(x:Int, y:Int, color:Rgba):Void { - data.set(getCoordsIndex(x,y), color); + data.set(getCoordsIndex(x, y), color); } -private inline function getCoordsIndex(x:Int, y:Int){ + private inline function getCoordsIndex(x:Int, y:Int) { var absoluteStart = offsetY * originalWidth + offsetX; - var absoluteXDiff = (originalWidth * y) + x + offsetX;// + () (originalWidth - width) * y; // TODO: maybe *(y-1) - var relativeIndex = 0;//width * y + x; - var index = absoluteStart + relativeIndex + absoluteXDiff - offsetX; - return index; -} + var absoluteIndex = (originalWidth * y) + x -offsetX;//-(originalWidth-offsetX); + var index = absoluteStart + absoluteIndex ; + return index; + } + /** * Makes a deep copy of the bitmap whole data (without considering its offset). * @return The deep copy of the bitmap data. */ public inline function clone():Bitmap { var bitmap = createBitmapOfLength(originalWidth, originalHeight, data.length); + bitmap.setOffset(getOffSet()); for (i in 0...data.length) { bitmap.data.set(i, data.get(i)); } diff --git a/geometrize/shape/Circle.hx b/geometrize/shape/Circle.hx index 2cc3aa2..cb5c971 100644 --- a/geometrize/shape/Circle.hx +++ b/geometrize/shape/Circle.hx @@ -14,7 +14,8 @@ class Circle extends Ellipse { rx = Std.random(32) + 1; ry = rx; } - + public function translate(vector:Util.Point) {} + override public function mutate():Void { var r = Std.random(2); switch (r) { diff --git a/geometrize/shape/Ellipse.hx b/geometrize/shape/Ellipse.hx index 4dc88e0..627225e 100644 --- a/geometrize/shape/Ellipse.hx +++ b/geometrize/shape/Ellipse.hx @@ -25,7 +25,8 @@ class Ellipse implements Shape { this.xBound = xBound; this.yBound = yBound; } - + public function translate(vector:Util.Point) {} + public function rasterize():Array { var lines:Array = []; var aspect:Float = rx / ry; diff --git a/geometrize/shape/Line.hx b/geometrize/shape/Line.hx index ef420c4..d901c8b 100644 --- a/geometrize/shape/Line.hx +++ b/geometrize/shape/Line.hx @@ -26,7 +26,8 @@ class Line implements Shape { this.xBound = xBound; this.yBound = yBound; } - + public function translate(vector:Util.Point) {} + public function rasterize():Array { var lines:Array = []; diff --git a/geometrize/shape/QuadraticBezier.hx b/geometrize/shape/QuadraticBezier.hx index 58af0d5..5114b11 100644 --- a/geometrize/shape/QuadraticBezier.hx +++ b/geometrize/shape/QuadraticBezier.hx @@ -31,7 +31,8 @@ class QuadraticBezier implements Shape { this.xBound = xBound; this.yBound = yBound; } - + public function translate(vector:Util.Point) {} + public function rasterize():Array { var lines:Array = []; var points:Array = []; diff --git a/geometrize/shape/Rectangle.hx b/geometrize/shape/Rectangle.hx index 48c81d3..ea03672 100644 --- a/geometrize/shape/Rectangle.hx +++ b/geometrize/shape/Rectangle.hx @@ -26,6 +26,13 @@ class Rectangle implements Shape { this.yBound = yBound; } + public function translate(vector:Util.Point) { + x1= x1+vector.x; + x2=x2+vector.x; + y1=y1+vector.y; + y2=y2+vector.y; + trace('translate'); + } public function rasterize():Array { var lines:Array = []; var yMin:Int = Util.min(y1, y2); diff --git a/geometrize/shape/RotatedEllipse.hx b/geometrize/shape/RotatedEllipse.hx index c0f5ada..a814ae3 100644 --- a/geometrize/shape/RotatedEllipse.hx +++ b/geometrize/shape/RotatedEllipse.hx @@ -28,7 +28,8 @@ class RotatedEllipse implements Shape { this.xBound = xBound; this.yBound = yBound; } - + public function translate(vector:Util.Point) {} + public function rasterize():Array { var pointCount:Int = 20; var points:Array<{x : Int, y: Int}> = []; diff --git a/geometrize/shape/RotatedRectangle.hx b/geometrize/shape/RotatedRectangle.hx index cac4543..696d6b8 100644 --- a/geometrize/shape/RotatedRectangle.hx +++ b/geometrize/shape/RotatedRectangle.hx @@ -29,7 +29,8 @@ class RotatedRectangle implements Shape { this.xBound = xBound; this.yBound = yBound; } - + public function translate(vector:Util.Point) {} + public function rasterize():Array { return Scanline.trim(Rasterizer.scanlinesForPolygon(getCornerPoints()), xBound, yBound); } diff --git a/geometrize/shape/Shape.hx b/geometrize/shape/Shape.hx index 0a56bf1..dc2e103 100644 --- a/geometrize/shape/Shape.hx +++ b/geometrize/shape/Shape.hx @@ -7,6 +7,7 @@ import geometrize.rasterizer.Scanline; * @author Sam Twidale (http://samcodes.co.uk/) */ interface Shape { + public function translate(vector:Util.Point):Void; /** * Creates a raster scanline representation of the shape. * @return Array of raster scanlines representing the shape. diff --git a/geometrize/shape/Triangle.hx b/geometrize/shape/Triangle.hx index 6cea9ce..46a8e2f 100644 --- a/geometrize/shape/Triangle.hx +++ b/geometrize/shape/Triangle.hx @@ -30,7 +30,8 @@ class Triangle implements Shape { this.xBound = xBound; this.yBound = yBound; } - + public function translate(vector:Util.Point) {} + public function rasterize():Array { return Scanline.trim(Rasterizer.scanlinesForPolygon([ { x: x1, y: y1 }, { x: x2, y: y2 }, { x: x3, y: y3 } ]), xBound, yBound); } From ee788c60f1bba84d5c6a85ba6dfb0cc95953ec03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Gur=C3=ADn?= Date: Thu, 11 Jul 2019 23:36:54 -0300 Subject: [PATCH 5/8] translate --- geometrize/State.hx | 2 ++ geometrize/Util.hx | 2 +- geometrize/bitmap/Bitmap.hx | 17 +++++++++--- geometrize/shape/Circle.hx | 1 - geometrize/shape/Ellipse.hx | 8 ++++-- geometrize/shape/Line.hx | 9 +++++-- geometrize/shape/QuadraticBezier.hx | 10 ++++++- geometrize/shape/Rectangle.hx | 39 ++++++++++++++-------------- geometrize/shape/RotatedEllipse.hx | 10 +++++-- geometrize/shape/RotatedRectangle.hx | 10 +++++-- geometrize/shape/Shape.hx | 17 ++++++++---- geometrize/shape/Triangle.hx | 10 ++++++- 12 files changed, 96 insertions(+), 39 deletions(-) diff --git a/geometrize/State.hx b/geometrize/State.hx index 0f08f7d..026e599 100644 --- a/geometrize/State.hx +++ b/geometrize/State.hx @@ -11,10 +11,12 @@ class State { * The geometric shape owned by the state. */ public var shape(default, null):Shape; + /** * The alpha of the shape. */ public var alpha(default, null):Int; + /** * The score of the state, a measure of the improvement applying the state to the current bitmap will have. */ diff --git a/geometrize/Util.hx b/geometrize/Util.hx index 47d9ab6..692967e 100644 --- a/geometrize/Util.hx +++ b/geometrize/Util.hx @@ -4,7 +4,7 @@ import geometrize.bitmap.Bitmap; import geometrize.bitmap.Rgba; /** - * Represents a point in 2D space. + * Represents a point or vector in 2D space. * @author Sam Twidale (http://samcodes.co.uk/) */ typedef Point = { diff --git a/geometrize/bitmap/Bitmap.hx b/geometrize/bitmap/Bitmap.hx index b41439f..b254064 100644 --- a/geometrize/bitmap/Bitmap.hx +++ b/geometrize/bitmap/Bitmap.hx @@ -20,6 +20,7 @@ class OffsetArea { private var offsetX:Int; private var offsetY:Int; @:optional private var savedOffset:Util.Rect; + /** * Sets the bitmap offset, this is, a region inside relative to which pixel read and write operations are made. * Calling this method without parameters will remove the offset and reset to default behavior. @@ -31,7 +32,6 @@ class OffsetArea { offsetX = 0; offsetY = 0; } else { - trace((offset.x + offset.width)+' - '+originalWidth); Sure.sure(offset.width>0); Sure.sure(offset.x + offset.width <= originalWidth); Sure.sure(offset.height > 0); @@ -44,6 +44,10 @@ class OffsetArea { offsetY = offset.y; } } + + /** + @returns current offset or null if none. + **/ public inline function getOffSet() { if(width!=originalWidth||height!=originalHeight||offsetX!=0||offsetY!=0){ return {x:offsetX, y: offsetY, width: width, height: height }; @@ -51,13 +55,20 @@ public inline function getOffSet() { return null; } -public function saveOffSet(?resetOffset: Bool) { +/** + * Saves current offset overriding previous saves. + * @param reset if given it will also remove current offset. + */ +public function saveOffSet(?reset: Bool) { savedOffset=getOffSet(); - if(resetOffset){ + if(reset){ setOffset(); } } +/** + * Restores previously saved offset, if any. + */ public function restoreOffset() { if(savedOffset!=null){ setOffset(savedOffset); diff --git a/geometrize/shape/Circle.hx b/geometrize/shape/Circle.hx index cb5c971..aba77fc 100644 --- a/geometrize/shape/Circle.hx +++ b/geometrize/shape/Circle.hx @@ -14,7 +14,6 @@ class Circle extends Ellipse { rx = Std.random(32) + 1; ry = rx; } - public function translate(vector:Util.Point) {} override public function mutate():Void { var r = Std.random(2); diff --git a/geometrize/shape/Ellipse.hx b/geometrize/shape/Ellipse.hx index 627225e..ef9cfc2 100644 --- a/geometrize/shape/Ellipse.hx +++ b/geometrize/shape/Ellipse.hx @@ -25,8 +25,12 @@ class Ellipse implements Shape { this.xBound = xBound; this.yBound = yBound; } - public function translate(vector:Util.Point) {} - + public function translate(vector:Util.Point) { + x = x + vector.x; + rx = rx + vector.x; + y = y + vector.y; + ry = ry + vector.y + } public function rasterize():Array { var lines:Array = []; var aspect:Float = rx / ry; diff --git a/geometrize/shape/Line.hx b/geometrize/shape/Line.hx index d901c8b..9a3b94b 100644 --- a/geometrize/shape/Line.hx +++ b/geometrize/shape/Line.hx @@ -25,9 +25,14 @@ class Line implements Shape { this.xBound = xBound; this.yBound = yBound; + } + + public function translate(vector:Util.Point) { + x1 = x1 + vector.x; + x2 = x2 + vector.x; + y1 = y1 + vector.y; + y2 = y2 + vector.y; } - public function translate(vector:Util.Point) {} - public function rasterize():Array { var lines:Array = []; diff --git a/geometrize/shape/QuadraticBezier.hx b/geometrize/shape/QuadraticBezier.hx index 5114b11..2837364 100644 --- a/geometrize/shape/QuadraticBezier.hx +++ b/geometrize/shape/QuadraticBezier.hx @@ -31,7 +31,15 @@ class QuadraticBezier implements Shape { this.xBound = xBound; this.yBound = yBound; } - public function translate(vector:Util.Point) {} + + public function translate(vector:Util.Point) { + x1 = x1 + vector.x; + x2 = x2 + vector.x; + cx = cx + vector.x; + cy = cy + vector.y; + y1 = y1 + vector.y; + y2 = y2 + vector.y; + } public function rasterize():Array { var lines:Array = []; diff --git a/geometrize/shape/Rectangle.hx b/geometrize/shape/Rectangle.hx index ea03672..3e7095a 100644 --- a/geometrize/shape/Rectangle.hx +++ b/geometrize/shape/Rectangle.hx @@ -12,27 +12,27 @@ class Rectangle implements Shape { public var y1:Int; public var x2:Int; public var y2:Int; - + public var xBound(default, null):Int; public var yBound(default, null):Int; - + public function new(xBound:Int, yBound:Int) { x1 = Std.random(xBound); y1 = Std.random(yBound); x2 = Util.clamp(x1 + Std.random(32) + 1, 0, xBound - 1); y2 = Util.clamp(y1 + Std.random(32) + 1, 0, yBound - 1); - + this.xBound = xBound; this.yBound = yBound; } - - public function translate(vector:Util.Point) { - x1= x1+vector.x; - x2=x2+vector.x; - y1=y1+vector.y; - y2=y2+vector.y; - trace('translate'); - } + + public function translate(vector:Util.Point) { + x1 = x1 + vector.x; + x2 = x2 + vector.x; + y1 = y1 + vector.y; + y2 = y2 + vector.y; + } + public function rasterize():Array { var lines:Array = []; var yMin:Int = Util.min(y1, y2); @@ -46,7 +46,7 @@ class Rectangle implements Shape { } return lines; } - + public function mutate():Void { var r = Std.random(2); switch (r) { @@ -58,7 +58,7 @@ class Rectangle implements Shape { y2 = Util.clamp(y2 + Util.random(-16, 16), 0, yBound - 1); } } - + public function clone():Shape { var rectangle = new Rectangle(xBound, yBound); rectangle.x1 = x1; @@ -67,16 +67,17 @@ class Rectangle implements Shape { rectangle.y2 = y2; return rectangle; } - + public function getType():ShapeType { return ShapeType.RECTANGLE; } - + public function getRawShapeData():Array { - return [ Util.min(x1, x2), Util.min(y1, y2), Util.max(x1, x2), Util.max(y1, y2) ]; + return [Util.min(x1, x2), Util.min(y1, y2), Util.max(x1, x2), Util.max(y1, y2)]; } - + public function getSvgShapeData():String { - return ""; + return ""; } -} \ No newline at end of file +} diff --git a/geometrize/shape/RotatedEllipse.hx b/geometrize/shape/RotatedEllipse.hx index a814ae3..a7bb8a9 100644 --- a/geometrize/shape/RotatedEllipse.hx +++ b/geometrize/shape/RotatedEllipse.hx @@ -28,8 +28,14 @@ class RotatedEllipse implements Shape { this.xBound = xBound; this.yBound = yBound; } - public function translate(vector:Util.Point) {} - + + public function translate(vector:Util.Point) { + x = x + vector.x; + rx = rx + vector.x; + y = y + vector.y; + ry = ry + vector.y + } + public function rasterize():Array { var pointCount:Int = 20; var points:Array<{x : Int, y: Int}> = []; diff --git a/geometrize/shape/RotatedRectangle.hx b/geometrize/shape/RotatedRectangle.hx index 696d6b8..35e8956 100644 --- a/geometrize/shape/RotatedRectangle.hx +++ b/geometrize/shape/RotatedRectangle.hx @@ -29,8 +29,7 @@ class RotatedRectangle implements Shape { this.xBound = xBound; this.yBound = yBound; } - public function translate(vector:Util.Point) {} - + public function rasterize():Array { return Scanline.trim(Rasterizer.scanlinesForPolygon(getCornerPoints()), xBound, yBound); } @@ -109,4 +108,11 @@ class RotatedRectangle implements Shape { return [ { x : ulx, y : uly }, { x : urx, y : ury }, { x : brx, y : bry }, { x : blx, y : bly } ]; } + + public function translate(vector:Util.Point) { + x1 = x1 + vector.x; + x2 = x2 + vector.x; + y1 = y1 + vector.y; + y2 = y2 + vector.y; + } } \ No newline at end of file diff --git a/geometrize/shape/Shape.hx b/geometrize/shape/Shape.hx index dc2e103..363601e 100644 --- a/geometrize/shape/Shape.hx +++ b/geometrize/shape/Shape.hx @@ -7,38 +7,45 @@ import geometrize.rasterizer.Scanline; * @author Sam Twidale (http://samcodes.co.uk/) */ interface Shape { - public function translate(vector:Util.Point):Void; /** * Creates a raster scanline representation of the shape. * @return Array of raster scanlines representing the shape. */ public function rasterize():Array; + /** * Modifies the shape a little, typically with a random component. * For improving the shape's fit to a bitmap (trial-and-error style). */ public function mutate():Void; + /** * Creates a deep copy of the shape. * @return A deep copy of the shape object. */ public function clone():Shape; - + /** * Gets the ShapeType of the shape. * @return The ShapeType of the shape. */ public function getType():ShapeType; - + /** * Gets a vector of data that represents the shape geometry, the format varies depending on the ShapeType. * @return The shape data. */ public function getRawShapeData():Array; - + /** * Gets a string that represents a SVG element that describes the shape geometry. * @return The SVG shape data that represents this shape. */ public function getSvgShapeData():String; -} \ No newline at end of file + + /** + * Translate this shape by given vector. This is currently only needed for SVG output when using + * Bitmap offsets so is not critical to implement if the usecase is another. + */ + public function translate(vector:Util.Point):Void; +} diff --git a/geometrize/shape/Triangle.hx b/geometrize/shape/Triangle.hx index 46a8e2f..073e0bf 100644 --- a/geometrize/shape/Triangle.hx +++ b/geometrize/shape/Triangle.hx @@ -30,7 +30,15 @@ class Triangle implements Shape { this.xBound = xBound; this.yBound = yBound; } - public function translate(vector:Util.Point) {} + + public function translate(vector:Util.Point) { + x1 = x1 + vector.x; + x2 = x2 + vector.x; + x3 = x3 + vector.x; + y1 = y1 + vector.y; + y2 = y2 + vector.y; + y3 = y3 + vector.y; + } public function rasterize():Array { return Scanline.trim(Rasterizer.scanlinesForPolygon([ { x: x1, y: y1 }, { x: x2, y: y2 }, { x: x3, y: y3 } ]), xBound, yBound); From 8122e57f1cff408e751f3baa277ad3abb6d9a0ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Gur=C3=ADn?= Date: Fri, 12 Jul 2019 01:13:59 -0300 Subject: [PATCH 6/8] bitmapoffset --- geometrize/Core.hx | 3 ++ geometrize/Model.hx | 18 +++++++- geometrize/bitmap/Bitmap.hx | 58 ++++++++++++------------- geometrize/runner/ImageRunner.hx | 11 ++++- geometrize/runner/ImageRunnerOptions.hx | 4 -- geometrize/shape/Ellipse.hx | 6 ++- geometrize/shape/RotatedEllipse.hx | 2 +- 7 files changed, 63 insertions(+), 39 deletions(-) diff --git a/geometrize/Core.hx b/geometrize/Core.hx index a5e3a06..08e7e0f 100644 --- a/geometrize/Core.hx +++ b/geometrize/Core.hx @@ -97,6 +97,7 @@ class Core { } } var result:Float = Math.sqrt(total / (width * height * 4.0)) / 255; + // trace('differenceFull: '+total+", "+width+", "+height+", "+result+", "+Math.isFinite(result)); Sure.sure(Math.isFinite(result)); return result; } @@ -144,6 +145,8 @@ class Core { } } var result:Float = Math.sqrt(total / rgbaCount) / 255; + // trace('differencePartial: '+total+", "+rgbaCount+", "+result+", "+Math.isFinite(result)); + Sure.sure(Math.isFinite(result)); return result; } diff --git a/geometrize/Model.hx b/geometrize/Model.hx index 38f0b68..a5ae870 100644 --- a/geometrize/Model.hx +++ b/geometrize/Model.hx @@ -7,6 +7,7 @@ import geometrize.rasterizer.Scanline; import geometrize.shape.Shape; import geometrize.shape.ShapeType; import geometrize.rasterizer.Rasterizer; +import geometrize.Util; /** * Container for info about a shape added to the model. @@ -73,6 +74,19 @@ class Model { this.score = Core.differenceFull(target, current); } + + /** + * The algorithm will only consider a region of the entire bitmap. + * New shapes will be generated randombly but only inside this region. + **/ + public inline function setOffset(?offset:Util.Rect):Void { + this.current.setOffset(offset); + this.current.setOffset(offset); + this.target.setOffset(offset); + this.width = target.width; + this.height = target.height; + this.score = Core.differenceFull(target, current); + } /** * Steps the optimization/fitting algorithm. @@ -84,7 +98,7 @@ class Model { */ public function step(shapeTypes:Array, alpha:Int, n:Int, age:Int):Array { var state = Core.bestHillClimbState(shapeTypes, alpha, n, age, target, current, buffer, score); - var results:Array = [ addShape(state.shape, state.alpha) ]; + var results:Array = [addShape(state.shape, state.alpha)]; return results; } @@ -108,7 +122,7 @@ class Model { if (currentOffset != null) { shape.translate(currentOffset); } - + var result:ShapeResult = { score: score, color: color, diff --git a/geometrize/bitmap/Bitmap.hx b/geometrize/bitmap/Bitmap.hx index b254064..a0b5327 100644 --- a/geometrize/bitmap/Bitmap.hx +++ b/geometrize/bitmap/Bitmap.hx @@ -46,34 +46,41 @@ class OffsetArea { } /** - @returns current offset or null if none. + * @returns current offset or null if none. **/ -public inline function getOffSet() { - if(width!=originalWidth||height!=originalHeight||offsetX!=0||offsetY!=0){ - return {x:offsetX, y: offsetY, width: width, height: height }; + public inline function getOffSet() { + if(width!=originalWidth||height!=originalHeight||offsetX!=0||offsetY!=0){ + return {x:offsetX, y: offsetY, width: width, height: height }; + } + return null; } - return null; -} -/** - * Saves current offset overriding previous saves. - * @param reset if given it will also remove current offset. - */ -public function saveOffSet(?reset: Bool) { - savedOffset=getOffSet(); - if(reset){ - setOffset(); + /** + * Saves current offset overriding previous saves. + * @param reset if given it will also remove current offset. + */ + public function saveOffSet(?reset: Bool) { + savedOffset=getOffSet(); + if(reset){ + setOffset(); + } } -} -/** - * Restores previously saved offset, if any. - */ -public function restoreOffset() { - if(savedOffset!=null){ - setOffset(savedOffset); + /** + * Restores previously saved offset, if any. + */ + public function restoreOffset() { + if(savedOffset!=null){ + setOffset(savedOffset); + } } -} + + private inline function getCoordsIndex(x:Int, y:Int) { + var absoluteStart = offsetY * originalWidth + offsetX; + var absoluteIndex = (originalWidth * y) + x; + var index = absoluteStart + absoluteIndex ; + return index; + } } @@ -181,13 +188,6 @@ class Bitmap extends OffsetArea { data.set(getCoordsIndex(x, y), color); } - private inline function getCoordsIndex(x:Int, y:Int) { - var absoluteStart = offsetY * originalWidth + offsetX; - var absoluteIndex = (originalWidth * y) + x -offsetX;//-(originalWidth-offsetX); - var index = absoluteStart + absoluteIndex ; - return index; - } - /** * Makes a deep copy of the bitmap whole data (without considering its offset). * @return The deep copy of the bitmap data. diff --git a/geometrize/runner/ImageRunner.hx b/geometrize/runner/ImageRunner.hx index 9498c9e..68ed32b 100644 --- a/geometrize/runner/ImageRunner.hx +++ b/geometrize/runner/ImageRunner.hx @@ -3,6 +3,7 @@ package geometrize.runner; import geometrize.Model; import geometrize.Model.ShapeResult; import geometrize.bitmap.Bitmap; +import geometrize.Util; import geometrize.bitmap.Rgba; import geometrize.runner.ImageRunnerOptions.Default; @@ -25,6 +26,14 @@ class ImageRunner { model = new Model(inputImage, backgroundColor); } + /** + * The algorithm will only consider a region of the entire bitmap. + * New shapes will be generated randombly but only inside this region. + **/ + public inline function setOffset(?offset:Util.Rect):Void { + model.setOffset(offset); + } + /** * Updates the model once. * @return An array containing data about the shapes just added to the model. @@ -47,4 +56,4 @@ class ImageRunner { Sure.sure(model != null); return model.current; } -} \ No newline at end of file +} diff --git a/geometrize/runner/ImageRunnerOptions.hx b/geometrize/runner/ImageRunnerOptions.hx index 48871b0..b336a6f 100644 --- a/geometrize/runner/ImageRunnerOptions.hx +++ b/geometrize/runner/ImageRunnerOptions.hx @@ -29,10 +29,6 @@ typedef ImageRunnerOptions = { */ @:optional var shapeMutationsPerStep:Int; - /** - * The algorithm will only consider a region of the entire bitmap. New shapes will be generated randombly but only inside this region. - **/ - @:optional var bitmapOffset:Rect; } class Default { diff --git a/geometrize/shape/Ellipse.hx b/geometrize/shape/Ellipse.hx index ef9cfc2..25c4dd5 100644 --- a/geometrize/shape/Ellipse.hx +++ b/geometrize/shape/Ellipse.hx @@ -25,12 +25,14 @@ class Ellipse implements Shape { this.xBound = xBound; this.yBound = yBound; } - public function translate(vector:Util.Point) { + + public function translate(vector:Util.Point) { x = x + vector.x; rx = rx + vector.x; y = y + vector.y; - ry = ry + vector.y + ry = ry + vector.y; } + public function rasterize():Array { var lines:Array = []; var aspect:Float = rx / ry; diff --git a/geometrize/shape/RotatedEllipse.hx b/geometrize/shape/RotatedEllipse.hx index a7bb8a9..27571f4 100644 --- a/geometrize/shape/RotatedEllipse.hx +++ b/geometrize/shape/RotatedEllipse.hx @@ -33,7 +33,7 @@ class RotatedEllipse implements Shape { x = x + vector.x; rx = rx + vector.x; y = y + vector.y; - ry = ry + vector.y + ry = ry + vector.y; } public function rasterize():Array { From eaca3765fa0c50eef090d595379b6539492a2eb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Gur=C3=ADn?= Date: Fri, 12 Jul 2019 01:24:09 -0300 Subject: [PATCH 7/8] bitmap offset as image runner method, works --- geometrize/Model.hx | 3 +- geometrize/bitmap/Bitmap.hx | 83 +------------------------ geometrize/bitmap/OffsetArea.hx | 96 +++++++++++++++++++++++++++++ geometrize/runner/ImageRunner.hx | 1 + geometrize/shape/Ellipse.hx | 14 ++--- geometrize/shape/Line.hx | 13 ++-- geometrize/shape/QuadraticBezier.hx | 18 +++--- geometrize/shape/Rectangle.hx | 14 ++--- geometrize/shape/RotatedEllipse.hx | 15 ++--- geometrize/shape/Triangle.hx | 18 +++--- 10 files changed, 147 insertions(+), 128 deletions(-) create mode 100644 geometrize/bitmap/OffsetArea.hx diff --git a/geometrize/Model.hx b/geometrize/Model.hx index a5ae870..26157c1 100644 --- a/geometrize/Model.hx +++ b/geometrize/Model.hx @@ -74,10 +74,11 @@ class Model { this.score = Core.differenceFull(target, current); } - + /** * The algorithm will only consider a region of the entire bitmap. * New shapes will be generated randombly but only inside this region. + * If null is passed it will reset the offset (default behaviour) **/ public inline function setOffset(?offset:Util.Rect):Void { this.current.setOffset(offset); diff --git a/geometrize/bitmap/Bitmap.hx b/geometrize/bitmap/Bitmap.hx index a0b5327..c38b7d7 100644 --- a/geometrize/bitmap/Bitmap.hx +++ b/geometrize/bitmap/Bitmap.hx @@ -4,93 +4,12 @@ import haxe.ds.Vector; import haxe.io.Bytes; import geometrize.Util; -class OffsetArea { - /** - * The width of the bitmap considering its offset, if any. - */ - public var width:Int; - - /** - * The height of the bitmap considering its offset, if any. - */ - public var height:Int; - - private var originalWidth:Int; - private var originalHeight:Int; - private var offsetX:Int; - private var offsetY:Int; - @:optional private var savedOffset:Util.Rect; - - /** - * Sets the bitmap offset, this is, a region inside relative to which pixel read and write operations are made. - * Calling this method without parameters will remove the offset and reset to default behavior. - **/ - public inline function setOffset(?offset:Util.Rect):Void { - if (offset == null) { - width = originalWidth; - height = originalHeight; - offsetX = 0; - offsetY = 0; - } else { - Sure.sure(offset.width>0); - Sure.sure(offset.x + offset.width <= originalWidth); - Sure.sure(offset.height > 0); - Sure.sure(offset.y + offset.height <= originalHeight); - Sure.sure(offset.x >= 0); - Sure.sure(offset.y >= 0); - width = offset.width; - height = offset.height; - offsetX = offset.x; - offsetY = offset.y; - } - } - - /** - * @returns current offset or null if none. - **/ - public inline function getOffSet() { - if(width!=originalWidth||height!=originalHeight||offsetX!=0||offsetY!=0){ - return {x:offsetX, y: offsetY, width: width, height: height }; - } - return null; - } - - /** - * Saves current offset overriding previous saves. - * @param reset if given it will also remove current offset. - */ - public function saveOffSet(?reset: Bool) { - savedOffset=getOffSet(); - if(reset){ - setOffset(); - } - } - - /** - * Restores previously saved offset, if any. - */ - public function restoreOffset() { - if(savedOffset!=null){ - setOffset(savedOffset); - } - } - - private inline function getCoordsIndex(x:Int, y:Int) { - var absoluteStart = offsetY * originalWidth + offsetX; - var absoluteIndex = (originalWidth * y) + x; - var index = absoluteStart + absoluteIndex ; - return index; - } - -} - /** * Helper class for working with bitmap data. * @author Sam Twidale (http://samcodes.co.uk/) */ @:expose class Bitmap extends OffsetArea { - /** * The bitmap data. */ @@ -194,7 +113,7 @@ class Bitmap extends OffsetArea { */ public inline function clone():Bitmap { var bitmap = createBitmapOfLength(originalWidth, originalHeight, data.length); - bitmap.setOffset(getOffSet()); + bitmap.setOffset(getOffSet()); for (i in 0...data.length) { bitmap.data.set(i, data.get(i)); } diff --git a/geometrize/bitmap/OffsetArea.hx b/geometrize/bitmap/OffsetArea.hx new file mode 100644 index 0000000..200b51f --- /dev/null +++ b/geometrize/bitmap/OffsetArea.hx @@ -0,0 +1,96 @@ +package geometrize.bitmap; + +import geometrize.Util; + +/** + * Base class implementing a rectangular area (originalWidth, originalHeight) with an + * internal rectangular offset (offsetX, offsetY, width, height). + **/ +class OffsetArea { + + /** + * The width of the bitmap considering its offset, if any. + */ + public var width:Int; + + /** + * The height of the bitmap considering its offset, if any. + */ + public var height:Int; + + private var originalWidth:Int; + private var originalHeight:Int; + private var offsetX:Int; + private var offsetY:Int; + @:optional private var savedOffset:Util.Rect; + + /** + * The algorithm will only consider a region of the entire bitmap. + * If null is passed it will reset the offset (default behaviour) + * New shapes will be generated randombly but only inside this region. + **/ + public inline function setOffset(?offset:Util.Rect):Void { + if (offset == null) { + width = originalWidth; + height = originalHeight; + offsetX = 0; + offsetY = 0; + } else { + Sure.sure(offset.width > 0); + Sure.sure(offset.x + offset.width <= originalWidth); + Sure.sure(offset.height > 0); + Sure.sure(offset.y + offset.height <= originalHeight); + Sure.sure(offset.x >= 0); + Sure.sure(offset.y >= 0); + width = offset.width; + height = offset.height; + offsetX = offset.x; + offsetY = offset.y; + } + } + + /** + * @returns current offset or null if none. + **/ + public inline function getOffSet() { + if (width != originalWidth || height != originalHeight || offsetX != 0 || offsetY != 0) { + return { + x: offsetX, + y: offsetY, + width: width, + height: height + }; + } + return null; + } + + /** + * Saves current offset overriding previous saves. + * @param reset if given it will also remove current offset. + */ + public function saveOffSet(?reset:Bool) { + savedOffset = getOffSet(); + if (reset) { + setOffset(); + } + } + + /** + * Restores previously saved offset, if any. + */ + public function restoreOffset() { + if (savedOffset != null) { + setOffset(savedOffset); + } + } + + /** + * Convert coordinates relative relative to the offset into absolute coordinatess. + **/ + private inline function getCoordsIndex(x:Int, y:Int) { + var absoluteStart = offsetY * originalWidth + offsetX; + var absoluteIndex = (originalWidth * y) + x; + var index = absoluteStart + absoluteIndex; + return index; + } +} diff --git a/geometrize/runner/ImageRunner.hx b/geometrize/runner/ImageRunner.hx index 68ed32b..2f2b1ce 100644 --- a/geometrize/runner/ImageRunner.hx +++ b/geometrize/runner/ImageRunner.hx @@ -28,6 +28,7 @@ class ImageRunner { /** * The algorithm will only consider a region of the entire bitmap. + * If null is passed it will reset the offset (default behaviour) * New shapes will be generated randombly but only inside this region. **/ public inline function setOffset(?offset:Util.Rect):Void { diff --git a/geometrize/shape/Ellipse.hx b/geometrize/shape/Ellipse.hx index 25c4dd5..74caf1f 100644 --- a/geometrize/shape/Ellipse.hx +++ b/geometrize/shape/Ellipse.hx @@ -26,13 +26,6 @@ class Ellipse implements Shape { this.yBound = yBound; } - public function translate(vector:Util.Point) { - x = x + vector.x; - rx = rx + vector.x; - y = y + vector.y; - ry = ry + vector.y; - } - public function rasterize():Array { var lines:Array = []; var aspect:Float = rx / ry; @@ -99,4 +92,11 @@ class Ellipse implements Shape { public function getSvgShapeData():String { return ""; } + + public function translate(vector:Util.Point) { + x = x + vector.x; + rx = rx + vector.x; + y = y + vector.y; + ry = ry + vector.y; + } } \ No newline at end of file diff --git a/geometrize/shape/Line.hx b/geometrize/shape/Line.hx index 9a3b94b..60eb820 100644 --- a/geometrize/shape/Line.hx +++ b/geometrize/shape/Line.hx @@ -27,12 +27,6 @@ class Line implements Shape { this.yBound = yBound; } - public function translate(vector:Util.Point) { - x1 = x1 + vector.x; - x2 = x2 + vector.x; - y1 = y1 + vector.y; - y2 = y2 + vector.y; - } public function rasterize():Array { var lines:Array = []; @@ -76,4 +70,11 @@ class Line implements Shape { public function getSvgShapeData():String { return ""; } + + public function translate(vector:Util.Point) { + x1 = x1 + vector.x; + x2 = x2 + vector.x; + y1 = y1 + vector.y; + y2 = y2 + vector.y; + } } \ No newline at end of file diff --git a/geometrize/shape/QuadraticBezier.hx b/geometrize/shape/QuadraticBezier.hx index 2837364..738aa2a 100644 --- a/geometrize/shape/QuadraticBezier.hx +++ b/geometrize/shape/QuadraticBezier.hx @@ -32,15 +32,6 @@ class QuadraticBezier implements Shape { this.yBound = yBound; } - public function translate(vector:Util.Point) { - x1 = x1 + vector.x; - x2 = x2 + vector.x; - cx = cx + vector.x; - cy = cy + vector.y; - y1 = y1 + vector.y; - y2 = y2 + vector.y; - } - public function rasterize():Array { var lines:Array = []; var points:Array = []; @@ -111,4 +102,13 @@ class QuadraticBezier implements Shape { public function getSvgShapeData():String { return ""; } + + public function translate(vector:Util.Point) { + x1 = x1 + vector.x; + x2 = x2 + vector.x; + cx = cx + vector.x; + cy = cy + vector.y; + y1 = y1 + vector.y; + y2 = y2 + vector.y; + } } \ No newline at end of file diff --git a/geometrize/shape/Rectangle.hx b/geometrize/shape/Rectangle.hx index 3e7095a..a7713a4 100644 --- a/geometrize/shape/Rectangle.hx +++ b/geometrize/shape/Rectangle.hx @@ -26,13 +26,6 @@ class Rectangle implements Shape { this.yBound = yBound; } - public function translate(vector:Util.Point) { - x1 = x1 + vector.x; - x2 = x2 + vector.x; - y1 = y1 + vector.y; - y2 = y2 + vector.y; - } - public function rasterize():Array { var lines:Array = []; var yMin:Int = Util.min(y1, y2); @@ -80,4 +73,11 @@ class Rectangle implements Shape { return ""; } + + public function translate(vector:Util.Point) { + x1 = x1 + vector.x; + x2 = x2 + vector.x; + y1 = y1 + vector.y; + y2 = y2 + vector.y; + } } diff --git a/geometrize/shape/RotatedEllipse.hx b/geometrize/shape/RotatedEllipse.hx index 27571f4..4f69b47 100644 --- a/geometrize/shape/RotatedEllipse.hx +++ b/geometrize/shape/RotatedEllipse.hx @@ -29,13 +29,6 @@ class RotatedEllipse implements Shape { this.yBound = yBound; } - public function translate(vector:Util.Point) { - x = x + vector.x; - rx = rx + vector.x; - y = y + vector.y; - ry = ry + vector.y; - } - public function rasterize():Array { var pointCount:Int = 20; var points:Array<{x : Int, y: Int}> = []; @@ -97,4 +90,12 @@ class RotatedEllipse implements Shape { s += ""; return s; } + + public function translate(vector:Util.Point) { + x = x + vector.x; + rx = rx + vector.x; + y = y + vector.y; + ry = ry + vector.y; + } + } \ No newline at end of file diff --git a/geometrize/shape/Triangle.hx b/geometrize/shape/Triangle.hx index 073e0bf..fcab441 100644 --- a/geometrize/shape/Triangle.hx +++ b/geometrize/shape/Triangle.hx @@ -31,15 +31,6 @@ class Triangle implements Shape { this.yBound = yBound; } - public function translate(vector:Util.Point) { - x1 = x1 + vector.x; - x2 = x2 + vector.x; - x3 = x3 + vector.x; - y1 = y1 + vector.y; - y2 = y2 + vector.y; - y3 = y3 + vector.y; - } - public function rasterize():Array { return Scanline.trim(Rasterizer.scanlinesForPolygon([ { x: x1, y: y1 }, { x: x2, y: y2 }, { x: x3, y: y3 } ]), xBound, yBound); } @@ -81,4 +72,13 @@ class Triangle implements Shape { public function getSvgShapeData():String { return ""; } + + public function translate(vector:Util.Point) { + x1 = x1 + vector.x; + x2 = x2 + vector.x; + x3 = x3 + vector.x; + y1 = y1 + vector.y; + y2 = y2 + vector.y; + y3 = y3 + vector.y; + } } \ No newline at end of file From fdd5debec64e36bfcf97c509c97ed7db22e6eef0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Gur=C3=ADn?= Date: Fri, 12 Jul 2019 03:33:27 -0300 Subject: [PATCH 8/8] getCoordsIndex public --- geometrize/bitmap/OffsetArea.hx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/geometrize/bitmap/OffsetArea.hx b/geometrize/bitmap/OffsetArea.hx index 200b51f..2011fdb 100644 --- a/geometrize/bitmap/OffsetArea.hx +++ b/geometrize/bitmap/OffsetArea.hx @@ -7,7 +7,7 @@ import geometrize.Util; * internal rectangular offset (offsetX, offsetY, width, height). **/ class OffsetArea { - + /** * The width of the bitmap considering its offset, if any. */ @@ -85,9 +85,9 @@ class OffsetArea { } /** - * Convert coordinates relative relative to the offset into absolute coordinatess. + * Convert coordinates relative to the offset into absolute coordinates in array index coordinates. **/ - private inline function getCoordsIndex(x:Int, y:Int) { + public inline function getCoordsIndex(x:Int, y:Int) { var absoluteStart = offsetY * originalWidth + offsetX; var absoluteIndex = (originalWidth * y) + x; var index = absoluteStart + absoluteIndex;