#include "pax.h" // ZFW Entry, fill pax first (pax+bag), rest is cargo void distribute(paxPayloadData_t* const targetPayload, const FuelData_t* const fuel, const double ZFWTarget, const UserData_t* const userData, const UserOptions_t* const userOptions) { // Find payload, num pax and extra cargo double payload = ZFWTarget - targetPayload->empty - targetPayload->pilot - targetPayload->firstOfficer - targetPayload->engineer - targetPayload->cabinCrewFront - targetPayload->cabinCrewRear - targetPayload->leftAux - targetPayload->rightAux; unsigned short numPax = max(0.0, min((double)MAX_PAX, floor(payload / (PAX_WEIGHT(userData->isImperial, userOptions) + BAG_WEIGHT(userData->isImperial, userOptions))))); unsigned int cargo = round(payload - numPax * PAX_WEIGHT(userData->isImperial, userOptions) - numPax * BAG_WEIGHT(userData->isImperial, userOptions)); distribute(targetPayload, fuel, numPax, cargo, userData, userOptions); } // SimBrief Entry, SB pax count and extra cargo void distribute(paxPayloadData_t* const targetPayload, const FuelData_t* const fuel, unsigned short numPax, unsigned int cargo, const UserData_t* const userData, const UserOptions_t* const userOptions) { // Clear targetPayload->paxCount.business1 = targetPayload->paxCount.business2 = targetPayload->paxCount.economy1 = targetPayload->paxCount.economy2 = targetPayload->paxCount.total = 0; targetPayload->forwardCargo = targetPayload->rearCargo = 0; unsigned short _numPax = 0; unsigned int count = MAX_PAX; // Initial distribution pax + bags while (numPax > 0 && count > 0) { if (numPax >= 4) { if (targetPayload->paxCount.business1 < MAX_BUSINESS_1) { targetPayload->paxCount.business1++; _numPax++; } if (targetPayload->paxCount.business2 < MAX_BUSINESS_2) { targetPayload->paxCount.business2++; _numPax++; } if (targetPayload->paxCount.economy1 < MAX_ECONOMY_1) { targetPayload->paxCount.economy1++; _numPax++; } if (targetPayload->paxCount.economy2 < MAX_ECONOMY_2) { targetPayload->paxCount.economy2++; _numPax++; } } else if (numPax == 3) { if (targetPayload->paxCount.business2 < MAX_BUSINESS_2) { targetPayload->paxCount.business2++; _numPax++; } if (targetPayload->paxCount.economy1 < MAX_ECONOMY_1) { targetPayload->paxCount.economy1++; _numPax++; } if (targetPayload->paxCount.economy2 < MAX_ECONOMY_2) { targetPayload->paxCount.economy2++; _numPax++; } } else if (numPax == 2) { if (targetPayload->paxCount.economy1 < MAX_ECONOMY_1) { targetPayload->paxCount.economy1++; _numPax++; } if (targetPayload->paxCount.economy2 < MAX_ECONOMY_2) { targetPayload->paxCount.economy2++; _numPax++; } } else if (numPax == 1) { if (targetPayload->paxCount.economy2 < MAX_ECONOMY_2) { targetPayload->paxCount.economy2++; _numPax++; } } numPax -= _numPax; targetPayload->paxCount.total += _numPax; if (_numPax % 2 == 0) { targetPayload->forwardCargo += (_numPax / 2) * BAG_WEIGHT(userData->isImperial, userOptions); targetPayload->rearCargo += (_numPax / 2) * BAG_WEIGHT(userData->isImperial, userOptions); } else { _numPax--; targetPayload->forwardCargo += (_numPax / 2 + 1) * BAG_WEIGHT(userData->isImperial, userOptions); targetPayload->rearCargo += (_numPax / 2) * BAG_WEIGHT(userData->isImperial, userOptions); } _numPax = 0; count--; } count = MAX_FRONT_CARGO(userData->isImperial); // Initial distibution of remaining cargo while (cargo > 0 && count > 0) { if (targetPayload->forwardCargo < MAX_FRONT_CARGO(userData->isImperial)) { targetPayload->forwardCargo++; cargo--; } if (targetPayload->rearCargo < MAX_REAR_CARGO(userData->isImperial, userData->isER) && cargo > 0) { targetPayload->rearCargo++; cargo--; } count--; } // Refinement pax count = MAX_PAX; while (count > 0) { generatePayload(targetPayload, userData->isImperial, userOptions); calculateCGs(targetPayload, fuel, &targetPayload->ZFWCG, &targetPayload->TOCG, userData->isImperial); // in front of target if (targetPayload->ZFWCG < targetPayload->CGTarget - CG_TOLERANCE) { if (targetPayload->paxCount.business1 > 0) { targetPayload->paxCount.business1--; } else if (targetPayload->paxCount.business2 > 0) { targetPayload->paxCount.business2--; } else if (targetPayload->paxCount.economy1 > 0) { targetPayload->paxCount.economy1--; } else { break; } if (targetPayload->paxCount.economy2 < MAX_ECONOMY_2) { targetPayload->paxCount.economy2++; } else if (targetPayload->paxCount.economy1 < MAX_ECONOMY_1) { targetPayload->paxCount.economy1++; } else if (targetPayload->paxCount.business2 < MAX_BUSINESS_2) { targetPayload->paxCount.business2++; } else { targetPayload->paxCount.business1++; } } // behind target else if (targetPayload->ZFWCG > targetPayload->CGTarget + CG_TOLERANCE) { if (targetPayload->paxCount.economy2 > 0) { targetPayload->paxCount.economy2--; } else if (targetPayload->paxCount.economy1 > 0) { targetPayload->paxCount.economy1--; } else if (targetPayload->paxCount.business2 > 0) { targetPayload->paxCount.business2--; } else { break; } if (targetPayload->paxCount.business1 < MAX_BUSINESS_1) { targetPayload->paxCount.business1++; } else if (targetPayload->paxCount.business2 < MAX_BUSINESS_2) { targetPayload->paxCount.business2++; } else if (targetPayload->paxCount.economy1 < MAX_ECONOMY_1) { targetPayload->paxCount.economy1++; } else { targetPayload->paxCount.economy2++; } } else { break; } count--; } // Refinement cargo count = MAX_FRONT_CARGO(userData->isImperial) + MAX_REAR_CARGO(userData->isImperial, userData->isER); while (count > 0) { generatePayload(targetPayload, userData->isImperial, userOptions); calculateCGs(targetPayload, fuel, &targetPayload->ZFWCG, &targetPayload->TOCG, userData->isImperial); // in front of target if (targetPayload->ZFWCG < targetPayload->CGTarget - CG_TOLERANCE) { if (targetPayload->forwardCargo > 0 && targetPayload->rearCargo < MAX_REAR_CARGO(userData->isImperial, userData->isER)) { if (targetPayload->forwardCargo > BAG_WEIGHT(userData->isImperial, userOptions) && targetPayload->rearCargo < MAX_FRONT_CARGO(userData->isImperial) - BAG_WEIGHT(userData->isImperial, userOptions)) { targetPayload->forwardCargo -= BAG_WEIGHT(userData->isImperial, userOptions); targetPayload->rearCargo += BAG_WEIGHT(userData->isImperial, userOptions); } else { targetPayload->forwardCargo--; targetPayload->rearCargo++; } } else { break; } } // behind target else if (targetPayload->ZFWCG > targetPayload->CGTarget + CG_TOLERANCE) { if (targetPayload->rearCargo > 0 && targetPayload->forwardCargo < MAX_FRONT_CARGO(userData->isImperial)) { if (targetPayload->rearCargo > BAG_WEIGHT(userData->isImperial, userOptions) && targetPayload->forwardCargo < MAX_REAR_CARGO(userData->isImperial, userData->isER) - BAG_WEIGHT(userData->isImperial, userOptions)) { targetPayload->rearCargo -= BAG_WEIGHT(userData->isImperial, userOptions); targetPayload->forwardCargo += BAG_WEIGHT(userData->isImperial, userOptions); } else { targetPayload->rearCargo--; targetPayload->forwardCargo++; } } else { break; } } else { break; } count--; } } // Updates pax stations with their respective weights // Used internally and used for Station Entry (pax only, cargo is set directly) void generatePayload(paxPayloadData_t* const targetPayload, const bool isImperial, const UserOptions_t* const userOptions) { targetPayload->business1Left = targetPayload->business1Center = targetPayload->business1Right = (targetPayload->paxCount.business1 / 3.0) * PAX_WEIGHT(isImperial, userOptions); targetPayload->business2Left = targetPayload->business2Center = targetPayload->business2Right = (targetPayload->paxCount.business2 / 3.0) * PAX_WEIGHT(isImperial, userOptions); targetPayload->economy1Left = targetPayload->economy1Center = targetPayload->economy1Right = (targetPayload->paxCount.economy1 / 3.0) * PAX_WEIGHT(isImperial, userOptions); targetPayload->economy2Left = targetPayload->economy2Center = targetPayload->economy2Right = (targetPayload->paxCount.economy2 / 3.0) * PAX_WEIGHT(isImperial, userOptions); targetPayload->total = targetPayload->empty + targetPayload->pilot + targetPayload->firstOfficer + targetPayload->engineer + targetPayload->cabinCrewFront + targetPayload->business1Left + targetPayload->business1Center + targetPayload->business1Right + targetPayload->business2Left + targetPayload->business2Center + targetPayload->business2Right + targetPayload->economy1Left + targetPayload->economy1Center + targetPayload->economy1Right + targetPayload->economy2Left + targetPayload->economy2Center + targetPayload->economy2Right + targetPayload->cabinCrewRear + targetPayload->forwardCargo + targetPayload->rearCargo + targetPayload->leftAux + targetPayload->rightAux; } // Normalise to Pounds // MANDATORY BEFORE SETTING WEIGHTS // USE ON COPY OF GLOBAL STATE ONLY void normalisePayload(paxPayloadData_t* const targetPayload, const bool isImperial) { targetPayload->empty = TO_POUNDS(isImperial, targetPayload->empty); targetPayload->pilot = TO_POUNDS(isImperial, targetPayload->pilot); targetPayload->firstOfficer = TO_POUNDS(isImperial, targetPayload->firstOfficer); targetPayload->engineer = TO_POUNDS(isImperial, targetPayload->engineer); targetPayload->cabinCrewFront = TO_POUNDS(isImperial, targetPayload->cabinCrewFront); targetPayload->business1Left = TO_POUNDS(isImperial, targetPayload->business1Left); targetPayload->business1Center = TO_POUNDS(isImperial, targetPayload->business1Center); targetPayload->business1Right = TO_POUNDS(isImperial, targetPayload->business1Right); targetPayload->business2Left = TO_POUNDS(isImperial, targetPayload->business2Left); targetPayload->business2Center = TO_POUNDS(isImperial, targetPayload->business2Center); targetPayload->business2Right = TO_POUNDS(isImperial, targetPayload->business2Right); targetPayload->economy1Left = TO_POUNDS(isImperial, targetPayload->economy1Left); targetPayload->economy1Center = TO_POUNDS(isImperial, targetPayload->economy1Center); targetPayload->economy1Right = TO_POUNDS(isImperial, targetPayload->economy1Right); targetPayload->economy2Left = TO_POUNDS(isImperial, targetPayload->economy2Left); targetPayload->economy2Center = TO_POUNDS(isImperial, targetPayload->economy2Center); targetPayload->economy2Right = TO_POUNDS(isImperial, targetPayload->economy2Right); targetPayload->cabinCrewRear = TO_POUNDS(isImperial, targetPayload->cabinCrewRear); targetPayload->forwardCargo = TO_POUNDS(isImperial, targetPayload->forwardCargo); targetPayload->rearCargo = TO_POUNDS(isImperial, targetPayload->rearCargo); targetPayload->leftAux = TO_POUNDS(isImperial, targetPayload->leftAux); targetPayload->rightAux = TO_POUNDS(isImperial, targetPayload->rightAux); } void calculateCGs(const paxPayloadData_t* const targetPayload, const FuelData_t* const fuel, double* const ZFWCG, double* const TOCG, const bool isImperial) { paxPayloadData_t localPayload = {}; memcpy(&localPayload, targetPayload, sizeof(localPayload)); normalisePayload(&localPayload, isImperial); double totalMoment = localPayload.empty * ARM_EMPTY + localPayload.pilot * ARM_PILOT + localPayload.firstOfficer * ARM_FIRST_OFFICER + localPayload.engineer * ARM_ENGINEER + localPayload.cabinCrewFront * ARM_PAX_CABIN_CREW_FRONT + localPayload.business1Left * ARM_PAX_BUSINESS1_LEFT + localPayload.business1Center * ARM_PAX_BUSINESS1_CENTER + localPayload.business1Right * ARM_PAX_BUSINESS1_RIGHT + localPayload.business2Left * ARM_PAX_BUSINESS2_LEFT + localPayload.business2Center * ARM_PAX_BUSINESS2_CENTER + localPayload.business2Right * ARM_PAX_BUSINESS2_RIGHT + localPayload.economy1Left * ARM_PAX_ECONOMY1_LEFT + localPayload.economy1Center * ARM_PAX_ECONOMY1_CENTER + localPayload.economy1Right * ARM_PAX_ECONOMY1_RIGHT + localPayload.economy2Left * ARM_PAX_ECONOMY2_LEFT + localPayload.economy2Center * ARM_PAX_ECONOMY2_CENTER + localPayload.economy2Right * ARM_PAX_ECONOMY2_RIGHT + localPayload.cabinCrewRear * ARM_PAX_CABIN_CREW_REAR + localPayload.forwardCargo * ARM_FORWARD_CARGO + localPayload.rearCargo * ARM_REAR_CARGO + localPayload.leftAux * ARM_LEFT_AUX + localPayload.rightAux * ARM_RIGHT_AUX; double totalWeight = localPayload.empty + localPayload.pilot + localPayload.firstOfficer + localPayload.engineer + localPayload.cabinCrewFront + localPayload.business1Left + localPayload.business1Center + localPayload.business1Right + localPayload.business2Left + localPayload.business2Center + localPayload.business2Right + localPayload.economy1Left + localPayload.economy1Center + localPayload.economy1Right + localPayload.economy2Left + localPayload.economy2Center + localPayload.economy2Right + localPayload.cabinCrewRear + localPayload.forwardCargo + localPayload.rearCargo + localPayload.leftAux + localPayload.rightAux; *ZFWCG = TO_PERCENT_MAC(totalMoment / totalWeight); totalMoment += fuel->main1 * ARM_MAIN1 + fuel->main3 * ARM_MAIN3 + fuel->main2 * ARM_MAIN2 + fuel->upperAux * ARM_UPPER_AUX + fuel->lowerAux * ARM_LOWER_AUX + fuel->main1Tip * ARM_MAIN1_TIP + fuel->main3Tip * ARM_MAIN3_TIP + fuel->tail * ARM_TAIL + fuel->forwardAux1 * ARM_FORWARD_AUX1 + fuel->forwardAux2 * ARM_FORWARD_AUX2; totalWeight += fuel->total; *TOCG = TO_PERCENT_MAC(totalMoment / totalWeight); } void load(const paxPayloadData_t* const targetPayload, const HANDLE simConnect, const bool isImperial) { paxPayloadData_t localPayload = {}; memcpy(&localPayload, targetPayload, sizeof(localPayload)); normalisePayload(&localPayload, isImperial); SimConnect_SetDataOnSimObject(simConnect, DATA_DEFINITION_PAYLOAD_PAX, SIMCONNECT_OBJECT_ID_USER, 0, 0, sizeof(paxPayloadDataSet_t), &localPayload); } void unload(const HANDLE simConnect, const bool isER) { paxPayloadDataSet_t localPayload = {}; localPayload.cabinCrewFront = FRONT_CREW_WEIGHT(true); localPayload.cabinCrewRear = REAR_CREW_WEIGHT(true); localPayload.leftAux = localPayload.rightAux = isER ? AUX_WEIGHT(true) : 0; localPayload.pilot = localPayload.firstOfficer = localPayload.engineer = PILOT_WEIGHT(true); SimConnect_SetDataOnSimObject(simConnect, DATA_DEFINITION_PAYLOAD_PAX, SIMCONNECT_OBJECT_ID_USER, 0, 0, sizeof(paxPayloadDataSet_t), &localPayload); } const double PAX_WEIGHT(const bool isImperial, const UserOptions_t* const options) { return (isImperial) ? (options->paxWeightLBS) : (options->paxWeightKG); } const double BAG_WEIGHT(const bool isImperial, const UserOptions_t* const options) { return (isImperial) ? (options->bagWeightLBS) : (options->bagWeightKG); }