mirror of
https://github.com/leozide/leocad
synced 2025-01-18 22:26:44 +01:00
Reorganized PLI function.
This commit is contained in:
parent
ddf6f9dbba
commit
3b8b22493a
4 changed files with 226 additions and 228 deletions
|
@ -23,6 +23,9 @@
|
|||
#include "lc_qpropertiesdialog.h"
|
||||
#include "lc_qutils.h"
|
||||
#include "lc_lxf.h"
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
|
||||
#include <QtConcurrent>
|
||||
#endif
|
||||
|
||||
void lcModelProperties::LoadDefaults()
|
||||
{
|
||||
|
@ -1401,6 +1404,227 @@ QImage lcModel::GetStepImage(bool Zoom, bool Highlight, int Width, int Height, l
|
|||
return Image;
|
||||
}
|
||||
|
||||
QImage lcModel::GetPartsListImage(int MaxWidth, lcStep Step) const
|
||||
{
|
||||
lcPartsList PartsList;
|
||||
|
||||
if (Step == 0)
|
||||
GetPartsList(gDefaultColor, true, false, PartsList);
|
||||
else
|
||||
GetPartsListForStep(Step, gDefaultColor, PartsList);
|
||||
|
||||
if (PartsList.empty())
|
||||
return QImage();
|
||||
|
||||
struct lcPartsListImage
|
||||
{
|
||||
QImage Thumbnail;
|
||||
const PieceInfo* Info;
|
||||
int ColorIndex;
|
||||
int Count;
|
||||
QRect Bounds;
|
||||
QPoint Position;
|
||||
};
|
||||
|
||||
std::vector<lcPartsListImage> Images;
|
||||
|
||||
for (const auto& PartIt : PartsList)
|
||||
{
|
||||
for (const auto& ColorIt : PartIt.second)
|
||||
{
|
||||
Images.push_back(lcPartsListImage());
|
||||
lcPartsListImage& Image = Images.back();
|
||||
Image.Info = PartIt.first;
|
||||
Image.ColorIndex = ColorIt.first;
|
||||
Image.Count = ColorIt.second;
|
||||
}
|
||||
}
|
||||
|
||||
auto ImageCompare = [](const lcPartsListImage& Image1, const lcPartsListImage& Image2)
|
||||
{
|
||||
if (Image1.ColorIndex != Image2.ColorIndex)
|
||||
return Image1.ColorIndex < Image2.ColorIndex;
|
||||
|
||||
return strcmp(Image1.Info->m_strDescription, Image2.Info->m_strDescription) < 0;
|
||||
};
|
||||
|
||||
std::sort(Images.begin(), Images.end(), ImageCompare);
|
||||
|
||||
View* View = gMainWindow->GetActiveView();
|
||||
View->MakeCurrent();
|
||||
lcContext* Context = View->mContext;
|
||||
const int ThumbnailSize = qMin(MaxWidth, 512);
|
||||
|
||||
std::pair<lcFramebuffer, lcFramebuffer> RenderFramebuffer = Context->CreateRenderFramebuffer(ThumbnailSize, ThumbnailSize);
|
||||
|
||||
if (!RenderFramebuffer.first.IsValid())
|
||||
{
|
||||
QMessageBox::warning(gMainWindow, tr("LeoCAD"), tr("Error creating images."));
|
||||
return QImage();
|
||||
}
|
||||
|
||||
Context->BindFramebuffer(RenderFramebuffer.first);
|
||||
|
||||
float OrthoSize = 200.0f;
|
||||
|
||||
lcMatrix44 ProjectionMatrix = lcMatrix44Ortho(-OrthoSize, OrthoSize, -OrthoSize, OrthoSize, -5000.0f, 5000.0f);
|
||||
lcMatrix44 ViewMatrix = lcMatrix44LookAt(lcVector3(-100.0f, -100.0f, 75.0f), lcVector3(0.0f, 0.0f, 0.0f), lcVector3(0.0f, 0.0f, 1.0f));
|
||||
const int Viewport[4] = { 0, 0, ThumbnailSize, ThumbnailSize };
|
||||
|
||||
float ExtraPixels = 0.0f;
|
||||
|
||||
for (lcPartsListImage& Image : Images)
|
||||
{
|
||||
const PieceInfo* Info = Image.Info;
|
||||
const lcBoundingBox& BoundingBox = Info->GetBoundingBox();
|
||||
|
||||
lcVector3 Center = (BoundingBox.Min + BoundingBox.Max) / 2.0f;
|
||||
|
||||
lcVector3 Points[8];
|
||||
lcGetBoxCorners(BoundingBox.Min, BoundingBox.Max, Points);
|
||||
|
||||
for (lcVector3& Point : Points)
|
||||
{
|
||||
Point = lcProjectPoint(Point, ViewMatrix, ProjectionMatrix, Viewport);
|
||||
|
||||
ExtraPixels = qMax(ExtraPixels, -Point.x);
|
||||
ExtraPixels = qMax(ExtraPixels, Point.x - ThumbnailSize);
|
||||
ExtraPixels = qMax(ExtraPixels, -Point.y);
|
||||
ExtraPixels = qMax(ExtraPixels, Point.y - ThumbnailSize);
|
||||
}
|
||||
}
|
||||
|
||||
if (ExtraPixels)
|
||||
{
|
||||
OrthoSize += ExtraPixels * (2.0f * OrthoSize / ThumbnailSize);
|
||||
ProjectionMatrix = lcMatrix44Ortho(-OrthoSize, OrthoSize, -OrthoSize, OrthoSize, -5000.0f, 5000.0f);
|
||||
}
|
||||
|
||||
Context->SetViewport(0, 0, ThumbnailSize, ThumbnailSize);
|
||||
Context->SetDefaultState();
|
||||
Context->SetProjectionMatrix(ProjectionMatrix);
|
||||
|
||||
for (lcPartsListImage& Image : Images)
|
||||
{
|
||||
glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
lcScene Scene;
|
||||
Scene.SetAllowWireframe(false);
|
||||
Scene.SetAllowLOD(false);
|
||||
Scene.Begin(ViewMatrix);
|
||||
|
||||
Image.Info->AddRenderMeshes(Scene, lcMatrix44Identity(), Image.ColorIndex, lcRenderMeshState::Default, true);
|
||||
|
||||
Scene.End();
|
||||
|
||||
Scene.Draw(Context);
|
||||
|
||||
Image.Thumbnail = Context->GetRenderFramebufferImage(RenderFramebuffer);
|
||||
}
|
||||
|
||||
Context->ClearFramebuffer();
|
||||
Context->DestroyRenderFramebuffer(RenderFramebuffer);
|
||||
Context->ClearResources();
|
||||
|
||||
auto CalculateImageBounds = [](lcPartsListImage& Image)
|
||||
{
|
||||
QImage& Thumbnail = Image.Thumbnail;
|
||||
int Width = Thumbnail.width();
|
||||
int Height = Thumbnail.height();
|
||||
|
||||
int MinX = Width;
|
||||
int MinY = Height;
|
||||
int MaxX = 0;
|
||||
int MaxY = 0;
|
||||
|
||||
for (int x = 0; x < Width; x++)
|
||||
{
|
||||
for (int y = 0; y < Height; y++)
|
||||
{
|
||||
if (qAlpha(Thumbnail.pixel(x, y)))
|
||||
{
|
||||
MinX = qMin(x, MinX);
|
||||
MinY = qMin(y, MinY);
|
||||
MaxX = qMax(x, MaxX);
|
||||
MaxY = qMax(y, MaxY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Image.Bounds = QRect(QPoint(MinX, MinY), QPoint(MaxX, MaxY));
|
||||
};
|
||||
|
||||
QtConcurrent::blockingMap(Images, CalculateImageBounds);
|
||||
|
||||
QImage DummyImage(16, 16, QImage::Format_ARGB32);
|
||||
QPainter DummyPainter(&DummyImage);
|
||||
|
||||
QFont Font("helvetica", 20, QFont::Bold);
|
||||
DummyPainter.setFont(Font);
|
||||
QFontMetrics FontMetrics = DummyPainter.fontMetrics();
|
||||
int Ascent = FontMetrics.ascent();
|
||||
|
||||
int CurrentHeight = 0;
|
||||
int ImageWidth = MaxWidth;
|
||||
|
||||
for (lcPartsListImage& Image : Images)
|
||||
CurrentHeight = qMax(Image.Bounds.height() + Ascent, CurrentHeight);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
int CurrentWidth = 0;
|
||||
int CurrentX = 0;
|
||||
int CurrentY = 0;
|
||||
int ColumnWidth = 0;
|
||||
int Spacing = 20;
|
||||
int NextHeightIncrease = INT_MAX;
|
||||
|
||||
for (lcPartsListImage& Image : Images)
|
||||
{
|
||||
if (CurrentY + Image.Bounds.height() + Ascent > CurrentHeight)
|
||||
{
|
||||
int NeededSpace = Image.Bounds.height() + Ascent - (CurrentHeight - CurrentY);
|
||||
NextHeightIncrease = qMin(NeededSpace, NextHeightIncrease);
|
||||
|
||||
CurrentY = 0;
|
||||
CurrentX += ColumnWidth + Spacing;
|
||||
ColumnWidth = 0;
|
||||
}
|
||||
|
||||
Image.Position = QPoint(CurrentX, CurrentY);
|
||||
CurrentY += Image.Bounds.height() + Ascent + Spacing;
|
||||
CurrentWidth = qMax(CurrentWidth, CurrentX + Image.Bounds.width());
|
||||
ColumnWidth = qMax(ColumnWidth, Image.Bounds.width());
|
||||
}
|
||||
|
||||
if (CurrentWidth < MaxWidth)
|
||||
{
|
||||
ImageWidth = CurrentWidth;
|
||||
break;
|
||||
}
|
||||
|
||||
CurrentHeight += NextHeightIncrease;
|
||||
}
|
||||
|
||||
QImage PainterImage(ImageWidth + 40, CurrentHeight + 40, QImage::Format_ARGB32);
|
||||
PainterImage.fill(QColor(255, 255, 255, 0));
|
||||
|
||||
QPainter Painter(&PainterImage);
|
||||
Painter.setFont(Font);
|
||||
|
||||
for (lcPartsListImage& Image : Images)
|
||||
{
|
||||
QPoint Position = Image.Position + QPoint(20, 20);
|
||||
Painter.drawImage(Position, Image.Thumbnail, Image.Bounds);
|
||||
Painter.drawText(QPoint(Position.x(), Position.y() + Image.Bounds.height() + Ascent), QString::number(Image.Count) + 'x');
|
||||
}
|
||||
|
||||
Painter.end();
|
||||
|
||||
return PainterImage;
|
||||
}
|
||||
|
||||
void lcModel::SaveStepImages(const QString& BaseName, bool AddStepSuffix, bool Zoom, bool Highlight, int Width, int Height, lcStep Start, lcStep End)
|
||||
{
|
||||
for (lcStep Step = Start; Step <= End; Step++)
|
||||
|
|
|
@ -229,6 +229,7 @@ public:
|
|||
void AddSubModelRenderMeshes(lcScene& Scene, const lcMatrix44& WorldMatrix, int DefaultColorIndex, lcRenderMeshState RenderMeshState, bool ParentActive) const;
|
||||
void DrawBackground(lcGLWidget* Widget);
|
||||
QImage GetStepImage(bool Zoom, bool Highlight, int Width, int Height, lcStep Step);
|
||||
QImage GetPartsListImage(int MaxWidth, lcStep Step) const;
|
||||
void SaveStepImages(const QString& BaseName, bool AddStepSuffix, bool Zoom, bool Highlight, int Width, int Height, lcStep Start, lcStep End);
|
||||
std::vector<std::pair<lcModel*, lcStep>> GetPageLayouts(std::vector<const lcModel*>& AddedModels);
|
||||
|
||||
|
|
|
@ -15,9 +15,6 @@
|
|||
#include "lc_zipfile.h"
|
||||
#include "lc_qimagedialog.h"
|
||||
#include "lc_qmodellistdialog.h"
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
|
||||
#include <QtConcurrent>
|
||||
#endif
|
||||
|
||||
lcHTMLExportOptions::lcHTMLExportOptions(const Project* Project)
|
||||
{
|
||||
|
@ -1492,229 +1489,6 @@ std::vector<std::pair<lcModel*, lcStep>> Project::GetPageLayouts() const
|
|||
return std::vector<std::pair<lcModel*, lcStep>>();
|
||||
}
|
||||
|
||||
QImage Project::CreatePartsListImage(lcModel* Model, lcStep Step)
|
||||
{
|
||||
lcPartsList PartsList;
|
||||
if (Step == 0)
|
||||
Model->GetPartsList(gDefaultColor, true, false, PartsList);
|
||||
else
|
||||
Model->GetPartsListForStep(Step, gDefaultColor, PartsList);
|
||||
|
||||
if (PartsList.empty())
|
||||
return QImage();
|
||||
|
||||
struct lcPartsListImage
|
||||
{
|
||||
QImage Thumbnail;
|
||||
const PieceInfo* Info;
|
||||
int ColorIndex;
|
||||
int Count;
|
||||
QRect Bounds;
|
||||
QPoint Position;
|
||||
};
|
||||
|
||||
std::vector<lcPartsListImage> Images;
|
||||
|
||||
for (const auto& PartIt : PartsList)
|
||||
{
|
||||
for (const auto& ColorIt : PartIt.second)
|
||||
{
|
||||
Images.push_back(lcPartsListImage());
|
||||
lcPartsListImage& Image = Images.back();
|
||||
Image.Info = PartIt.first;
|
||||
Image.ColorIndex = ColorIt.first;
|
||||
Image.Count = ColorIt.second;
|
||||
}
|
||||
}
|
||||
|
||||
auto ImageCompare = [](const lcPartsListImage& Image1, const lcPartsListImage& Image2)
|
||||
{
|
||||
if (Image1.ColorIndex != Image2.ColorIndex)
|
||||
return Image1.ColorIndex < Image2.ColorIndex;
|
||||
|
||||
return strcmp(Image1.Info->m_strDescription, Image2.Info->m_strDescription) < 0;
|
||||
};
|
||||
|
||||
std::sort(Images.begin(), Images.end(), ImageCompare);
|
||||
|
||||
View* View = gMainWindow->GetActiveView();
|
||||
View->MakeCurrent();
|
||||
lcContext* Context = View->mContext;
|
||||
const int ThumbnailSize = 512;
|
||||
|
||||
std::pair<lcFramebuffer, lcFramebuffer> RenderFramebuffer = Context->CreateRenderFramebuffer(ThumbnailSize, ThumbnailSize);
|
||||
|
||||
if (!RenderFramebuffer.first.IsValid())
|
||||
{
|
||||
QMessageBox::warning(gMainWindow, tr("LeoCAD"), tr("Error creating images."));
|
||||
return QImage();
|
||||
}
|
||||
|
||||
Context->BindFramebuffer(RenderFramebuffer.first);
|
||||
|
||||
float OrthoSize = 200.0f;
|
||||
|
||||
lcMatrix44 ProjectionMatrix = lcMatrix44Ortho(-OrthoSize, OrthoSize, -OrthoSize, OrthoSize, -5000.0f, 5000.0f);
|
||||
lcMatrix44 ViewMatrix = lcMatrix44LookAt(lcVector3(-100.0f, -100.0f, 75.0f), lcVector3(0.0f, 0.0f, 0.0f), lcVector3(0.0f, 0.0f, 1.0f));
|
||||
const int Viewport[4] = { 0, 0, ThumbnailSize, ThumbnailSize };
|
||||
|
||||
float ExtraPixels = 0.0f;
|
||||
|
||||
for (lcPartsListImage& Image : Images)
|
||||
{
|
||||
const PieceInfo* Info = Image.Info;
|
||||
const lcBoundingBox& BoundingBox = Info->GetBoundingBox();
|
||||
|
||||
lcVector3 Center = (BoundingBox.Min + BoundingBox.Max) / 2.0f;
|
||||
|
||||
lcVector3 Points[8];
|
||||
lcGetBoxCorners(BoundingBox.Min, BoundingBox.Max, Points);
|
||||
|
||||
for (lcVector3& Point : Points)
|
||||
{
|
||||
Point = lcProjectPoint(Point, ViewMatrix, ProjectionMatrix, Viewport);
|
||||
|
||||
ExtraPixels = qMax(ExtraPixels, -Point.x);
|
||||
ExtraPixels = qMax(ExtraPixels, Point.x - ThumbnailSize);
|
||||
ExtraPixels = qMax(ExtraPixels, -Point.y);
|
||||
ExtraPixels = qMax(ExtraPixels, Point.y - ThumbnailSize);
|
||||
}
|
||||
}
|
||||
|
||||
if (ExtraPixels)
|
||||
{
|
||||
OrthoSize += ExtraPixels * (2.0f * OrthoSize / ThumbnailSize);
|
||||
ProjectionMatrix = lcMatrix44Ortho(-OrthoSize, OrthoSize, -OrthoSize, OrthoSize, -5000.0f, 5000.0f);
|
||||
}
|
||||
|
||||
Context->SetViewport(0, 0, ThumbnailSize, ThumbnailSize);
|
||||
Context->SetDefaultState();
|
||||
Context->SetProjectionMatrix(ProjectionMatrix);
|
||||
|
||||
for (lcPartsListImage& Image : Images)
|
||||
{
|
||||
glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
lcScene Scene;
|
||||
Scene.SetAllowWireframe(false);
|
||||
Scene.SetAllowLOD(false);
|
||||
Scene.Begin(ViewMatrix);
|
||||
|
||||
Image.Info->AddRenderMeshes(Scene, lcMatrix44Identity(), Image.ColorIndex, lcRenderMeshState::Default, true);
|
||||
|
||||
Scene.End();
|
||||
|
||||
Scene.Draw(Context);
|
||||
|
||||
Image.Thumbnail = Context->GetRenderFramebufferImage(RenderFramebuffer);
|
||||
}
|
||||
|
||||
Context->ClearFramebuffer();
|
||||
Context->DestroyRenderFramebuffer(RenderFramebuffer);
|
||||
Context->ClearResources();
|
||||
|
||||
auto CalculateImageBounds = [](lcPartsListImage& Image)
|
||||
{
|
||||
QImage& Thumbnail = Image.Thumbnail;
|
||||
int Width = Thumbnail.width();
|
||||
int Height = Thumbnail.height();
|
||||
|
||||
int MinX = Width;
|
||||
int MinY = Height;
|
||||
int MaxX = 0;
|
||||
int MaxY = 0;
|
||||
|
||||
for (int x = 0; x < Width; x++)
|
||||
{
|
||||
for (int y = 0; y < Height; y++)
|
||||
{
|
||||
if (qAlpha(Thumbnail.pixel(x, y)))
|
||||
{
|
||||
MinX = qMin(x, MinX);
|
||||
MinY = qMin(y, MinY);
|
||||
MaxX = qMax(x, MaxX);
|
||||
MaxY = qMax(y, MaxY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Image.Bounds = QRect(QPoint(MinX, MinY), QPoint(MaxX, MaxY));
|
||||
};
|
||||
|
||||
QtConcurrent::blockingMap(Images, CalculateImageBounds);
|
||||
|
||||
QImage DummyImage(16, 16, QImage::Format_ARGB32);
|
||||
QPainter DummyPainter(&DummyImage);
|
||||
|
||||
QFont Font("helvetica", 20, QFont::Bold);
|
||||
DummyPainter.setFont(Font);
|
||||
QFontMetrics FontMetrics = DummyPainter.fontMetrics();
|
||||
int Ascent = FontMetrics.ascent();
|
||||
|
||||
int CurrentHeight = 0;
|
||||
int MaxWidth = 1024;
|
||||
|
||||
for (lcPartsListImage& Image : Images)
|
||||
{
|
||||
CurrentHeight = qMax(Image.Bounds.height() + Ascent, CurrentHeight);
|
||||
MaxWidth = qMax(MaxWidth, Image.Bounds.width());
|
||||
}
|
||||
|
||||
for (;;)
|
||||
{
|
||||
int CurrentWidth = 0;
|
||||
int CurrentX = 0;
|
||||
int CurrentY = 0;
|
||||
int ColumnWidth = 0;
|
||||
int Spacing = 20;
|
||||
int NextHeightIncrease = INT_MAX;
|
||||
|
||||
for (lcPartsListImage& Image : Images)
|
||||
{
|
||||
if (CurrentY + Image.Bounds.height() + Ascent > CurrentHeight)
|
||||
{
|
||||
int NeededSpace = Image.Bounds.height() + Ascent - (CurrentHeight - CurrentY);
|
||||
NextHeightIncrease = qMin(NeededSpace, NextHeightIncrease);
|
||||
|
||||
CurrentY = 0;
|
||||
CurrentX += ColumnWidth + Spacing;
|
||||
ColumnWidth = 0;
|
||||
}
|
||||
|
||||
Image.Position = QPoint(CurrentX, CurrentY);
|
||||
CurrentY += Image.Bounds.height() + Ascent + Spacing;
|
||||
CurrentWidth = qMax(CurrentWidth, CurrentX + Image.Bounds.width());
|
||||
ColumnWidth = qMax(ColumnWidth, Image.Bounds.width());
|
||||
}
|
||||
|
||||
if (CurrentWidth < MaxWidth)
|
||||
{
|
||||
MaxWidth = CurrentWidth;
|
||||
break;
|
||||
}
|
||||
|
||||
CurrentHeight += NextHeightIncrease;
|
||||
}
|
||||
|
||||
QImage PainterImage(MaxWidth + 40, CurrentHeight + 40, QImage::Format_ARGB32);
|
||||
PainterImage.fill(QColor(255, 255, 255, 0));
|
||||
|
||||
QPainter Painter(&PainterImage);
|
||||
Painter.setFont(Font);
|
||||
|
||||
for (lcPartsListImage& Image : Images)
|
||||
{
|
||||
QPoint Position = Image.Position + QPoint(20, 20);
|
||||
Painter.drawImage(Position, Image.Thumbnail, Image.Bounds);
|
||||
Painter.drawText(QPoint(Position.x(), Position.y() + Image.Bounds.height() + Ascent), QString::number(Image.Count) + 'x');
|
||||
}
|
||||
|
||||
Painter.end();
|
||||
|
||||
return PainterImage;
|
||||
}
|
||||
|
||||
void Project::ExportHTML(const lcHTMLExportOptions& Options)
|
||||
{
|
||||
QDir Dir(Options.PathName);
|
||||
|
@ -1736,7 +1510,7 @@ void Project::ExportHTML(const lcHTMLExportOptions& Options)
|
|||
|
||||
auto AddPartsListImage = [this, &Dir](QTextStream& Stream, lcModel* Model, lcStep Step, const QString& BaseName)
|
||||
{
|
||||
QImage Image = CreatePartsListImage(Model, Step);
|
||||
QImage Image = Model->GetPartsListImage(1024, Step);
|
||||
|
||||
if (!Image.isNull())
|
||||
{
|
||||
|
|
|
@ -108,7 +108,6 @@ public:
|
|||
protected:
|
||||
QString GetExportFileName(const QString& FileName, const QString& DefaultExtension, const QString& DialogTitle, const QString& DialogFilter) const;
|
||||
std::vector<lcModelPartsEntry> GetModelParts();
|
||||
QImage CreatePartsListImage(lcModel* Model, lcStep Step);
|
||||
void SetFileName(const QString& FileName);
|
||||
|
||||
bool mModified;
|
||||
|
|
Loading…
Reference in a new issue