File ACInfoModel.cpp¶
File List > AIAC > ACInfoModel.cpp
Go to the documentation of this file
// #####################################################################
// >>>>>>>>>>>>>>>>>>>>> BEGINNING OF LEGAL NOTICE >>>>>>>>>>>>>>>>>>>>>
//######################################################################
//
// This source file, along with its associated content, was authored by
// Andrea Settimi, Hong-Bin Yang, Naravich Chutisilp, and numerous other
// contributors. The code was originally developed at the Laboratory for
// Timber Construction (IBOIS, director: Prof. Yves Weinand) at the School of
// Architecture, Civil and Environmental Engineering (ENAC) at the Swiss
// Federal Institute of Technology in Lausanne (EPFL) for the Doctoral
// Research "Augmented Carpentry" (PhD researcher: Andrea Settimi,
// co-director: Dr. Julien Gamerro, director: Prof. Yves Weinand).
//
// Although the entire repository is distributed under the GPL license,
// these particular source files may also be used under the terms of the
// MIT license. By accessing or using this file, you agree to the following:
//
// 1. You may reproduce, modify, and distribute this file in accordance
// with the terms of the MIT license.
// 2. You must retain this legal notice in all copies or substantial
// portions of this file.
// 3. This file is provided "AS IS," without any express or implied
// warranties, including but not limited to the implied warranties of
// merchantability and fitness for a particular purpose.
//
// If you cannot or will not comply with the above conditions, you are
// not permitted to use this file. By proceeding, you acknowledge and
// accept all terms and conditions herein.
//
//######################################################################
// <<<<<<<<<<<<<<<<<<<<<<< END OF LEGAL NOTICE <<<<<<<<<<<<<<<<<<<<<<<<
// #####################################################################
//
#include "aiacpch.h"
#include "AIAC/Application.h"
#include "ACInfoModel.h"
#include "AIAC/Config.h"
#include <cmath>
namespace AIAC
{
void TimberInfo::Component::SetAsCurrent() {
m_State = ACIMState::CURRENT;
#ifndef HEADLESS_TEST
AIAC_APP.GetLayer<LayerModel>()->GetACInfoModel().GetDoc().child("acim").child("timber").child("current").last_child().set_value(m_ID.c_str());
AIAC_APP.GetLayer<LayerModel>()->GetACInfoModel().Save();
AIAC_APP.GetRenderer()->SetGlobalViewToActivatedComponent(Renderer::StandardView::TOP);
#endif
}
void TimberInfo::Component::SetAsDone() {
AIAC_INFO("timberInfo::Component::SetAsDone()");
m_State = ACIMState::DONE;
m_ACIMDocNode.child("state").last_child().set_value("Done");
AIAC_APP.GetLayer<LayerModel>()->GetACInfoModel().Save();
}
void TimberInfo::Component::SetAsNotDone() {
m_State = ACIMState::NOT_DONE;
m_ACIMDocNode.child("state").last_child().set_value("NotDone");
AIAC_APP.GetLayer<LayerModel>()->GetACInfoModel().Save();
}
void TimberInfo::Component::SetVisibility(bool visible) {
for (auto& go : m_GOPrimitives) {
go->SetVisibility(visible);
}
}
glm::vec3 TimberInfo::Component::GetCenter() const {
throw std::logic_error("GetCenter() is not defined for the derived class.");
}
void TimberInfo::Hole::SetAsCurrent() {
TimberInfo::Component::SetAsCurrent();
AIAC_INFO("Set Current Component to Hole #" + m_ID);
m_AxisGO->SetColor(HOLE_AXIS_COLOR[ACIMState::CURRENT]);
m_CylinderGO->SetColor(HOLE_CYLINDER_COLOR[ACIMState::CURRENT]);
}
void TimberInfo::Hole::SetAsDone() {
TimberInfo::Component::SetAsDone();
AIAC_INFO("Set " + m_ID + " as Done");
m_AxisGO->SetColor(HOLE_AXIS_COLOR[ACIMState::DONE]);
m_CylinderGO->SetColor(HOLE_CYLINDER_COLOR[ACIMState::DONE]);
}
void TimberInfo::Hole::SetAsNotDone() {
TimberInfo::Component::SetAsNotDone();
AIAC_INFO("Set " + m_ID + " as Not Done");
m_AxisGO->SetColor(HOLE_AXIS_COLOR[ACIMState::NOT_DONE]);
m_CylinderGO->SetColor(HOLE_CYLINDER_COLOR[ACIMState::NOT_DONE]);
}
void TimberInfo::Hole::SwapStartEnd() {
// holeInfo.m_Start = StringToVec3(hole.child("start").child("coordinates").child_value()) * m_Scale;
// holeInfo.m_StartExposed = StringToBool(hole.child("start").child("exposed").child_value());
// holeInfo.m_End = StringToVec3(hole.child("end").child("coordinates").child_value()) * m_Scale;
// holeInfo.m_EndExposed = StringToBool(hole.child("end").child("exposed").child_value());
// Update .acim doc
std::swap(m_Start, m_End);
std::swap(m_StartExposed, m_EndExposed);
m_ACIMDocNode.child("start").child("coordinates").last_child().set_value(Vec3ToString(m_Start / m_Scale).c_str());
m_ACIMDocNode.child("start").child("exposed").last_child().set_value(m_StartExposed ? "True" : "False");
m_ACIMDocNode.child("end").child("coordinates").last_child().set_value(Vec3ToString(m_End / m_Scale).c_str());
m_ACIMDocNode.child("end").child("exposed").last_child().set_value(m_EndExposed ? "True" : "False");
// Update system
auto curStart = m_StartPointGO->GetPosition();
auto curEnd = m_EndPointGO->GetPosition();
m_StartPointGO->SetPosition(curEnd);
m_EndPointGO->SetPosition(curStart);
m_AxisGO->SetPts(curEnd, curStart);
AIAC_APP.GetLayer<LayerModel>()->GetACInfoModel().Save();
}
void TimberInfo::Hole::SetVisibility(bool visible) {
TimberInfo::Component::SetVisibility(visible);
}
void TimberInfo::Cut::SetAsCurrent() {
TimberInfo::Component::SetAsCurrent();
AIAC_INFO("Set Current Component to " + m_ID);
for (const auto& [_, face] : m_Faces) {
if(face.m_GO != nullptr){
face.m_GO->SetColor(CUT_FACE_COLOR[ACIMState::CURRENT]);
}
}
for (const auto& [_, edge] : m_Edges) {
if(edge.m_GO != nullptr){
edge.m_GO->SetColor(CUT_EDGE_COLOR[ACIMState::CURRENT]);
}
}
}
void TimberInfo::Cut::SetAsDone() {
TimberInfo::Component::SetAsDone();
AIAC_INFO("Set " + m_ID + " as Done");
for (const auto& [_, face] : m_Faces) {
if(face.m_GO != nullptr){
face.m_GO->SetColor(CUT_FACE_COLOR[ACIMState::DONE]);
}
}
for (const auto& [_, edge] : m_Edges) {
if(edge.m_GO != nullptr){
edge.m_GO->SetColor(CUT_EDGE_COLOR[ACIMState::DONE]);
}
}
}
void TimberInfo::Cut::SetAsNotDone() {
TimberInfo::Component::SetAsNotDone();
AIAC_INFO("Set " + m_ID + " as Not Done");
for (const auto& [_, face] : m_Faces) {
if(face.m_GO != nullptr){
face.m_GO->SetColor(CUT_FACE_COLOR[ACIMState::NOT_DONE]);
}
}
for (const auto& [_, edge] : m_Edges) {
if(edge.m_GO != nullptr){
edge.m_GO->SetColor(CUT_EDGE_COLOR[ACIMState::NOT_DONE]);
}
}
}
void TimberInfo::Cut::SetVisibility(bool visible) {
TimberInfo::Component::SetVisibility(visible);
for (const auto& [_, face] : m_Faces) {
if(face.m_GO != nullptr){
face.m_GO->SetVisibility(visible);
}
}
for (const auto& [_, edge] : m_Edges) {
if(edge.m_GO != nullptr){
edge.m_GO->SetVisibility(visible);
}
}
}
void TimberInfo::Cut::HighlightFace(const std::string& faceID, glm::vec4 color) {
if(faceID == m_HighlightedFaceID) return;
// faceID is empty -> Reset everything to CURRENT
if(faceID.empty()){
for(auto& [_, face] : m_Faces){
if(face.m_GO != nullptr){
face.m_GO->SetColor(CUT_FACE_COLOR[ACIMState::CURRENT]);
}
}
for(auto& [_, edge] : m_Edges){
if(edge.m_GO != nullptr){
edge.m_GO->SetColor(CUT_EDGE_COLOR[ACIMState::CURRENT]);
}
}
m_HighlightedFaceID = "";
return;
}
if(m_HighlightedFaceID.empty()){
// init : set all to NOT_DONE
for(auto& [_, face] : m_Faces){
if(face.m_GO != nullptr){
face.m_GO->SetColor(CUT_FACE_COLOR[ACIMState::NOT_DONE]);
}
}
for(auto& [_, edge] : m_Edges){
if(edge.m_GO != nullptr){
edge.m_GO->SetColor(CUT_EDGE_COLOR[ACIMState::NOT_DONE]);
}
}
} else {
// reset the previous Highlighted face
m_Faces[m_HighlightedFaceID].m_GO->SetColor(CUT_FACE_COLOR[ACIMState::NOT_DONE]);
for(auto& edgeID : m_Faces[m_HighlightedFaceID].m_Edges){
if(m_Edges[edgeID].m_GO != nullptr){
m_Edges[edgeID].m_GO->SetColor(CUT_EDGE_COLOR[ACIMState::NOT_DONE]);
}
}
}
// set the new Highlighted face
m_HighlightedFaceID = faceID;
m_Faces[m_HighlightedFaceID].m_GO->SetColor(CUT_FACE_COLOR[ACIMState::CURRENT]);
for(auto& edgeID : m_Faces[m_HighlightedFaceID].m_Edges){
if(m_Edges[edgeID].m_GO != nullptr){
m_Edges[edgeID].m_GO->SetColor(CUT_EDGE_COLOR[ACIMState::CURRENT]);
}
}
}
std::vector<std::string> TimberInfo::GetAllComponentsIDs() const {
// This is only for C++20, but we're using C++17, I leave it here for future reference
// #include <ranges>
// auto kv = std::views::keys(m_Components);
// std::vector<std::string> keys{ kv.begin(), kv.end() };
// return keys;
std::vector<std::string> keys;
for (const auto& [key, _] : m_Components) {
keys.push_back(key);
}
return keys;
}
void TimberInfo::SetCurrentComponentTo(std::string id) {
if(GetCurrentComponent() != nullptr){
if(GetCurrentComponent()->IsMarkedDone){
GetCurrentComponent()->SetAsDone();
} else { // Not Done
GetCurrentComponent()->SetAsNotDone();
}
}
m_CurrentComponentID = id;
m_Components[id]->SetAsCurrent();
if(auto cut = dynamic_cast<Cut*>(m_Components[id]))
{
if(cut -> IsSingleFace())
// {
AIAC_APP.GetLayer<LayerFeedback>()->EnableCutPlane(true);
// } else {
// AIAC_APP.GetLayer<LayerFeedback>()->EnableCutPlane(false);
// }
}
ShowAllComponents();
HideAllComponentsExceptCurrent();
}
std::string TimberInfo::ShortenComponentID(std::string id) {
if(id.find("Hole") != std::string::npos){
return "H" + id.substr(5);
} else if(id.find("Cut") != std::string::npos){
return "C" + id.substr(4);
}
return id;
}
void TimberInfo::SetNextComponentAsCurrent()
{
auto ids = GetAllComponentsIDs();
auto it = std::find(ids.begin(), ids.end(), m_CurrentComponentID);
if(it == ids.end()){
AIAC_ERROR("TimberInfo::SetNextComponentAsCurrent() : Current Component ID not found");
return;
}
if(++it == ids.end()){
it = ids.begin();
}
SetCurrentComponentTo(*it);
}
void TimberInfo::SetPrevComponentAsCurrent()
{
auto ids = GetAllComponentsIDs();
auto it = std::find(ids.begin(), ids.end(), m_CurrentComponentID);
if(it == ids.end()){
AIAC_ERROR("TimberInfo::SetPrevComponentAsCurrent() : Current Component ID not found");
return;
}
if(it == ids.begin()){
it = ids.end();
}
SetCurrentComponentTo(*--it);
}
void TimberInfo::HideAllComponentsExceptCurrent() {
for (const auto& [_, component] : m_Components) {
if(component->m_ID != m_CurrentComponentID){
component->SetVisibility(false);
// if the component is a cut, we hide all the other cotas
if(auto cut = dynamic_cast<Cut*>(component)){
cut->SetVisibilityAllCotas(false);
}
}
}
this->IsShowingAllComponents = false;
}
void TimberInfo::ShowAllComponents() {
for (const auto& [_, component] : m_Components) {
for(auto& go: component->m_GOPrimitives){
component->SetVisibility(true);
}
// if the component is a cut, we show all the cotas
if(auto cut = dynamic_cast<Cut*>(component)){
if(IsShowingCotas)
cut->SetVisibilityAllCotas(true);
}
}
this->IsShowingAllComponents = true;
}
void TimberInfo::UpdateCotasVisibility(bool visible)
{
if (!visible || IsShowingAllComponents) {
this->IsShowingCotas = visible;
for (const auto& [_, component] : m_Components) {
if(auto cut = dynamic_cast<Cut*>(component)){
cut->SetVisibilityAllCotas(visible);
}
}
} else {
if(auto cut = dynamic_cast<Cut*>(this->GetCurrentComponent())){
cut->SetVisibilityAllCotas(visible);
}
}
}
bool ACInfoModel::Load(std::string path) {
// check if file is good
if(path.empty()){
AIAC_ERROR("ACInfoModel::Load() path is empty");
return false;
}
if(!std::filesystem::exists(path)){
AIAC_ERROR("ACInfoModel::Load() file does not exist");
return false;
}
if (std::filesystem::is_directory(path)){
AIAC_ERROR("ACInfoModel::Load() path is a directory");
return false;
}
if (path.find(".acim") == std::string::npos){
AIAC_ERROR("ACInfoModel::Load() file is not .acim");
return false;
}
m_FilePath = path;
Clear();
pugi::xml_parse_result result = m_ACIMDoc.load_file(path.c_str());
if (!result){
AIAC_ERROR("Could not load ACInfoModel from file: {0}", path);
return false;
}
for(auto timber = m_ACIMDoc.child("acim").child("timber"); timber; timber = timber.next_sibling("timber")){
TimberInfo timberInfo;
timberInfo.m_ID = timber.attribute("id").as_string();
timberInfo.m_State = StringToState(timber.child("state").child_value());
timberInfo.m_CurrentComponentID = timber.child("current").child_value();
AIAC_INFO("Timber: {0}", timberInfo.m_ID);
// Bounding Box
auto bboxNode = timber.child("bbox");
for(auto corner = bboxNode.child("corner"); corner; corner = corner.next_sibling("corner")){
auto c = StringToVec3(corner.child_value());
timberInfo.m_Bbox.push_back(c * m_Scale);
}
m_TimberInfo = timberInfo;
// Holes
for(auto hole = timber.child("hole"); hole; hole=hole.next_sibling("hole")){
TimberInfo::Hole holeInfo;
holeInfo.m_ACIMDocNode = hole;
holeInfo.m_ID = hole.attribute("id").as_string();
holeInfo.m_State = StringToState(hole.child("state").child_value());
holeInfo.IsMarkedDone = holeInfo.m_State == ACIMState::DONE;
holeInfo.m_Neighbors = StringToSet(hole.child("neighbours").child_value());
if(holeInfo.m_Neighbors.size() == 1 && *holeInfo.m_Neighbors.begin() == "-1"){
AIAC_INFO("Hole: {0} has no neighbors", holeInfo.m_ID);
holeInfo.m_Neighbors.clear();
}
holeInfo.m_Start = StringToVec3(hole.child("start").child("coordinates").child_value()) * m_Scale;
holeInfo.m_StartExposed = StringToBool(hole.child("start").child("exposed").child_value());
holeInfo.m_End = StringToVec3(hole.child("end").child("coordinates").child_value()) * m_Scale;
holeInfo.m_EndExposed = StringToBool(hole.child("end").child("exposed").child_value());
holeInfo.m_Radius = std::stof(hole.child("radius").child_value());
// build GOPrimitive
holeInfo.m_AxisGO = GOLine::Add(holeInfo.m_Start, holeInfo.m_End, 2.0f);
holeInfo.m_AxisGO->SetColor(HOLE_AXIS_COLOR[holeInfo.m_State]);
holeInfo.m_CylinderGO = GOCylinder::Add(holeInfo.m_Start, holeInfo.m_End, holeInfo.m_Radius);
holeInfo.m_CylinderGO->SetColor(HOLE_CYLINDER_COLOR[holeInfo.m_State]);
holeInfo.m_StartPointGO = GOPoint::Add(holeInfo.m_Start, 2.0f);
holeInfo.m_EndPointGO = GOPoint::Add(holeInfo.m_End, 2.0f);
std::string shortenHoleID = m_TimberInfo.ShortenComponentID(holeInfo.m_ID);
holeInfo.m_IDLabelGO = GOText::Add(shortenHoleID, holeInfo.m_End, m_LabelSize);
holeInfo.m_GOPrimitives.push_back(holeInfo.m_AxisGO);
holeInfo.m_GOPrimitives.push_back(holeInfo.m_CylinderGO);
holeInfo.m_GOPrimitives.push_back(holeInfo.m_StartPointGO);
holeInfo.m_GOPrimitives.push_back(holeInfo.m_EndPointGO);
holeInfo.m_GOPrimitives.push_back(holeInfo.m_IDLabelGO);
m_TimberInfo.m_Holes[holeInfo.m_ID] = holeInfo;
m_TimberInfo.m_Components[holeInfo.m_ID] = &m_TimberInfo.m_Holes[holeInfo.m_ID];
}
// cuts
for(auto cut = timber.child("cut"); cut; cut=cut.next_sibling("cut")){
TimberInfo::Cut cutInfo;
cutInfo.m_ACIMDocNode = cut;
cutInfo.m_ID = cut.attribute("id").as_string();
cutInfo.m_State = StringToState(cut.child("state").child_value());
cutInfo.IsMarkedDone = cutInfo.m_State == ACIMState::DONE;
cutInfo.m_Center = StringToVec3(cut.child("center").child_value()) * m_Scale;
std::string shortenCutID = m_TimberInfo.ShortenComponentID(cutInfo.m_ID);
cutInfo.m_IDLabelGO = GOText::Add(shortenCutID, cutInfo.m_Center, m_LabelSize);
cutInfo.m_GOPrimitives.push_back(cutInfo.m_IDLabelGO);
auto faces = cut.child("faces");
for(auto face = faces.child("face"); face; face=face.next_sibling("face")){
TimberInfo::Cut::Face faceInfo;
faceInfo.m_ID = face.attribute("id").as_string();
faceInfo.m_Exposed = StringToBool(face.child("exposed").child_value());
faceInfo.m_State = StringToState(face.child("state").child_value());
faceInfo.m_Edges = StringToSet(face.child("edges").child_value());
faceInfo.m_Center = glm::vec3(0.0f);
if(!faceInfo.m_Exposed){
cutInfo.m_NonExposedEdgeIDs.insert(faceInfo.m_Edges.begin(), faceInfo.m_Edges.end());
}
auto corners = face.child("corners");
for(auto corner = corners.child("corner"); corner; corner=corner.next_sibling("corner")){
faceInfo.m_Corners.push_back(StringToVec3(corner.child_value()) * m_Scale);
faceInfo.m_Center += faceInfo.m_Corners.back();
}
faceInfo.m_Center /= faceInfo.m_Corners.size();
// build face GO
if(faceInfo.m_Corners.size()<3){
AIAC_ERROR("Face: {0} has less than 3 corners", faceInfo.m_ID);
continue;
}
// skip exposed faces
if(faceInfo.m_Exposed){
continue;
}
// build normal
faceInfo.m_Normal = glm::normalize(glm::cross(faceInfo.m_Corners[1] - faceInfo.m_Corners[0],
faceInfo.m_Corners[2] - faceInfo.m_Corners[0]));
std::vector<uint32_t> indices;
auto baseCornerIdx = 0;
for(int i = 2; i < faceInfo.m_Corners.size(); i++){
indices.push_back(baseCornerIdx);
indices.push_back(i-1);
indices.push_back(i);
}
faceInfo.m_GO = GOMesh::Add(faceInfo.m_Corners, indices);
faceInfo.m_GO->SetColor(CUT_FACE_COLOR[cutInfo.m_State]);
// We only show non-exposed faces
if(faceInfo.m_Exposed){
faceInfo.m_GO->SetVisibility(false);
}
faceInfo.m_GOPrimitives.push_back(faceInfo.m_GO);
cutInfo.m_Faces[faceInfo.m_ID] = faceInfo;
if(!faceInfo.m_Exposed){
cutInfo.m_NonExposedFaceIDs.insert(faceInfo.m_ID);
}
}
auto edges = cut.child("edges");
for(auto edge = edges.child("edge"); edge; edge=edge.next_sibling("edge")){
auto id = edge.attribute("id").as_string();
TimberInfo::Cut::Edge edgeInfo;
edgeInfo.m_ID = edge.attribute("id").as_string();
edgeInfo.m_Start = StringToVec3(edge.child("start").child_value()) * m_Scale;
edgeInfo.m_End = StringToVec3(edge.child("end").child_value()) * m_Scale;
// build GOPrimitive edges and cotas, only on non-exposed edges
if(cutInfo.m_NonExposedEdgeIDs.find(id) != cutInfo.m_NonExposedEdgeIDs.end()){
// GOLines for edges
edgeInfo.m_GO = GOLine::Add(edgeInfo.m_Start, edgeInfo.m_End, m_EdgeWeight);
edgeInfo.m_GO->SetColor(CUT_EDGE_COLOR[cutInfo.m_State]);
edgeInfo.m_GOPrimitives.push_back(edgeInfo.m_GO);
// ----------------------------------------------
// GOTexts for cotas
auto mid = (edgeInfo.m_Start + edgeInfo.m_End) / 2.0f;
glm::vec3 cutCtr = cutInfo.m_Center;
float displacement = 0.02f * m_Scale;
glm::vec3 vecMidCtr = glm::normalize(mid - cutCtr);
// random value between 0 and 1
auto midMoved = mid + (vecMidCtr * displacement);
auto lineCotas = GOLine::Add(GOPoint(mid), GOPoint(midMoved));
lineCotas->SetColor(GOColor::GREEN_PUNK_TRANSP07);
lineCotas->SetWeight(GOWeight::Default);
edgeInfo.m_CotaLines.push_back(lineCotas);
auto cotasPt = GOPoint::Add(mid);
cotasPt->SetColor(GOColor::GREEN_DARKER_TRANSP07);
cotasPt->SetWeight(GOWeight::MediumThick);
edgeInfo.m_CotaPts.push_back(cotasPt);
float dist = glm::distance(edgeInfo.m_Start, edgeInfo.m_End);
float distmm = dist / m_Scale * 1000;
int roundedDistmm = std::round(distmm);
auto cotas = GOText::Add(
std::to_string(roundedDistmm) + "mm",
midMoved,
GOTextSize::Small);
cotas->SetColor(GOColor::GREEN);
edgeInfo.m_Cotas.push_back(cotas);
if (this->m_TimberInfo.IsShowingCotas) {
lineCotas->SetVisibility(true);
cotasPt->SetVisibility(true);
cotas->SetVisibility(true);
} else {
lineCotas->SetVisibility(false);
cotasPt->SetVisibility(false);
cotas->SetVisibility(false);
}
edgeInfo.m_GOPrimitives.push_back(lineCotas);
edgeInfo.m_GOPrimitives.push_back(cotasPt);
edgeInfo.m_GOPrimitives.push_back(cotas);
}
cutInfo.m_Edges[edgeInfo.m_ID] = edgeInfo;
}
// here we compute and add the neighbors
// compare the edges for each face and understand which faces are neighbors
for(auto& [faceID, face] : cutInfo.m_Faces){
for(auto& [edgeID, edge] : cutInfo.m_Edges){
if(face.m_Edges.find(edgeID) != face.m_Edges.end()){
for(auto& [otherFaceID, otherFace] : cutInfo.m_Faces){
if(faceID == otherFaceID) continue;
if(otherFace.m_Edges.find(edgeID) != otherFace.m_Edges.end()){
face.m_Neighbors.insert(otherFaceID);
}
}
}
}
}
m_TimberInfo.m_Cuts[cutInfo.m_ID] = cutInfo;
m_TimberInfo.m_Components[cutInfo.m_ID] = &m_TimberInfo.m_Cuts[cutInfo.m_ID];
}
if(m_TimberInfo.GetCurrentComponent() == nullptr){
m_TimberInfo.m_CurrentComponentID = m_TimberInfo.m_Components.begin()->first;
}
m_TimberInfo.GetCurrentComponent()->SetAsCurrent();
}
UpdateBboxGOLine();
m_TimberInfo.IsShowingAllComponents = true;
// Update the real world length
m_MeasuredBboxLength = GetRealWorldLength();
return true;
}
void ACInfoModel::Save() {
m_ACIMDoc.save_file(m_FilePath.c_str());
}
void ACInfoModel::Clear() {
for(auto& line : m_BboxGOLines)
GOLine::Remove(line);
m_BboxGOLines.clear();
for(auto& hole : m_TimberInfo.m_Holes){
for(auto& primitive : hole.second.m_GOPrimitives)
GOPrimitive::Remove(primitive);
}
m_TimberInfo.m_Holes.clear();
for(auto& cut : m_TimberInfo.m_Cuts){
for(auto& primitive : cut.second.m_GOPrimitives)
GOPrimitive::Remove(primitive);
for(auto& face : cut.second.m_Faces){
for(auto& primitive : face.second.m_GOPrimitives)
GOPrimitive::Remove(primitive);
}
for(auto& edge : cut.second.m_Edges){
for(auto& primitive : edge.second.m_GOPrimitives)
GOPrimitive::Remove(primitive);
edge.second.ClearCotas();
}
}
m_TimberInfo.m_Cuts.clear();
m_TimberInfo.m_Components.clear();
}
void ACInfoModel::UpdateBboxGOLine() {
auto bbox = m_TimberInfo.m_Bbox;
// update the GOLine references
for(auto& line : m_BboxGOLines)
GOLine::Remove(line);
// bottom
auto vec = glm::normalize(bbox[1] - bbox[0]);
m_BboxGOLines.push_back(GOLine::Add(bbox[0], bbox[0] + vec, 2.0f));
m_BboxGOLines.push_back(GOLine::Add(bbox[1], bbox[1] - vec, 2.0f));
vec = glm::normalize(bbox[2] - bbox[1]);
m_BboxGOLines.push_back(GOLine::Add(bbox[1], bbox[1] + vec, 2.0f));
m_BboxGOLines.push_back(GOLine::Add(bbox[2], bbox[2] - vec, 2.0f));
vec = glm::normalize(bbox[3] - bbox[2]);
m_BboxGOLines.push_back(GOLine::Add(bbox[2], bbox[2] + vec, 2.0f));
m_BboxGOLines.push_back(GOLine::Add(bbox[3], bbox[3] - vec, 2.0f));
vec = glm::normalize(bbox[0] - bbox[3]);
m_BboxGOLines.push_back(GOLine::Add(bbox[3], bbox[3] + vec, 2.0f));
m_BboxGOLines.push_back(GOLine::Add(bbox[0], bbox[0] - vec, 2.0f));
// m_BboxGOLines.push_back(GOLine::Add(bbox[0], bbox[1], 2.0f));
m_BboxGOLines.push_back(GOLine::Add(bbox[1], bbox[2], 2.0f));
// m_BboxGOLines.push_back(GOLine::Add(bbox[2], bbox[3], 2.0f));
m_BboxGOLines.push_back(GOLine::Add(bbox[3], bbox[0], 2.0f));
// top
vec = glm::normalize(bbox[5] - bbox[4]);
m_BboxGOLines.push_back(GOLine::Add(bbox[4], bbox[4] + vec, 2.0f));
m_BboxGOLines.push_back(GOLine::Add(bbox[5], bbox[5] - vec, 2.0f));
vec = glm::normalize(bbox[6] - bbox[5]);
m_BboxGOLines.push_back(GOLine::Add(bbox[5], bbox[5] + vec, 2.0f));
m_BboxGOLines.push_back(GOLine::Add(bbox[6], bbox[6] - vec, 2.0f));
vec = glm::normalize(bbox[7] - bbox[6]);
m_BboxGOLines.push_back(GOLine::Add(bbox[6], bbox[6] + vec, 2.0f));
m_BboxGOLines.push_back(GOLine::Add(bbox[7], bbox[7] - vec, 2.0f));
vec = glm::normalize(bbox[4] - bbox[7]);
m_BboxGOLines.push_back(GOLine::Add(bbox[7], bbox[7] + vec, 2.0f));
m_BboxGOLines.push_back(GOLine::Add(bbox[4], bbox[4] - vec, 2.0f));
// m_BboxGOLines.push_back(GOLine::Add(bbox[4], bbox[5], 2.0f));
m_BboxGOLines.push_back(GOLine::Add(bbox[5], bbox[6], 2.0f));
// m_BboxGOLines.push_back(GOLine::Add(bbox[6], bbox[7], 2.0f));
m_BboxGOLines.push_back(GOLine::Add(bbox[7], bbox[4], 2.0f));
// side
m_BboxGOLines.push_back(GOLine::Add(bbox[0], bbox[4], 2.0f));
m_BboxGOLines.push_back(GOLine::Add(bbox[1], bbox[5], 2.0f));
m_BboxGOLines.push_back(GOLine::Add(bbox[2], bbox[6], 2.0f));
m_BboxGOLines.push_back(GOLine::Add(bbox[3], bbox[7], 2.0f));
// color of the bounding box
for(auto line : m_BboxGOLines)
line->SetColor(GOColor::PURPLE);
SetBboxVisibility(false);
}
void ACInfoModel::Transform(glm::mat4x4 transformMat) {
// bounding box
auto bbox = m_TimberInfo.m_Bbox;
for(int i = 0 ; i < bbox.size() ; i++){
m_TimberInfo.m_Bbox[i] = glm::vec3(transformMat * glm::vec4(bbox[i], 1.0f));
}
bbox = m_TimberInfo.m_Bbox;
UpdateBboxGOLine();
// holes
for(auto& kv : m_TimberInfo.m_Holes){
auto& holeInfo = kv.second;
for(auto& objs : holeInfo.m_GOPrimitives){
objs->Transform(transformMat);
}
holeInfo.m_Start = glm::vec3(transformMat * glm::vec4(holeInfo.m_Start, 1.0f));
holeInfo.m_End = glm::vec3(transformMat * glm::vec4(holeInfo.m_End, 1.0f));
holeInfo.m_Center = (holeInfo.m_Start + holeInfo.m_End) * 0.5f;
}
// cuts
for(auto& kv : m_TimberInfo.m_Cuts){
auto& cutInfo = kv.second;
for(auto& objs : cutInfo.m_GOPrimitives){
objs->Transform(transformMat);
}
cutInfo.m_Center = glm::vec3(transformMat * glm::vec4(cutInfo.m_Center, 1.0f));
// Face
for(auto& kv : cutInfo.m_Faces){
auto& faceInfo = kv.second;
for(auto& objs : faceInfo.m_GOPrimitives){
objs->Transform(transformMat);
}
// FIXME: Add GOVec so we can use GO to manage everything.
// Normal, Center, and Corners are glm::vec3
for(auto& corner : faceInfo.m_Corners){
corner = glm::vec3(transformMat * glm::vec4(corner, 1.0f));
}
faceInfo.m_Center = glm::vec3(transformMat * glm::vec4(faceInfo.m_Center, 1.0f));
faceInfo.m_Normal = glm::normalize(glm::cross(faceInfo.m_Corners[1] - faceInfo.m_Corners[0],
faceInfo.m_Corners[2] - faceInfo.m_Corners[0]));
}
// Edge
for(auto& kv : cutInfo.m_Edges){
auto edgeInfo = kv.second;
for(auto& objs : edgeInfo.m_GOPrimitives){
objs->Transform(transformMat);
}
}
}
}
float ACInfoModel::GetLength(){
auto bbox = m_TimberInfo.m_Bbox;
float dist = 0.0f;
dist += glm::distance(bbox[0], bbox[1]);
dist += glm::distance(bbox[2], bbox[3]);
dist += glm::distance(bbox[4], bbox[5]);
dist += glm::distance(bbox[6], bbox[7]);
dist /= 4.0f;
return dist;
}
void ACInfoModel::SetBboxVisibility(bool visible){
for(auto line : m_BboxGOLines){
line->SetVisibility(visible);
}
}
void ACInfoModel::AddMeasuredBboxLength(const float diff) {
m_MeasuredBboxLength += diff;
}
void ACInfoModel::AdjustScale(){
float newScale = (GetLength() / m_Scale) / m_MeasuredBboxLength * m_Scale;
m_Scale = newScale;
AIAC::Config::UpdateEntry(AIAC::Config::SEC_AIAC, AIAC::Config::SCALE_FACTOR, newScale);
}
ACIMState StringToState(std::string state){
std::string notDoneStr = "NotDone";
std::string doneStr = "Done";
std::string currentStr = "Current";
if(!state.compare(0, notDoneStr.length(), notDoneStr)){
return ACIMState::NOT_DONE;
}
else if(!state.compare(0, doneStr.length(), doneStr)){
return ACIMState::DONE;
}
else if(!state.compare(0, currentStr.length(), currentStr)){
return ACIMState::CURRENT;
}
else {
AIAC_ERROR("Invalid state string: \"{0}\"", state);
return ACIMState::NOT_DONE;
}
}
glm::vec3 StringToVec3(std::string str){
glm::vec3 vec;
auto ss = stringstream(str);
ss >> vec.x >> vec.y >> vec.z;
return vec;
}
std::vector<std::string> StringToTokens(std::string str){
std::vector<std::string> tokens;
std::string token;
std::istringstream tokenStream(str);
while (std::getline(tokenStream, token, ' ')){
tokens.push_back(token);
}
return tokens;
}
std::set<std::string> StringToSet(std::string str){
std::set<std::string> set;
std::string token;
std::istringstream tokenStream(str);
while (std::getline(tokenStream, token, ' ')){
set.insert(token);
}
return set;
}
bool StringToBool(std::string str){
// convert str to lowercase
std::transform(str.begin(), str.end(), str.begin(), ::tolower);
std::string trueStr = "true";
std::string falseStr = "false";
if(!str.compare(0, trueStr.length(), trueStr)){
return true;
}
else if(!str.compare(0, falseStr.length(), falseStr)){
return false;
}
else {
AIAC_ERROR("Invalid bool string: {0}", str);
return false;
}
}
std::string Vec3ToString(glm::vec3 vec){
std::stringstream ss;
ss << vec.x << " " << vec.y << " " << vec.z;
return ss.str();
}
} // namespace AIAC