/**
 * 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;
}
Exemple #3
0
	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! */
        }
    }
}
Exemple #5
0
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);
    }
  }
}
Exemple #6
0
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);
  }
}
Exemple #7
0
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;
}
Exemple #9
0
/**
 * 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);
	}
}
Exemple #10
0
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;
}
Exemple #12
0
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... */
}
Exemple #13
0
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);
	}
}