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

Last change on this file since 548 was 546, checked in by Maciej Komosinski, 8 years ago

Renamed: Model::buildUsingNewShapes -> Model::buildUsingSolidShapeTypes()
Added class SolidsShapeTypeModel? (for making ball-and-stick Models look like solids-type Models)
ModelGeometryInfo? functions: findSizesAndAxesOfModel(), volume() and area() now accept ball-and-stick Models (using SolidsShapeTypeModel? class)
[refs #46] and possibly closes this issue (needs verification)

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