def perform(level, box, options):

    logging.info("BoundingBox coordinates: ({},{}),({},{}),({},{})".format(
        box.miny, box.maxy, box.minx, box.maxx, box.minz, box.maxz))

    # ==== PREPARATION =====
    (width, height, depth) = utilityFunctions.getBoxSize(box)
    logging.info("Selection box dimensions {}, {}, {}".format(
        width, height, depth))
    world = utilityFunctions.generateMatrix(level, box, width, depth, height)
    world_space = utilityFunctions.dotdict({
        "y_min": 0,
        "y_max": height - 1,
        "x_min": 0,
        "x_max": width - 1,
        "z_min": 0,
        "z_max": depth - 1
    })
    height_map = utilityFunctions.getHeightMap(level, box)

    # ==== PARTITIONING OF NEIGHBOURHOODS ====
    (center,
     neighbourhoods) = generateCenterAndNeighbourhood(world_space, height_map)
    all_buildings = []

    # ====  GENERATING CITY CENTER ====
    minimum_h = 50
    minimum_w = 25
    mininum_d = 25

    iterate = 100
    minimum_lots = 6
    available_lots = 0
    maximum_tries = 50
    current_try = 0
    threshold = 1
    partitioning_list = []
    temp_partitioning_list = []

    # run the partitioning algorithm for iterate times to get different partitionings of the same area
    logging.info(
        "Generating {} different partitionings for the the City Centre {}".
        format(iterate, center))
    while available_lots < minimum_lots and current_try < maximum_tries:

        for i in range(iterate):

            # generate a partitioning through some algorithm
            if RNG.random() < 0.5:
                partitioning = binarySpacePartitioning(center[0], center[1],
                                                       center[2], center[3],
                                                       center[4], center[5],
                                                       [])
            else:
                partitioning = quadtreeSpacePartitioning(
                    center[0], center[1], center[2], center[3], center[4],
                    center[5], [])

            # remove invalid partitions from the partitioning
            valid_partitioning = []
            for p in partitioning:
                (y_min, y_max, x_min, x_max, z_min, z_max) = (p[0], p[1], p[2],
                                                              p[3], p[4], p[5])
                failed_conditions = []
                cond1 = utilityFunctions.hasValidGroundBlocks(
                    x_min, x_max, z_min, z_max, height_map)
                if cond1 == False: failed_conditions.append(1)
                cond2 = utilityFunctions.hasMinimumSize(
                    y_min, y_max, x_min, x_max, z_min, z_max, minimum_h,
                    minimum_w, mininum_d)
                if cond2 == False: failed_conditions.append(2)
                cond3 = utilityFunctions.hasAcceptableSteepness(
                    x_min, x_max, z_min, z_max, height_map,
                    utilityFunctions.getScoreArea_type1, threshold)
                if cond3 == False: failed_conditions.append(3)
                if cond1 and cond2 and cond3:
                    score = utilityFunctions.getScoreArea_type1(
                        height_map, x_min, x_max, z_min, z_max)
                    valid_partitioning.append((score, p))
                else:
                    logging.info(
                        "Failed Conditions {}".format(failed_conditions))

            partitioning_list.extend(valid_partitioning)
            logging.info(
                "Generated a partition with {} valid lots and {} invalids ones"
                .format(len(valid_partitioning),
                        len(partitioning) - len(valid_partitioning)))

        # order partitions by steepness
        partitioning_list = sorted(partitioning_list)
        final_partitioning = utilityFunctions.getNonIntersectingPartitions(
            partitioning_list)

        available_lots = len(final_partitioning)
        logging.info(
            "Current partitioning with most available_lots: {}, current threshold {}"
            .format(available_lots, threshold))

        threshold += 1
        current_try += 1

    logging.info("Final lots ({}) for the City Centre {}: ".format(
        len(final_partitioning), center))
    for p in final_partitioning:
        logging.info("\t{}".format(p))

    for partition in final_partitioning:
        building = generateBuilding(world, partition, height_map)
        all_buildings.append(building)

    # ==== GENERATING NEIGHBOURHOODS ====

    minimum_h = 3
    minimum_w = 7
    mininum_d = 6

    iterate = 100
    maximum_tries = 50
    current_try = 0
    minimum_lots = 20
    available_lots = 0
    threshold = 1
    partitioning_list = []
    final_partitioning = []

    while available_lots < minimum_lots and current_try < maximum_tries:
        partitioning_list = []
        for i in range(iterate):
            for neigh in neighbourhoods:
                logging.info(
                    "Generating {} different partitionings for the neighbourhood {}"
                    .format(iterate, neigh))

                if RNG.random() < 0.5:
                    partitioning = binarySpacePartitioning(
                        neigh[0], neigh[1], neigh[2], neigh[3], neigh[4],
                        neigh[5], [])
                else:
                    partitioning = quadtreeSpacePartitioning(
                        neigh[0], neigh[1], neigh[2], neigh[3], neigh[4],
                        neigh[5], [])

                valid_partitioning = []
                for p in partitioning:
                    (y_min, y_max, x_min, x_max, z_min,
                     z_max) = (p[0], p[1], p[2], p[3], p[4], p[5])
                    failed_conditions = []
                    cond1 = utilityFunctions.hasValidGroundBlocks(
                        x_min, x_max, z_min, z_max, height_map)
                    if cond1 == False: failed_conditions.append(1)
                    cond2 = utilityFunctions.hasMinimumSize(
                        y_min, y_max, x_min, x_max, z_min, z_max, minimum_h,
                        minimum_w, mininum_d)
                    if cond2 == False: failed_conditions.append(2)
                    cond3 = utilityFunctions.hasAcceptableSteepness(
                        x_min, x_max, z_min, z_max, height_map,
                        utilityFunctions.getScoreArea_type1, threshold)
                    if cond3 == False: failed_conditions.append(3)
                    if cond1 and cond2 and cond3:
                        score = utilityFunctions.getScoreArea_type1(
                            height_map, x_min, x_max, z_min, z_max)
                        valid_partitioning.append((score, p))
                        logging.info("Passed the 3 conditions!")
                    else:
                        logging.info(
                            "Failed Conditions {}".format(failed_conditions))

                partitioning_list.extend(valid_partitioning)
                logging.info(
                    "Generated a partition with {} valid lots and {} invalids ones"
                    .format(len(valid_partitioning),
                            len(partitioning) - len(valid_partitioning)))

        temp_partitioning_list.extend(partitioning_list)
        # order partitions by steepness
        temp_partitioning_list = sorted(temp_partitioning_list)
        final_partitioning = utilityFunctions.getNonIntersectingPartitions(
            temp_partitioning_list)

        available_lots = len(final_partitioning)
        logging.info(
            "Current neighbourhood partitioning with most available_lots: {}, current threshold {}"
            .format(available_lots, threshold))

        threshold += 1
        current_try += 1

        logging.info("Final lots ({})for the neighbourhood {}: ".format(
            len(final_partitioning), neigh))
        for p in final_partitioning:
            logging.info("\t{}".format(p))

    for partition in final_partitioning:
        house = generateHouse(world, partition, height_map)
        all_buildings.append(house)

    # ==== GENERATE PATH MAP  ====
    # generate a path map that gives the cost of moving to each neighbouring cell
    pathMap = utilityFunctions.getPathMap(height_map, width, depth)

    # ==== CONNECTING BUILDINGS WITH ROADS  ====
    logging.info("Calling MST on {} buildings".format(len(all_buildings)))
    MST = utilityFunctions.getMST_Manhattan(all_buildings, pathMap, height_map)

    pavementBlockID = 4
    pavementBlockSubtype = 0
    for m in MST:
        p1 = m[1]
        p2 = m[2]
        logging.info("Pavement with distance {} between {} and {}".format(
            m[0], p1.entranceLot, p2.entranceLot))

        path = utilityFunctions.aStar(p1.entranceLot, p2.entranceLot, pathMap,
                                      height_map)
        if path != None:
            logging.info(
                "Found path between {} and {}. Generating road...".format(
                    p1.entranceLot, p2.entranceLot))
            GeneratePath.generatPath(world, path, height_map,
                                     (pavementBlockID, pavementBlockSubtype))
        else:
            logging.info(
                "Couldnt find path between {} and {}. Generating a straight road between them..."
                .format(p1.entranceLot, p2.entranceLot))
            GeneratePath.generatPath_StraightLine(
                world, p1.entranceLot[1], p1.entranceLot[2], p2.entranceLot[1],
                p2.entranceLot[2], height_map,
                (pavementBlockID, pavementBlockSubtype))

    # ==== UPDATE WORLD ====
    world.updateWorld()
