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

Last change on this file was 1111, checked in by Maciej Komosinski, 3 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
RevLine 
[286]1// This file is a part of Framsticks SDK.  http://www.framsticks.com/
[1111]2// Copyright (C) 1999-2021  Maciej Komosinski and Szymon Ulatowski.
[286]3// See LICENSE.txt for details.
[191]4
5#include "modelgeometryinfo.h"
6#include <frams/model/geometry/geometryutils.h>
7#include <frams/model/geometry/meshbuilder.h>
[1111]8#include <frams/vm/classes/collectionobj.h>
9#include <frams/vm/classes/3dobject.h>
[191]10
[660]11void ModelGeometryInfo::findSizesAndAxes(Model &input_model, const double density,
[191]12        Pt3D &sizes, Orient &axes)
13{
[546]14        SolidsShapeTypeModel model(input_model);
[191]15        SListTempl<Pt3D> points;
16        MeshBuilder::ModelApices apices(density);
[546]17        apices.initialize(&model.getModel());
[191]18        apices.addAllPointsToList(points);
[262]19        if (points.size() < 1) //maybe 1 or 2 points are also not enough for findSizesAndAxesOfPointsGroup() to work...
20        {
[546]21                logPrintf("ModelGeometryInfo", "findSizesAndAxesOfModel", LOG_ERROR, "Empty points sample for model with %d part(s)", model.getModel().getPartCount());
[262]22                sizes = Pt3D_0;
23                axes = Orient_1;
24                return;
25        }
[191]26        GeometryUtils::findSizesAndAxesOfPointsGroup(points, sizes, axes);
27}
28
[658]29void ModelGeometryInfo::boundingBox(const Model &model, Pt3D &lowerBoundary, Pt3D &upperBoundary)
[191]30{
[658]31        if (model.getPartCount() == 0) //should never happen. Invalid model provided?
[191]32        {
[658]33                lowerBoundary = Pt3D_0;
34                upperBoundary = Pt3D_0;
35                return;
[191]36        }
[1111]37
[191]38        boundingBox(model.getPart(0), lowerBoundary, upperBoundary);
[1111]39
[191]40        for (int i = 1; i < model.getPartCount(); i++)
41        {
42                Pt3D partLowerBoundary, partUpperBoundary;
43                boundingBox(model.getPart(i), partLowerBoundary, partUpperBoundary);
[1111]44
[191]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;
[1111]55
56        for (Octants::Octant o = Octants::FIRST; o < Octants::NUMBER; o = Octants::Octant(o + 1))
[191]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;
[1111]62
[191]63                vertex = part->o.transform(vertex) + part->p;
[1111]64
[191]65                lowerBoundary.getMin(vertex);
66                upperBoundary.getMax(vertex);
67        }
68}
69
[660]70double ModelGeometryInfo::volume(Model &input_model, const double density)
[191]71{
[546]72        SolidsShapeTypeModel model(input_model);
[191]73        Pt3D lowerBoundary, upperBoundary;
74        boundingBox(model, lowerBoundary, upperBoundary);
[1111]75
[191]76        MeshBuilder::BoundingBoxVolume iterator(density);
77        iterator.initialize(lowerBoundary, upperBoundary);
[1111]78
[191]79        Pt3D point;
80        int allPoints = 0, pointsInsideModel = 0;
[1111]81
[191]82        while (iterator.tryGetNext(point))
83        {
84                allPoints += 1;
85                pointsInsideModel += GeometryUtils::isPointInsideModel(point, model) ? 1 : 0;
86        }
[1111]87
[191]88        double boundingBoxVolume
89                = (upperBoundary.x - lowerBoundary.x)
90                * (upperBoundary.y - lowerBoundary.y)
91                * (upperBoundary.z - lowerBoundary.z);
[1111]92
[191]93        return boundingBoxVolume * (double)pointsInsideModel / (double)allPoints;
94}
95
[1111]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
[660]119double ModelGeometryInfo::area(Model &input_model, const double density)
[191]120{
[546]121        SolidsShapeTypeModel model(input_model);
[191]122        double area = 0.0;
[1111]123
124        for (int partIndex = 0; partIndex < model.getModel().getPartCount(); partIndex += 1)
[191]125        {
126                area += externalAreaOfPart(model, partIndex, density);
127        }
[1111]128
[191]129        return area;
130}
131
132double ModelGeometryInfo::externalAreaOfPart(const Model &model, const int partIndex, const double density)
133{
[261]134        Part *part = model.getPart(partIndex);
135        switch (part->shape)
[191]136        {
[1111]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);
[191]145        }
[375]146        logPrintf("ModelGeometryInfo", "externalAreaOfPart", LOG_ERROR, "Part shape=%d not supported", part->shape);
[234]147        return 0;
[191]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;
[1111]154
[191]155        while (surface.tryGetNext(point))
156        {
157                all += 1;
158                sur += GeometryUtils::isPointInsideModelExcludingPart(point, &model, partIndex) ? 0 : 1;
159        }
[1111]160
[191]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);
[1111]167
[191]168        MeshBuilder::EllipsoidSurface ellipsoid(density);
169        ellipsoid.initialize(part);
[1111]170
[191]171        double area = GeometryUtils::ellipsoidArea(part->scale);
[1111]172
[191]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);
[1111]179
[191]180        double externalArea = 0.0;
[1111]181
[191]182        MeshBuilder::RectangleSurface rectangle(density);
[1111]183
184        for (CuboidFaces::Face f = CuboidFaces::FIRST; f < CuboidFaces::NUMBER; f = CuboidFaces::Face(f + 1))
[191]185        {
186                rectangle.initialize(part, f);
[1111]187
[191]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;
[1111]192
[191]193                externalArea += externalAreaOfSurface(model, partIndex, rectangle, area);
194        }
[1111]195
[191]196        return externalArea;
197}
198
199double ModelGeometryInfo::externalAreaOfCylinder(const Model &model, const int partIndex, const double density)
200{
201        Part *part = model.getPart(partIndex);
[1111]202
[191]203        double externalArea = 0.0;
[1111]204
[191]205        MeshBuilder::EllipseSurface ellipse(density);
[1111]206
[191]207        double area = M_PI * part->scale.y * part->scale.z;
[1111]208
209        for (CylinderBases::Base b = CylinderBases::FIRST; b < CylinderBases::NUMBER; b = CylinderBases::Base(b + 1))
[191]210        {
211                ellipse.initialize(part, b);
[1111]212
[191]213                externalArea += externalAreaOfSurface(model, partIndex, ellipse, area);
214        }
[1111]215
[191]216        MeshBuilder::CylinderWallSurface cylinderWall(density);
217        cylinderWall.initialize(part);
[1111]218
219        area = 2.0 * part->scale.x * GeometryUtils::ellipsePerimeter(part->scale.y, part->scale.z);
220
[191]221        externalArea += externalAreaOfSurface(model, partIndex, cylinderWall, area);
[1111]222
[191]223        return externalArea;
224}
Note: See TracBrowser for help on using the repository browser.