added mixed building generation

This commit is contained in:
Grimsace
2026-02-06 09:01:09 -06:00
parent 1641360da9
commit 6eb4dad5c8
3 changed files with 188 additions and 4 deletions
+31 -1
View File
@@ -118,7 +118,11 @@ func GenerateBuildings(img *image.RGBA, width, height int, settings *Settings, r
// Attempt to create a building at the selected center
size := settings.MinBuildingSize + randSrc.Float64()*(settings.MaxBuildingSize-settings.MinBuildingSize)
pixels, ok := getBuildingPixels(center, size, settings.BuildingShape, isWater, isRoad, isBuilding, width, height, randSrc)
shape := settings.BuildingShape
if shape == "mixed" {
shape = chooseShape(randSrc, settings.BuildingShapeRatios)
}
pixels, ok := getBuildingPixels(center, size, shape, isWater, isRoad, isBuilding, width, height, randSrc)
if ok {
// If successful, draw the building and update data structures
for _, p := range pixels {
@@ -134,6 +138,32 @@ func GenerateBuildings(img *image.RGBA, width, height int, settings *Settings, r
return buildingPixels
}
// chooseShape selects a building shape based on the provided ratios.
func chooseShape(randSrc *rand.Rand, ratios map[string]float64) string {
// Create a slice of shapes and their cumulative weights
var shapes []string
var weights []float64
var cumulativeWeight float64
for shape, weight := range ratios {
shapes = append(shapes, shape)
cumulativeWeight += weight
weights = append(weights, cumulativeWeight)
}
// Generate a random number between 0 and the total weight
randNum := randSrc.Float64() * cumulativeWeight
// Find the shape corresponding to the random number
for i, weight := range weights {
if randNum < weight {
return shapes[i]
}
}
// Default to the first shape if something goes wrong
return shapes[0]
}
// getBuildingPixels determines the pixels for a single building based on its shape and checks for collisions.
func getBuildingPixels(center image.Point, size float64, shape string, isWater, isRoad, isBuilding map[image.Point]bool, width, height int, randSrc *rand.Rand) ([]image.Point, bool) {
var pixels []image.Point
+138 -1
View File
@@ -650,11 +650,147 @@ func main() {
buildingDistributionSlider.SetValue(settings.BuildingDistribution)
buildingShapeLabel := widget.NewLabel("Building Shape:")
buildingShapeSelect := widget.NewSelect([]string{"squares", "circles", "rectangles"}, func(s string) {
buildingShapeSelect := widget.NewSelect([]string{"squares", "circles", "rectangles", "mixed"}, func(s string) {
settings.BuildingShape = s
})
buildingShapeSelect.SetSelected(settings.BuildingShape)
// Create sliders for building shape ratios (visible only when "mixed" is selected)
squareRatioSlider := widget.NewSlider(0, 100)
circleRatioSlider := widget.NewSlider(0, 100)
rectangleRatioSlider := widget.NewSlider(0, 100)
squareRatioLabel := widget.NewLabel(fmt.Sprintf("Squares: %.0f%%", settings.BuildingShapeRatios["squares"]))
circleRatioLabel := widget.NewLabel(fmt.Sprintf("Circles: %.0f%%", settings.BuildingShapeRatios["circles"]))
rectangleRatioLabel := widget.NewLabel(fmt.Sprintf("Rectangles: %.0f%%", settings.BuildingShapeRatios["rectangles"]))
squareRatioSlider.SetValue(settings.BuildingShapeRatios["squares"])
circleRatioSlider.SetValue(settings.BuildingShapeRatios["circles"])
rectangleRatioSlider.SetValue(settings.BuildingShapeRatios["rectangles"])
ratioContainer := container.NewVBox(
squareRatioLabel,
squareRatioSlider,
circleRatioLabel,
circleRatioSlider,
rectangleRatioLabel,
rectangleRatioSlider,
)
updateRatioSliders := func() {
squareRatioSlider.SetValue(settings.BuildingShapeRatios["squares"])
circleRatioSlider.SetValue(settings.BuildingShapeRatios["circles"])
rectangleRatioSlider.SetValue(settings.BuildingShapeRatios["rectangles"])
squareRatioLabel.SetText(fmt.Sprintf("Squares: %.0f%%", settings.BuildingShapeRatios["squares"]))
circleRatioLabel.SetText(fmt.Sprintf("Circles: %.0f%%", settings.BuildingShapeRatios["circles"]))
rectangleRatioLabel.SetText(fmt.Sprintf("Rectangles: %.0f%%", settings.BuildingShapeRatios["rectangles"]))
}
squareRatioSlider.OnChanged = func(val float64) {
if settings.BuildingShape != "mixed" {
return
}
oldVal := settings.BuildingShapeRatios["squares"]
diff := val - oldVal
settings.BuildingShapeRatios["squares"] = val
settings.BuildingShapeRatios["circles"] -= diff / 2
settings.BuildingShapeRatios["rectangles"] -= diff / 2
// Clamp values to 0-100 range
if settings.BuildingShapeRatios["circles"] < 0 {
settings.BuildingShapeRatios["rectangles"] += settings.BuildingShapeRatios["circles"]
settings.BuildingShapeRatios["circles"] = 0
}
if settings.BuildingShapeRatios["rectangles"] < 0 {
settings.BuildingShapeRatios["circles"] += settings.BuildingShapeRatios["rectangles"]
settings.BuildingShapeRatios["rectangles"] = 0
}
if settings.BuildingShapeRatios["circles"] > 100 {
settings.BuildingShapeRatios["rectangles"] += settings.BuildingShapeRatios["circles"] - 100
settings.BuildingShapeRatios["circles"] = 100
}
if settings.BuildingShapeRatios["rectangles"] > 100 {
settings.BuildingShapeRatios["circles"] += settings.BuildingShapeRatios["rectangles"] - 100
settings.BuildingShapeRatios["rectangles"] = 100
}
updateRatioSliders()
}
circleRatioSlider.OnChanged = func(val float64) {
if settings.BuildingShape != "mixed" {
return
}
oldVal := settings.BuildingShapeRatios["circles"]
diff := val - oldVal
settings.BuildingShapeRatios["circles"] = val
settings.BuildingShapeRatios["squares"] -= diff / 2
settings.BuildingShapeRatios["rectangles"] -= diff / 2
// Clamp values to 0-100 range
if settings.BuildingShapeRatios["squares"] < 0 {
settings.BuildingShapeRatios["rectangles"] += settings.BuildingShapeRatios["squares"]
settings.BuildingShapeRatios["squares"] = 0
}
if settings.BuildingShapeRatios["rectangles"] < 0 {
settings.BuildingShapeRatios["squares"] += settings.BuildingShapeRatios["rectangles"]
settings.BuildingShapeRatios["rectangles"] = 0
}
if settings.BuildingShapeRatios["squares"] > 100 {
settings.BuildingShapeRatios["rectangles"] += settings.BuildingShapeRatios["squares"] - 100
settings.BuildingShapeRatios["squares"] = 100
}
if settings.BuildingShapeRatios["rectangles"] > 100 {
settings.BuildingShapeRatios["squares"] += settings.BuildingShapeRatios["rectangles"] - 100
settings.BuildingShapeRatios["rectangles"] = 100
}
updateRatioSliders()
}
rectangleRatioSlider.OnChanged = func(val float64) {
if settings.BuildingShape != "mixed" {
return
}
oldVal := settings.BuildingShapeRatios["rectangles"]
diff := val - oldVal
settings.BuildingShapeRatios["rectangles"] = val
settings.BuildingShapeRatios["squares"] -= diff / 2
settings.BuildingShapeRatios["circles"] -= diff / 2
// Clamp values to 0-100 range
if settings.BuildingShapeRatios["squares"] < 0 {
settings.BuildingShapeRatios["circles"] += settings.BuildingShapeRatios["squares"]
settings.BuildingShapeRatios["squares"] = 0
}
if settings.BuildingShapeRatios["circles"] < 0 {
settings.BuildingShapeRatios["squares"] += settings.BuildingShapeRatios["circles"]
settings.BuildingShapeRatios["circles"] = 0
}
if settings.BuildingShapeRatios["squares"] > 100 {
settings.BuildingShapeRatios["circles"] += settings.BuildingShapeRatios["squares"] - 100
settings.BuildingShapeRatios["squares"] = 100
}
if settings.BuildingShapeRatios["circles"] > 100 {
settings.BuildingShapeRatios["squares"] += settings.BuildingShapeRatios["circles"] - 100
settings.BuildingShapeRatios["circles"] = 100
}
updateRatioSliders()
}
buildingShapeSelect.OnChanged = func(s string) {
settings.BuildingShape = s
if s == "mixed" {
ratioContainer.Show()
} else {
ratioContainer.Hide()
}
}
// Initial visibility check
if settings.BuildingShape != "mixed" {
ratioContainer.Hide()
}
buildingsTab := container.NewTabItem("Buildings", container.NewVBox(
numBuildingsLabel,
numBuildingsSlider,
@@ -666,6 +802,7 @@ func main() {
buildingDistributionSlider,
buildingShapeLabel,
buildingShapeSelect,
ratioContainer,
))
imageTab := container.NewTabItem("Image", container.NewVBox(
+19 -2
View File
@@ -45,6 +45,9 @@ type Settings struct {
BuildingDistribution float64 `json:"building_distribution"`
BuildingShape string `json:"building_shape"`
// Ratios for mixed building shapes
BuildingShapeRatios map[string]float64 `json:"building_shape_ratios"`
// General settings
Seed int64 `json:"seed"`
LastExportPath string `json:"last_export_path"`
@@ -123,8 +126,13 @@ func LoadSettings() (*Settings, error) {
MinBuildingSize: 10,
MaxBuildingSize: 30,
BuildingDistribution: 20,
BuildingShape: "squares",
LastExportPath: homeDir,
BuildingShape: "mixed",
BuildingShapeRatios: map[string]float64{
"squares": 40,
"circles": 30,
"rectangles": 30,
},
LastExportPath: homeDir,
}, nil
}
return nil, err
@@ -138,6 +146,15 @@ func LoadSettings() (*Settings, error) {
return nil, err
}
// Ensure BuildingShapeRatios is initialized
if settings.BuildingShapeRatios == nil {
settings.BuildingShapeRatios = map[string]float64{
"squares": 40,
"circles": 30,
"rectangles": 30,
}
}
// Ensure LastExportPath is set to a default value if it's empty
if settings.LastExportPath == "" {
homeDir, err := os.UserHomeDir()