Type-safe Euclidean vectors in C++











up vote
5
down vote

favorite
2












I'm trying to follow the Raytracing in One Weekend book, and I found that he uses the same Vec3 class for everything - colors, coordinates, direction, and more:



struct Vec3 { float x, y, z };


He also overloads every possible operator of the Vec3 class to make it convenient to use, and adds plenty of member functions (length, distance_to, etc). While this definitely reduces the amount of code one has to write, it isn't terribly safe, and allows for things doesn't make sense (why would you want a distance_to between two Colors?). I was trying to fix that.



I defined a base Vector type:



struct Vector {
Vector(float, float, float);

float x;
float y;
float z;

float length() const;
};


According to the Wikipedia page, there can be 2 types of vectors - bound vectors (goes from point A to point B) and free vectors (the particular point is of no significance, only the magnitude and direction are). I defined these types too, but with very limited operators.



Notice how you can add a FreeVector to a BoundVector to give a BoundVector, but you cannot add 2 BoundVectors:



struct BoundVector : public Vector {
BoundVector(float, float, float);

BoundVector& operator+=(const FreeVector&);
BoundVector& operator-=(const FreeVector&);

FreeVector operator-(const BoundVector&) const;
};

struct FreeVector : public Vector {
FreeVector(float, float, float);
explicit FreeVector(const UnitVector&);

FreeVector& operator+=(const FreeVector&);
FreeVector& operator-=(const FreeVector&);

FreeVector& operator*=(float);
FreeVector& operator/=(float);

UnitVector unit() const;
float dot(const FreeVector&) const;
};

BoundVector operator+(BoundVector, const FreeVector&);
BoundVector operator-(BoundVector, const FreeVector&);

FreeVector operator+(FreeVector, const FreeVector&);
FreeVector operator-(FreeVector, const FreeVector&);

FreeVector operator*(FreeVector, float);
FreeVector operator/(FreeVector, float);


I would have liked the UnitVector class to extend the FreeVector (or even the Vector) class, but I can't, since the implementation is completely different. For starters, to ensure that it is guaranteed to be a unit vector (x*x + y*y + z*z == 1) I have to make all members const:



struct UnitVector {
UnitVector(float, float, float);
explicit UnitVector(const FreeVector&);

const float x;
const float y;
const float z;

FreeVector operator*(float) const;
FreeVector operator/(float) const;

private:
UnitVector(float, float, float, float);
};

UnitVector::UnitVector(const float x, const float y, const float z)
: UnitVector(x, y, z, std::sqrt(x * x + y * y + z * z)) {}

UnitVector::UnitVector(const FreeVector& v) : UnitVector(v.x, v.y, v.z) {}

FreeVector UnitVector::operator*(const float k) const {
return FreeVector(x * k, y * k, z * k);
}

FreeVector UnitVector::operator/(const float k) const {
return FreeVector(x / k, y / k, z / k);
}

UnitVector::UnitVector(const float x, const float y, const float z, const float r)
: x{x / r}, y{y / r}, z{z / r} {}


UnitVectors allow you to define directions in a much better manner:



struct Ray {
BoundVector source;
UnitVector direction;

BoundVector parametric_eq(float) const;
};

BoundVector Ray::parametric_eq(const float t) const {
return source + direction * t;
}


However, this is not all sunshine and roses, as it sometimes results in very ugly-looking static_casts:



struct Lambertian : public Material {
FreeVector albedo;
std::optional<Scatter> scatter(const Ray&, const Strike&) const override;
};

FreeVector random_in_unit_sphere() {
std::random_device r;
std::default_random_engine gen(r());
std::uniform_real_distribution<float> distribution(0, 1);

while (true) {
const FreeVector v(distribution(gen), distribution(gen), distribution(gen));
if (v.length() < 1) return v;
}
}

std::optional<Scatter> Lambertian::scatter(const Ray& ray,
const Strike& strike) const {
return Scatter{.attenuation = albedo,
.scattered = Ray{.source = strike.point,
.direction = static_cast<UnitVector>(
static_cast<FreeVector>(strike.normal) +
random_in_unit_sphere())}};
}


Note that the std::optional is added here because the material may choose to absorb the Ray completely with some probability, and hence not scatter it at all.



