RectangleFoundation RectangleFromJunction(Junction j, Vector3 axis, int maxAlongEdge, int maxAlongAxis)
    {
        int     alongAxis = Randomiser.intBetweenEven(minLengthR, maxLengthR);
        Vector3 center    = j.position + alongAxis / 2f * axis;
        int     alongEdge = Randomiser.intBetweenEven((int)(alongAxis * minRatio), (int)(alongAxis * maxRatio));

        alongEdge = Randomiser.clampInRange(alongEdge, minLengthR, maxAlongEdge);
        Vector3[] corners = new Vector3[4];
        corners [0] = j.position + GenericUtils.rotateClockwise(axis) * (-1) * alongEdge / 2f;
        corners [1] = corners [0] + axis * alongAxis;
        corners [2] = corners [1] + GenericUtils.rotateClockwise(axis) * alongEdge;
        corners [3] = corners [2] + axis * alongAxis * (-1);
        if (axis.x != 0)
        {
            return(new RectangleFoundation(corners, center, alongAxis, alongEdge));
        }
        return(new RectangleFoundation(corners, center, alongEdge, alongAxis));
    }
    bool addNewMinaret()
    {
        Edge     curEdge      = freeEdges[Randomiser.intBetween(0, freeEdges.Count / 2)];
        Junction junction     = new Junction(Randomiser.pointOnEdge(curEdge), curEdge.axisDirection);
        Vector3  measurePoint = junction.position + 0.2f * curEdge.axisDirection;

        if (!checkJunction(measurePoint))
        {
            return(false);
        }
        int distanceAlongEdge = Mathf.Min(
            Randomiser.measureDistance(measurePoint, GenericUtils.rotateClockwise(curEdge.axisDirection), maxLengthR / 2),
            Randomiser.measureDistance(measurePoint, -1 * GenericUtils.rotateClockwise(curEdge.axisDirection), maxLengthR / 2)
            );

        if (distanceAlongEdge < minLengthS)
        {
            return(false);
        }
        int distanceAlongAxis = Randomiser.measureDistance(measurePoint, curEdge.axisDirection, minaretSize);

        if (distanceAlongAxis * 2 < minaretSize)
        {
            return(false);
        }
        distanceAlongAxis = Randomiser.clampInRange(distanceAlongAxis, minaretSize, (int)(distanceAlongEdge * 2));
        MinaretFoundation minaret = minaretFromJunction(junction, curEdge.axisDirection, Mathf.Min(distanceAlongEdge * 2, distanceAlongAxis));

        if (!checkMinaretConsistency(minaret))
        {
            minaret.delete();
            return(false);
        }
        if (!checkOverlaps(minaret))
        {
            minaret.delete();
            return(false);
        }
        minarets.Add(minaret);
        freeEdges.Remove(curEdge);
        usedEdges.Add(curEdge);
        return(true);
    }
    void generateFirstRect()
    {
        int l1 = Randomiser.intBetweenEven(minLengthR, maxLengthR);
        int l2 = Randomiser.intBetweenEven((int)(l1 * minRatio), (int)(l1 * maxRatio));

        l2 = Randomiser.clampInRange(l2, minLengthR, maxLengthR);
        Vector3 center = Vector3.zero;

        Vector3[] corners = new Vector3[4];
        corners[0]  = center + (Vector3.forward * l1 / 2f) + (Vector3.left * l2 / 2f);
        corners [1] = corners [0] + Vector3.right * l2;
        corners [2] = corners [1] + Vector3.back * l1;
        corners[3]  = corners [2] + Vector3.left * l2;
        RectangleFoundation newRect = new RectangleFoundation(corners, center, l2, l1);

        rectangles.Add(newRect);
        freeEdges.AddRange(newRect.getEdges());
        freeCorners.AddRange(newRect.corners);
        allCorners.AddRange(newRect.corners);
    }
    bool addNewSquare()
    {
        Edge     curEdge      = freeEdges[Randomiser.intBetween(0, freeEdges.Count / 2)];
        Junction junction     = new Junction(Randomiser.pointOnEdge(curEdge), curEdge.axisDirection);
        Vector3  measurePoint = junction.position + 0.2f * curEdge.axisDirection;

        if (!checkJunction(measurePoint))
        {
            return(false);
        }
        int distanceAlongEdge = Mathf.Min(
            Randomiser.measureDistance(measurePoint, GenericUtils.rotateClockwise(curEdge.axisDirection), maxLengthR / 2),
            Randomiser.measureDistance(measurePoint, -1 * GenericUtils.rotateClockwise(curEdge.axisDirection), maxLengthR / 2)
            );

        if (distanceAlongEdge < minLengthS)
        {
            return(false);
        }
        int distanceAlongAxis = Randomiser.measureDistance(measurePoint, curEdge.axisDirection, maxLengthR);

        if (distanceAlongAxis * 2 < minLengthS)
        {
            return(false);
        }
        distanceAlongAxis = Randomiser.clampInRange(distanceAlongAxis, minLengthR, (int)(distanceAlongEdge * 2));
        SquareFoundation square = SquareFromJunction(junction, curEdge.axisDirection, Mathf.Min(distanceAlongEdge * 2, distanceAlongAxis));

        if (!checkSquareConsistency(square))
        {
            square.delete();
            return(false);
        }
        if (!checkOverlaps(square))
        {
            square.delete();
            return(false);
        }
        updateLists(square, curEdge, junction, squares, true, false);
        return(true);
    }