Ejemplo n.º 2
0
def perform(level, box, options):

    logging.info("BoundingBox coordinates: ({},{}),({},{}),({},{})".format(
        box.miny, box.maxy, box.minx, box.maxx, box.minz, box.maxz))

    # ==== PREPARATION =====
    (width, height, depth) = utilityFunctions.getBoxSize(box)
    logging.info("Selection box dimensions {}, {}, {}".format(
        width, height, depth))
    world = utilityFunctions.generateMatrix(level, box, width, depth, height)
    world_space = utilityFunctions.dotdict({
        "y_min": 0,
        "y_max": height - 1,
        "x_min": 0,
        "x_max": width - 1,
        "z_min": 0,
        "z_max": depth - 1
    })
    height_map = utilityFunctions.getHeightMap(level, box, None, False)

    # === Wood quantity and Biome analyzer === #
    air_like = [
        0, 4, 5, 6, 20, 23, 29, 30, 35, 37, 38, 39, 40, 44, 46, 47, 50, 59, 66,
        83, 85, 86, 95, 102, 104, 105, 107, 126, 141, 142, 160, 175
    ]
    wood_height_map = utilityFunctions.getHeightMap(level, box, air_like, True)
    (usable_wood, biome) = EnvironmentAnalyzer.determinate_usable_wood(
        level, wood_height_map, box.minx, box.maxx, box.minz, box.maxz)

    # ===  City stats === #
    biome_with_well = ['Desert', 'Badlands']
    APARTMENT_SIZE = 2
    HOUSE_SIZE = 4
    GREENHOUSE_CAPACITY = 15
    inhabitants = 0
    greenhouse_count = 0
    well_count = 0

    # ==== PARTITIONING OF THE SELECTION IN AREA IN ORDER TO FLATTEN ====
    # Work in progress do not use
    #earthwork_height_map = utilityFunctions.getHeightMap(level,box, None, True)
    #area_partitioning_and_flattening(world_space, earthwork_height_map, world, biome)

    # ==== PARTITIONING OF NEIGHBOURHOODS ====
    (center,
     neighbourhoods) = generateCenterAndNeighbourhood(world_space, height_map)
    all_buildings = []

    # ====  GENERATING CITY CENTER ====
    minimum_h = 50
    minimum_w = 25
    mininum_d = 25

    iterate = 100
    minimum_lots = 6
    available_lots = 0
    maximum_tries = 50
    current_try = 0
    threshold = 1
    partitioning_list = []
    temp_partitioning_list = []

    # run the partitioning algorithm for iterate times to get different partitionings of the same area
    logging.info(
        "Generating {} different partitionings for the the City Centre {}".
        format(iterate, center))
    while available_lots < minimum_lots and current_try < maximum_tries:

        for i in range(iterate):

            # generate a partitioning through some algorithm
            if RNG.random() < 0.5:
                partitioning = binarySpacePartitioning(center[0], center[1],
                                                       center[2], center[3],
                                                       center[4], center[5],
                                                       [])
            else:
                partitioning = quadtreeSpacePartitioning(
                    center[0], center[1], center[2], center[3], center[4],
                    center[5], [])

            # remove invalid partitions from the partitioning
            valid_partitioning = []
            for p in partitioning:
                (y_min, y_max, x_min, x_max, z_min, z_max) = (p[0], p[1], p[2],
                                                              p[3], p[4], p[5])
                failed_conditions = []
                cond1 = utilityFunctions.hasValidGroundBlocks(
                    x_min, x_max, z_min, z_max, height_map)
                if cond1 == False: failed_conditions.append(1)
                cond2 = utilityFunctions.hasMinimumSize(
                    y_min, y_max, x_min, x_max, z_min, z_max, minimum_h,
                    minimum_w, mininum_d)
                if cond2 == False: failed_conditions.append(2)
                cond3 = utilityFunctions.hasAcceptableSteepness(
                    x_min, x_max, z_min, z_max, height_map,
                    utilityFunctions.getScoreArea_type1, threshold)
                if cond3 == False: failed_conditions.append(3)
                if cond1 and cond2 and cond3:
                    score = utilityFunctions.getScoreArea_type1(
                        height_map, x_min, x_max, z_min, z_max)
                    valid_partitioning.append((score, p))
                else:
                    logging.info(
                        "Failed Conditions {}".format(failed_conditions))

            partitioning_list.extend(valid_partitioning)
            logging.info(
                "Generated a partition with {} valid lots and {} invalids ones"
                .format(len(valid_partitioning),
                        len(partitioning) - len(valid_partitioning)))

        # order partitions by steepness
        partitioning_list = sorted(partitioning_list)
        final_partitioning = utilityFunctions.getNonIntersectingPartitions(
            partitioning_list)

        available_lots = len(final_partitioning)
        logging.info(
            "Current partitioning with most available_lots: {}, current threshold {}"
            .format(available_lots, threshold))

        threshold += 1
        current_try += 1

    logging.info("Final lots ({}) for the City Centre {}: ".format(
        len(final_partitioning), center))
    for p in final_partitioning:
        logging.info("\t{}".format(p))

    for partition in final_partitioning:
        building, apartments_inhabitants = generateBuilding(
            world, partition, height_map, usable_wood, biome)
        inhabitants += apartments_inhabitants
        all_buildings.append(building)

    # ==== GENERATING NEIGHBOURHOODS ====

    minimum_h = 10
    minimum_w = 16
    mininum_d = 16

    iterate = 100
    maximum_tries = 50
    current_try = 0
    minimum_lots = 20
    available_lots = 0
    threshold = 1
    partitioning_list = []
    final_partitioning = []

    while available_lots < minimum_lots and current_try < maximum_tries:
        partitioning_list = []
        for i in range(iterate):
            for neigh in neighbourhoods:
                logging.info(
                    "Generating {} different partitionings for the neighbourhood {}"
                    .format(iterate, neigh))

                if RNG.random() < 0.5:
                    partitioning = binarySpacePartitioning(
                        neigh[0], neigh[1], neigh[2], neigh[3], neigh[4],
                        neigh[5], [])
                else:
                    partitioning = quadtreeSpacePartitioning(
                        neigh[0], neigh[1], neigh[2], neigh[3], neigh[4],
                        neigh[5], [])

                valid_partitioning = []
                for p in partitioning:
                    (y_min, y_max, x_min, x_max, z_min,
                     z_max) = (p[0], p[1], p[2], p[3], p[4], p[5])
                    failed_conditions = []
                    cond1 = utilityFunctions.hasValidGroundBlocks(
                        x_min, x_max, z_min, z_max, height_map)
                    if cond1 == False: failed_conditions.append(1)
                    cond2 = utilityFunctions.hasMinimumSize(
                        y_min, y_max, x_min, x_max, z_min, z_max, minimum_h,
                        minimum_w, mininum_d)
                    if cond2 == False: failed_conditions.append(2)
                    cond3 = utilityFunctions.hasAcceptableSteepness(
                        x_min, x_max, z_min, z_max, height_map,
                        utilityFunctions.getScoreArea_type1, threshold)
                    if cond3 == False: failed_conditions.append(3)
                    if cond1 and cond2 and cond3:
                        score = utilityFunctions.getScoreArea_type1(
                            height_map, x_min, x_max, z_min, z_max)
                        valid_partitioning.append((score, p))
                        logging.info("Passed the 3 conditions!")
                    else:
                        logging.info(
                            "Failed Conditions {}".format(failed_conditions))

                partitioning_list.extend(valid_partitioning)
                logging.info(
                    "Generated a partition with {} valid lots and {} invalids ones"
                    .format(len(valid_partitioning),
                            len(partitioning) - len(valid_partitioning)))

        temp_partitioning_list.extend(partitioning_list)
        # order partitions by steepness
        temp_partitioning_list = sorted(temp_partitioning_list)
        final_partitioning = utilityFunctions.getNonIntersectingPartitions(
            temp_partitioning_list)

        available_lots = len(final_partitioning)
        logging.info(
            "Current neighbourhood partitioning with most available_lots: {}, current threshold {}"
            .format(available_lots, threshold))

        threshold += 1
        current_try += 1

        logging.info("Final lots ({})for the neighbourhood {}: ".format(
            len(final_partitioning), neigh))
        for p in final_partitioning:
            logging.info("\t{}".format(p))

    for partition in final_partitioning:
        if well_count < 1 and biome in biome_with_well:
            well = generateWell(world, partition, height_map, biome)
            well_count += 1
            all_buildings.append(well)
        elif greenhouse_count * GREENHOUSE_CAPACITY < inhabitants:
            greenhouse = generateGreenhouse(world, partition, height_map,
                                            usable_wood, biome)
            greenhouse_count += 1
            all_buildings.append(greenhouse)
        else:
            house = generateHouse(world, partition, height_map, usable_wood,
                                  biome)
            inhabitants += RNG.randint(1, HOUSE_SIZE)
            all_buildings.append(house)

    # ==== GENERATE PATH MAP  ====
    # generate a path map that gives the cost of moving to each neighbouring cell
    pathMap = utilityFunctions.getPathMap(height_map, width, depth)

    # ==== CONNECTING BUILDINGS WITH ROADS  ====
    logging.info("Calling MST on {} buildings".format(len(all_buildings)))
    MST = utilityFunctions.getMST_Manhattan(all_buildings, pathMap, height_map)

    pavementBlockID = BlocksInfo.getPavmentId(biome)
    for m in MST:
        p1 = m[1]
        p2 = m[2]
        logging.info("Pavement with distance {} between {} and {}".format(
            m[0], p1.entranceLot, p2.entranceLot))

        path = utilityFunctions.aStar(p1.entranceLot, p2.entranceLot, pathMap,
                                      height_map)
        if path != None:
            logging.info(
                "Found path between {} and {}. Generating road...".format(
                    p1.entranceLot, p2.entranceLot))
            GeneratePath.generatPath(world, path, height_map, pavementBlockID)
        else:
            logging.info(
                "Couldnt find path between {} and {}. Generating a straight road between them..."
                .format(p1.entranceLot, p2.entranceLot))
            GeneratePath.generatPath_StraightLine(world, p1.entranceLot[1],
                                                  p1.entranceLot[2],
                                                  p2.entranceLot[1],
                                                  p2.entranceLot[2],
                                                  height_map, pavementBlockID)

    # ==== UPDATE WORLD ====
    world.updateWorld()