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

Last change on this file was 1111, checked in by Maciej Komosinski, 4 years ago

Added a function to get voxels of sampled Model geometry from script

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