Is there a way to reduce the number of static_casts in the last example (or at least the overhead due to them)?



Any other feedback, comments and nitpickings are also welcomed.










share|improve this question







New contributor




ajeetdsouza is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.




















  • designated initializers are a very nice feature of C++20... but we're in 2018! I'm not even sure which compilers do support it already
    – papagaga
    Nov 24 at 1:57










  • Strangely, CMake didn't support it so I couldn't use set(CMAKE_CXX_STANDARD 2a), but GCC stopped complaining once I added set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++2a) to the CMakeLists.txt file.
    – ajeetdsouza
    Nov 24 at 2:02






  • 1




    From a purely mathematical point of view, a bounded vector is in fact a pair of two free vectors. Try to model your classes with that in mind. A mathematical point of view could be very helpful.
    – vnp
    2 days ago












  • I did explore that option too, but I eventually settled for this (all bound vectors relative to the origin) because the bounded vectors were more space efficient (and even a little boost in efficiency really matters when you're doing raytracing). Although, in most cases, they are bound to the origin, in some cases in the book itself you come across a situation where the 2 free vector representation would have been helpful (such as the Camera class). In such cases, I used one bound vector position and a free vector to denote the direction taken from there.
    – ajeetdsouza
    2 days ago















up vote
5
down vote

favorite
2












I'm trying to follow the Raytracing in One Weekend book, and I found that he uses the same Vec3 class for everything - colors, coordinates, direction, and more:



struct Vec3 { float x, y, z };


He also overloads every possible operator of the Vec3 class to make it convenient to use, and adds plenty of member functions (length, distance_to, etc). While this definitely reduces the amount of code one has to write, it isn't terribly safe, and allows for things doesn't make sense (why would you want a distance_to between two Colors?). I was trying to fix that.



I defined a base Vector type:



struct Vector {
Vector(float, float, float);

float x;
float y;
float z;

float length() const;
};


According to the Wikipedia page, there can be 2 types of vectors - bound vectors (goes from point A to point B) and free vectors (the particular point is of no significance, only the magnitude and direction are). I defined these types too, but with very limited operators.



Notice how you can add a FreeVector to a BoundVector to give a BoundVector, but you cannot add 2 BoundVectors:



struct BoundVector : public Vector {
BoundVector(float, float, float);

BoundVector& operator+=(const FreeVector&);
BoundVector& operator-=(const FreeVector&);

FreeVector operator-(const BoundVector&) const;
};

struct FreeVector : public Vector {
FreeVector(float, float, float);
explicit FreeVector(const UnitVector&);

FreeVector& operator+=(const FreeVector&);
FreeVector& operator-=(const FreeVector&);

FreeVector& operator*=(float);
FreeVector& operator/=(float);

UnitVector unit() const;
float dot(const FreeVector&) const;
};

BoundVector operator+(BoundVector, const FreeVector&);
BoundVector operator-(BoundVector, const FreeVector&);

FreeVector operator+(FreeVector, const FreeVector&);
FreeVector operator-(FreeVector, const FreeVector&);

FreeVector operator*(FreeVector, float);
FreeVector operator/(FreeVector, float);


I would have liked the UnitVector class to extend the FreeVector (or even the Vector) class, but I can't, since the implementation is completely different. For starters, to ensure that it is guaranteed to be a unit vector (x*x + y*y + z*z == 1) I have to make all members const:



struct UnitVector {
UnitVector(float, float, float);
explicit UnitVector(const FreeVector&);

const float x;
const float y;
const float z;

FreeVector operator*(float) const;
FreeVector operator/(float) const;

private:
UnitVector(float, float, float, float);
};

UnitVector::UnitVector(const float x, const float y, const float z)
: UnitVector(x, y, z, std::sqrt(x * x + y * y + z * z)) {}

UnitVector::UnitVector(const FreeVector& v) : UnitVector(v.x, v.y, v.z) {}

FreeVector UnitVector::operator*(const float k) const {
return FreeVector(x * k, y * k, z * k);
}

FreeVector UnitVector::operator/(const float k) const {
return FreeVector(x / k, y / k, z / k);
}

UnitVector::UnitVector(const float x, const float y, const float z, const float r)
: x{x / r}, y{y / r}, z{z / r} {}


UnitVectors allow you to define directions in a much better manner:



struct Ray {
BoundVector source;
UnitVector direction;

BoundVector parametric_eq(float) const;
};

BoundVector Ray::parametric_eq(const float t) const {
return source + direction * t;
}


However, this is not all sunshine and roses, as it sometimes results in very ugly-looking static_casts:



struct Lambertian : public Material {
FreeVector albedo;
std::optional<Scatter> scatter(const Ray&, const Strike&) const override;
};

FreeVector random_in_unit_sphere() {
std::random_device r;
std::default_random_engine gen(r());
std::uniform_real_distribution<float> distribution(0, 1);

while (true) {
const FreeVector v(distribution(gen), distribution(gen), distribution(gen));
if (v.length() < 1) return v;
}
}

std::optional<Scatter> Lambertian::scatter(const Ray& ray,
const Strike& strike) const {
return Scatter{.attenuation = albedo,
.scattered = Ray{.source = strike.point,
.direction = static_cast<UnitVector>(
static_cast<FreeVector>(strike.normal) +
random_in_unit_sphere())}};
}


Note that the std::optional is added here because the material may choose to absorb the Ray completely with some probability, and hence not scatter it at all.



Is there a way to reduce the number of static_casts in the last example (or at least the overhead due to them)?



Any other feedback, comments and nitpickings are also welcomed.










share|improve this question







New contributor




ajeetdsouza is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.




















  • designated initializers are a very nice feature of C++20... but we're in 2018! I'm not even sure which compilers do support it already
    – papagaga
    Nov 24 at 1:57










  • Strangely, CMake didn't support it so I couldn't use set(CMAKE_CXX_STANDARD 2a), but GCC stopped complaining once I added set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++2a) to the CMakeLists.txt file.
    – ajeetdsouza
    Nov 24 at 2:02






  • 1




    From a purely mathematical point of view, a bounded vector is in fact a pair of two free vectors. Try to model your classes with that in mind. A mathematical point of view could be very helpful.
    – vnp
    2 days ago












  • I did explore that option too, but I eventually settled for this (all bound vectors relative to the origin) because the bounded vectors were more space efficient (and even a little boost in efficiency really matters when you're doing raytracing). Although, in most cases, they are bound to the origin, in some cases in the book itself you come across a situation where the 2 free vector representation would have been helpful (such as the Camera class). In such cases, I used one bound vector position and a free vector to denote the direction taken from there.
    – ajeetdsouza
    2 days ago













up vote
5
down vote

favorite
2









up vote
5
down vote

favorite
2






2





I'm trying to follow the Raytracing in One Weekend book, and I found that he uses the same Vec3 class for everything - colors, coordinates, direction, and more:



struct Vec3 { float x, y, z };


He also overloads every possible operator of the Vec3 class to make it convenient to use, and adds plenty of member functions (length, distance_to, etc). While this definitely reduces the amount of code one has to write, it isn't terribly safe, and allows for things doesn't make sense (why would you want a distance_to between two Colors?). I was trying to fix that.



I defined a base Vector type:



struct Vector {
Vector(float, float, float);

float x;
float y;
float z;

float length() const;
};


According to the Wikipedia page, there can be 2 types of vectors - bound vectors (goes from point A to point B) and free vectors (the particular point is of no significance, only the magnitude and direction are). I defined these types too, but with very limited operators.



Notice how you can add a FreeVector to a BoundVector to give a BoundVector, but you cannot add 2 BoundVectors:



struct BoundVector : public Vector {
BoundVector(float, float, float);

BoundVector& operator+=(const FreeVector&);
BoundVector& operator-=(const FreeVector&);

FreeVector operator-(const BoundVector&) const;
};

struct FreeVector : public Vector {
FreeVector(float, float, float);
explicit FreeVector(const UnitVector&);

FreeVector& operator+=(const FreeVector&);
FreeVector& operator-=(const FreeVector&);

FreeVector& operator*=(float);
FreeVector& operator/=(float);

UnitVector unit() const;
float dot(const FreeVector&) const;
};

BoundVector operator+(BoundVector, const FreeVector&);
BoundVector operator-(BoundVector, const FreeVector&);

FreeVector operator+(FreeVector, const FreeVector&);
FreeVector operator-(FreeVector, const FreeVector&);

FreeVector operator*(FreeVector, float);
FreeVector operator/(FreeVector, float);


I would have liked the UnitVector class to extend the FreeVector (or even the Vector) class, but I can't, since the implementation is completely different. For starters, to ensure that it is guaranteed to be a unit vector (x*x + y*y + z*z == 1) I have to make all members const:



struct UnitVector {
UnitVector(float, float, float);
explicit UnitVector(const FreeVector&);

const float x;
const float y;
const float z;

FreeVector operator*(float) const;
FreeVector operator/(float) const;

private:
UnitVector(float, float, float, float);
};

UnitVector::UnitVector(const float x, const float y, const float z)
: UnitVector(x, y, z, std::sqrt(x * x + y * y + z * z)) {}

UnitVector::UnitVector(const FreeVector& v) : UnitVector(v.x, v.y, v.z) {}

FreeVector UnitVector::operator*(const float k) const {
return FreeVector(x * k, y * k, z * k);
}

FreeVector UnitVector::operator/(const float k) const {
return FreeVector(x / k, y / k, z / k);
}

UnitVector::UnitVector(const float x, const float y, const float z, const float r)
: x{x / r}, y{y / r}, z{z / r} {}


UnitVectors allow you to define directions in a much better manner:



struct Ray {
BoundVector source;
UnitVector direction;

BoundVector parametric_eq(float) const;
};

BoundVector Ray::parametric_eq(const float t) const {
return source + direction * t;
}


However, this is not all sunshine and roses, as it sometimes results in very ugly-looking static_casts:



struct Lambertian : public Material {
FreeVector albedo;
std::optional<Scatter> scatter(const Ray&, const Strike&) const override;
};

FreeVector random_in_unit_sphere() {
std::random_device r;
std::default_random_engine gen(r());
std::uniform_real_distribution<float> distribution(0, 1);

while (true) {
const FreeVector v(distribution(gen), distribution(gen), distribution(gen));
if (v.length() < 1) return v;
}
}

std::optional<Scatter> Lambertian::scatter(const Ray& ray,
const Strike& strike) const {
return Scatter{.attenuation = albedo,
.scattered = Ray{.source = strike.point,
.direction = static_cast<UnitVector>(
static_cast<FreeVector>(strike.normal) +
random_in_unit_sphere())}};
}


Note that the std::optional is added here because the material may choose to absorb the Ray completely with some probability, and hence not scatter it at all.



Is there a way to reduce the number of static_casts in the last example (or at least the overhead due to them)?



Any other feedback, comments and nitpickings are also welcomed.










share|improve this question







New contributor




ajeetdsouza is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











I'm trying to follow the Raytracing in One Weekend book, and I found that he uses the same Vec3 class for everything - colors, coordinates, direction, and more:



struct Vec3 { float x, y, z };


He also overloads every possible operator of the Vec3 class to make it convenient to use, and adds plenty of member functions (length, distance_to, etc). While this definitely reduces the amount of code one has to write, it isn't terribly safe, and allows for things doesn't make sense (why would you want a distance_to between two Colors?). I was trying to fix that.



I defined a base Vector type:



struct Vector {
Vector(float, float, float);

float x;
float y;
float z;

float length() const;
};


According to the Wikipedia page, there can be 2 types of vectors - bound vectors (goes from point A to point B) and free vectors (the particular point is of no significance, only the magnitude and direction are). I defined these types too, but with very limited operators.



Notice how you can add a FreeVector to a BoundVector to give a BoundVector, but you cannot add 2 BoundVectors:



struct BoundVector : public Vector {
BoundVector(float, float, float);

BoundVector& operator+=(const FreeVector&);
BoundVector& operator-=(const FreeVector&);

FreeVector operator-(const BoundVector&) const;
};

struct FreeVector : public Vector {
FreeVector(float, float, float);
explicit FreeVector(const UnitVector&);

FreeVector& operator+=(const FreeVector&);
FreeVector& operator-=(const FreeVector&);

FreeVector& operator*=(float);
FreeVector& operator/=(float);

UnitVector unit() const;
float dot(const FreeVector&) const;
};

BoundVector operator+(BoundVector, const FreeVector&);
BoundVector operator-(BoundVector, const FreeVector&);

FreeVector operator+(FreeVector, const FreeVector&);
FreeVector operator-(FreeVector, const FreeVector&);

FreeVector operator*(FreeVector, float);
FreeVector operator/(FreeVector, float);


I would have liked the UnitVector class to extend the FreeVector (or even the Vector) class, but I can't, since the implementation is completely different. For starters, to ensure that it is guaranteed to be a unit vector (x*x + y*y + z*z == 1) I have to make all members const:



struct UnitVector {
UnitVector(float, float, float);
explicit UnitVector(const FreeVector&);

const float x;
const float y;
const float z;

FreeVector operator*(float) const;
FreeVector operator/(float) const;

private:
UnitVector(float, float, float, float);
};

UnitVector::UnitVector(const float x, const float y, const float z)
: UnitVector(x, y, z, std::sqrt(x * x + y * y + z * z)) {}

UnitVector::UnitVector(const FreeVector& v) : UnitVector(v.x, v.y, v.z) {}

FreeVector UnitVector::operator*(const float k) const {
return FreeVector(x * k, y * k, z * k);
}

FreeVector UnitVector::operator/(const float k) const {
return FreeVector(x / k, y / k, z / k);
}

UnitVector::UnitVector(const float x, const float y, const float z, const float r)
: x{x / r}, y{y / r}, z{z / r} {}


UnitVectors allow you to define directions in a much better manner:



struct Ray {
BoundVector source;
UnitVector direction;

BoundVector parametric_eq(float) const;
};

BoundVector Ray::parametric_eq(const float t) const {
return source + direction * t;
}


However, this is not all sunshine and roses, as it sometimes results in very ugly-looking static_casts:



struct Lambertian : public Material {
FreeVector albedo;
std::optional<Scatter> scatter(const Ray&, const Strike&) const override;
};

FreeVector random_in_unit_sphere() {
std::random_device r;
std::default_random_engine gen(r());
std::uniform_real_distribution<float> distribution(0, 1);

while (true) {
const FreeVector v(distribution(gen), distribution(gen), distribution(gen));
if (v.length() < 1) return v;
}
}

std::optional<Scatter> Lambertian::scatter(const Ray& ray,
const Strike& strike) const {
return Scatter{.attenuation = albedo,
.scattered = Ray{.source = strike.point,
.direction = static_cast<UnitVector>(
static_cast<FreeVector>(strike.normal) +
random_in_unit_sphere())}};
}


Note that the std::optional is added here because the material may choose to absorb the Ray completely with some probability, and hence not scatter it at all.



Is there a way to reduce the number of static_casts in the last example (or at least the overhead due to them)?



Any other feedback, comments and nitpickings are also welcomed.







c++ coordinate-system raytracing






share|improve this question







New contributor




ajeetdsouza is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











share|improve this question







New contributor




ajeetdsouza is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









share|improve this question




share|improve this question






New contributor




ajeetdsouza is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









asked Nov 24 at 1:52









ajeetdsouza

262




262




New contributor




ajeetdsouza is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.





New contributor





ajeetdsouza is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.






ajeetdsouza is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.












  • designated initializers are a very nice feature of C++20... but we're in 2018! I'm not even sure which compilers do support it already
    – papagaga
    Nov 24 at 1:57










  • Strangely, CMake didn't support it so I couldn't use set(CMAKE_CXX_STANDARD 2a), but GCC stopped complaining once I added set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++2a) to the CMakeLists.txt file.
    – ajeetdsouza
    Nov 24 at 2:02






  • 1




    From a purely mathematical point of view, a bounded vector is in fact a pair of two free vectors. Try to model your classes with that in mind. A mathematical point of view could be very helpful.
    – vnp
    2 days ago












  • I did explore that option too, but I eventually settled for this (all bound vectors relative to the origin) because the bounded vectors were more space efficient (and even a little boost in efficiency really matters when you're doing raytracing). Although, in most cases, they are bound to the origin, in some cases in the book itself you come across a situation where the 2 free vector representation would have been helpful (such as the Camera class). In such cases, I used one bound vector position and a free vector to denote the direction taken from there.
    – ajeetdsouza
    2 days ago


















  • designated initializers are a very nice feature of C++20... but we're in 2018! I'm not even sure which compilers do support it already
    – papagaga
    Nov 24 at 1:57










  • Strangely, CMake didn't support it so I couldn't use set(CMAKE_CXX_STANDARD 2a), but GCC stopped complaining once I added set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++2a) to the CMakeLists.txt file.
    – ajeetdsouza
    Nov 24 at 2:02






  • 1




    From a purely mathematical point of view, a bounded vector is in fact a pair of two free vectors. Try to model your classes with that in mind. A mathematical point of view could be very helpful.
    – vnp
    2 days ago












  • I did explore that option too, but I eventually settled for this (all bound vectors relative to the origin) because the bounded vectors were more space efficient (and even a little boost in efficiency really matters when you're doing raytracing). Although, in most cases, they are bound to the origin, in some cases in the book itself you come across a situation where the 2 free vector representation would have been helpful (such as the Camera class). In such cases, I used one bound vector position and a free vector to denote the direction taken from there.
    – ajeetdsouza
    2 days ago
















designated initializers are a very nice feature of C++20... but we're in 2018! I'm not even sure which compilers do support it already
– papagaga
Nov 24 at 1:57




designated initializers are a very nice feature of C++20... but we're in 2018! I'm not even sure which compilers do support it already
– papagaga
Nov 24 at 1:57












Strangely, CMake didn't support it so I couldn't use set(CMAKE_CXX_STANDARD 2a), but GCC stopped complaining once I added set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++2a) to the CMakeLists.txt file.
– ajeetdsouza
Nov 24 at 2:02




