Replace CalculateMass with a more accurate version, contributed by Ubit.
Thank you.viewer-2-initial-appearance
parent
2427e16b42
commit
f220a2c5eb
|
@ -403,300 +403,285 @@ namespace OpenSim.Region.Physics.OdePlugin
|
||||||
|
|
||||||
private float CalculateMass()
|
private float CalculateMass()
|
||||||
{
|
{
|
||||||
float volume = 0;
|
float volume = _size.X * _size.Y * _size.Z; // default
|
||||||
|
float tmp;
|
||||||
// No material is passed to the physics engines yet.. soo..
|
|
||||||
// we're using the m_density constant in the class definition
|
|
||||||
|
|
||||||
float returnMass = 0;
|
float returnMass = 0;
|
||||||
|
float hollowAmount = (float)_pbs.ProfileHollow * 2.0e-5f;
|
||||||
|
float hollowVolume = hollowAmount * hollowAmount;
|
||||||
|
|
||||||
switch (_pbs.ProfileShape)
|
switch (_pbs.ProfileShape)
|
||||||
{
|
{
|
||||||
case ProfileShape.Square:
|
case ProfileShape.Square:
|
||||||
// Profile Volume
|
// default box
|
||||||
|
|
||||||
volume = _size.X*_size.Y*_size.Z;
|
|
||||||
|
|
||||||
// If the user has 'hollowed out'
|
|
||||||
// ProfileHollow is one of those 0 to 50000 values :P
|
|
||||||
// we like percentages better.. so turning into a percentage
|
|
||||||
|
|
||||||
if (((float) _pbs.ProfileHollow/50000f) > 0.0)
|
|
||||||
{
|
|
||||||
float hollowAmount = (float) _pbs.ProfileHollow/50000f;
|
|
||||||
|
|
||||||
// calculate the hollow volume by it's shape compared to the prim shape
|
|
||||||
float hollowVolume = 0;
|
|
||||||
switch (_pbs.HollowShape)
|
|
||||||
{
|
|
||||||
case HollowShape.Square:
|
|
||||||
case HollowShape.Same:
|
|
||||||
// Cube Hollow volume calculation
|
|
||||||
float hollowsizex = _size.X*hollowAmount;
|
|
||||||
float hollowsizey = _size.Y*hollowAmount;
|
|
||||||
float hollowsizez = _size.Z*hollowAmount;
|
|
||||||
hollowVolume = hollowsizex*hollowsizey*hollowsizez;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HollowShape.Circle:
|
|
||||||
// Hollow shape is a perfect cyllinder in respect to the cube's scale
|
|
||||||
// Cyllinder hollow volume calculation
|
|
||||||
float hRadius = _size.X/2;
|
|
||||||
float hLength = _size.Z;
|
|
||||||
|
|
||||||
// pi * r2 * h
|
|
||||||
hollowVolume = ((float) (Math.PI*Math.Pow(hRadius, 2)*hLength)*hollowAmount);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HollowShape.Triangle:
|
|
||||||
// Equilateral Triangular Prism volume hollow calculation
|
|
||||||
// Triangle is an Equilateral Triangular Prism with aLength = to _size.Y
|
|
||||||
|
|
||||||
float aLength = _size.Y;
|
|
||||||
// 1/2 abh
|
|
||||||
hollowVolume = (float) ((0.5*aLength*_size.X*_size.Z)*hollowAmount);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
hollowVolume = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
volume = volume - hollowVolume;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
case ProfileShape.Circle:
|
|
||||||
if (_pbs.PathCurve == (byte)Extrusion.Straight)
|
if (_pbs.PathCurve == (byte)Extrusion.Straight)
|
||||||
{
|
{
|
||||||
// Cylinder
|
if (hollowAmount > 0.0)
|
||||||
float volume1 = (float)(Math.PI * Math.Pow(_size.X/2, 2) * _size.Z);
|
|
||||||
float volume2 = (float)(Math.PI * Math.Pow(_size.Y/2, 2) * _size.Z);
|
|
||||||
|
|
||||||
// Approximating the cylinder's irregularity.
|
|
||||||
if (volume1 > volume2)
|
|
||||||
{
|
{
|
||||||
volume = (float)volume1 - (volume1 - volume2);
|
|
||||||
}
|
|
||||||
else if (volume2 > volume1)
|
|
||||||
{
|
|
||||||
volume = (float)volume2 - (volume2 - volume1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Regular cylinder
|
|
||||||
volume = volume1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// We don't know what the shape is yet, so use default
|
|
||||||
volume = _size.X * _size.Y * _size.Z;
|
|
||||||
}
|
|
||||||
// If the user has 'hollowed out'
|
|
||||||
// ProfileHollow is one of those 0 to 50000 values :P
|
|
||||||
// we like percentages better.. so turning into a percentage
|
|
||||||
|
|
||||||
if (((float)_pbs.ProfileHollow / 50000f) > 0.0)
|
|
||||||
{
|
|
||||||
float hollowAmount = (float)_pbs.ProfileHollow / 50000f;
|
|
||||||
|
|
||||||
// calculate the hollow volume by it's shape compared to the prim shape
|
|
||||||
float hollowVolume = 0;
|
|
||||||
switch (_pbs.HollowShape)
|
switch (_pbs.HollowShape)
|
||||||
{
|
{
|
||||||
|
case HollowShape.Square:
|
||||||
case HollowShape.Same:
|
case HollowShape.Same:
|
||||||
case HollowShape.Circle:
|
|
||||||
// Hollow shape is a perfect cyllinder in respect to the cube's scale
|
|
||||||
// Cyllinder hollow volume calculation
|
|
||||||
float hRadius = _size.X / 2;
|
|
||||||
float hLength = _size.Z;
|
|
||||||
|
|
||||||
// pi * r2 * h
|
|
||||||
hollowVolume = ((float)(Math.PI * Math.Pow(hRadius, 2) * hLength) * hollowAmount);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HollowShape.Square:
|
case HollowShape.Circle:
|
||||||
// Cube Hollow volume calculation
|
|
||||||
float hollowsizex = _size.X * hollowAmount;
|
hollowVolume *= 0.78539816339f;
|
||||||
float hollowsizey = _size.Y * hollowAmount;
|
|
||||||
float hollowsizez = _size.Z * hollowAmount;
|
|
||||||
hollowVolume = hollowsizex * hollowsizey * hollowsizez;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HollowShape.Triangle:
|
case HollowShape.Triangle:
|
||||||
// Equilateral Triangular Prism volume hollow calculation
|
|
||||||
// Triangle is an Equilateral Triangular Prism with aLength = to _size.Y
|
|
||||||
|
|
||||||
float aLength = _size.Y;
|
hollowVolume *= (0.5f * .5f);
|
||||||
// 1/2 abh
|
|
||||||
hollowVolume = (float)((0.5 * aLength * _size.X * _size.Z) * hollowAmount);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
hollowVolume = 0;
|
hollowVolume = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
volume = volume - hollowVolume;
|
volume *= (1.0f - hollowVolume);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
|
||||||
|
{
|
||||||
|
//a tube
|
||||||
|
|
||||||
|
volume *= 0.78539816339e-2f * (float)(200 - _pbs.PathScaleX);
|
||||||
|
tmp= 1.0f -2.0e-2f * (float)(200 - _pbs.PathScaleY);
|
||||||
|
volume -= volume*tmp*tmp;
|
||||||
|
|
||||||
|
if (hollowAmount > 0.0)
|
||||||
|
{
|
||||||
|
hollowVolume *= hollowAmount;
|
||||||
|
|
||||||
|
switch (_pbs.HollowShape)
|
||||||
|
{
|
||||||
|
case HollowShape.Square:
|
||||||
|
case HollowShape.Same:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HollowShape.Circle:
|
||||||
|
hollowVolume *= 0.78539816339f;;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HollowShape.Triangle:
|
||||||
|
hollowVolume *= 0.5f * 0.5f;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
hollowVolume = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
volume *= (1.0f - hollowVolume);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ProfileShape.Circle:
|
||||||
|
|
||||||
|
if (_pbs.PathCurve == (byte)Extrusion.Straight)
|
||||||
|
{
|
||||||
|
volume *= 0.78539816339f; // elipse base
|
||||||
|
|
||||||
|
if (hollowAmount > 0.0)
|
||||||
|
{
|
||||||
|
switch (_pbs.HollowShape)
|
||||||
|
{
|
||||||
|
case HollowShape.Same:
|
||||||
|
case HollowShape.Circle:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HollowShape.Square:
|
||||||
|
hollowVolume *= 0.5f * 2.5984480504799f;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HollowShape.Triangle:
|
||||||
|
hollowVolume *= .5f * 1.27323954473516f;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
hollowVolume = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
volume *= (1.0f - hollowVolume);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
|
||||||
|
{
|
||||||
|
volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - _pbs.PathScaleX);
|
||||||
|
tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY);
|
||||||
|
volume *= (1.0f - tmp * tmp);
|
||||||
|
|
||||||
|
if (hollowAmount > 0.0)
|
||||||
|
{
|
||||||
|
|
||||||
|
// calculate the hollow volume by it's shape compared to the prim shape
|
||||||
|
hollowVolume *= hollowAmount;
|
||||||
|
|
||||||
|
switch (_pbs.HollowShape)
|
||||||
|
{
|
||||||
|
case HollowShape.Same:
|
||||||
|
case HollowShape.Circle:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HollowShape.Square:
|
||||||
|
hollowVolume *= 0.5f * 2.5984480504799f;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HollowShape.Triangle:
|
||||||
|
hollowVolume *= .5f * 1.27323954473516f;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
hollowVolume = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
volume *= (1.0f - hollowVolume);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ProfileShape.HalfCircle:
|
case ProfileShape.HalfCircle:
|
||||||
if (_pbs.PathCurve == (byte)Extrusion.Curve1)
|
if (_pbs.PathCurve == (byte)Extrusion.Curve1)
|
||||||
{
|
{
|
||||||
if (_size.X == _size.Y && _size.Y == _size.Z)
|
volume *= 0.52359877559829887307710723054658f;
|
||||||
{
|
|
||||||
// regular sphere
|
|
||||||
// v = 4/3 * pi * r^3
|
|
||||||
float sradius3 = (float)Math.Pow((_size.X / 2), 3);
|
|
||||||
volume = (float)((4f / 3f) * Math.PI * sradius3);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// we treat this as a box currently
|
|
||||||
volume = _size.X * _size.Y * _size.Z;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// We don't know what the shape is yet, so use default
|
|
||||||
volume = _size.X * _size.Y * _size.Z;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ProfileShape.EquilateralTriangle:
|
case ProfileShape.EquilateralTriangle:
|
||||||
/*
|
|
||||||
v = (abs((xB*yA-xA*yB)+(xC*yB-xB*yC)+(xA*yC-xC*yA))/2) * h
|
|
||||||
|
|
||||||
// seed mesh
|
if (_pbs.PathCurve == (byte)Extrusion.Straight)
|
||||||
Vertex MM = new Vertex(-0.25f, -0.45f, 0.0f);
|
{
|
||||||
Vertex PM = new Vertex(+0.5f, 0f, 0.0f);
|
volume *= 0.32475953f;
|
||||||
Vertex PP = new Vertex(-0.25f, +0.45f, 0.0f);
|
|
||||||
*/
|
if (hollowAmount > 0.0)
|
||||||
float xA = -0.25f * _size.X;
|
|
||||||
float yA = -0.45f * _size.Y;
|
|
||||||
|
|
||||||
float xB = 0.5f * _size.X;
|
|
||||||
float yB = 0;
|
|
||||||
|
|
||||||
float xC = -0.25f * _size.X;
|
|
||||||
float yC = 0.45f * _size.Y;
|
|
||||||
|
|
||||||
volume = (float)((Math.Abs((xB * yA - xA * yB) + (xC * yB - xB * yC) + (xA * yC - xC * yA)) / 2) * _size.Z);
|
|
||||||
|
|
||||||
// If the user has 'hollowed out'
|
|
||||||
// ProfileHollow is one of those 0 to 50000 values :P
|
|
||||||
// we like percentages better.. so turning into a percentage
|
|
||||||
float fhollowFactor = ((float)_pbs.ProfileHollow / 1.9f);
|
|
||||||
if (((float)fhollowFactor / 50000f) > 0.0)
|
|
||||||
{
|
{
|
||||||
float hollowAmount = (float)fhollowFactor / 50000f;
|
|
||||||
|
|
||||||
// calculate the hollow volume by it's shape compared to the prim shape
|
// calculate the hollow volume by it's shape compared to the prim shape
|
||||||
float hollowVolume = 0;
|
|
||||||
switch (_pbs.HollowShape)
|
switch (_pbs.HollowShape)
|
||||||
{
|
{
|
||||||
case HollowShape.Same:
|
case HollowShape.Same:
|
||||||
case HollowShape.Triangle:
|
case HollowShape.Triangle:
|
||||||
// Equilateral Triangular Prism volume hollow calculation
|
hollowVolume *= .25f;
|
||||||
// Triangle is an Equilateral Triangular Prism with aLength = to _size.Y
|
|
||||||
|
|
||||||
float aLength = _size.Y;
|
|
||||||
// 1/2 abh
|
|
||||||
hollowVolume = (float)((0.5 * aLength * _size.X * _size.Z) * hollowAmount);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HollowShape.Square:
|
case HollowShape.Square:
|
||||||
// Cube Hollow volume calculation
|
hollowVolume *= 0.499849f * 3.07920140172638f;
|
||||||
float hollowsizex = _size.X * hollowAmount;
|
|
||||||
float hollowsizey = _size.Y * hollowAmount;
|
|
||||||
float hollowsizez = _size.Z * hollowAmount;
|
|
||||||
hollowVolume = hollowsizex * hollowsizey * hollowsizez;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HollowShape.Circle:
|
case HollowShape.Circle:
|
||||||
// Hollow shape is a perfect cyllinder in respect to the cube's scale
|
// Hollow shape is a perfect cyllinder in respect to the cube's scale
|
||||||
// Cyllinder hollow volume calculation
|
// Cyllinder hollow volume calculation
|
||||||
float hRadius = _size.X / 2;
|
|
||||||
float hLength = _size.Z;
|
|
||||||
|
|
||||||
// pi * r2 * h
|
hollowVolume *= 0.1963495f * 3.07920140172638f;
|
||||||
hollowVolume = ((float)((Math.PI * Math.Pow(hRadius, 2) * hLength)/2) * hollowAmount);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
hollowVolume = 0;
|
hollowVolume = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
volume = volume - hollowVolume;
|
volume *= (1.0f - hollowVolume);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
|
||||||
|
{
|
||||||
|
volume *= 0.32475953f;
|
||||||
|
volume *= 0.01f * (float)(200 - _pbs.PathScaleX);
|
||||||
|
tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY);
|
||||||
|
volume *= (1.0f - tmp * tmp);
|
||||||
|
|
||||||
|
if (hollowAmount > 0.0)
|
||||||
|
{
|
||||||
|
|
||||||
|
hollowVolume *= hollowAmount;
|
||||||
|
|
||||||
|
switch (_pbs.HollowShape)
|
||||||
|
{
|
||||||
|
case HollowShape.Same:
|
||||||
|
case HollowShape.Triangle:
|
||||||
|
hollowVolume *= .25f;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HollowShape.Square:
|
||||||
|
hollowVolume *= 0.499849f * 3.07920140172638f;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HollowShape.Circle:
|
||||||
|
|
||||||
|
hollowVolume *= 0.1963495f * 3.07920140172638f;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
hollowVolume = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
volume *= (1.0f - hollowVolume);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// we don't have all of the volume formulas yet so
|
|
||||||
// use the common volume formula for all
|
|
||||||
volume = _size.X*_size.Y*_size.Z;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate Path cut effect on volume
|
|
||||||
// Not exact, in the triangle hollow example
|
|
||||||
// They should never be zero or less then zero..
|
|
||||||
// we'll ignore it if it's less then zero
|
|
||||||
|
|
||||||
// ProfileEnd and ProfileBegin are values
|
|
||||||
// from 0 to 50000
|
|
||||||
|
|
||||||
// Turning them back into percentages so that I can cut that percentage off the volume
|
float taperX1;
|
||||||
|
float taperY1;
|
||||||
|
float taperX;
|
||||||
|
float taperY;
|
||||||
|
float pathBegin;
|
||||||
|
float pathEnd;
|
||||||
|
float profileBegin;
|
||||||
|
float profileEnd;
|
||||||
|
|
||||||
float PathCutEndAmount = _pbs.ProfileEnd;
|
if (_pbs.PathCurve == (byte)Extrusion.Straight || _pbs.PathCurve == (byte)Extrusion.Flexible)
|
||||||
float PathCutStartAmount = _pbs.ProfileBegin;
|
|
||||||
if (((PathCutStartAmount + PathCutEndAmount)/50000f) > 0.0f)
|
|
||||||
{
|
{
|
||||||
float pathCutAmount = ((PathCutStartAmount + PathCutEndAmount)/50000f);
|
taperX1 = _pbs.PathScaleX * 0.01f;
|
||||||
|
if (taperX1 > 1.0f)
|
||||||
|
taperX1 = 2.0f - taperX1;
|
||||||
|
taperX = 1.0f - taperX1;
|
||||||
|
|
||||||
// Check the return amount for sanity
|
taperY1 = _pbs.PathScaleY * 0.01f;
|
||||||
if (pathCutAmount >= 0.99f)
|
if (taperY1 > 1.0f)
|
||||||
pathCutAmount = 0.99f;
|
taperY1 = 2.0f - taperY1;
|
||||||
|
taperY = 1.0f - taperY1;
|
||||||
volume = volume - (volume*pathCutAmount);
|
|
||||||
}
|
|
||||||
UInt16 taperX = _pbs.PathScaleX;
|
|
||||||
UInt16 taperY = _pbs.PathScaleY;
|
|
||||||
float taperFactorX = 0;
|
|
||||||
float taperFactorY = 0;
|
|
||||||
|
|
||||||
// Mass = density * volume
|
|
||||||
if (taperX != 100)
|
|
||||||
{
|
|
||||||
if (taperX > 100)
|
|
||||||
{
|
|
||||||
taperFactorX = 1.0f - ((float)taperX / 200);
|
|
||||||
//m_log.Warn("taperTopFactorX: " + extr.taperTopFactorX.ToString());
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
taperFactorX = 1.0f - ((100 - (float)taperX) / 100);
|
taperX = _pbs.PathTaperX * 0.01f;
|
||||||
//m_log.Warn("taperBotFactorX: " + extr.taperBotFactorX.ToString());
|
if (taperX < 0.0f)
|
||||||
}
|
taperX = -taperX;
|
||||||
volume = (float)volume * ((taperFactorX / 3f) + 0.001f);
|
taperX1 = 1.0f - taperX;
|
||||||
|
|
||||||
|
taperY = _pbs.PathTaperY * 0.01f;
|
||||||
|
if (taperY < 0.0f)
|
||||||
|
taperY = -taperY;
|
||||||
|
taperY1 = 1.0f - taperY;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (taperY != 100)
|
|
||||||
{
|
volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY);
|
||||||
if (taperY > 100)
|
|
||||||
{
|
pathBegin = (float)_pbs.PathBegin * 2.0e-5f;
|
||||||
taperFactorY = 1.0f - ((float)taperY / 200);
|
pathEnd = 1.0f - (float)_pbs.PathEnd * 2.0e-5f;
|
||||||
//m_log.Warn("taperTopFactorY: " + extr.taperTopFactorY.ToString());
|
volume *= (pathEnd - pathBegin);
|
||||||
}
|
|
||||||
else
|
// this is crude aproximation
|
||||||
{
|
profileBegin = (float)_pbs.ProfileBegin * 2.0e-5f;
|
||||||
taperFactorY = 1.0f - ((100 - (float)taperY) / 100);
|
profileEnd = 1.0f - (float)_pbs.ProfileEnd * 2.0e-5f;
|
||||||
//m_log.Warn("taperBotFactorY: " + extr.taperBotFactorY.ToString());
|
volume *= (profileEnd - profileBegin);
|
||||||
}
|
|
||||||
volume = (float)volume * ((taperFactorY / 3f) + 0.001f);
|
|
||||||
}
|
|
||||||
returnMass = m_density * volume;
|
returnMass = m_density * volume;
|
||||||
if (returnMass <= 0) returnMass = 0.0001f;//ckrinke: Mass must be greater then zero.
|
|
||||||
|
if (returnMass <= 0)
|
||||||
|
returnMass = 0.0001f;//ckrinke: Mass must be greater then zero.
|
||||||
|
// else if (returnMass > _parent_scene.maximumMassObject)
|
||||||
|
// returnMass = _parent_scene.maximumMassObject;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue