Skip to content

Commit b9e7bb8

Browse files
authored
Merge pull request #103 from dxrcy/coord-2d
2D Coordinate Type
2 parents afafcf2 + 3356186 commit b9e7bb8

File tree

8 files changed

+201
-26
lines changed

8 files changed

+201
-26
lines changed

example/pyramid.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,7 @@ int main() {
2929
int min_height = *std::min_element(heights.begin(), heights.end());
3030

3131
// Build rings, diminishing up to pyramid height
32-
mcpp::Coordinate base_pt = heights.base_pt();
33-
base_pt.y = min_height;
32+
mcpp::Coordinate base_pt = heights.base_pt().with_height(min_height);
3433
int side_len = pyramid_base_len;
3534
for (int i = 0; i < PYRAMID_HEIGHT; i++) {
3635
make_ring(base_pt + mcpp::Coordinate(i, i, i), side_len - (i * 2));

include/mcpp/coordinate.h

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
*
88
*/
99
namespace mcpp {
10+
11+
struct Coordinate2D;
12+
1013
/**
1114
* Represented using integers since sub-unit coordinates are not of particular
1215
* relevance. Allows for operations such as addition between coordinates.
@@ -49,6 +52,8 @@ struct Coordinate {
4952
*/
5053
Coordinate operator+(const Coordinate& obj) const;
5154

55+
Coordinate operator+(const Coordinate2D& obj) const;
56+
5257
/**
5358
* @brief Checks if two Coordinate objects are equal.
5459
*
@@ -93,6 +98,106 @@ struct Coordinate {
9398
friend std::ostream& operator<<(std::ostream& out, const Coordinate& coord);
9499
};
95100

101+
/**
102+
* @brief Height-agnostic coordinate class.
103+
*
104+
* Represented using integers since sub-unit coordinates are not of particular
105+
* relevance. Allows for operations such as addition between flat coordinates.
106+
*/
107+
struct Coordinate2D {
108+
/**
109+
* @brief Constructs a Coordinate2D object with integer values.
110+
*
111+
* @param x The x-coordinate.
112+
* @param z The z-coordinate.
113+
*/
114+
constexpr Coordinate2D(int x, int z) : x(x), z(z) {}
115+
116+
/**
117+
* @brief Constructs a Coordinate2D object with zero values.
118+
*/
119+
constexpr Coordinate2D() : x(0), z(0) {}
120+
121+
/**
122+
* @brief Constructs a Coordinate2D object with double values.
123+
*
124+
* @param x The x-coordinate as a double.
125+
* @param z The z-coordinate as a double.
126+
*/
127+
constexpr Coordinate2D(double x, double z) : x(static_cast<int>(x)), z(static_cast<int>(z)) {}
128+
129+
/**
130+
* @brief Constructs a Coordinate2D object from a Coordinate object.
131+
*
132+
* @param coord The Coordinate object.
133+
*/
134+
constexpr Coordinate2D(const Coordinate& coord) : x(coord.x), z(coord.z) {}
135+
136+
/**
137+
* @brief Constructs a Coordinate object from a Coordinate2D object and a
138+
* y value.
139+
*
140+
* @param coord The Coordinate2D object.
141+
* @param y The y value.
142+
*/
143+
Coordinate with_height(int y) const;
144+
145+
/**
146+
* @brief Adds two Coordinate2D objects.
147+
*
148+
* @param obj The Coordinate2D object to add.
149+
* @return A new Coordinate2D object representing the sum of the two
150+
* coordinates.
151+
*/
152+
Coordinate2D operator+(const Coordinate2D& obj) const;
153+
154+
/**
155+
* @brief Checks if two Coordinate2D objects are equal.
156+
*
157+
* @param obj The Coordinate2D object to compare with.
158+
* @return True if the flat coordinates are equal, false otherwise.
159+
*/
160+
bool operator==(const Coordinate2D& obj) const;
161+
162+
/**
163+
* @brief Checks if two Coordinate2D objects are not equal.
164+
*
165+
* @param obj The Coordinate2D object to compare with.
166+
* @return True if the flat coordinates are not equal, false otherwise.
167+
*/
168+
bool operator!=(const Coordinate2D& obj) const;
169+
170+
/**
171+
* @brief Subtracts one Coordinate2D object from another.
172+
*
173+
* @param obj The Coordinate2D object to subtract.
174+
* @return A new Coordinate2D object representing the difference between
175+
* the two coordinates.
176+
*/
177+
Coordinate2D operator-(const Coordinate2D& obj) const;
178+
179+
/**
180+
* @brief Implements hash algorithm for Coordinate2D object using non-negative
181+
* mapping and weighted coordinate values.
182+
*
183+
* @param obj The Coordinate2D object to hash.
184+
* @return Hash of Coordinate2D object.
185+
*/
186+
std::size_t operator()(const Coordinate2D& obj) const;
187+
188+
/**
189+
* @brief Outputs the Coordinate2D object to an ostream.
190+
*
191+
* @param out The output stream.
192+
* @param coord The Coordinate2D object to output.
193+
* @return The output stream with the Coordinate object's values.
194+
*/
195+
friend std::ostream& operator<<(std::ostream& out, const Coordinate2D& coord);
196+
197+
int x;
198+
int z;
199+
};
200+
96201
/**
97202
* @brief Convert coordinate to string representation.
98203
*

include/mcpp/heightmap.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,15 @@ namespace mcpp {
1212
*/
1313
struct HeightMap {
1414
private:
15-
Coordinate _base_pt;
15+
Coordinate2D _base_pt;
1616
uint16_t _x_len;
1717
uint16_t _z_len;
1818
std::unique_ptr<int16_t[]> _raw_heights;
1919

2020
public:
2121
// Constructors and assignment
22-
HeightMap(const Coordinate& loc1, const Coordinate& loc2, const std::vector<int16_t>& heights);
22+
HeightMap(const Coordinate2D& loc1, const Coordinate2D& loc2,
23+
const std::vector<int16_t>& heights);
2324
~HeightMap() = default;
2425

2526
HeightMap(const HeightMap& other)
@@ -45,10 +46,10 @@ struct HeightMap {
4546

4647
/**
4748
* Get the height at a Minecraft coordinate if saved inside the height map
48-
* @param loc: Coordinate in Minecraft world to access in the map
49+
* @param loc: Coordinate2D in Minecraft world to access in the map
4950
* @return: height at specified coordinate
5051
*/
51-
int16_t get_worldspace(const Coordinate& loc) const;
52+
int16_t get_worldspace(const Coordinate2D& loc) const;
5253

5354
/**
5455
* Fill a coordinate inplace with the highest y coordinate at the `loc`'s x
@@ -73,7 +74,7 @@ struct HeightMap {
7374
* Gets the minimum coordinate in the HeightMap.
7475
* @return the minimum coordinate in the HeightMap.
7576
*/
76-
Coordinate base_pt() const;
77+
Coordinate2D base_pt() const;
7778

7879
/**
7980
* @brief An iterator for the HeightMap structure.

include/mcpp/mcpp.h

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -134,31 +134,45 @@ class MinecraftConnection {
134134
[[nodiscard]] Chunk getBlocks(const Coordinate& loc1, const Coordinate& loc2) const;
135135

136136
/**
137-
* @brief Returns the height of the specific provided x and z coordinate
137+
* @brief Returns the height of the specific provided 2D coordinate
138138
*
139139
* ***IMPORTANT:***
140140
* DO NOT USE FOR LARGE AREAS, IT WILL BE VERY SLOW
141141
* USE getHeights() INSTEAD
142142
*
143-
* Gets the y-value of the highest non-air block at the specified (x, z)
143+
* Gets the y-value of the highest non-air block at the specified 2D
144144
* coordinate.
145-
* @param x
146-
* @param z
145+
* @param loc 2D coordinate
147146
* @return Returns the integer y-height at the requested coordinate.
148147
*/
149-
[[nodiscard]] int32_t getHeight(int x, int z) const;
148+
[[nodiscard]] int32_t getHeight(Coordinate2D loc) const;
149+
150+
/**
151+
* @brief Returns the coordinate with the x, z, and in-world height of the
152+
* specific provided 2D coordinate
153+
*
154+
* ***IMPORTANT:***
155+
* DO NOT USE FOR LARGE AREAS, IT WILL BE VERY SLOW
156+
* USE getHeights() INSTEAD
157+
*
158+
* Gets the y-value of the highest non-air block at the specified 2D
159+
* coordinate, and creates a new 3D coordinate.
160+
* @param loc 2D coordinate
161+
* @return Returns the coordinate with the filled-in height.
162+
*/
163+
Coordinate fillHeight(Coordinate2D loc) const;
150164

151165
/**
152166
* @brief Provides a scaled option of the getHeight call to allow for
153167
* considerable performance gains.
154168
*
155169
* \par USE THIS instead of getHeight in a for loop.
156170
*
157-
* @param loc1
158-
* @param loc2
171+
* @param loc1 1st corner of rectangle
172+
* @param loc2 2nd corner of rectangle
159173
* @return Returns a vector of integers representing the 2D area of heights.
160174
*/
161-
[[nodiscard]] HeightMap getHeights(const Coordinate& loc1, const Coordinate& loc2) const;
175+
[[nodiscard]] HeightMap getHeights(const Coordinate2D& loc1, const Coordinate2D& loc2) const;
162176

163177
// NOLINTEND(readability-identifier-naming)
164178
};

src/coordinate.cpp

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,14 @@ Coordinate Coordinate::operator+(const Coordinate& obj) const {
1010
return result;
1111
}
1212

13+
Coordinate Coordinate::operator+(const Coordinate2D& obj) const {
14+
Coordinate result;
15+
result.x = this->x + obj.x;
16+
result.y = this->y;
17+
result.z = this->z + obj.z;
18+
return result;
19+
}
20+
1321
bool Coordinate::operator==(const Coordinate& obj) const {
1422
return (this->x == obj.x) && (this->y == obj.y) && (this->z == obj.z);
1523
}
@@ -44,4 +52,46 @@ std::ostream& operator<<(std::ostream& out, const Coordinate& coord) {
4452
out << to_string(coord);
4553
return out;
4654
}
55+
56+
Coordinate Coordinate2D::with_height(int y) const { return Coordinate(this->x, y, this->z); }
57+
58+
Coordinate2D Coordinate2D::operator+(const Coordinate2D& obj) const {
59+
Coordinate2D result;
60+
result.x = this->x + obj.x;
61+
result.z = this->z + obj.z;
62+
return result;
63+
}
64+
65+
bool Coordinate2D::operator==(const Coordinate2D& obj) const {
66+
return (this->x == obj.x) && (this->z == obj.z);
67+
}
68+
69+
bool Coordinate2D::operator!=(const Coordinate2D& obj) const { return !(*this == obj); }
70+
71+
Coordinate2D Coordinate2D::operator-(const Coordinate2D& obj) const {
72+
Coordinate2D result;
73+
result.x = this->x - obj.x;
74+
result.z = this->z - obj.z;
75+
return result;
76+
}
77+
78+
std::size_t Coordinate2D::operator()(const mcpp::Coordinate2D& obj) const {
79+
int lower = -3e7, upper = 3e7;
80+
size_t base = upper - lower + 1;
81+
82+
size_t nx = obj.x - lower;
83+
size_t nz = obj.z - lower;
84+
85+
return nx * base + nz;
86+
}
87+
88+
std::string to_string(const Coordinate2D& coord) {
89+
using std::to_string;
90+
return "(" + to_string(coord.x) + "," + to_string(coord.z) + ")";
91+
}
92+
93+
std::ostream& operator<<(std::ostream& out, const Coordinate2D& coord) {
94+
out << to_string(coord);
95+
return out;
96+
}
4797
} // namespace mcpp

src/heightmap.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
#include <cstdint>
33

44
namespace mcpp {
5-
HeightMap::HeightMap(const Coordinate& loc1, const Coordinate& loc2,
5+
HeightMap::HeightMap(const Coordinate2D& loc1, const Coordinate2D& loc2,
66
const std::vector<int16_t>& heights) {
77
_base_pt = Coordinate{
88
std::min(loc1.x, loc2.x),
@@ -37,7 +37,7 @@ int16_t HeightMap::get(int x, int z) const {
3737
return _raw_heights[(x * _z_len) + z];
3838
}
3939

40-
int16_t HeightMap::get_worldspace(const Coordinate& loc) const {
40+
int16_t HeightMap::get_worldspace(const Coordinate2D& loc) const {
4141
return get(loc.x - _base_pt.x, loc.z - _base_pt.z);
4242
}
4343

@@ -47,5 +47,5 @@ uint16_t HeightMap::x_len() const { return _x_len; }
4747

4848
uint16_t HeightMap::z_len() const { return _z_len; }
4949

50-
Coordinate HeightMap::base_pt() const { return _base_pt; }
50+
Coordinate2D HeightMap::base_pt() const { return _base_pt; }
5151
} // namespace mcpp

src/mcpp.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -103,20 +103,26 @@ Chunk MinecraftConnection::getBlocks(const Coordinate& loc1, const Coordinate& l
103103
return Chunk{loc1, loc2, result};
104104
}
105105

106-
int MinecraftConnection::getHeight(int x, int z) const {
107-
std::string response = _conn->send_receive_command("world.getHeight", x, z);
106+
int MinecraftConnection::getHeight(Coordinate2D loc) const {
107+
std::string response = _conn->send_receive_command("world.getHeight", loc.x, loc.z);
108108
return stoi(response);
109109
}
110110

111-
HeightMap MinecraftConnection::getHeights(const Coordinate& loc1, const Coordinate& loc2) const {
111+
Coordinate MinecraftConnection::fillHeight(Coordinate2D loc) const {
112+
int y = this->getHeight(loc);
113+
return Coordinate(loc.x, y, loc.z);
114+
}
115+
116+
HeightMap MinecraftConnection::getHeights(const Coordinate2D& loc1,
117+
const Coordinate2D& loc2) const {
112118
std::string response =
113119
_conn->send_receive_command("world.getHeights", loc1.x, loc1.z, loc2.x, loc2.z);
114120

115121
// Returned in format "1,2,3,4,5"
116122
std::vector<int16_t> parsed;
117123
split_response(response, parsed);
118124

119-
return {loc1, loc2, parsed};
125+
return HeightMap{loc1, loc2, parsed};
120126
}
121127

122128
} // namespace mcpp

test/minecraft_tests.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ TEST_CASE("Test the main mcpp class") {
115115
SUBCASE("getHeight") {
116116
Coordinate heightTestLoc(300, 200, 300);
117117
mc.setBlock(heightTestLoc, Blocks::DIRT);
118-
auto height = mc.getHeight(heightTestLoc.x, heightTestLoc.z);
118+
auto height = mc.getHeight(heightTestLoc);
119119
CHECK_EQ(height, heightTestLoc.y);
120120

121121
// Clean up
@@ -384,14 +384,14 @@ TEST_CASE("HeightMap functionality") {
384384
// Copy assignment
385385
mc.setBlocks({10, 310, 10}, {20, 320, 20}, Blocks::AIR);
386386
mc.setBlocks({10, 310, 10}, {20, 310, 20}, Blocks::STONE);
387-
auto map = mc.getHeights({10, 10, 10}, {20, 20, 20});
387+
auto map = mc.getHeights({10, 10}, {20, 20});
388388
HeightMap map_copy = map; // Contains 310
389389
CHECK_EQ(map.get(0, 0), map_copy.get(0, 0));
390390
CHECK_EQ(map.get(0, 0), 310);
391391

392392
// Reassignment
393393
mc.setBlock({10, 311, 10}, Blocks::STONE);
394-
map = mc.getHeights({10, 10, 10}, {20, 20, 20}); // Now contains 311
394+
map = mc.getHeights({10, 10}, {20, 20}); // Now contains 311
395395
CHECK_NE(map.get(0, 0), map_copy.get(0, 0));
396396
CHECK_EQ(map.get(0, 0), 311);
397397

@@ -402,7 +402,7 @@ TEST_CASE("HeightMap functionality") {
402402
// Copy constructor
403403
auto map_copy2 = HeightMap(map); // Contains 310
404404
mc.setBlock({10, 312, 10}, Blocks::STONE);
405-
map = mc.getHeights({10, 10, 10}, {20, 20, 20}); // Now contains 312
405+
map = mc.getHeights({10, 10}, {20, 20}); // Now contains 312
406406
CHECK_NE(map_copy2.get(0, 0), 312);
407407
CHECK_EQ(map.get(0, 0), 312);
408408

0 commit comments

Comments
 (0)