Strangely, CMake didn't support it so I couldn't use set(CMAKE_CXX_STANDARD 2a), but GCC stopped complaining once I added set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++2a) to the CMakeLists.txt file.
– ajeetdsouza
Nov 24 at 2:02




1




1




From a purely mathematical point of view, a bounded vector is in fact a pair of two free vectors. Try to model your classes with that in mind. A mathematical point of view could be very helpful.
– vnp
2 days ago






From a purely mathematical point of view, a bounded vector is in fact a pair of two free vectors. Try to model your classes with that in mind. A mathematical point of view could be very helpful.
– vnp
2 days ago














I did explore that option too, but I eventually settled for this (all bound vectors relative to the origin) because the bounded vectors were more space efficient (and even a little boost in efficiency really matters when you're doing raytracing). Although, in most cases, they are bound to the origin, in some cases in the book itself you come across a situation where the 2 free vector representation would have been helpful (such as the Camera class). In such cases, I used one bound vector position and a free vector to denote the direction taken from there.
– ajeetdsouza
2 days ago




I did explore that option too, but I eventually settled for this (all bound vectors relative to the origin) because the bounded vectors were more space efficient (and even a little boost in efficiency really matters when you're doing raytracing). Although, in most cases, they are bound to the origin, in some cases in the book itself you come across a situation where the 2 free vector representation would have been helpful (such as the Camera class). In such cases, I used one bound vector position and a free vector to denote the direction taken from there.
– ajeetdsouza
2 days ago















active

oldest

votes











Your Answer





StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
});
});
}, "mathjax-editing");

StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "196"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});






ajeetdsouza is a new contributor. Be nice, and check out our Code of Conduct.










 

draft saved


draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f208317%2ftype-safe-euclidean-vectors-in-c%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown






























active

oldest

votes













active

oldest

votes









active

oldest

votes






active

oldest

votes








ajeetdsouza is a new contributor. Be nice, and check out our Code of Conduct.










 

draft saved


draft discarded


















ajeetdsouza is a new contributor. Be nice, and check out our Code of Conduct.













ajeetdsouza is a new contributor. Be nice, and check out our Code of Conduct.












ajeetdsouza is a new contributor. Be nice, and check out our Code of Conduct.















 


draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f208317%2ftype-safe-euclidean-vectors-in-c%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Morgemoulin

Scott Moir

Souastre