1 /// Provides a wrapper around a `mg_point_3d`.
2 module memgraph.point3d;
3 
4 import memgraph.mgclient, memgraph.detail, memgraph.value, memgraph.enums;
5 
6 /// Represents a single location in 3-dimensional space.
7 ///
8 /// Contains SRID along with its x, y and z coordinates.
9 struct Point3d {
10 	/// Create a deep copy of `other` point 3d.
11 	this(inout ref Point3d other) {
12 		this(mg_point_3d_copy(other.ptr));
13 	}
14 
15 	/// Create a point 3d from a Value.
16 	this(inout ref Value value) {
17 		assert(value.type == Type.Point3d);
18 		this(mg_point_3d_copy(mg_value_point_3d(value.ptr)));
19 	}
20 
21 	/// Assigns a point 3d to another. The target of the assignment gets detached from
22 	/// whatever point 3d it was attached to, and attaches itself to the new point 3d.
23 	ref Point3d opAssign(Point3d rhs) @safe return {
24 		import std.algorithm.mutation : swap;
25 		swap(this, rhs);
26 		return this;
27 	}
28 
29 	/// Return a printable string representation of this time.
30 	string toString() const {
31 		import std.conv : to;
32 		return to!string(srid) ~ " " ~ to!string(x) ~ " " ~ to!string(y) ~ " " ~ to!string(z);
33 	}
34 
35 	/// Compares this point 3d with `other`.
36 	/// Return: true if same, false otherwise.
37 	bool opEquals(const ref Point3d other) const {
38 		return Detail.arePoint3dsEqual(ptr_, other.ptr);
39 	}
40 
41 	/// Returns SRID of the 3D point.
42 	long srid() const { return mg_point_3d_srid(ptr_); }
43 	/// Returns the x coordinate of the 3D point.
44 	double x() const { return mg_point_3d_x(ptr_); }
45 	/// Returns the y coordinate of the 3D point.
46 	double y() const { return mg_point_3d_y(ptr_); }
47 	/// Returns the z coordinate of the 3D point.
48 	double z() const { return mg_point_3d_z(ptr_); }
49 
50 	this(this) {
51 		if (ptr_)
52 			ptr_ = mg_point_3d_copy(ptr_);
53 	}
54 
55 	@safe @nogc ~this() {
56 		if (ptr_)
57 			mg_point_3d_destroy(ptr_);
58 	}
59 
60 package:
61 	/// Create a Point3d using the given `mg_point_3d`.
62 	this(mg_point_3d *ptr) @trusted {
63 		assert(ptr != null);
64 		ptr_ = ptr;
65 	}
66 
67 	/// Create a Point3d from a copy of the given `mg_point_3d`.
68 	this(const mg_point_3d *ptr) {
69 		assert(ptr != null);
70 		this(mg_point_3d_copy(ptr));
71 	}
72 
73 	const (mg_point_3d *) ptr() const { return ptr_; }
74 
75 private:
76 	mg_point_3d *ptr_;
77 }
78 
79 unittest {
80 	import std.conv : to;
81 	import memgraph.enums;
82 
83 	auto tm = mg_point_3d_alloc(&mg_system_allocator);
84 	assert(tm != null);
85 	tm.srid = 42;
86 	tm.x = 2;
87 	tm.y = 3;
88 	tm.z = 7;
89 
90 	auto t = Point3d(tm);
91 	assert(t.srid == 42);
92 	assert(t.x == 2);
93 	assert(t.y == 3);
94 	assert(t.z == 7);
95 
96 	const t1 = t;
97 	assert(t1 == t);
98 
99 	assert(to!string(t) == "42 2 3 7");
100 
101 	auto t2 = Point3d(mg_point_3d_copy(t.ptr));
102 	assert(t2 == t);
103 
104 	const t3 = Point3d(t2);
105 	assert(t3 == t);
106 
107 	const v = Value(t);
108 	const t4 = Point3d(v);
109 	assert(t4 == t);
110 	assert(v == t);
111 	assert(to!string(v) == to!string(t));
112 
113 	t2 = t;
114 	assert(t2 == t);
115 
116 	const v1 = Value(t2);
117 	assert(v1.type == Type.Point3d);
118 	const v2 = Value(t2);
119 	assert(v2.type == Type.Point3d);
120 
121 	assert(v1 == v2);
122 
123 	const t5 = Point3d(t3);
124 	assert(t5 == t3);
125 }