Files
TimeCoil/src/coil/segment.cpp

212 lines
5.8 KiB
C++

#include <glm/common.hpp>
#include <glm/ext/matrix_float4x4.hpp>
#include <glm/ext/matrix_transform.hpp>
#include <glm/trigonometric.hpp>
#include <cstring>
#include <iostream>
#include <fstream>
#include <glm/glm.hpp>
#include <cstdint>
#include <utils/utils.hpp>
#include <coil/segment.hpp>
#include <coil/coil.hpp>
using glm::vec4;
using glm::vec3;
using glm::mat4;
using glm::radians;
using glm::rotate;
using glm::sin;
using glm::cos;
using glm::translate;
using std::endl;
using std::cout;
using std::cerr;
CoilSegment::CoilSegment(
Coil* coil,
uint16_t year,
uint16_t height,
int shift,
uint32_t sliceDetailization
):
coil(coil), year(year),
height(height), shift(shift),
sliceDetailization(sliceDetailization),
slicePointsAmount(sliceDetailization + 2),
//evil shit
leap(year % 4 == 0? year % 100 == 0? year % 400 == 0 : true : false) {
init();
// calculate();
}
void CoilSegment::init () {
verticesLength = getDaysAmount() * slicePointsAmount * FIELDS_IN_POINT;
vertices = (float *) malloc(verticesLength * sizeof(float));
if (vertices == NULL) {
cerr << "Allocation failed" << endl;
exit(-1);
}
calculate();
}
void CoilSegment::printVertices() {
for (uint16_t day = 0; day < getDaysAmount(); day ++) {
cout << "Day " << day << ", " <<
"x: " << vertices[FIELDS_IN_POINT * day + 0] << ", " <<
"y: " << vertices[FIELDS_IN_POINT * day + 1] << ", " <<
"z: " << vertices[FIELDS_IN_POINT * day + 2] << ", " <<
"r: " << vertices[FIELDS_IN_POINT * day + 3] << ", " <<
"g: " << vertices[FIELDS_IN_POINT * day + 4] << ", " <<
"b: " << vertices[FIELDS_IN_POINT * day + 5] << endl;
}
}
float *CoilSegment::calculateSlice() {
uint32_t size = slicePointsAmount * 3 * sizeof(float);
float *slice = (float *)malloc(size);
mat4 transform = mat4(1.);
transform = glm::scale(
transform,
vec3(
coil->getWidth(),
10,
1
)
);
// Start of a slice
slice[0] = cos(0);
slice[1] = sin(0);
slice[2] = 0;
float degreeByPoint = -180. / (sliceDetailization + 1);
for (uint32_t i = 1; i <= sliceDetailization; i ++) {
uint32_t offset = 3 * i;
slice[offset + 0] = round_to_precision(cos(radians(degreeByPoint * i)), 5);
slice[offset + 1] = round_to_precision(sin(radians(degreeByPoint * i)), 5);
slice[offset + 2] = 0;
}
// End of a slice
uint32_t endIndex = (size / sizeof(float) - 3);
slice[endIndex + 0] = round_to_precision(cos(radians(180.)), 5);
slice[endIndex + 1] = round_to_precision(sin(radians(180.)), 5);
slice[endIndex + 2] = 0;
return slice;
}
void CoilSegment::constructSegment(float *slice) {
float degreesPerDay = 360.f / getDaysAmount();
for (uint32_t day = 0; day < getDaysAmount(); day ++) {
float daysDegree = day * degreesPerDay;
vec3 daysPosition = vec3(
cos(radians(daysDegree)) * coil->getRadius(),
height * (float)day/getDaysAmount() + shift * height,
sin(radians(daysDegree)) * coil->getRadius()
);
mat4 transform = mat4(1.);
transform = translate(
transform,
daysPosition
);
transform = rotate(
transform,
-radians(daysDegree),
vec3(
0.0,
1.0,
0.0
)
);
for (uint32_t slicePoint = 0; slicePoint < slicePointsAmount; slicePoint ++) {
uint32_t slicePointOffset = 3 * slicePoint;
vec4 point(
slice[slicePointOffset + 0],
slice[slicePointOffset + 1],
slice[slicePointOffset + 2],
1
);
point = transform * point;
uint64_t currentPointOffset = day * slicePointsAmount * FIELDS_IN_POINT + slicePointOffset*2;
vertices[currentPointOffset + 0] = point.x;
vertices[currentPointOffset + 1] = point.y;
vertices[currentPointOffset + 2] = point.z;
vertices[currentPointOffset + 3] = (float)slicePoint / slicePointsAmount;
vertices[currentPointOffset + 4] = 0;
vertices[currentPointOffset + 5] = 0;
}
}
free(slice);
}
// Sample layout of 2 slices with 3 points.
// |x |y |z |r |g |b | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
// | point | point | point | point | point | point |
// | slice | slice |
//
void CoilSegment::calculate() {
float *slice = calculateSlice();
constructSegment(slice);
}
float *CoilSegment::getVertices() { return vertices; }
uint64_t CoilSegment::getVerticesLength() { return verticesLength; }
uint64_t CoilSegment::getVerticesAmount() { return verticesLength / FIELDS_IN_POINT; }
uint16_t CoilSegment::getYear() { return year; }
void CoilSegment::exportSliceToCSV(float *slice) {
cout << "Exporting slice to csv" << endl;
std::ofstream outFile("./slice_export.csv");
outFile << "x,y,z" << endl;
for (uint32_t i = 0; i < slicePointsAmount; i ++) {
uint32_t offset = FIELDS_IN_POINT * i;
outFile
<< slice[offset + 0] << ","
<< slice[offset + 1] << ",0" << endl;
}
}
void CoilSegment::exportSegmentToCsv() {
cout << "Exporting segment to csv" << endl;
std::ofstream outFile("./segment_export.csv");
outFile << "x,y,z" << endl;
for (uint16_t day = 0; day < getDaysAmount(); day ++) {
uint64_t dayOffset = day * slicePointsAmount * FIELDS_IN_POINT;
for (uint32_t point_in_slice = 0; point_in_slice < slicePointsAmount; point_in_slice ++) {
uint32_t sliceOffset = point_in_slice * FIELDS_IN_POINT;
outFile << vertices[dayOffset + sliceOffset + 0] << ","
<< vertices[dayOffset + sliceOffset + 1] << ","
<< vertices[dayOffset + sliceOffset + 2] << endl;
}
}
}
uint16_t CoilSegment::getDaysAmount() { return leap? 366 : 365; }
bool const CoilSegment::isLeap() { return leap; }
uint32_t CoilSegment::getSliceDetailization() { return sliceDetailization; }
uint32_t CoilSegment::getSlicePointsAmount() { return sliceDetailization + 2; }