求两个球体相交部分体积,公式及推导,C++实现

公式

两球相交分为两种情况:
第一种 大球完全包围了小球
第二种 两球相交但无完全包含关系

第一种情况的答案是显而易见的,直接求出小球体积即可
下面给出第二种情况的求解方法
在这里插入图片描述

V = π h 1 2 ( R − 1 3 h 1 ) + π h 2 2 ( r − 1 3 h 2 ) V = \pi h_1^2(R-\frac{1}{3}h_1) + \pi h_2^2(r-\frac{1}{3}h_2) V=πh12(R31h1)+πh22(r31h2)
图中角 α \alpha α与角 β \beta β位置标反了(多谢评论区小伙伴的提醒)

推导

我们把相交部分面积分为两部分,一部分是大球刨出去的体积,一部分是小球抛出去的体积,并且这两部分面积计算公式相同。
接下来我们证明其中大球刨去体积的公式。
先做一些准备工作
cos ⁡ α = R 2 + d 2 − r 2 2 R d \cos\alpha = \frac{R^2+d^2-r^2}{2Rd} cosα=2RdR2+d2r2
h 1 = R − R c o s α h_1 = R-Rcos\alpha h1=RRcosα
为了应用黎曼积分求体积,首先要得到大球被抛去部分的圆面面积公式。
由于刨去部分圆面的半径随着圆面的圆心从E点到F点的距离变小而变小,为了研究这两者间的关系,我们设圆面的圆心到F点的距离为 x x x
得到圆面半径的表达式为 R 2 − ( R c o s α + x ) 2 ) \sqrt{R^2-(Rcos\alpha+x)^2}) R2(Rcosα+x)2 ) ,从而圆面面积表达式为 π ( R 2 − ( R c o s α + x ) 2 ) \pi(R^2-(Rcos\alpha+x)^2) π(R2(Rcosα+x)2)
于是得到大球抛去体积 V 1 V_1 V1 的积分公式为
V 1 = ∫ 0 h 1 π ( R 2 − ( R c o s α + x ) 2 ) d x V_1 = \int_0^{h_1}\pi(R^2-(Rcos\alpha+x)^2) dx V1=0h1π(R2(Rcosα+x)2)dx
经过一系列牛顿-莱布尼茨公式之后化简得到
V 1 = π ( − 1 3 h 1 2 − R h 1 2 c o s α + R 2 h 1 s i n 2 α ) V_1 = \pi(-\frac{1}{3}h_1^2-Rh_1^2cos\alpha+R^2h_1sin^ 2\alpha) V1=π(31h12Rh12cosα+R2h1sin2α)
再把 c o s α cos\alpha cosα 代入化简后得到
V 1 = π h 1 2 ( R − 1 3 h 1 ) V_1 = \pi h_1^2(R-\frac{1}{3}h_1) V1=πh12(R31h1)
同理可得小球被刨去的体积
V 2 = π h 2 2 ( r − 1 3 h 2 ) V_2 = \pi h_2^2(r-\frac{1}{3}h_2) V2=πh22(r31h2)
总体积
V = V 1 + V 2 = π h 1 2 ( R − 1 3 h 1 ) + π h 2 2 ( r − 1 3 h 2 ) V = V_1 + V_2 = \pi h_1^2(R-\frac{1}{3}h_1) + \pi h_2^2(r-\frac{1}{3}h_2) V=V1+V2=πh12(R31h1)+πh22(r31h2)

代码

话不多说,上代码

#include<iostream>
#include<cmath>
#define Pi 3.14

using namespace std;

class Sphere	//属性分别为:(x,y,z)三个坐标以及半径
{
private:
	double m_x;
	double m_y;
	double m_z;
	double m_r;
public:
	Sphere():m_x(0),m_y(0), m_z(0), m_r(0)
	{
	}
	Sphere(double x,double y,double z,double r) :m_x(x), m_y(y), m_z(z), m_r(r)
	{
	}

