source: cpp/frams/model/geometry/modelgeometryinfo.cpp @ 270

Last change on this file since 270 was 262, checked in by Maciej Komosinski, 10 years ago

Geometry evaluation no longer crashes for models that contain only unsupported cylinder shapes [refs #46]

  • Property svn:eol-style set to native
File size: 5.7 KB
Line 
1// This file is a part of the Framsticks GDK.
2// Copyright (C) 2002-2014  Maciej Komosinski and Szymon Ulatowski.  See LICENSE.txt for details.
3// Refer to http://www.framsticks.com/ for further information.
4
5#include "modelgeometryinfo.h"
6#include <frams/model/geometry/geometryutils.h>
7#include <frams/model/geometry/meshbuilder.h>
8
9void ModelGeometryInfo::findSizesAndAxesOfModel(const Model &model, const double density,
10        Pt3D &sizes, Orient &axes)
11{
12        SListTempl<Pt3D> points;
13        MeshBuilder::ModelApices apices(density);
14        apices.initialize(&model);
15        apices.addAllPointsToList(points);
16        if (points.size() < 1) //maybe 1 or 2 points are also not enough for findSizesAndAxesOfPointsGroup() to work...
17        {
18                FMprintf("ModelGeometryInfo", "findSizesAndAxesOfModel", FMLV_ERROR, "Empty points sample for model with %d part(s)", model.getPartCount());
19                sizes = Pt3D_0;
20                axes = Orient_1;
21                return;
22        }
23        GeometryUtils::findSizesAndAxesOfPointsGroup(points, sizes, axes);
24}
25
26bool ModelGeometryInfo::boundingBox(const Model &model, Pt3D &lowerBoundary, Pt3D &upperBoundary)
27{
28        if (model.getPartCount() == 0)
29        {
30                return false;
31        }
32       
33        boundingBox(model.getPart(0), lowerBoundary, upperBoundary);
34       
35        for (int i = 1; i < model.getPartCount(); i++)
36        {
37                Pt3D partLowerBoundary, partUpperBoundary;
38                boundingBox(model.getPart(i), partLowerBoundary, partUpperBoundary);
39               
40                lowerBoundary.getMin(partLowerBoundary);
41                upperBoundary.getMax(partUpperBoundary);
42        }
43       
44        return true;
45}
46
47void ModelGeometryInfo::boundingBox(const Part *part, Pt3D &lowerBoundary, Pt3D &upperBoundary)
48{
49        lowerBoundary.x = upperBoundary.x = part->p.x;
50        lowerBoundary.y = upperBoundary.y = part->p.y;
51        lowerBoundary.z = upperBoundary.z = part->p.z;
52       
53        for (Octants::Octant o = Octants::FIRST; o < Octants::NUMBER; o = Octants::Octant(o+1))
54        {
55                Pt3D vertex = part->scale;
56                vertex.x *= Octants::isPositiveX(o) ? +1 : -1;
57                vertex.y *= Octants::isPositiveY(o) ? +1 : -1;
58                vertex.z *= Octants::isPositiveZ(o) ? +1 : -1;
59               
60                vertex = part->o.transform(vertex) + part->p;
61               
62                lowerBoundary.getMin(vertex);
63                upperBoundary.getMax(vertex);
64        }
65}
66
67double ModelGeometryInfo::volume(const Model &model, const double density)
68{
69        Pt3D lowerBoundary, upperBoundary;
70        boundingBox(model, lowerBoundary, upperBoundary);
71       
72        MeshBuilder::BoundingBoxVolume iterator(density);
73        iterator.initialize(lowerBoundary, upperBoundary);
74       
75        Pt3D point;
76        int allPoints = 0, pointsInsideModel = 0;
77       
78        while (iterator.tryGetNext(point))
79        {
80                allPoints += 1;
81                pointsInsideModel += GeometryUtils::isPointInsideModel(point, model) ? 1 : 0;
82        }
83       
84        double boundingBoxVolume
85                = (upperBoundary.x - lowerBoundary.x)
86                * (upperBoundary.y - lowerBoundary.y)
87                * (upperBoundary.z - lowerBoundary.z);
88       
89        return boundingBoxVolume * (double)pointsInsideModel / (double)allPoints;
90}
91
92double ModelGeometryInfo::area(const Model &model, const double density)
93{
94        double area = 0.0;
95       
96        for (int partIndex = 0; partIndex < model.getPartCount(); partIndex+=1)
97        {
98                area += externalAreaOfPart(model, partIndex, density);
99        }
100       
101        return area;
102}
103
104double ModelGeometryInfo::externalAreaOfPart(const Model &model, const int partIndex, const double density)
105{
106        Part *part = model.getPart(partIndex);
107        switch (part->shape)
108        {
109                case Part::SHAPE_ELLIPSOID:
110                        return externalAreaOfEllipsoid(model, partIndex, density);
111                       
112                case Part::SHAPE_CUBOID:
113                        return externalAreaOfCuboid(model, partIndex, density);
114                       
115                case Part::SHAPE_CYLINDER:
116                        return externalAreaOfCylinder(model, partIndex, density);
117        }
118        FMprintf("ModelGeometryInfo", "externalAreaOfPart", FMLV_ERROR, "Part shape=%d not supported", part->shape);
119        return 0;
120}
121
122double externalAreaOfSurface(const Model &model, const int partIndex, MeshBuilder::Iterator &surface, const double area)
123{
124        Pt3D point;
125        int all = 0, sur = 0;
126       
127        while (surface.tryGetNext(point))
128        {
129                all += 1;
130                sur += GeometryUtils::isPointInsideModelExcludingPart(point, &model, partIndex) ? 0 : 1;
131        }
132       
133        return sur * area / all;
134}
135
136double ModelGeometryInfo::externalAreaOfEllipsoid(const Model &model, const int partIndex, const double density)
137{
138        Part *part = model.getPart(partIndex);
139       
140        MeshBuilder::EllipsoidSurface ellipsoid(density);
141        ellipsoid.initialize(part);
142       
143        double area = GeometryUtils::ellipsoidArea(part->scale);
144       
145        return externalAreaOfSurface(model, partIndex, ellipsoid, area);
146}
147
148double ModelGeometryInfo::externalAreaOfCuboid(const Model &model, const int partIndex, const double density)
149{
150        Part *part = model.getPart(partIndex);
151       
152        double externalArea = 0.0;
153       
154        MeshBuilder::RectangleSurface rectangle(density);
155       
156        for (CuboidFaces::Face f = CuboidFaces::FIRST; f < CuboidFaces::NUMBER; f = CuboidFaces::Face(f+1))
157        {
158                rectangle.initialize(part, f);
159               
160                double area = 4.0;
161                area *= !CuboidFaces::isX(f) ? part->scale.x : 1.0;
162                area *= !CuboidFaces::isY(f) ? part->scale.y : 1.0;
163                area *= !CuboidFaces::isZ(f) ? part->scale.z : 1.0;
164               
165                externalArea += externalAreaOfSurface(model, partIndex, rectangle, area);
166        }
167       
168        return externalArea;
169}
170
171double ModelGeometryInfo::externalAreaOfCylinder(const Model &model, const int partIndex, const double density)
172{
173        Part *part = model.getPart(partIndex);
174       
175        double externalArea = 0.0;
176       
177        MeshBuilder::EllipseSurface ellipse(density);
178       
179        double area = M_PI * part->scale.y * part->scale.z;
180       
181        for (CylinderBases::Base b = CylinderBases::FIRST; b < CylinderBases::NUMBER; b = CylinderBases::Base(b+1))
182        {
183                ellipse.initialize(part, b);
184               
185                externalArea += externalAreaOfSurface(model, partIndex, ellipse, area);
186        }
187       
188        MeshBuilder::CylinderWallSurface cylinderWall(density);
189        cylinderWall.initialize(part);
190       
191        area = 2.0*part->scale.x * GeometryUtils::ellipsePerimeter(part->scale.y, part->scale.z);
192       
193        externalArea += externalAreaOfSurface(model, partIndex, cylinderWall, area);
194       
195        return externalArea;
196}
Note: See TracBrowser for help on using the repository browser.