Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ElmerCSC
GitHub Repository: ElmerCSC/elmerfem
Path: blob/devel/ElmerGUI/Application/cad/cadview.cpp
3203 views
1
/*****************************************************************************
2
* *
3
* Elmer, A Finite Element Software for Multiphysical Problems *
4
* *
5
* Copyright 1st April 1995 - , CSC - IT Center for Science Ltd., Finland *
6
* *
7
* This program is free software; you can redistribute it and/or *
8
* modify it under the terms of the GNU General Public License *
9
* as published by the Free Software Foundation; either version 2 *
10
* of the License, or (at your option) any later version. *
11
* *
12
* This program is distributed in the hope that it will be useful, *
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15
* GNU General Public License for more details. *
16
* *
17
* You should have received a copy of the GNU General Public License *
18
* along with this program (in file fem/GPL-2); if not, write to the *
19
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, *
20
* Boston, MA 02110-1301, USA. *
21
* *
22
*****************************************************************************/
23
24
/*****************************************************************************
25
* *
26
* ElmerGUI cadview *
27
* *
28
*****************************************************************************
29
* *
30
* Authors: Mikko Lyly, Juha Ruokolainen and Peter RÃ¥back *
31
* Email: [email protected] *
32
* Web: http://www.csc.fi/elmer *
33
* Address: CSC - IT Center for Science Ltd. *
34
* Keilaranta 14 *
35
* 02101 Espoo, Finland *
36
* *
37
* Original Date: 15 Mar 2008 *
38
* *
39
*****************************************************************************/
40
41
#if WITH_QT5 || WITH_QT6
42
#include <QtWidgets>
43
#else
44
#include <QtGui>
45
#endif
46
47
#include <iostream>
48
49
#include "cadview.h"
50
51
#if VTK_MAJOR_VERSION >= 8
52
#include <vtkVersionMacros.h>
53
#include <QVTKOpenGLNativeWidget.h>
54
#else
55
#include <QVTKWidget.h>
56
#endif
57
58
#include <vtkActor.h>
59
#include <vtkAppendPolyData.h>
60
#include <vtkCallbackCommand.h>
61
#include <vtkCleanPolyData.h>
62
#include <vtkDataSetMapper.h>
63
#include <vtkFeatureEdges.h>
64
#include <vtkFloatArray.h>
65
#include <vtkPoints.h>
66
#include <vtkPolyDataMapper.h>
67
#include <vtkPolyDataNormals.h>
68
#include <vtkPropPicker.h>
69
#include <vtkProperty.h>
70
#include <vtkRenderWindow.h>
71
#include <vtkRenderer.h>
72
#include <vtkTriangle.h>
73
74
#include <BRepAdaptor_Curve2d.hxx>
75
#include <BRepBndLib.hxx>
76
#include <BRepGProp.hxx>
77
#include <BRepTools.hxx>
78
#include <BRep_Builder.hxx>
79
#if OCE_FOUND
80
#include <BRepMesh.hxx>
81
#endif
82
#include <BRep_Tool.hxx>
83
#include <Bnd_Box.hxx>
84
#include <GCPnts_TangentialDeflection.hxx>
85
#include <GProp_GProps.hxx>
86
#include <GeomLProp_SLProps.hxx>
87
#include <IGESControl_Reader.hxx>
88
#include <Poly_Triangulation.hxx>
89
#include <STEPControl_Reader.hxx>
90
#include <TopExp_Explorer.hxx>
91
#include <TopTools_HSequenceOfShape.hxx>
92
#include <TopoDS.hxx>
93
#include <TopoDS_Edge.hxx>
94
#include <TopoDS_Face.hxx>
95
#include <TopoDS_Shape.hxx>
96
97
using namespace std;
98
static void pickEventHandler(vtkObject* caller, unsigned long eid,
99
void* clientdata, void* calldata)
100
{
101
CadView* cadView = reinterpret_cast<CadView*>(clientdata);
102
103
#if VTK_MAJOR_VERSION >= 8
104
QVTKOpenGLNativeWidget* qvtkWidget = cadView->GetQVTKWidget();
105
#else
106
QVTKWidget* qvtkWidget = cadView->GetQVTKWidget();
107
#endif
108
109
#if VTK_MAJOR_VERSION >= 9
110
vtkAbstractPicker* picker = qvtkWidget->interactor()->GetPicker();
111
#else
112
vtkAbstractPicker* picker = qvtkWidget->GetInteractor()->GetPicker();
113
#endif
114
vtkPropPicker* propPicker = vtkPropPicker::SafeDownCast(picker);
115
vtkActor* actor = propPicker->GetActor();
116
117
int faceNumber = cadView->getFaceNumber(actor);
118
119
if (faceNumber > 0) {
120
vtkProperty *p = actor->GetProperty();
121
122
double color[3];
123
p->GetColor(color);
124
125
// Toggle color:
126
//--------------
127
if (color[0] < 0.5) {
128
cout << "Selected face: ";
129
p->SetColor(1, 0, 0);
130
} else {
131
cout << "Unselected face: ";
132
p->SetColor(0, 1, 1);
133
}
134
cout << faceNumber << endl;
135
}
136
}
137
138
CadView::CadView(QWidget *parent) : QMainWindow(parent) {
139
setWindowTitle("ElmerGUI geometry viewer");
140
setWindowIcon(QIcon(":/icons/Mesh3D.png"));
141
142
createActions();
143
createMenus();
144
145
#if VTK_MAJOR_VERSION >= 8
146
qVTKWidget = new QVTKOpenGLNativeWidget(this);
147
qVTKWidget->setFormat(QVTKOpenGLNativeWidget::defaultFormat());
148
#else
149
qVTKWidget = new QVTKWidget(this);
150
#endif
151
setCentralWidget(qVTKWidget);
152
153
renderer = vtkRenderer::New();
154
renderer->SetBackground(1, 1, 1);
155
#if VTK_MAJOR_VERSION >=9
156
qVTKWidget->renderWindow()->AddRenderer(renderer);
157
#else
158
qVTKWidget->GetRenderWindow()->AddRenderer(renderer);
159
#endif
160
renderer->GetRenderWindow()->Render();
161
162
vtkPropPicker *propPicker = vtkPropPicker::New();
163
vtkCallbackCommand *cbcPick = vtkCallbackCommand::New();
164
#if VTK_MAJOR_VERSION >= 9
165
qVTKWidget->interactor()->SetPicker(propPicker);
166
cbcPick->SetClientData(this);
167
cbcPick->SetCallback(pickEventHandler);
168
qVTKWidget->interactor()->GetPicker()->AddObserver(vtkCommand::PickEvent,
169
cbcPick);
170
#else
171
qVTKWidget->GetInteractor()->SetPicker(propPicker);
172
cbcPick->SetClientData(this);
173
cbcPick->SetCallback(pickEventHandler);
174
qVTKWidget->GetInteractor()->GetPicker()->AddObserver(vtkCommand::PickEvent,
175
cbcPick);
176
#endif
177
propPicker->Delete();
178
cbcPick->Delete();
179
180
stlSurfaceData = vtkAppendPolyData::New();
181
stlEdgeData = vtkAppendPolyData::New();
182
183
cadPreferences = new CadPreferences(this);
184
185
modelLength = 0.0;
186
numberOfFaces = 0;
187
fileName = "";
188
modelDim = -1;
189
}
190
191
CadView::~CadView() {}
192
193
QSize CadView::minimumSizeHint() const { return QSize(64, 64); }
194
195
QSize CadView::sizeHint() const { return QSize(720, 576); }
196
197
void CadView::createActions() {
198
exitAct = new QAction(QIcon::fromTheme("emblem-unreadable"), tr("&Quit"), this);
199
exitAct->setShortcut(tr("Ctrl+Q"));
200
connect(exitAct, SIGNAL(triggered()), this, SLOT(closeSlot()));
201
202
cadPreferencesAct = new QAction(QIcon::fromTheme("preferences-system"), tr("Preferences..."), this);
203
cadPreferencesAct->setShortcut(tr("Ctrl+P"));
204
connect(cadPreferencesAct, SIGNAL(triggered()), this,
205
SLOT(cadPreferencesSlot()));
206
207
reloadAct = new QAction(QIcon::fromTheme("view-refresh"), tr("Reload geometry"), this);
208
reloadAct->setShortcut(tr("Ctrl+R"));
209
connect(reloadAct, SIGNAL(triggered()), this, SLOT(reloadSlot()));
210
}
211
212
void CadView::createMenus() {
213
fileMenu = menuBar()->addMenu(tr("&File"));
214
fileMenu->addAction(reloadAct);
215
fileMenu->addSeparator();
216
fileMenu->addAction(exitAct);
217
218
modelMenu = menuBar()->addMenu(tr("&Model"));
219
modelMenu->addAction(cadPreferencesAct);
220
}
221
222
void CadView::closeSlot() { close(); }
223
224
void CadView::cadPreferencesSlot() { cadPreferences->show(); }
225
226
void CadView::reloadSlot() {
227
if (this->fileName.isEmpty())
228
return;
229
readFile(this->fileName);
230
}
231
232
bool CadView::readFile(QString fileName) {
233
double deflection = cadPreferences->ui.deflection->text().toDouble();
234
double featureAngle = cadPreferences->ui.featureAngle->text().toDouble();
235
bool mergePoints = cadPreferences->ui.mergePoints->isChecked();
236
237
if (deflection < 0.0) {
238
deflection = 0.0005;
239
cout << "Bad value for deflection. Using: " << deflection << endl;
240
}
241
242
if (featureAngle < 0.0) {
243
featureAngle = 30.0;
244
cout << "Bad value for feature angle. Using: " << featureAngle << endl;
245
}
246
247
if (stlSurfaceData->GetOutput()->GetNumberOfPoints() > 0)
248
stlSurfaceData->Delete();
249
250
if (stlEdgeData->GetOutput()->GetNumberOfPoints() > 0)
251
stlEdgeData->Delete();
252
253
stlSurfaceData = vtkAppendPolyData::New();
254
stlEdgeData = vtkAppendPolyData::New();
255
256
if (fileName.isEmpty()) {
257
cout << "File name is empty. Aborting." << endl;
258
return false;
259
}
260
261
QFileInfo fileInfo(fileName);
262
QString fileSuffix = fileInfo.suffix().toLower();
263
264
// TopoDS_Shape shape;
265
266
if (fileSuffix == "brep")
267
shape = readBrep(fileName);
268
269
if ((fileSuffix == "step") || (fileSuffix == "stp"))
270
shape = readStep(fileName);
271
272
if ((fileSuffix == "iges") || (fileSuffix == "igs"))
273
shape = readIges(fileName);
274
275
if (shape.IsNull()) {
276
cout << "Cad import: No shapes. Aborting" << endl;
277
return false;
278
}
279
280
BRepTools::Clean(shape);
281
282
// Check 3D properties:
283
//----------------------
284
GProp_GProps System;
285
BRepGProp::VolumeProperties(shape, System);
286
double mass = System.Mass();
287
288
if (mass < 1.0e-12) {
289
QMessageBox message;
290
message.setIcon(QMessageBox::Warning);
291
message.setText("Non 3D-shape detected");
292
message.setInformativeText(
293
"The cad import features of ElmerGUI are currently limited to 3D "
294
"models. Please consider using external software or other formats for "
295
"meshing 1D and 2D geometries.");
296
message.exec();
297
}
298
299
// Go:
300
//-----
301
this->fileName = fileName;
302
303
actorToFace.clear();
304
305
clearScreen();
306
307
// Compute bounding box:
308
//----------------------
309
Bnd_Box boundingBox;
310
double min[3], max[3];
311
312
BRepBndLib::Add(shape, boundingBox);
313
boundingBox.Get(min[0], min[1], min[2], max[0], max[1], max[2]);
314
315
cout << "Bounding box: "
316
<< "[ " << min[0] << ", " << min[1] << ", " << min[2] << "] x "
317
<< "[ " << max[0] << ", " << max[1] << ", " << max[2] << "]" << endl;
318
319
double length = sqrt((max[2] - min[2]) * (max[2] - min[2]) +
320
(max[1] - min[1]) * (max[1] - min[1]) +
321
(max[0] - min[0]) * (max[0] - min[0]));
322
323
deflection *= length; // use relative units
324
325
double t0 = sqrt((max[0] - min[0]) * (max[0] - min[0]));
326
double t1 = sqrt((max[1] - min[1]) * (max[1] - min[1]));
327
double t2 = sqrt((max[2] - min[2]) * (max[2] - min[2]));
328
329
modelDim = 3;
330
331
double tol = 1.0e-6 * length;
332
333
if ((t0 < tol) || (t1 < tol) || (t2 < tol)) {
334
modelDim = 2;
335
// cout << "Cad import: Shape seems to be 2D. Unable to proceed. Aborting."
336
// << endl; return false;
337
}
338
339
// Construct model data and draw surfaces:
340
//-----------------------------------------
341
#if OCC_VERSION_HEX >= 0x060800
342
BRepMesh_IncrementalMesh(shape, deflection);
343
#else
344
BRepMesh::Mesh(shape, deflection);
345
#endif
346
347
numberOfFaces = 0;
348
TopExp_Explorer expFace;
349
for (expFace.Init(shape, TopAbs_FACE); expFace.More(); expFace.Next()) {
350
TopoDS_Face Face = TopoDS::Face(expFace.Current());
351
352
TopLoc_Location Location;
353
Handle(Poly_Triangulation) Triangulation =
354
BRep_Tool::Triangulation(Face, Location);
355
356
if (Triangulation.IsNull()) {
357
cout << "Encountered empty triangulation after face: "
358
<< numberOfFaces + 1 << endl;
359
continue;
360
}
361
362
const gp_Trsf &Transformation = Location.Transformation();
363
364
int nofTriangles = Triangulation->NbTriangles();
365
int nofNodes = Triangulation->NbNodes();
366
367
if (nofTriangles < 1) {
368
cout << "No triangles for mesh on face: " << numberOfFaces + 1 << endl;
369
continue;
370
}
371
372
if (nofNodes < 1) {
373
cout << "No nodes for mesh on face: " << numberOfFaces + 1 << endl;
374
continue;
375
}
376
377
numberOfFaces++;
378
379
int n0, n1, n2;
380
vtkPolyData *partGrid = vtkPolyData::New();
381
vtkTriangle *triangle = vtkTriangle::New();
382
partGrid->Allocate(nofTriangles, nofTriangles);
383
384
#if OCC_VERSION_HEX >= 0x070600
385
for (int i = 1; i <= nofTriangles; i++) {
386
Triangulation->Triangle(i).Get(n0, n1, n2);
387
388
if (Face.Orientation() != TopAbs_FORWARD) {
389
int tmp = n2;
390
n2 = n1;
391
n1 = tmp;
392
}
393
394
triangle->GetPointIds()->SetId(0, n0 - 1);
395
triangle->GetPointIds()->SetId(1, n1 - 1);
396
triangle->GetPointIds()->SetId(2, n2 - 1);
397
398
partGrid->InsertNextCell(triangle->GetCellType(),
399
triangle->GetPointIds());
400
}
401
402
double x[3];
403
vtkPoints *partPoints = vtkPoints::New();
404
405
for (int i = 1; i <= nofNodes; i++) {
406
gp_XYZ XYZ = Triangulation->Node(i).Coord();
407
408
Transformation.Transforms(XYZ);
409
x[0] = XYZ.X();
410
x[1] = XYZ.Y();
411
x[2] = XYZ.Z();
412
partPoints->InsertPoint(i - 1, x);
413
}
414
#else
415
const Poly_Array1OfTriangle &Triangles = Triangulation->Triangles();
416
const TColgp_Array1OfPnt &Nodes = Triangulation->Nodes();
417
418
for (int i = Triangles.Lower(); i <= Triangles.Upper(); i++) {
419
Triangles(i).Get(n0, n1, n2);
420
421
if (Face.Orientation() != TopAbs_FORWARD) {
422
int tmp = n2;
423
n2 = n1;
424
n1 = tmp;
425
}
426
427
triangle->GetPointIds()->SetId(0, n0 - Nodes.Lower());
428
triangle->GetPointIds()->SetId(1, n1 - Nodes.Lower());
429
triangle->GetPointIds()->SetId(2, n2 - Nodes.Lower());
430
431
partGrid->InsertNextCell(triangle->GetCellType(),
432
triangle->GetPointIds());
433
}
434
435
double x[3];
436
vtkPoints *partPoints = vtkPoints::New();
437
438
for (int i = Nodes.Lower(); i <= Nodes.Upper(); i++) {
439
gp_XYZ XYZ = Nodes(i).Coord();
440
441
Transformation.Transforms(XYZ);
442
x[0] = XYZ.X();
443
x[1] = XYZ.Y();
444
x[2] = XYZ.Z();
445
partPoints->InsertPoint(i - Nodes.Lower(), x);
446
}
447
#endif
448
449
partGrid->SetPoints(partPoints);
450
451
452
// Draw part:
453
//-----------
454
vtkCleanPolyData *partCleaner = vtkCleanPolyData::New();
455
#if VTK_MAJOR_VERSION <= 5
456
partCleaner->SetInput(partGrid);
457
#else
458
partCleaner->SetInputData(partGrid);
459
partCleaner->Update();
460
#endif
461
if (mergePoints) {
462
partCleaner->PointMergingOn();
463
} else {
464
partCleaner->PointMergingOff();
465
}
466
467
vtkPolyDataNormals *partNormals = vtkPolyDataNormals::New();
468
partNormals->SetInputConnection(partCleaner->GetOutputPort());
469
partNormals->SetFeatureAngle(featureAngle);
470
471
vtkDataSetMapper *partMapper = vtkDataSetMapper::New();
472
partMapper->SetInputConnection(partNormals->GetOutputPort());
473
partMapper->ScalarVisibilityOff();
474
475
vtkActor *partActor = vtkActor::New();
476
partActor->SetPickable(1);
477
partActor->GetProperty()->SetColor(0, 1, 1);
478
partActor->SetMapper(partMapper);
479
renderer->AddActor(partActor);
480
actorToFace.insert(partActor, numberOfFaces);
481
482
vtkFeatureEdges *partFeature = vtkFeatureEdges::New();
483
partFeature->SetInputConnection(partCleaner->GetOutputPort());
484
partFeature->SetFeatureAngle(featureAngle);
485
partFeature->FeatureEdgesOff();
486
partFeature->BoundaryEdgesOn();
487
partFeature->NonManifoldEdgesOn();
488
partFeature->ManifoldEdgesOff();
489
490
vtkDataSetMapper *partFeatureMapper = vtkDataSetMapper::New();
491
partFeatureMapper->SetInputConnection(partFeature->GetOutputPort());
492
partFeatureMapper->SetResolveCoincidentTopologyToPolygonOffset();
493
partFeatureMapper->ScalarVisibilityOff();
494
495
vtkActor *partFeatureActor = vtkActor::New();
496
partFeatureActor->SetPickable(0);
497
partFeatureActor->GetProperty()->SetColor(0, 0, 0);
498
partFeatureActor->SetMapper(partFeatureMapper);
499
renderer->AddActor(partFeatureActor);
500
501
// Add triangles and edges to STL structures:
502
//--------------------------------------------
503
#if VTK_MAJOR_VERSION <= 5
504
stlSurfaceData->AddInput(partCleaner->GetOutput());
505
stlEdgeData->AddInput(partFeature->GetOutput());
506
#else
507
stlSurfaceData->AddInputData(partCleaner->GetOutput());
508
stlEdgeData->AddInputData(partFeature->GetOutput());
509
#endif
510
511
// Clean up:
512
//----------
513
partFeatureActor->Delete();
514
partFeatureMapper->Delete();
515
partFeature->Delete();
516
partActor->Delete();
517
partNormals->Delete();
518
partMapper->Delete();
519
partCleaner->Delete();
520
partGrid->Delete();
521
partPoints->Delete();
522
triangle->Delete();
523
}
524
525
if (numberOfFaces < 1) {
526
cout << "Cad import: error: no surface triangulation was generated. "
527
"Aborting."
528
<< endl;
529
return false;
530
}
531
532
stlSurfaceData->Update();
533
stlEdgeData->Update();
534
modelLength = stlSurfaceData->GetOutput()->GetLength();
535
cout << "StlSurfaceData: points: "
536
<< stlSurfaceData->GetOutput()->GetNumberOfPoints() << endl;
537
cout << "StlSurfaceData: cells: "
538
<< stlSurfaceData->GetOutput()->GetNumberOfCells() << endl;
539
cout << "StlEdgeData: lines: " << stlEdgeData->GetOutput()->GetNumberOfLines()
540
<< endl;
541
cout << "StlModelData: length: " << modelLength << endl;
542
543
// Draw:
544
//------
545
renderer->ResetCamera();
546
#if VTK_MAJOR_VERSION >= 9
547
qVTKWidget->renderWindow()->Render();
548
#else
549
qVTKWidget->GetRenderWindow()->Render();
550
#endif
551
552
QCoreApplication::processEvents();
553
554
return true;
555
}
556
557
void CadView::generateSTLSlot() {
558
double meshMinSize = modelLength * cadPreferences->ui.minh->text().toDouble();
559
double meshMaxSize = modelLength * cadPreferences->ui.maxh->text().toDouble();
560
bool restrictBySTL = cadPreferences->ui.restrictBySTL->isChecked();
561
562
// Check also the MainWindow meshing preferences:
563
if (mp->maxh < meshMaxSize)
564
meshMaxSize = mp->maxh;
565
double meshFineness = mp->fineness;
566
567
if (meshMaxSize > 0.1 * modelLength)
568
meshMaxSize = 0.1 * modelLength;
569
570
if (meshMinSize > meshMaxSize)
571
meshMinSize = meshMaxSize;
572
573
if (meshMinSize < 0)
574
meshMinSize = modelLength * 0.005;
575
576
if (meshMaxSize < 0)
577
meshMaxSize = modelLength * 0.1;
578
579
cout << "Cad import: max mesh size: " << meshMaxSize << endl;
580
cout << "Cad import: mesh fineness: " << meshFineness << endl;
581
582
// Add STL triangles to geometry:
583
//--------------------------------
584
vtkCleanPolyData *stlSurface = vtkCleanPolyData::New();
585
stlSurface->PointMergingOn();
586
#if VTK_MAJOR_VERSION <= 5
587
stlSurface->SetInput(stlSurfaceData->GetOutput());
588
#else
589
stlSurface->SetInputConnection(stlSurfaceData->GetOutputPort());
590
#endif
591
592
stlSurface->Update();
593
594
if (stlSurface->GetOutput()->GetNumberOfCells() < 1) {
595
cout << "Cad import: error: geometry undefined - no STL available" << endl;
596
return;
597
}
598
599
double p0[3], p1[3], p2[3];
600
for (int i = 0; i < stlSurface->GetOutput()->GetNumberOfCells(); i++) {
601
vtkCell *cell = stlSurface->GetOutput()->GetCell(i);
602
int nofCellPoints = cell->GetNumberOfPoints();
603
vtkPoints *cellPoints = cell->GetPoints();
604
605
if (nofCellPoints == 3) {
606
cellPoints->GetPoint(0, p0);
607
cellPoints->GetPoint(1, p1);
608
cellPoints->GetPoint(2, p2);
609
nglib::Ng_STL_AddTriangle(geom, p0, p1, p2, NULL);
610
}
611
}
612
613
// Add STL edges to geometry:
614
//----------------------------
615
vtkCleanPolyData *stlEdge = vtkCleanPolyData::New();
616
stlEdge->PointMergingOn();
617
#if VTK_MAJOR_VERSION <= 5
618
stlEdge->SetInput(stlEdgeData->GetOutput());
619
#else
620
stlEdge->SetInputConnection(stlEdgeData->GetOutputPort());
621
#endif
622
623
stlEdge->Update();
624
625
for (int i = 0; i < stlEdge->GetOutput()->GetNumberOfCells(); i++) {
626
vtkCell *cell = stlEdge->GetOutput()->GetCell(i);
627
int nofCellPoints = cell->GetNumberOfPoints();
628
vtkPoints *cellPoints = cell->GetPoints();
629
630
if (nofCellPoints == 2) {
631
cellPoints->GetPoint(0, p0);
632
cellPoints->GetPoint(1, p1);
633
nglib::Ng_STL_AddEdge(geom, p0, p1);
634
}
635
}
636
637
// Init STL geometry:
638
//--------------------
639
nglib::Ng_STL_InitSTLGeometry(geom);
640
641
// Generate edges:
642
//-----------------
643
nglib::Ng_STL_MakeEdges(geom, mesh, mp);
644
645
// Global mesh size restrictions:
646
//--------------------------------
647
nglib::Ng_RestrictMeshSizeGlobal(mesh, meshMaxSize);
648
649
// Local mesh size restrictions:
650
//-------------------------------
651
if (restrictBySTL)
652
restrictMeshSizeLocal(mesh, stlSurface->GetOutput(), meshMaxSize,
653
meshMinSize);
654
}
655
656
#if VTK_MAJOR_VERSION >= 8
657
QVTKOpenGLNativeWidget* CadView::GetQVTKWidget()
658
#else
659
QVTKWidget* CadView::GetQVTKWidget()
660
#endif
661
{
662
return this->qVTKWidget;
663
}
664
665
void CadView::clearScreen() {
666
cout << "Clear screen" << endl;
667
vtkActorCollection *actors = renderer->GetActors();
668
vtkActor *lastActor = actors->GetLastActor();
669
while (lastActor != NULL) {
670
renderer->RemoveActor(lastActor);
671
lastActor = actors->GetLastActor();
672
}
673
}
674
675
TopoDS_Shape CadView::readBrep(QString fileName) {
676
TopoDS_Shape shape;
677
BRep_Builder builder;
678
Standard_Boolean result;
679
680
result = BRepTools::Read(shape, fileName.toLatin1().data(), builder);
681
682
if (!result)
683
cout << "Read brep failed" << endl;
684
685
return shape;
686
}
687
688
TopoDS_Shape CadView::readStep(QString fileName) {
689
TopoDS_Shape shape;
690
Handle_TopTools_HSequenceOfShape shapes;
691
STEPControl_Reader stepReader;
692
IFSelect_ReturnStatus status;
693
694
status = stepReader.ReadFile(fileName.toLatin1().data());
695
696
if (status == IFSelect_RetDone) {
697
bool failsonly = false;
698
stepReader.PrintCheckLoad(failsonly, IFSelect_ItemsByEntity);
699
700
int nbr = stepReader.NbRootsForTransfer();
701
stepReader.PrintCheckTransfer(failsonly, IFSelect_ItemsByEntity);
702
703
for (Standard_Integer n = 1; n <= nbr; n++) {
704
bool ok = stepReader.TransferRoot(n);
705
int nbs = stepReader.NbShapes();
706
707
// Display warning if nbs > 1
708
//----------------------------
709
if (nbs > 1) {
710
QMessageBox message;
711
message.setIcon(QMessageBox::Warning);
712
message.setText("Loading multiple shapes");
713
message.setInformativeText(
714
"The mesh generators of ElmerGUI are currently unable to handle "
715
"cad files with multiple shapes. Please consider using external "
716
"software for mesh generation in this case.");
717
message.exec();
718
}
719
720
if (nbs > 0) {
721
shapes = new TopTools_HSequenceOfShape();
722
for (int i = 1; i <= nbs; i++) {
723
cout << "Added shape: " << i << endl;
724
shape = stepReader.Shape(i);
725
shapes->Append(shape);
726
}
727
}
728
}
729
}
730
731
return shape;
732
}
733
734
TopoDS_Shape CadView::readIges(QString fileName) {
735
TopoDS_Shape shape;
736
IGESControl_Reader igesReader;
737
IFSelect_ReturnStatus status;
738
739
status = igesReader.ReadFile(fileName.toLatin1().data());
740
741
if (status == IFSelect_RetDone) {
742
igesReader.TransferRoots();
743
shape = igesReader.OneShape();
744
}
745
746
return shape;
747
}
748
749
void CadView::restrictMeshSizeLocal(nglib::Ng_Mesh *mesh, vtkPolyData *stlData,
750
double meshMaxSize, double meshMinSize) {
751
int n0, n1, n2;
752
double h, h0, h1, h2;
753
double t[3], p0[3], p1[3], p2[3];
754
vtkFloatArray *mshSize = vtkFloatArray::New();
755
mshSize->SetNumberOfComponents(1);
756
mshSize->SetNumberOfTuples(stlData->GetNumberOfPoints());
757
758
for (int i = 0; i < stlData->GetNumberOfPoints(); i++)
759
mshSize->SetComponent(i, 0, meshMaxSize);
760
761
for (int i = 0; i < stlData->GetNumberOfCells(); i++) {
762
vtkCell *cell = stlData->GetCell(i);
763
int nofCellPoints = cell->GetNumberOfPoints();
764
vtkPoints *cellPoints = cell->GetPoints();
765
766
if (nofCellPoints == 3) {
767
n0 = cell->GetPointId(0);
768
n1 = cell->GetPointId(1);
769
n2 = cell->GetPointId(2);
770
771
h0 = mshSize->GetComponent(n0, 0);
772
h1 = mshSize->GetComponent(n1, 0);
773
h2 = mshSize->GetComponent(n2, 0);
774
775
cellPoints->GetPoint(0, p0);
776
cellPoints->GetPoint(1, p1);
777
cellPoints->GetPoint(2, p2);
778
779
differenceOf(t, p0, p1);
780
h = lengthOf(t);
781
if (h < meshMinSize)
782
h = meshMinSize;
783
if (h < h1)
784
mshSize->SetComponent(n1, 0, h);
785
if (h < h0)
786
mshSize->SetComponent(n0, 0, h);
787
788
differenceOf(t, p2, p0);
789
h = lengthOf(t);
790
if (h < meshMinSize)
791
h = meshMinSize;
792
if (h < h2)
793
mshSize->SetComponent(n2, 0, h);
794
if (h < h0)
795
mshSize->SetComponent(n0, 0, h);
796
797
differenceOf(t, p2, p1);
798
h = lengthOf(t);
799
if (h < meshMinSize)
800
h = meshMinSize;
801
if (h < h2)
802
mshSize->SetComponent(n2, 0, h);
803
if (h < h1)
804
mshSize->SetComponent(n1, 0, h);
805
}
806
}
807
808
for (int i = 0; i < stlData->GetNumberOfPoints(); i++) {
809
h = mshSize->GetComponent(i, 0);
810
if (h < meshMinSize)
811
h = meshMinSize;
812
if (h > meshMaxSize)
813
h = meshMaxSize;
814
stlData->GetPoint(i, p0);
815
nglib::Ng_RestrictMeshSizePoint(mesh, p0, h);
816
}
817
818
mshSize->Delete();
819
}
820
821
void CadView::generateSTL() { this->generateSTLSlot(); }
822
823
void CadView::setMesh(nglib::Ng_Mesh *mesh) { this->mesh = mesh; }
824
825
void CadView::setGeom(nglib::Ng_STL_Geometry *geom) { this->geom = geom; }
826
827
void CadView::setMp(nglib::Ng_Meshing_Parameters *mp) { this->mp = mp; }
828
829
void CadView::setDeflection(double deflection) {
830
if (deflection < 0)
831
return;
832
833
this->cadPreferences->ui.deflection->setText(QString::number(deflection));
834
}
835
836
double CadView::lengthOf(double *v) {
837
return sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
838
}
839
840
void CadView::differenceOf(double *u, double *v, double *w) {
841
u[0] = v[0] - w[0];
842
u[1] = v[1] - w[1];
843
u[2] = v[2] - w[2];
844
}
845
846
int CadView::getFaceNumber(vtkActor *actor) {
847
if (actor == NULL)
848
return -1;
849
return actorToFace.value(actor);
850
}
851
852
int CadView::getDim() { return modelDim; }
853
854
void CadView::generateIn2dFile() {
855
cout << "Generating In2D file from 2D Iges geometry" << endl;
856
857
QVector<pt> pts;
858
QVector<seg> segs;
859
860
bool firstPoint = true;
861
int numberOfFaces = 0;
862
int numberOfPts = 0;
863
int numberOfSegs = 0;
864
gp_Pnt previousPnt;
865
866
// Loop over faces:
867
//------------------
868
TopExp_Explorer expFace(shape, TopAbs_FACE);
869
for (expFace; expFace.More(); expFace.Next()) {
870
TopoDS_Face Face = TopoDS::Face(expFace.Current());
871
cout << "Face: " << ++numberOfFaces << endl;
872
873
// Loop over edges:
874
//------------------
875
int numberOfEdges = 0;
876
TopExp_Explorer expEdge(Face, TopAbs_EDGE);
877
for (expEdge; expEdge.More(); expEdge.Next()) {
878
TopoDS_Edge Edge = TopoDS::Edge(expEdge.Current());
879
cout << " Edge: " << ++numberOfEdges << endl;
880
881
// Divide edge into segments:
882
//----------------------------
883
double AngularDeflection = 0.1;
884
double CurvatureDeflection = 0.1;
885
int MinPoints = 2;
886
double Tolerance = 1.0e-9;
887
888
BRepAdaptor_Curve2d Curve(Edge, Face);
889
GCPnts_TangentialDeflection TD(Curve, AngularDeflection,
890
CurvatureDeflection, MinPoints, Tolerance);
891
892
int nofPoints = TD.NbPoints();
893
cout << " Points: " << nofPoints << endl;
894
895
// Loop over points:
896
//-------------------
897
for (int i = 2; i <= nofPoints; i++) {
898
gp_Pnt value;
899
900
if (firstPoint) {
901
value = TD.Value(1);
902
firstPoint = false;
903
previousPnt = value;
904
pt p;
905
p.n = ++numberOfPts;
906
p.x = value.X();
907
p.y = value.Y();
908
pts.push_back(p);
909
}
910
911
double p0 = TD.Parameter(i - 1);
912
double p1 = TD.Parameter(i);
913
914
double dist = sqrt((p1 - p0) * (p1 - p0));
915
916
if (dist < Tolerance) {
917
cout << " Skipped one (based on parameter)" << endl;
918
continue;
919
}
920
921
value = TD.Value(i);
922
923
double dx = value.X() - previousPnt.X();
924
double dy = value.Y() - previousPnt.Y();
925
926
dist = sqrt(dx * dx + dy * dy);
927
928
if (dist < Tolerance) {
929
cout << " Skipped one (based on value)" << endl;
930
continue;
931
}
932
933
pt p;
934
p.n = ++numberOfPts;
935
p.x = value.X();
936
p.y = value.Y();
937
pts.push_back(p);
938
939
seg s;
940
s.p0 = numberOfPts - 1;
941
s.p1 = numberOfPts;
942
s.bc = numberOfEdges;
943
segs.push_back(s);
944
numberOfSegs++;
945
946
previousPnt = value;
947
}
948
}
949
}
950
951
// Write the in2d file:
952
//----------------------
953
fstream file("iges2ng.in2d", ios::out);
954
955
file << "splinecurves2dv2" << endl;
956
file << "1" << endl << endl;
957
958
file << "points" << endl;
959
for (int i = 0; i < pts.size() - 1; i++) {
960
pt p = pts[i];
961
file << p.n << " " << p.x << " " << p.y << endl;
962
}
963
964
seg s;
965
file << endl << "segments" << endl;
966
for (int i = 0; i < segs.size() - 1; i++) {
967
s = segs[i];
968
file << "1 0 2 " << s.p0 << " " << s.p1 << " -bc=" << s.bc << endl;
969
}
970
971
file << "1 0 2 " << s.p1 << " 1 -bc=" << s.bc << endl;
972
973
file << endl << "materials" << endl;
974
file << "1 mat1 -maxh=100000" << endl;
975
976
file.close();
977
}
978
979