	double getx();
	double gety();
	double getz();
	double getr();
	void modi_x(double x);
	void modi_y(double y);
	void modi_z(double z);
	void modi_r(double r);
	bool intersect(Sphere& o);
	double vol_ints(Sphere& o);
	double distance(Sphere& o);
};
//获得属性
double Sphere::getx()
{
	return m_x;
}
double Sphere::gety()
{
	return m_y;
}
double Sphere::getz()
{
	return m_z;
}
double Sphere::getr()
{
	return m_r;
}
//修改属性
void Sphere::modi_x(double x)
{
	m_x = x;
}
void Sphere::modi_y(double y)
{
	m_y = y;
}
void Sphere::modi_z(double z)
{
	m_z = z;
}
void Sphere::modi_r(double r)
{
	m_r = r;
}
//判断两个球是否相交
bool Sphere::intersect(Sphere& o)
{
	if (m_x == o.m_x && m_y == o.m_y && m_z == o.m_z)
		return true;
	else
	{
		double dis = distance(o);
		if ((m_r + o.m_r) * (m_r + o.m_r) > dis)
			return true;
		else
			return false;
	}
}
//计算两球圆心之间的距离
double Sphere::distance(Sphere& o)
{
	return (m_x - o.m_x) * (m_x - o.m_x) + (m_y - o.m_y) * (m_y - o.m_y) + (m_z - o.m_z) * (m_z - o.m_z);
}
//计算两球相交部分体积
double Sphere::vol_ints(Sphere& o)
{
	if (!intersect(o))
		return 0;
	else
	{
		double dis = distance(o);
		double max = m_r > o.m_r ? m_r : o.m_r;
		double min = m_r > o.m_r ? o.m_r : m_r;
		if (sqrt(dis) + min <= max)
			return 4 / 3 * Pi * pow(min, 3);
		else
		{
			double cos_a = (max * max + dis * dis - min * min) / (2 * max * dis);
			double cos_b = (min * min + dis * dis - max * max) / (2 * min * dis);
			double h_a = max * (1 - cos_a);
			double h_b = min * (1 - cos_b);
			return (Pi / 3) * (3 * max - h_a) * h_a * h_a + (Pi / 3) * (3 * min - h_b) * h_b * h_b;
		}
	}
}

第一次写文章,发现错误的话请各位多多指教

  • 7
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
以下是使用虚函数求球体和圆柱体的体积和表面积的C++代码示例: ``` #include <iostream> #include <cmath> using namespace std; class Shape { public: virtual double getVolume() = 0; virtual double getSurfaceArea() = 0; }; class Sphere : public Shape { private: double radius; public: Sphere(double r) { radius = r; } double getVolume() { return (4.0/3.0) * M_PI * pow(radius, 3); } double getSurfaceArea() { return 4 * M_PI * pow(radius, 2); } }; class Cylinder : public Shape { private: double radius; double height; public: Cylinder(double r, double h) { radius = r; height = h; } double getVolume() { return M_PI * pow(radius, 2) * height; } double getSurfaceArea() { return 2 * M_PI * radius * (radius + height); } }; int main() { Shape* shape; Sphere sphere(2.0); Cylinder cylinder(2.0, 5.0); shape = &sphere; cout << "Sphere Volume: " << shape->getVolume() << endl; cout << "Sphere Surface Area: " << shape->getSurfaceArea() << endl; shape = &cylinder; cout << "Cylinder Volume: " << shape->getVolume() << endl; cout << "Cylinder Surface Area: " << shape->getSurfaceArea() << endl; return 0; } ``` 在上面的代码中,我们定义了一个抽象基类`Shape`,包含两个纯虚函数`getVolume`和`getSurfaceArea`。然后,我们定义了两个派生类`Sphere`和`Cylinder`,分别表示球体和圆柱体。这两个派生类继承了`Shape`类,并实现了`getVolume`和`getSurfaceArea`函数。 在`main`函数中,我们首先创建了一个`Sphere`对象和一个`Cylinder`对象,并将它们的地址分别赋给一个`Shape`指针变量`shape`。然后,我们通过`shape`指针调用了`getVolume`和`getSurfaceArea`函数,分别输出了球体和圆柱体的体积和表面积。 需要注意的是,我们在`Shape`类中将`getVolume`和`getSurfaceArea`函数声明为纯虚函数,这意味着我们不能直接创建`Shape`对象,而只能通过派生类来创建对象。这种技术称为抽象类,它可以帮助我们实现多态性,即在运行时根据对象的实际类型来调用相应的函数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值