Source: utils/datastructures/GirihTile.js

"use strict";
/**
 * @classdesc This is a general tile superclass. All other tile classes extends this one.
 *
 * Rule:
 *  * the outer and the inner sub polygons must be inside the main polygon's bounds.
 *
 * @requires Bounds
 * @requires Polyon
 * @requires Vertex
 * @requires XYCoords
 *
 * @author   Ikaros Kappler
 * @date     2013-11-27
 * @modified 2014-04-05 Ikaros Kappler (member array outerTilePolygons added).
 * @modified 2015-03-19 Ikaros Kappler (added toSVG()).
 * @modified 2020-10-30 Refactored the this super class to work with PlotBoilerplate.
 * @modified 2020-11-11 Ported the class from vanilla JS to TypeScript.
 * @version  2.0.1-alpha
 * @name GirihTile
 **/
var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
var Bounds_1 = require("../../Bounds");
var Line_1 = require("../../Line");
var Polygon_1 = require("../../Polygon");
var Vertex_1 = require("../../Vertex");
var TileType;
(function (TileType) {
    TileType["UNKNOWN"] = "UNKNOWN";
    TileType["DECAGON"] = "DECAGON";
    TileType["PENTAGON"] = "PENTAGON";
    TileType["IRREGULAR_HEXAGON"] = "IRREGULAR_HEXAGON";
    TileType["RHOMBUS"] = "RHOMBUS";
    TileType["BOW_TIE"] = "BOW_TIE";
    // This is not part of the actual girih tile set!
    TileType["PENROSE_RHOMBUS"] = "PENROSE_RHOMBUS";
})(TileType = exports.TileType || (exports.TileType = {}));
;
;
var GirihTile = /** @class */ (function (_super) {
    __extends(GirihTile, _super);
    /**
     * @constructor
     * @memberof GirihTile
     * @abstract class
     * @param {Vertex} position   - The position of the tile.
     * @param {number} edgeLength - The edge length (usually GirihTile.DEFAULT_EDGE_LENGTH).
     * @param {TileType} tileType - One of `TileType.*` enum members.
     **/
    function GirihTile(position, edgeLength, tileType) {
        var _this = _super.call(this, [], false) || this;
        if (typeof tileType == "undefined")
            tileType = TileType.UNKNOWN;
        _this.edgeLength = edgeLength;
        _this.position = position;
        _this.rotation = 0.0; // angle;
        _this.symmetry = 10;
        _this.uniqueSymmetries = 10;
        // An array of polygons.
        // The inner tile polygons are those that do not share edges with the outer
        // tile bounds (vertices are OK).
        _this.innerTilePolygons = [];
        // A second array of polygons.
        // The outer tile polygons are those that make up the whole tile area
        // _together with the inner tile polygons (!)_; the union of the
        // inner tile polygons and the outer tile polygons covers exactly
        // the whole tile polygon.
        // The intersection of both sets is empty.
        // Outer tile polygon share at least one (partial) edge with the complete
        // tile polygon (length > 0).
        _this.outerTilePolygons = [];
        // this.imageProperties      = null;
        _this.textureSource = new Bounds_1.Bounds(new Vertex_1.Vertex(), new Vertex_1.Vertex());
        _this.tileType = tileType;
        return _this;
    }
    ;
    /**
     * Move this tile around (together will all inner polygons).
     * As this function overrides Polygon.move(...), the returned
     * instance (this) must be of type `Polygon`.
     *
     * @name move
     * @instance
     * @override
     * @memberof GirihTile
     * @param {XYCoords} amount
     * @return {Polygon} this
     */
    GirihTile.prototype.move = function (amount) {
        Polygon_1.Polygon.prototype.move.call(this, amount);
        for (var i in this.innerTilePolygons)
            this.innerTilePolygons[i].move(amount);
        for (var i in this.outerTilePolygons)
            this.outerTilePolygons[i].move(amount);
        this.position.add(amount);
        return this;
    };
    ;
    /**
     * Find the adjacent tile (given by the template tile)
     * Note that the tile itself will be modified (rotated and moved to the correct position).
     *
     * @name findAdjacentTilePosition
     * @memberof GirihTile
     * @instance
     * @param {number} edgeIndex - The edge number of the you you want to find adjacency for.
     * @param {Polygon} tile - The polygon (or tile) you want to find adjacency for at the specified edge.
     * @return {IAdjacency|null} Adjacency information or null if the passed tile does not match.
     */
    GirihTile.prototype.findAdjacentTilePosition = function (edgeIndex, tile) {
        var edgeA = new Line_1.Line(this.vertices[edgeIndex % this.vertices.length], this.vertices[(edgeIndex + 1) % this.vertices.length]);
        // Find adjacent edge
        for (var i = 0; i < tile.vertices.length; i++) {
            var edgeB = new Line_1.Line(tile.vertices[i % tile.vertices.length].clone(), tile.vertices[(i + 1) % tile.vertices.length].clone());
            // Goal: edgeA.a==edgeB.b && edgeA.b==edgeB.a
            // So move edgeB
            var offset = edgeB.b.difference(edgeA.a);
            edgeB.add(offset);
            if (edgeB.a.distance(edgeA.b) < GirihTile.epsilon) {
                return { edgeIndex: i, offset: offset };
            }
        }
        return null;
    };
    ;
    /**
     * Find all possible adjacent tile positions (and rotations) for `neighbourTile`.
     *
     * @name transformTileToAdjacencies
     * @memberof GirihTile
     * @instance
     * @param {number} baseEdgeIndex - The edge number of the you you want to find adjacencies for.
     * @param {GirihTile} neighbourTile - The polygon (or tile) you want to find adjacencies for at the specified edge.
     * @return {IAdjacency|null} Adjacency information or null if the passed tile does not match.
     */
    GirihTile.prototype.transformTileToAdjacencies = function (baseEdgeIndex, neighbourTile) {
        // Find a rotation for that tile to match
        var i = 0;
        var foundAlignments = [];
        var positionedTile = null;
        while (i < neighbourTile.uniqueSymmetries) {
            positionedTile = this.transformTilePositionToAdjacency(baseEdgeIndex, neighbourTile);
            if (positionedTile != null) {
                positionedTile = positionedTile.clone();
                foundAlignments.push(positionedTile);
            }
            neighbourTile.rotate((Math.PI * 2) / neighbourTile.symmetry);
            i++;
        }
        return foundAlignments;
    };
    ;
    /**
     * Apply adjacent tile position to `neighbourTile`.
     *
     * @name transformTilePositionToAdjacencies
     * @memberof GirihTile
     * @instance
     * @param {number} baseEdgeIndex - The edge number of the you you want to apply adjacent position for.
     * @param {Polygon} neighbourTile - The polygon (or tile) you want to find adjacency for at the specified edge.
     * @return {Polygon|null} the passed tile itself if adjacency was found, null otherwise.
     */
    GirihTile.prototype.transformTilePositionToAdjacency = function (baseEdgeIndex, neighbourTile) {
        // Find the position for that tile to match (might not exist)
        // { edgeIndex:number, offset:XYCoords }
        var adjacency = this.findAdjacentTilePosition(baseEdgeIndex, neighbourTile);
        if (adjacency != null) {
            neighbourTile.move(adjacency.offset);
            return neighbourTile;
        }
        return null;
    };
    ;
    /**
     * Get the inner tile polygon at the given index.
     * This function applies MOD to the index.
     *
     * @name getInnerTilePolygonAt
     * @instance
     * @memberof GirihTile
     * @param {number} index
     * @return {Polygon} The sub polygon (inner tile) at the given index.
     **/
    GirihTile.prototype.getInnerTilePolygonAt = function (index) {
        if (index < 0)
            return this.innerTilePolygons[this.innerTilePolygons.length - (Math.abs(index) % this.innerTilePolygons.length)];
        else
            return this.innerTilePolygons[index % this.innerTilePolygons.length];
    };
    ;
    /**
     * Get the outer tile polygon at the given index.
     * This function applies MOD to the index.
     *
     * @name getOuterTilePolygonAt
     * @instance
     * @memberof GirihTile
     * @param {number} index
     * @return {Polygon} The sub polygon (outer tile) at the given index.
     **/
    GirihTile.prototype.getOuterTilePolygonAt = function (index) {
        if (index < 0)
            return this.outerTilePolygons[this.outerTilePolygons.length - (Math.abs(index) % this.outerTilePolygons.length)];
        else
            return this.outerTilePolygons[index % this.outerTilePolygons.length];
    };
    ;
    /**
     * Rotate this tile
     * Note: this function behaves a bitdifferent than the genuine Polygon.rotate function!
     *       Polygon has the default center of rotation at (0,0).
     *       The GirihTile rotates around its center (position) by default.
     *
     * @name rotate
     * @instance
     * @memberof GirihTile
     * @param {number} angle - The angle to use for rotation.
     * @param {Vertex?} center - The center of rotation (default is this.position).
     * @return {Polygon} this
     **/
    GirihTile.prototype.rotate = function (angle, center) {
        if (typeof center === "undefined")
            center = this.position;
        _super.prototype.rotate.call(this, angle, center);
        for (var i in this.innerTilePolygons) {
            this.innerTilePolygons[i].rotate(angle, center);
        }
        for (var i in this.outerTilePolygons) {
            this.outerTilePolygons[i].rotate(angle, center);
        }
        this.rotation += angle;
        return this;
    };
    ;
    /**
     * This function locates the closest tile edge (polygon edge)
     * to the passed point.
     *
     * Currently the edge distance to a point is measured by the
     * euclidian distance from the edge's middle point.
     *
     * Idea: move this function to Polygon?
     *
     * @name locateEdgeAtPoint
     * @instance
     * @memberof GirihTile
     * @param {XYCoords} point     - The point to detect the closest edge for.
     * @param {number}   tolerance - The tolerance (=max distance) the detected edge
     *                               must be inside.
     * @return {nmber} the edge index (index of the starting vertex, so [index,index+1] is the edge ) or -1 if not found.
     **/
    GirihTile.prototype.locateEdgeAtPoint = function (point, tolerance) {
        if (this.vertices.length == 0)
            return -1;
        var middle = new Vertex_1.Vertex(0, 0);
        var tmpDistance = 0;
        var resultDistance = tolerance * 2; // definitely outside the tolerance :)
        var resultIndex = -1;
        for (var i = 0; i < this.vertices.length; i++) {
            var vertI = this.getVertexAt(i);
            var vertJ = this.getVertexAt(i + 1);
            // Create a point in the middle of the edge	
            middle.x = vertI.x + (vertJ.x - vertI.x) / 2.0;
            middle.y = vertI.y + (vertJ.y - vertI.y) / 2.0;
            tmpDistance = middle.distance(point);
            if (tmpDistance <= tolerance && (resultIndex == -1 || tmpDistance < resultDistance)) {
                resultDistance = tmpDistance;
                resultIndex = i;
            }
        }
        return resultIndex;
    };
    /**
     * An epsilon to use for detecting adjacent edges. 0.001 seems to be a good value.
     * Adjust if needed.
     *
     * @name epsilon
     * @member {number}
     * @memberof GirihTile
     * @type {number}
     * @static
     */
    GirihTile.epsilon = 0.001;
    /**
     * The default edge length.
     *
     * @name DEFAULT_EDGE_LENGTH
     * @member {number}
     * @memberof GirihTile
     * @type {number}
     * @readonly
     * @static
     */
    GirihTile.DEFAULT_EDGE_LENGTH = 58;
    return GirihTile;
}(Polygon_1.Polygon));
exports.GirihTile = GirihTile;
; // END class
//# sourceMappingURL=GirihTile.js.map