1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
|
//
// BOMController.swift
// ShedCalc
//
// Created by Jacky Jack on 01/08/2026.
//
import SwiftUI
import Combine
private func roundUpPieces(_ value: Float) -> Int {
Int(value.rounded(.up))
}
private func roundUpPieces(_ value: Double) -> Int {
Int(value.rounded(.up))
}
struct MaterialItem: Identifiable {
let materialName: String
let pricePerMeter: Double
let totalMeters: Double
let totalPrice: Double
let metersPerPiece: Double
let totalPieces: Double
let id = UUID()
}
class BOMController {
func calcBOM(from paramModel: ParamModel) -> [MaterialItem] {
var items: [MaterialItem] = []
items.append(calcOSB(from: paramModel))
items.append(calcWallTimber2x4(from: paramModel))
items.append(calcFloorTimber2x4(from: paramModel))
items.append(calcRoofTimber2x4(from: paramModel))
items.append(calcRoofFelt(from: paramModel))
items.append(calcWeatherWrap(from: paramModel))
items.append(calcCladding(from: paramModel))
return items
}
private func calcOSB(from paramModel: ParamModel) -> MaterialItem {
let totalOSBarea = paramModel.floorArea()
let OSBPrice = totalOSBarea*paramModel.OSBSheetPrice
let OSBPricePerMeter = paramModel.OSBSheetPrice / (1.2*2.4)
let totalPieces = roundUpPieces(totalOSBarea / (1.2*2.4))
return MaterialItem(
materialName: "OSB",
pricePerMeter: Double(OSBPricePerMeter),
totalMeters: Double(totalOSBarea),
totalPrice: Double(totalPieces)*Double(paramModel.OSBSheetPrice),
metersPerPiece:Double(paramModel.OSBSheetPrice),
totalPieces: Double(totalPieces))
}
private func calcWallTimber2x4(from paramModel: ParamModel) -> MaterialItem {
let totalLength = paramModel.totalWallBeamLength()
let timberBeamPrice = paramModel.timberBeamPrice
let totalPrice = totalLength*timberBeamPrice
let pieceSize = paramModel.timberLengthSize
let totalPieces = roundUpPieces(totalLength/pieceSize)
return MaterialItem(
materialName: "2x4",
pricePerMeter: Double(timberBeamPrice),
totalMeters: Double(totalLength),
totalPrice: Double(totalPrice),
metersPerPiece:Double(pieceSize),
totalPieces: Double(totalPieces)
)
}
private func calcFloorTimber2x4(from paramModel: ParamModel) -> MaterialItem {
let joistLength = paramModel.totalJoistBeamLength() * 2
let spacersLength = Double(paramModel.lengthBeamNum())*paramModel.beamSpace
let timberBeamPrice = paramModel.timberBeamPrice
let totalLength = Double(paramModel.lengthBeamNum())*paramModel.beamSpace
let totalPrice = totalLength*timberBeamPrice
let pieceSize = Double(paramModel.timberLengthSize)
let totalPieces = roundUpPieces(totalLength/pieceSize)
return MaterialItem(
materialName: "Floor 2x4",
pricePerMeter: Double(timberBeamPrice),
totalMeters: Double(totalLength),
totalPrice: Double(totalPrice),
metersPerPiece:Double(pieceSize),
totalPieces: Double(totalPieces)
)
}
private func calcRoofTimber2x4(from paramModel: ParamModel) -> MaterialItem {
let joistLength = paramModel.totalJoistBeamLength() * 2
let spacersLength = Double(paramModel.lengthBeamNum())*paramModel.beamSpace
let timberBeamPrice = paramModel.timberBeamPrice
let totalLength = Double(paramModel.lengthBeamNum())*paramModel.beamSpace
let totalPrice = totalLength*timberBeamPrice
let pieceSize = Double(paramModel.timberLengthSize)
let totalPieces = roundUpPieces(totalLength/pieceSize)
return MaterialItem(
materialName: "Roof 2x4",
pricePerMeter: Double(timberBeamPrice),
totalMeters: Double(totalLength),
totalPrice: Double(totalPrice),
metersPerPiece:Double(pieceSize),
totalPieces: Double(totalPieces)
)
}
private func calcRoofFelt(from paramModel: ParamModel) -> MaterialItem {
let roofArea = paramModel.roofArea()
let feltRollArea = Double(paramModel.feltWidth)*Double(paramModel.feltLength)
var feltPricePerMeter:Double = 0.0
if paramModel.feltPrice > 0.0 {
feltPricePerMeter = Double(paramModel.feltPrice) / feltRollArea
}
let totalPieces = roundUpPieces(Double(roofArea)/Double(feltRollArea))
let totalPrice = Double(totalPieces) * paramModel.feltPrice
return MaterialItem(
materialName: "Roof Felt",
pricePerMeter: Double(feltPricePerMeter),
totalMeters: Double(roofArea),
totalPrice: Double(totalPrice),
metersPerPiece:Double(feltRollArea),
totalPieces: Double(totalPieces)
)
}
private func calcWeatherWrap(from paramModel: ParamModel) -> MaterialItem {
return MaterialItem(
materialName: "Weather Wrap",
pricePerMeter: Double(0.1),
totalMeters: Double(0.1),
totalPrice: Double(0.1),
metersPerPiece:Double(0.1),
totalPieces: Double(0.1)
)
}
private func calcCladding(from paramModel: ParamModel) -> MaterialItem {
let wallArea = Double(paramModel.length*paramModel.height)*2 + Double(paramModel.width*paramModel.height)*2
let singleCladArea = paramModel.claddingLength * (Double(paramModel.claddingWidth) - paramModel.claddingOverlap)
let claddingPieces = wallArea/singleCladArea
let totalPieces = roundUpPieces(claddingPieces)
let totalPrice = Double(totalPieces) * paramModel.claddingPrice
return MaterialItem(
materialName: "Cladding",
pricePerMeter: Double(paramModel.claddingPrice),
totalMeters: Double(claddingPieces*paramModel.claddingLength),
totalPrice: Double(totalPrice),
metersPerPiece:Double(paramModel.claddingLength),
totalPieces: Double(totalPieces)
)
}
private func calcBeam(from paramModel: ParamModel) -> MaterialItem {
return MaterialItem(materialName: "2x4", pricePerMeter: 1.0, totalMeters: 10, totalPrice: 100, metersPerPiece: 1.2, totalPieces: 11.2)
}
}
|