/** * Calculate how far tiles can be altered beyond a given paste area bound. * * When pasting, some tiles around the paste area may be altered (during terraforming). * The function return the limit on how far it can happen. Calculations are not exact, * the goal is to give a safe range that will include any possible case. * * Result is based on current and desired heights at neighbour corners of the paste area. * * @param curr_h1 Current height on the first corner. * @param curr_h2 Current height on the second corner. * @param new_h1 Desired height on the first corner. * @param new_h2 Desired height on the second corner. * @param length Distance (in tiles) between corners. * @return How far (in tiles) terraforming can reach beyond the given bound. * * @pre Tile heights and the length can't create an impossible layout, heights can't differ * too much: \n * <tt> Delta(curr_h1, curr_h2) <= length </tt> \n * <tt> Delta(new_h1, new_h2) <= length </tt> \n * * @see CopyPasteAreasMayColide */ static uint CalcMaxPasteRange(uint curr_h1, uint new_h1, uint curr_h2, uint new_h2, uint length) { uint min_curr_h = CeilDiv(max<int>(curr_h1 + curr_h2 - length, 0), 2); uint max_curr_h = min((curr_h1 + curr_h2 + length) / 2, MAX_TILE_HEIGHT); uint min_new_h = CeilDiv(max<int>(new_h1 + new_h2 - length, 0), 2); uint max_new_h = min((new_h1 + new_h2 + length) / 2, MAX_TILE_HEIGHT); return max(Delta(max_new_h, min_curr_h), Delta(max_curr_h, min_new_h)); }
/** * Send an update about a company. * @param c The company to send the update of. */ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCompanyUpdate(const Company *c) { char company_name[NETWORK_COMPANY_NAME_LENGTH]; char manager_name[NETWORK_COMPANY_NAME_LENGTH]; SetDParam(0, c->index); GetString(company_name, STR_COMPANY_NAME, lastof(company_name)); SetDParam(0, c->index); GetString(manager_name, STR_PRESIDENT_NAME, lastof(manager_name)); Packet *p = new Packet(ADMIN_PACKET_SERVER_COMPANY_UPDATE); p->Send_uint8 (c->index); p->Send_string(company_name); p->Send_string(manager_name); p->Send_uint8 (c->colour); p->Send_bool (NetworkCompanyIsPassworded(c->index)); p->Send_uint8 (CeilDiv(c->months_of_bankruptcy, 3)); // send as quarters_of_bankruptcy for (size_t i = 0; i < lengthof(c->share_owners); i++) { p->Send_uint8(c->share_owners[i]); } this->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; }
inline int PlatformLengthPenalty(int platform_length) { int cost = 0; const Train *v = Yapf().GetVehicle(); assert(v != NULL); assert(v->type == VEH_TRAIN); assert(v->gcache.cached_total_length != 0); int missing_platform_length = CeilDiv(v->gcache.cached_total_length, TILE_SIZE) - platform_length; if (missing_platform_length < 0) { /* apply penalty for longer platform than needed */ cost += Yapf().PfGetSettings().rail_longer_platform_penalty + Yapf().PfGetSettings().rail_longer_platform_per_tile_penalty * -missing_platform_length; } else if (missing_platform_length > 0) { /* apply penalty for shorter platform than needed */ cost += Yapf().PfGetSettings().rail_shorter_platform_penalty + Yapf().PfGetSettings().rail_shorter_platform_per_tile_penalty * missing_platform_length; } return cost; }
int cs_clipline(PSD psd,int *_x0, int *_y0, int *_x1, int *_y1, int *clip_first, int *clip_last) { int first,last, code; int x0,y0,x1,y1; int x,y; int dx,dy; int xmajor; int slope; int tempclipminx,tempclipminy,tempclipmaxx,tempclipmaxy; if (psd->doclip) { tempclipminx = psd->clipminx; tempclipminy = psd->clipminy; tempclipmaxx = psd->clipmaxx; tempclipmaxy = psd->clipmaxy; } else { tempclipminx = 0; tempclipminy = 0; tempclipmaxx = psd->xres - 1; tempclipmaxy = psd->yres - 1; } first = 0; last = 0; outcode(first,*_x0,*_y0); outcode(last,*_x1,*_y1); if ((first | last) == 0) { return CLIP_VISIBLE; /* Trivially accepted! */ } if ((first & last) != 0) { return CLIP_INVISIBLE; /* Trivially rejected! */ } x0=*_x0; y0=*_y0; x1=*_x1; y1=*_y1; dx = x1 - x0; dy = y1 - y0; xmajor = (abs(dx) > abs(dy)); slope = ((dx>=0) && (dy>=0)) || ((dx<0) && (dy<0)); for (;;) { code = first; if (first==0) code = last; if (code&OC_LEFT) { x = tempclipminx; if (xmajor) { y = *_y0 + FloorDiv(dy*(x - *_x0)*2 + dx, 2*dx); } else { if (slope) { y = *_y0 + CeilDiv(dy*((x - *_x0)*2 - 1), 2*dx); } else { y = *_y0 + FloorDiv(dy*((x - *_x0)*2 - 1), 2*dx); } } } else if (code&OC_RIGHT) { x = tempclipmaxx; if (xmajor) { y = *_y0 + FloorDiv(dy*(x - *_x0)*2 + dx, 2*dx); } else { if (slope) { y = *_y0 + CeilDiv(dy*((x - *_x0)*2 + 1), 2*dx)-1; } else { y = *_y0 + FloorDiv(dy*((x - *_x0)*2 + 1), 2*dx)+1; } } } else if (code&OC_TOP) { y = tempclipminy; if (xmajor) { if (slope) { x = *_x0 + CeilDiv(dx*((y - *_y0)*2 - 1), 2*dy); } else { x = *_x0 + FloorDiv(dx*((y - *_y0)*2 - 1), 2*dy); } } else { x = *_x0 + FloorDiv( dx*(y - *_y0)*2 + dy, 2*dy); } } else { /* OC_BOTTOM */ y = tempclipmaxy; if (xmajor) { if (slope) { x = *_x0 + CeilDiv(dx*((y - *_y0)*2 + 1), 2*dy)-1; } else { x = *_x0 + FloorDiv(dx*((y - *_y0)*2 + 1), 2*dy)+1; } } else { x = *_x0 + FloorDiv(dx*(y - *_y0)*2 + dy, 2*dy); } } if (first!=0) { x0 = x; y0 = y; outcode(first,x0,y0); *clip_first = 1; } else { x1 = x; y1 = y; last = code; outcode(last,x1,y1); *clip_last = 1; } if ((first & last) != 0) { return CLIP_INVISIBLE; /* Trivially rejected! */ } if ((first | last) == 0) { *_x0=x0; *_y0=y0; *_x1=x1; *_y1=y1; return CLIP_PARTIAL; /* Trivially accepted! */ } } }
void PadCopyTransposeMatrix(Queue &queue, const Device &device, const Databases &db, EventPointer event, const std::vector<Event> &waitForEvents, const size_t src_one, const size_t src_two, const size_t src_ld, const size_t src_offset, const Buffer<T> &src, const size_t dest_one, const size_t dest_two, const size_t dest_ld, const size_t dest_offset, const Buffer<T> &dest, const T alpha, const Program &program, const bool do_pad, const bool do_transpose, const bool do_conjugate, const bool upper = false, const bool lower = false, const bool diagonal_imag_zero = false) { // Determines whether or not the fast-version could potentially be used auto use_fast_kernel = (src_offset == 0) && (dest_offset == 0) && (do_conjugate == false) && (src_one == dest_one) && (src_two == dest_two) && (src_ld == dest_ld) && (upper == false) && (lower == false) && (diagonal_imag_zero == false); // Determines the right kernel auto kernel_name = std::string{}; if (do_transpose) { if (use_fast_kernel && IsMultiple(src_ld, db["TRA_WPT"]) && IsMultiple(src_one, db["TRA_WPT"]*db["TRA_DIM"]) && IsMultiple(src_two, db["TRA_WPT"]*db["TRA_DIM"])) { kernel_name = "TransposeMatrixFast"; } else { use_fast_kernel = false; kernel_name = (do_pad) ? "TransposePadMatrix" : "TransposeMatrix"; } } else { if (use_fast_kernel && IsMultiple(src_ld, db["COPY_VW"]) && IsMultiple(src_one, db["COPY_VW"]*db["COPY_DIMX"]) && IsMultiple(src_two, db["COPY_WPT"]*db["COPY_DIMY"])) { kernel_name = "CopyMatrixFast"; } else { use_fast_kernel = false; kernel_name = (do_pad) ? "CopyPadMatrix" : "CopyMatrix"; } } // Retrieves the kernel from the compiled binary auto kernel = Kernel(program, kernel_name); // Sets the kernel arguments if (use_fast_kernel) { kernel.SetArgument(0, static_cast<int>(src_ld)); kernel.SetArgument(1, src()); kernel.SetArgument(2, dest()); kernel.SetArgument(3, GetRealArg(alpha)); } else { kernel.SetArgument(0, static_cast<int>(src_one)); kernel.SetArgument(1, static_cast<int>(src_two)); kernel.SetArgument(2, static_cast<int>(src_ld)); kernel.SetArgument(3, static_cast<int>(src_offset)); kernel.SetArgument(4, src()); kernel.SetArgument(5, static_cast<int>(dest_one)); kernel.SetArgument(6, static_cast<int>(dest_two)); kernel.SetArgument(7, static_cast<int>(dest_ld)); kernel.SetArgument(8, static_cast<int>(dest_offset)); kernel.SetArgument(9, dest()); kernel.SetArgument(10, GetRealArg(alpha)); if (do_pad) { kernel.SetArgument(11, static_cast<int>(do_conjugate)); } else { kernel.SetArgument(11, static_cast<int>(upper)); kernel.SetArgument(12, static_cast<int>(lower)); kernel.SetArgument(13, static_cast<int>(diagonal_imag_zero)); } } // Launches the kernel and returns the error code. Uses global and local thread sizes based on // parameters in the database. if (do_transpose) { if (use_fast_kernel) { const auto global = std::vector<size_t>{ dest_one / db["TRA_WPT"], dest_two / db["TRA_WPT"] }; const auto local = std::vector<size_t>{db["TRA_DIM"], db["TRA_DIM"]}; RunKernel(kernel, queue, device, global, local, event, waitForEvents); } else { const auto global = std::vector<size_t>{ Ceil(CeilDiv(dest_one, db["PADTRA_WPT"]), db["PADTRA_TILE"]), Ceil(CeilDiv(dest_two, db["PADTRA_WPT"]), db["PADTRA_TILE"]) }; const auto local = std::vector<size_t>{db["PADTRA_TILE"], db["PADTRA_TILE"]}; RunKernel(kernel, queue, device, global, local, event, waitForEvents); } } else { if (use_fast_kernel) { const auto global = std::vector<size_t>{ dest_one / db["COPY_VW"], dest_two / db["COPY_WPT"] }; const auto local = std::vector<size_t>{db["COPY_DIMX"], db["COPY_DIMY"]}; RunKernel(kernel, queue, device, global, local, event, waitForEvents); } else { const auto global = std::vector<size_t>{ Ceil(CeilDiv(dest_one, db["PAD_WPTX"]), db["PAD_DIMX"]), Ceil(CeilDiv(dest_two, db["PAD_WPTY"]), db["PAD_DIMY"]) }; const auto local = std::vector<size_t>{db["PAD_DIMX"], db["PAD_DIMY"]}; RunKernel(kernel, queue, device, global, local, event, waitForEvents); } } }
void PadCopyTransposeMatrixBatched(Queue &queue, const Device &device, const Databases &db, EventPointer event, const std::vector<Event> &waitForEvents, const size_t src_one, const size_t src_two, const size_t src_ld, const Buffer<int> &src_offsets, const Buffer<T> &src, const size_t dest_one, const size_t dest_two, const size_t dest_ld, const Buffer<int> &dest_offsets, const Buffer<T> &dest, const Program &program, const bool do_pad, const bool do_transpose, const bool do_conjugate, const size_t batch_count) { // Determines the right kernel auto kernel_name = std::string{}; if (do_transpose) { kernel_name = (do_pad) ? "TransposePadMatrixBatched" : "TransposeMatrixBatched"; } else { kernel_name = (do_pad) ? "CopyPadMatrixBatched" : "CopyMatrixBatched"; } // Retrieves the kernel from the compiled binary auto kernel = Kernel(program, kernel_name); // Sets the kernel arguments kernel.SetArgument(0, static_cast<int>(src_one)); kernel.SetArgument(1, static_cast<int>(src_two)); kernel.SetArgument(2, static_cast<int>(src_ld)); kernel.SetArgument(3, src_offsets()); kernel.SetArgument(4, src()); kernel.SetArgument(5, static_cast<int>(dest_one)); kernel.SetArgument(6, static_cast<int>(dest_two)); kernel.SetArgument(7, static_cast<int>(dest_ld)); kernel.SetArgument(8, dest_offsets()); kernel.SetArgument(9, dest()); if (do_pad) { kernel.SetArgument(10, static_cast<int>(do_conjugate)); } // Launches the kernel and returns the error code. Uses global and local thread sizes based on // parameters in the database. if (do_transpose) { const auto global = std::vector<size_t>{ Ceil(CeilDiv(dest_one, db["PADTRA_WPT"]), db["PADTRA_TILE"]), Ceil(CeilDiv(dest_two, db["PADTRA_WPT"]), db["PADTRA_TILE"]), batch_count }; const auto local = std::vector<size_t>{db["PADTRA_TILE"], db["PADTRA_TILE"], 1}; RunKernel(kernel, queue, device, global, local, event, waitForEvents); } else { const auto global = std::vector<size_t>{ Ceil(CeilDiv(dest_one, db["PAD_WPTX"]), db["PAD_DIMX"]), Ceil(CeilDiv(dest_two, db["PAD_WPTY"]), db["PAD_DIMY"]), batch_count }; const auto local = std::vector<size_t>{db["PAD_DIMX"], db["PAD_DIMY"], 1}; RunKernel(kernel, queue, device, global, local, event, waitForEvents); } }
PetscInt ProcessGridNumLevels(const PetscInt p[]) { PetscMPIInt pmax = p[2],plev; if (pmax < 1) return -1; for (plev=0; pmax > 1; pmax = CeilDiv(pmax,2)) plev++; return plev; }
/** * Replace a whole vehicle chain * @param chain vehicle chain to let autoreplace/renew operator on * @param flags command flags * @param wagon_removal remove wagons when the resulting chain occupies more tiles than the old did * @param nothing_to_do is set to 'false' when something was done (only valid when not failed) * @return cost or error */ static CommandCost ReplaceChain(Vehicle **chain, DoCommandFlag flags, bool wagon_removal, bool *nothing_to_do) { Vehicle *old_head = *chain; assert(old_head->IsPrimaryVehicle()); CommandCost cost = CommandCost(EXPENSES_NEW_VEHICLES, 0); if (old_head->type == VEH_TRAIN) { /* Store the length of the old vehicle chain, rounded up to whole tiles */ uint16 old_total_length = CeilDiv(Train::From(old_head)->gcache.cached_total_length, TILE_SIZE) * TILE_SIZE; int num_units = 0; ///< Number of units in the chain for (Train *w = Train::From(old_head); w != NULL; w = w->GetNextUnit()) num_units++; Train **old_vehs = CallocT<Train *>(num_units); ///< Will store vehicles of the old chain in their order Train **new_vehs = CallocT<Train *>(num_units); ///< New vehicles corresponding to old_vehs or NULL if no replacement Money *new_costs = MallocT<Money>(num_units); ///< Costs for buying and refitting the new vehicles /* Collect vehicles and build replacements * Note: The replacement vehicles can only successfully build as long as the old vehicles are still in their chain */ int i; Train *w; for (w = Train::From(old_head), i = 0; w != NULL; w = w->GetNextUnit(), i++) { assert(i < num_units); old_vehs[i] = w; CommandCost ret = BuildReplacementVehicle(old_vehs[i], (Vehicle**)&new_vehs[i], true); cost.AddCost(ret); if (cost.Failed()) break; new_costs[i] = ret.GetCost(); if (new_vehs[i] != NULL) *nothing_to_do = false; } Train *new_head = (new_vehs[0] != NULL ? new_vehs[0] : old_vehs[0]); /* Note: When autoreplace has already failed here, old_vehs[] is not completely initialized. But it is also not needed. */ if (cost.Succeeded()) { /* Separate the head, so we can start constructing the new chain */ Train *second = Train::From(old_head)->GetNextUnit(); if (second != NULL) cost.AddCost(CmdMoveVehicle(second, NULL, DC_EXEC | DC_AUTOREPLACE, true)); assert(Train::From(new_head)->GetNextUnit() == NULL); /* Append engines to the new chain * We do this from back to front, so that the head of the temporary vehicle chain does not change all the time. * That way we also have less trouble when exceeding the unitnumber limit. * OTOH the vehicle attach callback is more expensive this way :s */ Train *last_engine = NULL; ///< Shall store the last engine unit after this step if (cost.Succeeded()) { for (int i = num_units - 1; i > 0; i--) { Train *append = (new_vehs[i] != NULL ? new_vehs[i] : old_vehs[i]); if (RailVehInfo(append->engine_type)->railveh_type == RAILVEH_WAGON) continue; if (new_vehs[i] != NULL) { /* Move the old engine to a separate row with DC_AUTOREPLACE. Else * moving the wagon in front may fail later due to unitnumber limit. * (We have to attach wagons without DC_AUTOREPLACE.) */ CmdMoveVehicle(old_vehs[i], NULL, DC_EXEC | DC_AUTOREPLACE, false); } if (last_engine == NULL) last_engine = append; cost.AddCost(CmdMoveVehicle(append, new_head, DC_EXEC, false)); if (cost.Failed()) break; } if (last_engine == NULL) last_engine = new_head; } /* When wagon removal is enabled and the new engines without any wagons are already longer than the old, we have to fail */ if (cost.Succeeded() && wagon_removal && new_head->gcache.cached_total_length > old_total_length) cost = CommandCost(STR_ERROR_TRAIN_TOO_LONG_AFTER_REPLACEMENT); /* Append/insert wagons into the new vehicle chain * We do this from back to front, so we can stop when wagon removal or maximum train length (i.e. from mammoth-train setting) is triggered. */ if (cost.Succeeded()) { for (int i = num_units - 1; i > 0; i--) { assert(last_engine != NULL); Vehicle *append = (new_vehs[i] != NULL ? new_vehs[i] : old_vehs[i]); if (RailVehInfo(append->engine_type)->railveh_type == RAILVEH_WAGON) { /* Insert wagon after 'last_engine' */ CommandCost res = CmdMoveVehicle(append, last_engine, DC_EXEC, false); /* When we allow removal of wagons, either the move failing due * to the train becoming too long, or the train becoming longer * would move the vehicle to the empty vehicle chain. */ if (wagon_removal && (res.Failed() ? res.GetErrorMessage() == STR_ERROR_TRAIN_TOO_LONG : new_head->gcache.cached_total_length > old_total_length)) { CmdMoveVehicle(append, NULL, DC_EXEC | DC_AUTOREPLACE, false); break; } cost.AddCost(res); if (cost.Failed()) break; } else { /* We have reached 'last_engine', continue with the next engine towards the front */ assert(append == last_engine); last_engine = last_engine->GetPrevUnit(); } } } /* Sell superfluous new vehicles that could not be inserted. */ if (cost.Succeeded() && wagon_removal) { assert(new_head->gcache.cached_total_length <= _settings_game.vehicle.max_train_length * TILE_SIZE); for (int i = 1; i < num_units; i++) { Vehicle *wagon = new_vehs[i]; if (wagon == NULL) continue; if (wagon->First() == new_head) break; assert(RailVehInfo(wagon->engine_type)->railveh_type == RAILVEH_WAGON); /* Sell wagon */ CommandCost ret = DoCommand(0, wagon->index, 0, DC_EXEC, GetCmdSellVeh(wagon)); assert(ret.Succeeded()); new_vehs[i] = NULL; /* Revert the money subtraction when the vehicle was built. * This value is different from the sell value, esp. because of refitting */ cost.AddCost(-new_costs[i]); } } /* The new vehicle chain is constructed, now take over orders and everything... */ if (cost.Succeeded()) cost.AddCost(CopyHeadSpecificThings(old_head, new_head, flags)); if (cost.Succeeded()) { /* Success ! */ if ((flags & DC_EXEC) != 0 && new_head != old_head) { *chain = new_head; } /* Transfer cargo of old vehicles and sell them */ for (int i = 0; i < num_units; i++) { Vehicle *w = old_vehs[i]; /* Is the vehicle again part of the new chain? * Note: We cannot test 'new_vehs[i] != NULL' as wagon removal might cause to remove both */ if (w->First() == new_head) continue; if ((flags & DC_EXEC) != 0) TransferCargo(w, new_head, true); /* Sell the vehicle. * Note: This might temporarly construct new trains, so use DC_AUTOREPLACE to prevent * it from failing due to engine limits. */ cost.AddCost(DoCommand(0, w->index, 0, flags | DC_AUTOREPLACE, GetCmdSellVeh(w))); if ((flags & DC_EXEC) != 0) { old_vehs[i] = NULL; if (i == 0) old_head = NULL; } } if ((flags & DC_EXEC) != 0) CheckCargoCapacity(new_head); } /* If we are not in DC_EXEC undo everything, i.e. rearrange old vehicles. * We do this from back to front, so that the head of the temporary vehicle chain does not change all the time. * Note: The vehicle attach callback is disabled here :) */ if ((flags & DC_EXEC) == 0) { /* Separate the head, so we can reattach the old vehicles */ Train *second = Train::From(old_head)->GetNextUnit(); if (second != NULL) CmdMoveVehicle(second, NULL, DC_EXEC | DC_AUTOREPLACE, true); assert(Train::From(old_head)->GetNextUnit() == NULL); for (int i = num_units - 1; i > 0; i--) { CommandCost ret = CmdMoveVehicle(old_vehs[i], old_head, DC_EXEC | DC_AUTOREPLACE, false); assert(ret.Succeeded()); } } } /* Finally undo buying of new vehicles */ if ((flags & DC_EXEC) == 0) { for (int i = num_units - 1; i >= 0; i--) { if (new_vehs[i] != NULL) { DoCommand(0, new_vehs[i]->index, 0, DC_EXEC, GetCmdSellVeh(new_vehs[i])); new_vehs[i] = NULL; } } } free(old_vehs); free(new_vehs); free(new_costs); } else { /* Build and refit replacement vehicle */ Vehicle *new_head = NULL; cost.AddCost(BuildReplacementVehicle(old_head, &new_head, true)); /* Was a new vehicle constructed? */ if (cost.Succeeded() && new_head != NULL) { *nothing_to_do = false; /* The new vehicle is constructed, now take over orders and everything... */ cost.AddCost(CopyHeadSpecificThings(old_head, new_head, flags)); if (cost.Succeeded()) { /* The new vehicle is constructed, now take over cargo */ if ((flags & DC_EXEC) != 0) { TransferCargo(old_head, new_head, true); *chain = new_head; } /* Sell the old vehicle */ cost.AddCost(DoCommand(0, old_head->index, 0, flags, GetCmdSellVeh(old_head))); } /* If we are not in DC_EXEC undo everything */ if ((flags & DC_EXEC) == 0) { DoCommand(0, new_head->index, 0, DC_EXEC, GetCmdSellVeh(new_head)); } } } return cost; }
/** * Update the timetable for the vehicle. * @param v The vehicle to update the timetable for. * @param travelling Whether we just travelled or waited at a station. */ void UpdateVehicleTimetable(Vehicle *v, bool travelling) { uint timetabled = travelling ? v->current_order.travel_time : v->current_order.wait_time; uint time_taken = v->current_order_time; v->current_order_time = 0; if (v->current_order.IsType(OT_IMPLICIT)) return; // no timetabling of auto orders VehicleOrderID first_manual_order = 0; for (Order *o = v->GetFirstOrder(); o != NULL && o->IsType(OT_IMPLICIT); o = o->next) { ++first_manual_order; } bool just_started = false; /* This vehicle is arriving at the first destination in the timetable. */ if (v->cur_real_order_index == first_manual_order && travelling) { /* If the start date hasn't been set, or it was set automatically when * the vehicle last arrived at the first destination, update it to the * current time. Otherwise set the late counter appropriately to when * the vehicle should have arrived. */ just_started = !HasBit(v->vehicle_flags, VF_TIMETABLE_STARTED); if (v->timetable_start != 0) { v->lateness_counter = (_date - v->timetable_start) * DAY_TICKS + _date_fract; v->timetable_start = 0; } SetBit(v->vehicle_flags, VF_TIMETABLE_STARTED); SetWindowDirty(WC_VEHICLE_TIMETABLE, v->index); } if (!HasBit(v->vehicle_flags, VF_TIMETABLE_STARTED)) return; if (HasBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE)) { if (travelling && !HasBit(v->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME)) { /* Need to clear that now as otherwise we are not able to reduce the wait time */ v->current_order.wait_time = 0; } if (just_started) return; /* Modify station waiting time only if our new value is larger (this is * always the case when we cleared the timetable). */ if (!v->current_order.IsType(OT_CONDITIONAL) && (travelling || time_taken > v->current_order.wait_time)) { /* Round the time taken up to the nearest day, as this will avoid * confusion for people who are timetabling in days, and can be * adjusted later by people who aren't. * For trains/aircraft multiple movement cycles are done in one * tick. This makes it possible to leave the station and process * e.g. a depot order in the same tick, causing it to not fill * the timetable entry like is done for road vehicles/ships. * Thus always make sure at least one tick is used between the * processing of different orders when filling the timetable. */ time_taken = CeilDiv(max(time_taken, 1U), DAY_TICKS) * DAY_TICKS; ChangeTimetable(v, v->cur_real_order_index, time_taken, travelling); } if (v->cur_real_order_index == first_manual_order && travelling) { /* If we just started we would have returned earlier and have not reached * this code. So obviously, we have completed our round: So turn autofill * off again. */ ClrBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE); ClrBit(v->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME); } return; } if (just_started) return; /* Vehicles will wait at stations if they arrive early even if they are not * timetabled to wait there, so make sure the lateness counter is updated * when this happens. */ if (timetabled == 0 && (travelling || v->lateness_counter >= 0)) return; v->lateness_counter -= (timetabled - time_taken); /* When we are more late than this timetabled bit takes we (somewhat expensively) * check how many ticks the (fully filled) timetable has. If a timetable cycle is * shorter than the amount of ticks we are late we reduce the lateness by the * length of a full cycle till lateness is less than the length of a timetable * cycle. When the timetable isn't fully filled the cycle will be INVALID_TICKS. */ if (v->lateness_counter > (int)timetabled) { Ticks cycle = v->orders.list->GetTimetableTotalDuration(); if (cycle != INVALID_TICKS && v->lateness_counter > cycle) { v->lateness_counter %= cycle; } } for (v = v->FirstShared(); v != NULL; v = v->NextShared()) { SetWindowDirty(WC_VEHICLE_TIMETABLE, v->index); } }
StatusCode Xher2<T>::DoHer2(const Layout layout, const Triangle triangle, const size_t n, const T alpha, const Buffer<T> &x_buffer, const size_t x_offset, const size_t x_inc, const Buffer<T> &y_buffer, const size_t y_offset, const size_t y_inc, const Buffer<T> &a_buffer, const size_t a_offset, const size_t a_ld, const bool packed) { // Makes sure the dimensions are larger than zero if (n == 0) { return StatusCode::kInvalidDimension; } // The data is either in the upper or lower triangle const auto is_upper = ((triangle == Triangle::kUpper && layout != Layout::kRowMajor) || (triangle == Triangle::kLower && layout == Layout::kRowMajor)); const auto is_rowmajor = (layout == Layout::kRowMajor); // Tests the matrix and the vectors for validity auto status = StatusCode::kSuccess; if (packed) { status = TestMatrixAP(n, a_buffer, a_offset); } else { status = TestMatrixA(n, n, a_buffer, a_offset, a_ld); } if (ErrorIn(status)) { return status; } status = TestVectorX(n, x_buffer, x_offset, x_inc); if (ErrorIn(status)) { return status; } status = TestVectorY(n, y_buffer, y_offset, y_inc); if (ErrorIn(status)) { return status; } // Upload the scalar argument as a constant buffer to the device (needed for half-precision) auto alpha_buffer = Buffer<T>(context_, 1); alpha_buffer.Write(queue_, 1, &alpha); // Retrieves the kernel from the compiled binary try { const auto program = GetProgramFromCache(context_, PrecisionValue<T>(), routine_name_); auto kernel = Kernel(program, "Xher2"); // Sets the kernel arguments kernel.SetArgument(0, static_cast<int>(n)); kernel.SetArgument(1, alpha_buffer()); kernel.SetArgument(2, x_buffer()); kernel.SetArgument(3, static_cast<int>(x_offset)); kernel.SetArgument(4, static_cast<int>(x_inc)); kernel.SetArgument(5, y_buffer()); kernel.SetArgument(6, static_cast<int>(y_offset)); kernel.SetArgument(7, static_cast<int>(y_inc)); kernel.SetArgument(8, a_buffer()); kernel.SetArgument(9, static_cast<int>(a_offset)); kernel.SetArgument(10, static_cast<int>(a_ld)); kernel.SetArgument(11, static_cast<int>(is_upper)); kernel.SetArgument(12, static_cast<int>(is_rowmajor)); // Launches the kernel auto global_one = Ceil(CeilDiv(n, db_["WPT"]), db_["WGS1"]); auto global_two = Ceil(CeilDiv(n, db_["WPT"]), db_["WGS2"]); auto global = std::vector<size_t>{global_one, global_two}; auto local = std::vector<size_t>{db_["WGS1"], db_["WGS2"]}; status = RunKernel(kernel, queue_, device_, global, local, event_); if (ErrorIn(status)) { return status; } // Succesfully finished the computation return StatusCode::kSuccess; } catch (...) { return StatusCode::kInvalidKernel; } }
/** * Computes ceil(a / b) * b for non-negative a and b. * @param a Numerator * @param b Denominator * @return a rounded up to the nearest multiple of b. */ static inline uint Ceil(uint a, uint b) { return CeilDiv(a, b) * b; }
static int _ggi_clip2d(ggi_visual *vis,int *_x0, int *_y0, int *_x1, int *_y1, int *clip_first, int *clip_last) { int first,last, code; int x0,y0,x1,y1; int x,y; int dx,dy; unsigned int absdx, absdy; int xmajor; int slope; int i; *clip_first = first = 0; *clip_last = last = 0; outcode(first,*_x0,*_y0); outcode(last,*_x1,*_y1); if ((first | last) == 0) { return 1; /* Trivially accepted! */ } if ((first & last) != 0) { return 0; /* Trivially rejected! */ } x0=*_x0; y0=*_y0; x1=*_x1; y1=*_y1; dx = x1 - x0; dy = y1 - y0; absdx = x0 < x1 ? x1 - x0 : x0 - x1; absdy = y0 < y1 ? y1 - y0 : y0 - y1; xmajor = absdx > absdy; slope = ((x1>=x0) && (y1>=y0)) || ((x1<x0) && (y1<y0)); if ((absdx > MAX_DIFF) || (absdy > MAX_DIFF)) { return _ggi_clip2d_3(vis, _x0, _y0, _x1, _y1, clip_first, clip_last); } for (i = 0; i < 4; i++) { code = first; if (first==0) code = last; if (code&OC_LEFT) { x = LIBGGI_GC(vis)->cliptl.x; if (xmajor) { y = *_y0 + FloorDiv(dy*(x - *_x0)*2 + dx, 2*dx); } else { if (slope) { y = *_y0 + CeilDiv(dy*((x - *_x0)*2 - 1), 2*dx); } else { y = *_y0 + FloorDiv(dy*((x - *_x0)*2 - 1), 2*dx); } } } else if (code&OC_RIGHT) { x = LIBGGI_GC(vis)->clipbr.x - 1; if (xmajor) { y = *_y0 + FloorDiv(dy*(x - *_x0)*2 + dx, 2*dx); } else { if (slope) { y = *_y0 + CeilDiv(dy*((x - *_x0)*2 + 1), 2*dx)-1; } else { y = *_y0 + FloorDiv(dy*((x - *_x0)*2 + 1), 2*dx)+1; } } } else if (code&OC_TOP) { y = LIBGGI_GC(vis)->cliptl.y; if (xmajor) { if (slope) { x = *_x0 + CeilDiv(dx*((y - *_y0)*2 - 1), 2*dy); } else { x = *_x0 + FloorDiv(dx*((y - *_y0)*2 - 1), 2*dy); } } else { x = *_x0 + FloorDiv( dx*(y - *_y0)*2 + dy, 2*dy); } } else { /* OC_BOTTOM */ LIB_ASSERT((code & OC_BOTTOM), "unknown outcode\n"); y = LIBGGI_GC(vis)->clipbr.y - 1; if (xmajor) { if (slope) { x = *_x0 + CeilDiv(dx*((y - *_y0)*2 + 1), 2*dy)-1; } else { x = *_x0 + FloorDiv(dx*((y - *_y0)*2 + 1), 2*dy)+1; } } else { x = *_x0 + FloorDiv(dx*(y - *_y0)*2 + dy, 2*dy); } } if (first!=0) { x0 = x; y0 = y; outcode(first,x0,y0); *clip_first = 1; } else { x1 = x; y1 = y; last = code; outcode(last,x1,y1); *clip_last = 1; } if ((first & last) != 0) { return 0; /* Trivially rejected! */ } if ((first | last) == 0) { *_x0=x0; *_y0=y0; *_x1=x1; *_y1=y1; return 1; /* Trivially accepted! */ } } return 0; /* Aieee! Failed to clip, clip whole line... */ }
void UpdateVehicleTimetable(Vehicle *v, bool travelling) { uint timetabled = travelling ? v->current_order.travel_time : v->current_order.wait_time; uint time_taken = v->current_order_time; v->current_order_time = 0; if (!_settings_game.order.timetabling) return; bool just_started = false; /* This vehicle is arriving at the first destination in the timetable. */ if (v->cur_order_index == 0 && travelling) { /* If the start date hasn't been set, or it was set automatically when * the vehicle last arrived at the first destination, update it to the * current time. Otherwise set the late counter appropriately to when * the vehicle should have arrived. */ just_started = !HasBit(v->vehicle_flags, VF_TIMETABLE_STARTED); if (v->timetable_start != 0) { v->lateness_counter = (_date - v->timetable_start) * DAY_TICKS + _date_fract; v->timetable_start = 0; } SetBit(v->vehicle_flags, VF_TIMETABLE_STARTED); SetWindowDirty(WC_VEHICLE_TIMETABLE, v->index); } if (!HasBit(v->vehicle_flags, VF_TIMETABLE_STARTED)) return; if (HasBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE)) { if (travelling && !HasBit(v->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME)) { /* Need to clear that now as otherwise we are not able to reduce the wait time */ v->current_order.wait_time = 0; } if (just_started) return; /* Modify station waiting time only if our new value is larger (this is * always the case when we cleared the timetable). */ if (!v->current_order.IsType(OT_CONDITIONAL) && (travelling || time_taken > v->current_order.wait_time)) { /* Round the time taken up to the nearest day, as this will avoid * confusion for people who are timetabling in days, and can be * adjusted later by people who aren't. */ time_taken = CeilDiv(time_taken, DAY_TICKS) * DAY_TICKS; ChangeTimetable(v, v->cur_order_index, time_taken, travelling); } if (v->cur_order_index == 0 && travelling) { /* If we just started we would have returned earlier and have not reached * this code. So obviously, we have completed our round: So turn autofill * off again. */ ClrBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE); ClrBit(v->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME); } return; } if (just_started) return; /* Vehicles will wait at stations if they arrive early even if they are not * timetabled to wait there, so make sure the lateness counter is updated * when this happens. */ if (timetabled == 0 && (travelling || v->lateness_counter >= 0)) return; v->lateness_counter -= (timetabled - time_taken); for (v = v->FirstShared(); v != NULL; v = v->NextShared()) { SetWindowDirty(WC_VEHICLE_TIMETABLE, v->index); } }