Jelajahi Sumber

上传文件至 ''

第一次提交
wubowen 3 bulan lalu
induk
melakukan
130ed831aa
5 mengubah file dengan 1516 tambahan dan 2 penghapusan
  1. 1395 0
      CreatePipeTool.h
  2. 93 2
      README.md
  3. 1 0
      base.cpp
  4. 5 0
      base.h
  5. 22 0
      occ_qt_test.sln

+ 1395 - 0
CreatePipeTool.h

@@ -0,0 +1,1395 @@
+#pragma once
+#include <BRepAlgoAPI_Cut.hxx>
+#include <BRepAlgoAPI_Fuse.hxx>
+#include <BRepBuilderAPI_MakeEdge.hxx>
+#include <BRepBuilderAPI_MakeFace.hxx>
+#include <BRepBuilderAPI_MakePolygon.hxx>
+#include <BRepBuilderAPI_MakeWire.hxx>
+#include <BRepFilletAPI_MakeFillet.hxx>
+#include <BRepOffsetAPI_MakePipe.hxx>
+#include <BRepOffsetAPI_ThruSections.hxx>
+#include <BRepPrimAPI_MakePrism.hxx>
+#include <GC_MakeArcOfCircle.hxx>
+#include <GeomAPI_ExtremaCurveCurve.hxx>
+#include <GeomAPI_IntCS.hxx>
+#include <Geom_Line.hxx>
+#include <Standard_UUID.hxx>
+#include <TopExp_Explorer.hxx>
+#include <TopoDS_Face.hxx>
+#include <TopoDS_Shape.hxx>
+#include <TopoDS_Wire.hxx>
+#include <algorithm>
+#include <gp_Ax2.hxx>
+#include <gp_Circ.hxx>
+#include <gp_Lin.hxx>
+#include <gp_Pnt.hxx>
+#include <iostream>
+
+using namespace std;
+
+struct Pipe {
+	Pipe(gp_Pnt p1, gp_Pnt p2, double r)
+		: startP(p1)
+		, endP(p2)
+		, radius(r) {
+	};
+	Pipe(std::string ndstr, gp_Pnt p1, gp_Pnt p2, double r)
+		: nd(ndstr)
+		, startP(p1)
+		, endP(p2)
+		, radius(r) {
+	};
+	std::string id; // 唯一标识
+	std::string nd; // 公称通径
+	gp_Pnt startP; // 起始点
+	gp_Pnt endP; // 结束点
+	double radius = -1; // 公称半径
+	std::string startConnectId; // 起始管接头id
+	std::string endConnectId; // 终点管接头id
+};
+
+struct PipeConnect {
+	PipeConnect() {};
+	PipeConnect(int n, double r1, double r2)
+		: type(n)
+		, radiusD1(r1)
+		, radiusD2(r2) {
+	};
+	PipeConnect(int n, std::string tj, double r1, double r2, double C, double M) // 四通用
+		: type(n)
+		, nd(tj)
+		, radiusD1(r1)
+		, radiusD2(r2)
+		, lengthC(C)
+		, lengthM(M) {
+	};
+	PipeConnect(int n, std::string tj, double r1, double C) // 二通用
+		: type(n)
+		, nd(tj)
+		, radiusD1(r1)
+		, lengthC(C) {
+	};
+	PipeConnect(int n, gp_Pnt p1, double r1, double r2)
+		: type(n)
+		, center(p1)
+		, radiusD1(r1)
+		, radiusD2(r2) {
+	};
+	std::string id; // 唯一标识
+	int type; // 类型 2:弯头 3:三通 4:四通 5:变径管
+	// 1.当type=2时为弯头,此时radiusD1为图例中的0.5*OD,radiusD2和lengthM的值为空,lengthC表示为图例中的A短半径
+	// 2.当type=3或4时,points前两个点对应截面半径为radiusD1,后两个对应radiusD2
+	// 3.当type=5时,points前两个点对应变径管的起始点和结束点
+	std::string nd; // 公称通径
+	double radiusD1 = -1; // 公称半径
+	double radiusD2 = -1; // 公称半径
+	double lengthC = -1; // C/短半径
+	double lengthM = -1; // M
+	gp_Pnt center; // 中心点(管道的交点)
+	vector<gp_Pnt> points; // 截面中心点
+};
+
+struct PipeResult {
+	std::vector<Pipe> pipes;
+	std::vector<PipeConnect> pipeConnects;
+	bool isOk;
+	std::string error;
+};
+
+class CreatePipeTool {
+public:
+	static TopoDS_Wire CreateCircularWire(const gp_Pnt& center, const gp_Dir& normal, double radius)
+	{
+		if (radius <= 0) {
+			return {};
+		}
+		gp_Ax2 axis2(center, normal);
+		gp_Circ circle = gp_Circ(axis2, radius);
+		BRepBuilderAPI_MakeEdge edgeMaker(circle);
+		TopoDS_Edge edge = edgeMaker;
+		if (!edgeMaker.IsDone()) {
+			throw std::runtime_error("Failed to create edge from circle.");
+		}
+		BRepBuilderAPI_MakeWire wireMaker(edge);
+		TopoDS_Wire wire = wireMaker;
+		if (!wireMaker.IsDone()) {
+			throw std::runtime_error("Failed to create wire from edge.");
+		}
+		return wire;
+	}
+
+	static ShapeResult getPipe(Pipe pipe)
+	{
+		ShapeResult result;
+
+		gp_Vec vec(pipe.endP.XYZ() - pipe.startP.XYZ());
+		gp_Dir dir(vec);
+		TopoDS_Wire wire = CreateCircularWire(pipe.startP, dir, pipe.radius);
+		TopoDS_Face face = BRepBuilderAPI_MakeFace(wire);
+		BRepPrimAPI_MakePrism prism(face, vec);
+		result.shape = prism.Shape();
+		return result;
+	}
+
+	static ShapeResult getPipeChange(PipeConnect pipeCon)
+	{
+		ShapeResult result;
+		if (pipeCon.points.size() < 2) {
+			result.isOk = false;
+			result.error += "pipeCon.points.size() < 2 \n";
+			return result;
+		}
+		try {
+			gp_Vec vec(pipeCon.points[1].XYZ() - pipeCon.points[0].XYZ());
+			gp_Dir dir(vec);
+			TopoDS_Wire wire1 = CreateCircularWire(pipeCon.points[0], dir, pipeCon.radiusD1);
+			TopoDS_Wire wire2 = CreateCircularWire(pipeCon.points[1], dir, pipeCon.radiusD2);
+			BRepOffsetAPI_ThruSections generator(Standard_True); // 标志是否生成Solid
+			generator.AddWire(wire1);
+			generator.AddWire(wire2);
+			result.shape = generator.Shape();
+		}
+		catch (const std::exception& e) {
+			result.isOk = false;
+			std::string ee = e.what();
+			result.error += "Error: " + ee + "\n";
+		}
+
+		return result;
+	}
+
+	static ShapeResult FuseShapes(const TopoDS_Shape& shape1, const TopoDS_Shape& shape2)
+	{
+		ShapeResult result;
+		try {
+			BRepAlgoAPI_Fuse fuse(shape1, shape2);
+			if (!fuse.IsDone()) {
+				result.error += "Boolean operation failed.\n";
+				throw std::runtime_error("");
+			}
+			result.shape = fuse.Shape();
+		}
+		catch (const std::exception& e) {
+			result.isOk = false;
+			std::string ee = e.what();
+			result.error += "Error: " + ee + "\n";
+		}
+		return result;
+	}
+
+	static ShapeResult CutShapes(const TopoDS_Shape& shape1, const TopoDS_Shape& shape2)
+	{
+		ShapeResult result;
+		try {
+			BRepAlgoAPI_Cut cut(shape1, shape2);
+			if (!cut.IsDone()) {
+				result.error += "Boolean operation failed.\n";
+				throw std::runtime_error("");
+			}
+			result.shape = cut.Shape();
+		}
+		catch (const std::exception& e) {
+			result.isOk = false;
+			std::string ee = e.what();
+			result.error += "Error: " + ee + "\n";
+		}
+		return result;
+	}
+
+	// 根据参数计算管道shape
+	static TopoDS_Shape getCylinder(Pipe pipe)
+	{
+		gp_Vec vec(pipe.endP.XYZ() - pipe.startP.XYZ());
+		gp_Dir dir(vec);
+		TopoDS_Wire wire = CreateCircularWire(pipe.startP, dir, pipe.radius);
+		TopoDS_Face Face = BRepBuilderAPI_MakeFace(wire);
+		BRepPrimAPI_MakePrism prism(Face, vec);
+		return prism.Shape();
+	}
+
+
+	static ShapeResult getPipeConnect3Part(PipeConnect pipeCon, int num)
+	{
+		ShapeResult result;
+		try {
+			gp_Pnt startP(0, 0, 0);
+			gp_Pnt endP(0, 0, 50);
+			Pipe pipe1(startP, endP, 30);
+
+			gp_Pnt startP2(0, 0, 25);
+			gp_Pnt endP2(40, 0, 25);
+			Pipe pipe2(startP2, endP2, 20);
+
+			if (num == 0) {
+				ShapeResult res1 = getPipe(pipe1);
+				if (!res1.isOk) {
+					result = res1;
+					return result;
+				}
+				TopoDS_Shape shape2 = getCylinder(pipe2);
+				result = CutShapes(res1.shape, shape2);
+			}
+			else {
+				ShapeResult res1 = getPipe(pipe2);
+				if (!res1.isOk) {
+					result = res1;
+					return result;
+				}
+				TopoDS_Shape shape2 = getCylinder(pipe1);
+				result = CutShapes(res1.shape, shape2);
+			}
+		}
+		catch (const std::exception& e) {
+			result.isOk = false;
+			std::string ee = e.what();
+			result.error += "Error: " + ee + "\n";
+		}
+		return result;
+	}
+
+	static ShapeResult getPipeConnect3(PipeConnect pipeCon)
+	{
+		ShapeResult result;
+		if (pipeCon.points.size() < 3) {
+			result.isOk = false;
+			result.error += "pipeCon.points.size() < 3 \n";
+			return result;
+		}
+		try {
+			// ShapeResult res1 = getPipeConnect3Part(pipeCon, 0);
+			// ShapeResult res2 = getPipeConnect3Part(pipeCon, 1);
+			Pipe pipe1(pipeCon.points[0], pipeCon.points[1], pipeCon.radiusD1);
+			Pipe pipe2(pipeCon.points[2], pipeCon.center, pipeCon.radiusD2);
+			ShapeResult res1 = getPipe(pipe1);
+			ShapeResult res2 = getPipe(pipe2);
+			result = FuseShapes(res1.shape, res2.shape);
+		}
+		catch (const std::exception& e) {
+			result.isOk = false;
+			std::string ee = e.what();
+			result.error += "Error: " + ee + "\n";
+		}
+		return result;
+	}
+
+	static ShapeResult getPipeConnect4(PipeConnect pipeCon)
+	{
+		ShapeResult result;
+		if (pipeCon.points.size() < 4) {
+			result.isOk = false;
+			result.error += "pipeCon.points.size() < 4 \n";
+			return result;
+		}
+		try {
+			Pipe pipe1(pipeCon.points[0], pipeCon.points[1], pipeCon.radiusD1);
+			Pipe pipe2(pipeCon.points[2], pipeCon.points[3], pipeCon.radiusD2);
+			ShapeResult res1 = getPipe(pipe1);
+			ShapeResult res2 = getPipe(pipe2);
+			result = FuseShapes(res1.shape, res2.shape);
+		}
+		catch (const std::exception& e) {
+			result.isOk = false;
+			std::string ee = e.what();
+			result.error += "Error: " + ee + "\n";
+		}
+		return result;
+	}
+
+	// 创建一个圆弧路径
+	static TopoDS_Wire CreateWireFromArc(
+		const gp_Pnt& startPt, const gp_Pnt& circleCenter, const gp_Pnt& endPt, double radius)
+	{
+		// 使用GC_MakeArcOfCircle创建圆弧
+		gp_Vec vec1(startPt.XYZ() - circleCenter.XYZ());
+		gp_Vec vec2(endPt.XYZ() - circleCenter.XYZ());
+		gp_Vec midVec = vec1 + vec2;
+		midVec.Normalize();
+		midVec.Multiply(radius);
+		gp_Pnt midPt = circleCenter.Translated(midVec);
+		GC_MakeArcOfCircle mkArc(startPt, midPt, endPt);
+		if (!mkArc.IsDone()) {
+			throw std::runtime_error("Failed to create arc of circle.");
+		}
+
+		Handle(Geom_TrimmedCurve) arc = mkArc.Value();
+		BRepBuilderAPI_MakeEdge edgeMaker(arc);
+		if (!edgeMaker.IsDone()) {
+			throw std::runtime_error("Failed to create edge from arc.");
+		}
+		TopoDS_Edge edge = edgeMaker;
+
+		BRepBuilderAPI_MakeWire wireMaker(edge);
+		if (!wireMaker.IsDone()) {
+			throw std::runtime_error("Failed to create wire from edge.");
+		}
+
+		return wireMaker.Wire();
+	}
+
+	// 创建一个圆形截面
+	static TopoDS_Wire CreateCircularSection(const gp_Pnt& center, gp_Dir normal, double radius)
+	{
+		gp_Ax2 axis2(center, normal);
+		gp_Circ circle = gp_Circ(axis2, radius);
+		BRepBuilderAPI_MakeEdge edgeMaker(circle);
+		TopoDS_Edge edge = edgeMaker;
+		BRepBuilderAPI_MakeWire wireMaker(edge);
+		return wireMaker.Wire();
+	}
+
+	// 执行管道操作(沿路径拉伸)
+	static TopoDS_Shape SweepAlongPath(const TopoDS_Wire& section, const TopoDS_Wire& path)
+	{
+		TopoDS_Face face = BRepBuilderAPI_MakeFace(section);
+		BRepOffsetAPI_MakePipe pipeMaker(path, face);
+		return pipeMaker.Shape();
+	}
+
+	static ShapeResult getPipeConnect2(PipeConnect pipeCon)
+	{
+		ShapeResult result;
+		if (pipeCon.points.size() < 2) {
+			result.isOk = false;
+			result.error += "pipeCon.points.size() < 2 \n";
+			return result;
+		}
+		if (pipeCon.lengthC < 0) {
+			result.isOk = false;
+			result.error += "短半径值无效 \n";
+			return result;
+		}
+		try {
+			gp_Vec vec1(pipeCon.center.XYZ() - pipeCon.points[0].XYZ());
+			gp_Dir dir1(vec1);
+			gp_Vec vec2(pipeCon.points[1].XYZ() - pipeCon.center.XYZ());
+			gp_Dir dir2(vec2);
+			TopoDS_Wire cir = CreateCircularSection(pipeCon.points[0], vec1, pipeCon.radiusD1);
+			gp_Vec vecToCenter(dir2);
+			vecToCenter *= pipeCon.lengthC;
+			gp_Pnt circleCenter = pipeCon.points[0].Translated(vecToCenter);
+			TopoDS_Wire path = CreateWireFromArc(pipeCon.points[0], circleCenter, pipeCon.points[1], pipeCon.lengthC);
+
+			result.shape = /*path*/ SweepAlongPath(cir, path);
+		}
+		catch (const std::exception& e) {
+			std::string ee = e.what();
+			result.error += "Error: " + ee + "\n";
+		}
+		return result;
+	}
+
+
+	// 根据参数计算管道接头和变径管
+	static ShapeResult getPipeConnect(PipeConnect pipeCon)
+	{
+		ShapeResult result;
+		switch (pipeCon.type) {
+		case 2: {
+			result = getPipeConnect2(pipeCon);
+			break;
+		}
+		case 3: {
+			result = getPipeConnect3(pipeCon);
+			break;
+		}
+		case 4: {
+			result = getPipeConnect4(pipeCon);
+			break;
+		}
+		case 5: {
+			result = getPipeChange(pipeCon);
+			break;
+		}
+		default:
+			break;
+		}
+
+		return result;
+	}
+
+	std::string GenerateUUID()
+	{
+		// 生成一个新的随机UUID
+
+		// 将UUID转换为字符串形式以便打印
+		std::string uuidStr /*= aUUID.()*/;
+
+		return uuidStr;
+	}
+
+	// 计算两条直线的交点
+	static bool calculateIntersection(gp_Pnt& intersectionPoint, const gp_Lin& line1, const gp_Lin& line2)
+	{
+		// 将直线转换为参数方程的形式
+		gp_Pnt origin1 = line1.Location();
+		gp_Dir direction1 = line1.Direction();
+		gp_Pnt origin2 = line2.Location();
+		gp_Dir direction2 = line2.Direction();
+
+		// 使用向量数学计算交点
+		gp_Vec v1(origin1, origin2);
+		gp_Vec dirVec1(direction1);
+		gp_Vec dirVec2(direction2);
+
+		// 计算分母,两个方向向量的叉乘大小
+		gp_Vec crossProduct = dirVec1.Crossed(dirVec2);
+		double denom = crossProduct.Magnitude(); // 分母应该是叉乘向量的模
+
+		if (std::abs(denom) < 1e-6) { // 平行或共线
+			std::cerr << "Lines are parallel or coincident." << std::endl;
+			return false; // 返回默认构造的点作为错误指示
+		}
+
+		// 计算t参数,即从line1的原点到交点的距离参数
+		double t = (v1.Crossed(dirVec2)).Magnitude() / denom;
+		// 计算line1上的交点
+		gp_Vec vecOnLine1(dirVec1);
+		vecOnLine1.Multiply(t);
+		intersectionPoint = origin1.Translated(vecOnLine1);
+		return true;
+	}
+
+	// 求交点
+	static bool computeInterPt(gp_Pnt& intersectionPoint, const vector<Pipe>& pipes)
+	{
+		if (pipes.size() < 2)
+			return false;
+
+		gp_Lin line1(pipes.front().startP, gp_Dir(gp_Vec(pipes.front().startP, pipes.front().endP)));
+		gp_Lin line2(pipes[1].startP, gp_Dir(gp_Vec(pipes[1].startP, pipes[1].endP)));
+		if (!calculateIntersection(intersectionPoint, line1, line2)) {
+			std::cout << "No intersection found." << std::endl;
+			return false;
+		}
+		return true;
+	}
+
+	static bool AreLinesCollinear(const gp_Lin& line1, const gp_Lin& line2, double tolerance = 1e-7)
+	{
+		// 获取两条直线的方向向量
+		gp_Dir dir1 = line1.Direction();
+		gp_Dir dir2 = line2.Direction();
+		// 检查方向向量是否相同或相反
+		if (!dir1.IsEqual(dir2, tolerance) && !dir1.IsOpposite(dir2, tolerance)) {
+			return false;
+		}
+		// 获取line1上的一个点并检查它是否在line2上
+		gp_Pnt pointOnLine1 = line1.Location();
+		double u = 0.0;
+		return line2.Contains(pointOnLine1, u);
+	}
+
+	static bool IsPipesCollinear(const vector<Pipe>& pipes)
+	{
+		if (pipes.size() < 2)
+			return false;
+
+		gp_Lin line1(pipes.front().startP, gp_Dir(gp_Vec(pipes.front().startP, pipes.front().endP)));
+		gp_Lin line2(pipes[1].startP, gp_Dir(gp_Vec(pipes[1].startP, pipes[1].endP)));
+		return AreLinesCollinear(line1, line2);
+	}
+	static bool isAlmostEqual(double a, double b, double tolerance = 1e-6)
+	{
+		if (std::abs(a - b) <= tolerance)
+			return true;
+
+		return false;
+	}
+
+	static std::vector<PipeConnect> getAllPipeConnect4()
+	{
+		std::vector<PipeConnect> vecPipeConnect4;
+		PipeConnect con4_50_50_50(4, "50*50*50", 57 * 0.5, 57 * 0.5, 64, 64);
+		PipeConnect con4_50_50_40(4, "50*50*40", 57 * 0.5, 45 * 0.5, 64, 60);
+
+		vecPipeConnect4.insert(vecPipeConnect4.end(), { con4_50_50_50, con4_50_50_40 });
+		return vecPipeConnect4;
+	}
+
+	static std::vector<PipeConnect> getAllPipeConnect5()
+	{
+		std::vector<PipeConnect> vecPipeConnect5;
+		//PipeConnect con5_40_32(5, "40*32", 48.3 * 0.5, 42.4 * 0.5, 64, 64);
+		//PipeConnect con5_40_25(5, "40*25", 48.3 * 0.5, 33.7 * 0.5, 64, 64);
+		//PipeConnect con5_50_40(5, "50*40", 60.3 * 0.5, 48.3 * 0.5, 76, 76);
+		//PipeConnect con5_50_32(5, "50*32", 60.3 * 0.5, 42.4 * 0.5, 76, 76);
+		PipeConnect con5_40_32(5, "40*32", 45 * 0.5, 38 * 0.5, 64, 64);
+		PipeConnect con5_40_25(5, "40*25", 45 * 0.5, 32 * 0.5, 64, 64);
+		PipeConnect con5_50_40(5, "50*40", 57 * 0.5, 45 * 0.5, 76, 76);
+		PipeConnect con5_50_32(5, "50*32", 57 * 0.5, 38 * 0.5, 76, 76);
+
+		vecPipeConnect5.insert(vecPipeConnect5.end(), { con5_40_32, con5_40_25, con5_50_40, con5_50_32 });
+		return vecPipeConnect5;
+	}
+
+	static std::vector<PipeConnect> getAllPipeConnect2()
+	{
+		std::vector<PipeConnect> vecPipeConnect2;
+		PipeConnect con4_50(2, "50", 57 * 0.5, 50);
+		PipeConnect con4_40(2, "40", 45 * 0.5, 40);
+
+		vecPipeConnect2.insert(vecPipeConnect2.end(), { con4_50, con4_40 });
+		return vecPipeConnect2;
+	}
+
+	static PipeConnect getPipeConnect4(bool& isneedChange1, bool& isneedChange2, double r1, double r2)
+	{
+		PipeConnect conRes;
+		conRes.type = 4;
+		std::vector<PipeConnect> vecPipeConnect4 = getAllPipeConnect4();
+		if (vecPipeConnect4.size() < 1) {
+			return conRes;
+		}
+		std::vector<int> numTrue1, numTrue2;
+		for (int i = 0; i < vecPipeConnect4.size(); i++) {
+			PipeConnect con = vecPipeConnect4[i];
+			int num = 0;
+			if (isAlmostEqual(con.radiusD1, r1))
+				num++;
+			if (isAlmostEqual(con.radiusD2, r2))
+				num++;
+			numTrue1.push_back(num);
+		}
+		for (int i = 0; i < vecPipeConnect4.size(); i++) {
+			PipeConnect con = vecPipeConnect4[i];
+			int num = 0;
+			if (isAlmostEqual(con.radiusD1, r2))
+				num++;
+			if (isAlmostEqual(con.radiusD2, r1))
+				num++;
+			numTrue2.push_back(num);
+		}
+
+		if (numTrue1.empty()) {
+			return conRes;
+		}
+		int maxIndex1 = 0;
+		int maxValue1 = numTrue1[0];
+		for (int i = 1; i < numTrue1.size(); ++i) {
+			if (numTrue1[i] > maxValue1) {
+				maxValue1 = numTrue1[i];
+				maxIndex1 = i;
+			}
+		}
+
+		if (numTrue2.empty()) {
+			return conRes;
+		}
+		int maxIndex2 = 0;
+		int maxValue2 = numTrue2[0];
+		for (int i = 1; i < numTrue2.size(); ++i) {
+			if (numTrue2[i] > maxValue2) {
+				maxValue2 = numTrue2[i];
+				maxIndex2 = i;
+			}
+		}
+
+		if (maxValue1 == 0 && maxValue2 == 0) {
+			return vecPipeConnect4[0];
+		}
+
+		if (maxIndex1 >= maxIndex2) {
+			conRes = vecPipeConnect4[maxIndex1];
+		}
+		else {
+			conRes.nd = vecPipeConnect4[maxIndex2].nd;
+			conRes.radiusD1 = vecPipeConnect4[maxIndex2].radiusD2;
+			conRes.radiusD2 = vecPipeConnect4[maxIndex2].radiusD1;
+			conRes.lengthC = vecPipeConnect4[maxIndex2].lengthM;
+			conRes.lengthM = vecPipeConnect4[maxIndex2].lengthC;
+		}
+		if (isAlmostEqual(conRes.radiusD1, r1))
+			isneedChange1 = false;
+		if (isAlmostEqual(conRes.radiusD2, r2))
+			isneedChange2 = false;
+		conRes.id = "newConnect"; // 用UUID
+		return conRes;
+	}
+
+	static std::string getNominalDiameter1(const PipeConnect& con)
+	{
+		std::string str = con.nd;
+		std::string result = str;
+		size_t pos = str.find('*');
+		if (pos != std::string::npos && pos != 0) {
+			result = str.substr(0, pos);
+		}
+
+		return result;
+	}
+
+	static std::string getNominalDiameter2(const PipeConnect& con)
+	{
+		std::string str = con.nd;
+		std::string result = str;
+		size_t pos = str.rfind('*');
+		if (pos != std::string::npos && pos != str.length() - 1) {
+			result = str.substr(pos + 1);
+		}
+
+		return result;
+	}
+
+	static PipeConnect getPipeConnect5(bool& isexist, std::string D1, std::string D2)
+	{
+		PipeConnect conRes;
+		conRes.type = 5;
+		std::vector<PipeConnect> vecPipeConnect5 = getAllPipeConnect5();
+		if (vecPipeConnect5.size() < 1) {
+			return conRes;
+		}
+
+		for (int i = 0; i < vecPipeConnect5.size(); i++) {
+			PipeConnect con = vecPipeConnect5[i];
+			if ((getNominalDiameter1(con) == D1 && getNominalDiameter2(con) == D2)
+				|| (getNominalDiameter1(con) == D2 && getNominalDiameter2(con) == D1)) {
+				isexist = true;
+				conRes = con;
+				conRes.id = "newConnect"; // 用UUID				
+				return conRes;
+			}
+		}
+
+		isexist = false;
+		conRes.id = "newConnect"; // 用UUID
+		return conRes;
+	}
+
+	static PipeConnect getPipeConnect4(bool& isneedChange1, bool& isneedChange2, std::string D1, std::string D2)
+	{
+		PipeConnect conRes;
+		conRes.type = 4;
+		std::vector<PipeConnect> vecPipeConnect4 = getAllPipeConnect4();
+		if (vecPipeConnect4.size() < 1) {
+			return conRes;
+		}
+		std::vector<int> numTrue1, numTrue2;
+		for (int i = 0; i < vecPipeConnect4.size(); i++) {
+			PipeConnect con = vecPipeConnect4[i];
+
+			int num = 0;
+			if (getNominalDiameter1(con) == D1)
+				num++;
+			if (getNominalDiameter2(con) == D2)
+				num++;
+			numTrue1.push_back(num);
+		}
+		for (int i = 0; i < vecPipeConnect4.size(); i++) {
+			PipeConnect con = vecPipeConnect4[i];
+			int num = 0;
+			if (getNominalDiameter1(con) == D2)
+				num++;
+			if (getNominalDiameter2(con) == D1)
+				num++;
+			numTrue2.push_back(num);
+		}
+
+		if (numTrue1.empty()) {
+			return conRes;
+		}
+		int maxIndex1 = 0;
+		int maxValue1 = numTrue1[0];
+		for (int i = 1; i < numTrue1.size(); ++i) {
+			if (numTrue1[i] > maxValue1) {
+				maxValue1 = numTrue1[i];
+				maxIndex1 = i;
+			}
+		}
+
+		if (numTrue2.empty()) {
+			return conRes;
+		}
+		int maxIndex2 = 0;
+		int maxValue2 = numTrue2[0];
+		for (int i = 1; i < numTrue2.size(); ++i) {
+			if (numTrue2[i] > maxValue2) {
+				maxValue2 = numTrue2[i];
+				maxIndex2 = i;
+			}
+		}
+
+		if (maxValue1 == 0 && maxValue2 == 0) {
+			return vecPipeConnect4[0];
+		}
+
+		if (maxValue1 >= maxValue2) {
+			conRes = vecPipeConnect4[maxIndex1];
+			if (getNominalDiameter1(conRes) == D1)
+				isneedChange1 = false;
+			if (getNominalDiameter2(conRes) == D2)
+				isneedChange2 = false;
+		}
+		else {
+			conRes.nd = vecPipeConnect4[maxIndex2].nd;
+			conRes.radiusD1 = vecPipeConnect4[maxIndex2].radiusD2;
+			conRes.radiusD2 = vecPipeConnect4[maxIndex2].radiusD1;
+			conRes.lengthC = vecPipeConnect4[maxIndex2].lengthM;
+			conRes.lengthM = vecPipeConnect4[maxIndex2].lengthC;
+			if (getNominalDiameter2(conRes) == D1)
+				isneedChange1 = false;
+			if (getNominalDiameter1(conRes) == D2)
+				isneedChange2 = false;
+		}
+
+		conRes.id = "newConnect"; // 用UUID
+		return conRes;
+	}
+
+	static PipeConnect getPipeConnect3(bool& isneedChange1, bool& isneedChange2, double D1, double D2)
+	{
+		PipeConnect conRes;
+		std::vector<PipeConnect> vecPipeConnect4 = getAllPipeConnect4();
+		if (vecPipeConnect4.size() < 1) {
+			return conRes;
+		}
+		std::vector<int> numTrue1;
+		for (int i = 0; i < vecPipeConnect4.size(); i++) {
+			PipeConnect con = vecPipeConnect4[i];
+			int num = 0;
+			if (isAlmostEqual(con.radiusD1, D1))
+				num++;
+			if (isAlmostEqual(con.radiusD2, D2))
+				num++;
+			numTrue1.push_back(num);
+		}
+
+		if (numTrue1.empty()) {
+			return conRes;
+		}
+		int maxIndex1 = 0;
+		int maxValue1 = numTrue1[0];
+		for (int i = 1; i < numTrue1.size(); ++i) {
+			if (numTrue1[i] > maxValue1) {
+				maxValue1 = numTrue1[i];
+				maxIndex1 = i;
+			}
+		}
+
+		if (maxValue1 == 0) {
+			return vecPipeConnect4[0];
+		}
+		conRes = vecPipeConnect4[maxIndex1];
+		conRes.type = 3;
+		conRes.id = "newConnect"; // 用UUID
+		if (isAlmostEqual(conRes.radiusD1, D1))
+			isneedChange1 = false;
+		if (isAlmostEqual(conRes.radiusD2, D2))
+			isneedChange2 = false;
+		return conRes;
+	}
+
+	static PipeConnect getPipeConnect3(bool& isneedChange1, bool& isneedChange2, std::string D1, std::string D2)
+	{
+		PipeConnect conRes;
+		std::vector<PipeConnect> vecPipeConnect4 = getAllPipeConnect4();
+		if (vecPipeConnect4.size() < 1) {
+			return conRes;
+		}
+		std::vector<int> numTrue1;
+		for (int i = 0; i < vecPipeConnect4.size(); i++) {
+			PipeConnect con = vecPipeConnect4[i];
+			int num = 0;
+			if (getNominalDiameter1(con) == D1)
+				num++;
+			if (getNominalDiameter2(con) == D2)
+				num++;
+			numTrue1.push_back(num);
+		}
+
+		if (numTrue1.empty()) {
+			return conRes;
+		}
+
+		int maxIndex1 = 0;
+		int maxValue1 = numTrue1[0];
+		for (int i = 1; i < numTrue1.size(); ++i) {
+			if (numTrue1[i] > maxValue1) {
+				maxValue1 = numTrue1[i];
+				maxIndex1 = i;
+			}
+		}
+
+		if (maxValue1 == 0) {
+			return vecPipeConnect4[0];
+		}
+		conRes = vecPipeConnect4[maxIndex1];
+		conRes.type = 3;
+		conRes.id = "newConnect"; // 用UUID
+		if (getNominalDiameter1(conRes) == D1)
+			isneedChange1 = false;
+		if (getNominalDiameter2(conRes) == D2)
+			isneedChange2 = false;
+		return conRes;
+	}
+
+	static PipeConnect getPipeConnect2(bool& isneedChange1, bool& isneedChange2, double D1, double D2)
+	{
+		PipeConnect conRes;
+		conRes.type = 2;
+		std::vector<PipeConnect> vecPipeConnect2 = getAllPipeConnect2();
+		if (vecPipeConnect2.size() < 1) {
+			return conRes;
+		}
+		std::vector<int> numTrue1;
+		for (int i = 0; i < vecPipeConnect2.size(); i++) {
+			PipeConnect con = vecPipeConnect2[i];
+			int num = 0;
+			if (isAlmostEqual(con.radiusD1, D1))
+				num++;
+			if (isAlmostEqual(con.radiusD1, D2))
+				num++;
+			numTrue1.push_back(num);
+		}
+
+		if (numTrue1.empty()) {
+			return conRes;
+		}
+		int maxIndex1 = 0;
+		int maxValue1 = numTrue1[0];
+		for (int i = 1; i < numTrue1.size(); ++i) {
+			if (numTrue1[i] > maxValue1) {
+				maxValue1 = numTrue1[i];
+				maxIndex1 = i;
+			}
+		}
+
+		if (maxValue1 == 0) {
+			return vecPipeConnect2[0];
+		}
+		conRes = vecPipeConnect2[maxIndex1];
+		conRes.id = "newConnect"; // 用UUID
+		if (isAlmostEqual(conRes.radiusD1, D1))
+			isneedChange1 = false;
+		if (isAlmostEqual(conRes.radiusD1, D2))
+			isneedChange2 = false;
+		return conRes;
+	}
+
+	static PipeConnect getPipeConnect2(bool& isneedChange1, bool& isneedChange2, std::string D1, std::string D2)
+	{
+		PipeConnect conRes;
+		conRes.type = 2;
+		std::vector<PipeConnect> vecPipeConnect2 = getAllPipeConnect2();
+		if (vecPipeConnect2.size() < 1) {
+			return conRes;
+		}
+		std::vector<int> numTrue1;
+		for (int i = 0; i < vecPipeConnect2.size(); i++) {
+			PipeConnect con = vecPipeConnect2[i];
+			int num = 0;
+			if (getNominalDiameter1(con) == D1)
+				num++;
+			if (getNominalDiameter1(con) == D2)
+				num++;
+			numTrue1.push_back(num);
+		}
+
+		if (numTrue1.empty()) {
+			return conRes;
+		}
+		int maxIndex1 = 0;
+		int maxValue1 = numTrue1[0];
+		for (int i = 1; i < numTrue1.size(); ++i) {
+			if (numTrue1[i] > maxValue1) {
+				maxValue1 = numTrue1[i];
+				maxIndex1 = i;
+			}
+		}
+
+		if (maxValue1 == 0) {
+			return vecPipeConnect2[0];
+		}
+		conRes = vecPipeConnect2[maxIndex1];
+		conRes.id = "newConnect"; // 用UUID
+		if (getNominalDiameter1(conRes) == D1)
+			isneedChange1 = false;
+		if (getNominalDiameter1(conRes) == D2)
+			isneedChange2 = false;
+		return conRes;
+	}
+
+	static void AdjustPipesSequence(vector<Pipe>& pipes)
+	{
+		// 调整顺序:原管道(黄色)在前,新管道(红色)在后 (没id代表管道需要新增,有id代表需要修改)
+		if (pipes.size() < 2)
+			return;
+		if (pipes[0].id.empty() && !pipes[1].id.empty()) {
+			std::reverse(pipes.begin(), pipes.end());
+		}
+	}
+
+	static void countPipesByPart2Pipe(vector<Pipe>& pipes, vector<PipeConnect>& pipeCons)
+	{
+		if (pipes.size() < 2)
+			return;
+
+		AdjustPipesSequence(pipes);
+
+		gp_Pnt p1 = pipes[0].startP;
+		gp_Pnt p2 = pipes[0].endP;
+		gp_Pnt p3 = pipes[1].startP;
+		gp_Pnt p4 = pipes[1].endP;
+		double lenLine1 = p1.Distance(p2);
+		double lenLine2 = p3.Distance(p4);
+
+		gp_Pnt intersectionPoint;
+		bool isPipesCollinear = IsPipesCollinear(pipes);
+		if (isPipesCollinear) // 共线
+		{
+			gp_Pnt pipe1nearPt = p1.Distance(p3) < p2.Distance(p3) ? p1 : p2;
+			gp_Pnt pipe2nearPt = p3.Distance(pipe1nearPt) < p4.Distance(p3) ? p3 : p4;
+			intersectionPoint = gp_Pnt((pipe1nearPt.X() + pipe2nearPt.X()) * 0.5,
+				(pipe1nearPt.Y() + pipe2nearPt.Y()) * 0.5,
+				(pipe1nearPt.Z() + pipe2nearPt.Z()) * 0.5);
+		}
+		computeInterPt(intersectionPoint, pipes);
+		double dis_p1_int = p1.Distance(intersectionPoint);
+		double dis_p2_int = p2.Distance(intersectionPoint);
+		double dis_p3_int = p3.Distance(intersectionPoint);
+		double dis_p4_int = p4.Distance(intersectionPoint);
+		bool intPonLine1 = dis_p1_int + dis_p2_int - lenLine1 <= 1e-6 ? true : false;
+		bool intPonLine2 = dis_p3_int + dis_p4_int - lenLine2 <= 1e-6 ? true : false;
+
+		auto computeNewPt = [intersectionPoint](gp_Vec vec, double len) {
+			vec.Normalize();
+			vec.Multiply(len);
+			gp_Pnt line1newPt = intersectionPoint.Translated(vec);
+			return line1newPt;
+			};
+
+		if (isPipesCollinear) // 共线
+		{
+			if (pipes[0].nd == pipes[1].nd)
+			{
+				if (dis_p1_int < dis_p2_int) {
+					pipes[0].startP = dis_p3_int > dis_p4_int ? p3 : p4;
+					pipes[0].startConnectId = dis_p3_int > dis_p4_int ? pipes[1].startConnectId : pipes[1].endConnectId;
+				}
+				else {
+					pipes[0].endP = dis_p3_int > dis_p4_int ? p3 : p4;
+					pipes[0].endConnectId = dis_p3_int > dis_p4_int ? pipes[1].startConnectId : pipes[1].endConnectId;
+				}
+				pipes.erase(pipes.begin() + 1);
+				return;
+			}
+			else
+			{
+				bool isexist = true;
+				PipeConnect newChange1 = getPipeConnect5(isexist, pipes[0].nd, pipes[1].nd);
+				if (!isexist)
+				{
+					return;
+				}
+				gp_Pnt pipe1farPt = p1.Distance(p3) > p2.Distance(p3) ? p1 : p2;
+				gp_Pnt pipe2farPt = p3.Distance(pipe1farPt) > p4.Distance(p3) ? p3 : p4;
+				gp_Vec vec1 = gp_Vec(pipe2farPt.XYZ() - pipe1farPt.XYZ());
+				gp_Pnt changeStartPt = computeNewPt(vec1, -(newChange1.lengthC * 0.5));
+				gp_Pnt changeEndPt = computeNewPt(vec1, (newChange1.lengthC * 0.5));
+				if (pipes[0].radius > pipes[0].radius) {
+					newChange1.points.insert(newChange1.points.end(), { changeStartPt, changeEndPt });
+				}
+				else
+				{
+					newChange1.points.insert(newChange1.points.end(), { changeEndPt, changeStartPt });
+				}
+				pipeCons.push_back(newChange1);
+
+				if (dis_p1_int < dis_p2_int) {
+					pipes[0].startP = changeStartPt;
+					pipes[0].startConnectId = newChange1.id;
+				}
+				else {
+					pipes[0].endP = changeStartPt;
+					pipes[0].endConnectId = newChange1.id;
+				}
+				if (dis_p3_int < dis_p4_int) {
+					pipes[1].startP = changeEndPt;
+					pipes[1].startConnectId = newChange1.id;
+				}
+				else {
+					pipes[1].endP = changeEndPt;
+					pipes[1].endConnectId = newChange1.id;
+				}
+				return;
+			}
+		}
+
+		// 查表
+		bool isneedChange1 = true;
+		bool isneedChange2 = true;
+		PipeConnect Con4 = getPipeConnect4(isneedChange1, isneedChange2, pipes[0].nd, pipes[1].nd);
+
+		bool isOver = false;
+		// 截断后为新增管道
+		auto insertPipe = [&pipes](Pipe& pipe, gp_Pnt newPipeStartPt, gp_Pnt pipeNewEndPt, std::string connectId) {
+			Pipe newPipe1(newPipeStartPt, pipe.endP, pipe.radius);
+			newPipe1.startConnectId = connectId;
+			pipes.push_back(newPipe1);
+			// pipe.endP = pipeNewEndPt;
+			// pipe.endConnectId = connectId;
+			};
+		// ChangePipe起点是接头、终点是管道
+		auto insert2ChangePipe1Pipe =
+			[&](Pipe& pipe, gp_Pnt pt1, gp_Pnt pt2, gp_Vec vec1, gp_Vec vec2, std::string strConDiameter, double lenCM) {
+			bool isexist = false;
+			PipeConnect newChange1 = getPipeConnect5(isexist, strConDiameter, pipe.nd);
+			if (!isexist) {
+				std::cout << "The PipeChange is not existed " << std::endl;
+				isOver = true;
+			}
+			gp_Pnt changeEndPt1 = computeNewPt(vec1, lenCM + newChange1.lengthC);
+			newChange1.points.insert(newChange1.points.end(), { pt1, changeEndPt1 });
+			pipeCons.push_back(newChange1);
+
+			PipeConnect newChange2 = getPipeConnect5(isexist, strConDiameter, pipe.nd);
+			if (!isexist) {
+				std::cout << "The PipeChange is not existed " << std::endl;
+				isOver = true;
+			}
+			gp_Pnt changeEndPt2 = computeNewPt(vec2, lenCM + newChange2.lengthC);
+			newChange2.points.insert(newChange2.points.end(), { pt2, changeEndPt2 });
+			pipeCons.push_back(newChange2);
+
+			Pipe newPipe1(changeEndPt2, pipe.endP, pipe.radius);
+			newPipe1.startConnectId = newChange2.id;
+			pipes.push_back(newPipe1);
+
+			return std::pair<gp_Pnt, std::string>(changeEndPt1, newChange1.id);
+			};
+
+		auto insertOneChangePipe
+			= [&](Pipe& pipe, gp_Pnt conPt, gp_Vec vecInterPt2Pt, std::string strConDiameter, double lenCM) {
+			bool isexist = false;
+			PipeConnect newChange1 = getPipeConnect5(isexist, strConDiameter, pipe.nd);
+			if (!isexist) {
+				std::cout << "The PipeChange is not existed " << std::endl;
+				isOver = true;
+			}
+			gp_Pnt changeEndPt1 = computeNewPt(vecInterPt2Pt, lenCM + newChange1.lengthC);
+			newChange1.points.insert(newChange1.points.end(), { conPt, changeEndPt1 });
+			pipeCons.push_back(newChange1);
+			};
+		// 先检查是否能形成四通、不行再看能否形成三通、最后二通(弯头)
+		if (intPonLine1 && intPonLine2 && !Con4.nd.empty() && dis_p1_int >= Con4.lengthC && dis_p2_int >= Con4.lengthC
+			&& dis_p3_int >= Con4.lengthM && dis_p4_int >= Con4.lengthM) // 四通
+		{
+			gp_Vec vec1 = gp_Vec(p1.XYZ() - intersectionPoint.XYZ());
+			gp_Pnt conPt1 = computeNewPt(vec1, Con4.lengthC);
+			gp_Vec vec2 = gp_Vec(p2.XYZ() - intersectionPoint.XYZ());
+			gp_Pnt conPt2 = computeNewPt(vec2, Con4.lengthC);
+			gp_Vec vec3 = gp_Vec(p3.XYZ() - intersectionPoint.XYZ());
+			gp_Pnt conPt3 = computeNewPt(vec3, Con4.lengthM);
+			gp_Vec vec4 = gp_Vec(p4.XYZ() - intersectionPoint.XYZ());
+			gp_Pnt conPt4 = computeNewPt(vec4, Con4.lengthM);
+			Con4.points.insert(Con4.points.end(), { conPt1, conPt2, conPt3, conPt4 });
+			Con4.center = intersectionPoint;
+			pipeCons.push_back(Con4);
+
+			if (!isneedChange1) {
+				// 现有条件不足以证明应该把Con4.id给startConnectId还是endConnectId
+				// 新增管道
+				insertPipe(pipes[0], conPt2, conPt1, Con4.id);
+				pipes[0].endP = conPt1;
+				pipes[0].endConnectId = Con4.id;
+
+				if (!isneedChange2) {
+					insertPipe(pipes[1], conPt4, conPt3, Con4.id);
+					pipes[1].endP = conPt3;
+					pipes[1].endConnectId = Con4.id;
+				}
+				else {
+					// 2需要接变径管
+					std::pair<gp_Pnt, std::string> pair = insert2ChangePipe1Pipe(
+						pipes[1], conPt3, conPt4, vec3, vec4, getNominalDiameter2(Con4), Con4.lengthM);
+					if (isOver)
+					{
+						pipeCons.clear();
+						return;
+					}
+					pipes[1].endP = pair.first;
+					pipes[1].endConnectId = pair.second;
+				}
+			}
+			else {
+				std::pair<gp_Pnt, std::string> pair = insert2ChangePipe1Pipe(
+					pipes[0], conPt1, conPt2, vec1, vec2, getNominalDiameter1(Con4), Con4.lengthC);
+				if (isOver) {
+					pipeCons.clear();
+					return;
+				}
+				pipes[0].endP = pair.first;
+				pipes[0].endConnectId = pair.second;
+
+				if (!isneedChange2) {
+					insertPipe(pipes[1], conPt4, conPt3, Con4.id);
+					pipes[1].endP = conPt3;
+					pipes[1].endConnectId = Con4.id;
+				}
+				else {
+					std::pair<gp_Pnt, std::string> pair = insert2ChangePipe1Pipe(
+						pipes[1], conPt3, conPt4, vec3, vec4, getNominalDiameter2(Con4), Con4.lengthM);
+					if (isOver) {
+						pipeCons.clear();
+						return;
+					}
+					pipes[1].endP = pair.first;
+					pipes[1].endConnectId = pair.second;
+				}
+			}
+		}
+		// 三通和四通规格一样
+		else if ((intPonLine1 && dis_p1_int >= Con4.lengthC && dis_p2_int >= Con4.lengthC)
+			|| (intPonLine2 && dis_p3_int >= Con4.lengthM && dis_p4_int >= Con4.lengthM)) // 三通
+		{
+			bool isneedChange1 = true;
+			bool isneedChange2 = true;
+			if (intPonLine1 && dis_p1_int >= Con4.lengthC && dis_p2_int >= Con4.lengthC) {
+				PipeConnect Con3 = getPipeConnect3(isneedChange1, isneedChange2, pipes[0].nd, pipes[1].nd);
+				gp_Vec vec1 = gp_Vec(p1.XYZ() - intersectionPoint.XYZ());
+				gp_Pnt conPt1 = computeNewPt(vec1, Con3.lengthC);
+				gp_Vec vec2 = gp_Vec(p2.XYZ() - intersectionPoint.XYZ());
+				gp_Pnt conPt2 = computeNewPt(vec2, Con3.lengthC);
+				gp_Vec vecLine2;
+				if (dis_p3_int < dis_p4_int) {
+					vecLine2 = gp_Vec(p4.XYZ() - intersectionPoint.XYZ());
+				}
+				else {
+					vecLine2 = gp_Vec(p3.XYZ() - intersectionPoint.XYZ());
+				}
+				gp_Pnt conLine2Pt = computeNewPt(vecLine2, Con3.lengthM);
+				Con3.points.insert(Con3.points.end(), { conPt1, conPt2, conLine2Pt });
+				Con3.center = intersectionPoint;
+				pipeCons.push_back(Con3);
+
+				if (!isneedChange1) {
+					insertPipe(pipes[0], conPt2, conPt1, Con3.id);
+					pipes[0].endP = conPt1;
+					pipes[0].endConnectId = Con3.id;
+				}
+				else {
+					std::pair<gp_Pnt, std::string> pair = insert2ChangePipe1Pipe(
+						pipes[0], conPt1, conPt2, vec1, vec2, getNominalDiameter1(Con3), Con3.lengthC);
+					if (isOver) {
+						pipeCons.clear();
+						return;
+					}
+					pipes[0].endP = pair.first;
+					pipes[0].endConnectId = pair.second;
+				}
+
+				if (!isneedChange2) {
+					if (dis_p3_int < dis_p4_int) {
+						pipes[1].startP = conLine2Pt;
+						pipes[1].startConnectId = Con3.id;
+					}
+					else {
+						pipes[1].endP = conLine2Pt;
+						pipes[1].endConnectId = Con3.id;
+					}
+				}
+				else {
+					insertOneChangePipe(pipes[1], conLine2Pt, vecLine2, getNominalDiameter2(Con3), Con3.lengthM);
+					if (isOver) {
+						pipeCons.clear();
+						return;
+					}
+					if (dis_p3_int < dis_p4_int) {
+						pipes[1].startP = conLine2Pt;
+						pipes[1].startConnectId = Con3.id;
+					}
+					else {
+						pipes[1].endP = conLine2Pt;
+						pipes[1].endConnectId = Con3.id;
+					}
+
+					std::pair<gp_Pnt, std::string> pair = insert2ChangePipe1Pipe(
+						pipes[0], conPt1, conPt2, vec1, vec2, getNominalDiameter1(Con3), Con3.lengthC);
+					if (isOver) {
+						pipeCons.clear();
+						return;
+					}
+					pipes[0].endP = pair.first;
+					pipes[0].endConnectId = pair.second;
+				}
+			}
+			else // Line2被贯穿
+			{
+				PipeConnect Con3 = getPipeConnect3(isneedChange2, isneedChange1, pipes[1].nd, pipes[0].nd);
+				gp_Vec vecLine1; // 此时向量应用远端的
+				if (dis_p1_int < dis_p2_int) {
+					vecLine1 = gp_Vec(p2.XYZ() - intersectionPoint.XYZ());
+				}
+				else {
+					vecLine1 = gp_Vec(p1.XYZ() - intersectionPoint.XYZ());
+				}
+				gp_Pnt conLine1Pt = computeNewPt(vecLine1, Con3.lengthC);
+				gp_Vec vec3 = gp_Vec(p3.XYZ() - intersectionPoint.XYZ());
+				gp_Pnt conPt3 = computeNewPt(vec3, Con3.lengthM);
+				gp_Vec vec4 = gp_Vec(p4.XYZ() - intersectionPoint.XYZ());
+				gp_Pnt conPt4 = computeNewPt(vec4, Con3.lengthM);
+				if (!isneedChange2) {
+					insertPipe(pipes[1], conPt4, conPt3, Con3.id);
+					pipes[1].endP = conPt3;
+					pipes[1].endConnectId = Con3.id;
+				}
+				else {
+					std::pair<gp_Pnt, std::string> pair = insert2ChangePipe1Pipe(
+						pipes[1], conPt3, conPt4, vec3, vec4, getNominalDiameter1(Con3), Con3.lengthC);
+					if (isOver) {
+						pipeCons.clear();
+						return;
+					}
+					pipes[1].endP = pair.first;
+					pipes[1].endConnectId = pair.second;
+				}
+				Con3.points.insert(Con3.points.end(), { conPt3, conPt4, conLine1Pt });
+				Con3.center = intersectionPoint;
+				pipeCons.push_back(Con3);
+
+				if (!isneedChange1) {
+					if (dis_p1_int < dis_p2_int) {
+						pipes[0].startP = conLine1Pt;
+						pipes[0].startConnectId = Con3.id;
+					}
+					else {
+						pipes[0].endP = conLine1Pt;
+						pipes[0].endConnectId = Con3.id;
+					}
+				}
+				else {
+					insertOneChangePipe(pipes[0], conLine1Pt, vecLine1, getNominalDiameter1(Con3), Con3.lengthM);
+					if (isOver) {
+						pipeCons.clear();
+						return;
+					}
+					if (dis_p1_int < dis_p2_int) {
+						pipes[0].startP = conLine1Pt;
+						pipes[0].startConnectId = Con3.id;
+					}
+					else {
+						pipes[0].endP = conLine1Pt;
+						pipes[0].endConnectId = Con3.id;
+					}
+				}
+			}
+		}
+		else // 二通接头
+		{
+			bool isneedChange1 = true;
+			bool isneedChange2 = true;
+			PipeConnect Con2 = getPipeConnect2(isneedChange1, isneedChange2, pipes[0].nd, pipes[1].nd);
+			gp_Vec vec1; // 此时向量应用远端的
+			if (dis_p1_int < dis_p2_int) {
+				vec1 = gp_Vec(p2.XYZ() - intersectionPoint.XYZ());
+			}
+			else {
+				vec1 = gp_Vec(p1.XYZ() - intersectionPoint.XYZ());
+			}
+			gp_Pnt con2StartPt = computeNewPt(vec1, Con2.lengthC);
+			gp_Vec vec2;
+			if (dis_p3_int < dis_p4_int) {
+				vec2 = gp_Vec(p4.XYZ() - intersectionPoint.XYZ());
+			}
+			else {
+				vec2 = gp_Vec(p3.XYZ() - intersectionPoint.XYZ());
+			}
+			gp_Pnt con2EndPt = computeNewPt(vec2, Con2.lengthC);
+			Con2.points.push_back(con2StartPt);
+			Con2.points.push_back(con2EndPt);
+			Con2.center = intersectionPoint;
+			pipeCons.push_back(Con2);
+
+			if (!isneedChange1) {
+				if (dis_p1_int < dis_p2_int) {
+					pipes.front().startP = con2StartPt;
+					pipes.front().startConnectId = Con2.id;
+				}
+				else {
+					pipes.front().endP = con2StartPt;
+					pipes.front().endConnectId = Con2.id;
+				}
+
+				if (!isneedChange2) {
+					if (dis_p3_int < dis_p4_int) {
+						pipes[1].startP = con2EndPt;
+					}
+					else {
+						pipes[1].endP = con2EndPt;
+					}
+				}
+				else {
+					insertOneChangePipe(pipes[1], con2EndPt, vec2, getNominalDiameter1(Con2), Con2.lengthC);
+					if (isOver) {
+						pipeCons.clear();
+						return;
+					}
+					if (dis_p3_int < dis_p4_int) {
+						pipes[1].startP = pipeCons.back().points.back();
+					}
+					else {
+						pipes[1].endP = pipeCons.back().points.back();
+					}
+				}
+			}
+			else {
+				// 1需要接变径管
+				insertOneChangePipe(pipes[0], con2StartPt, vec1, getNominalDiameter1(Con2), Con2.lengthC);
+				if (isOver) {
+					pipeCons.clear();
+					return;
+				}
+				if (dis_p1_int < dis_p2_int) {
+					pipes.front().startP = pipeCons.back().points.back();
+					pipes.front().startConnectId = pipeCons.back().id;
+				}
+				else {
+					pipes.front().endP = pipeCons.back().points.back();
+					pipes.front().endConnectId = pipeCons.back().id;
+				}
+
+				if (!isneedChange2) {
+					if (dis_p3_int < dis_p4_int) {
+						pipes[1].startP = con2EndPt;
+					}
+					else {
+						pipes[1].endP = con2EndPt;
+					}
+				}
+				else {
+					// 2也需要接变径管
+					insertOneChangePipe(pipes[1], con2StartPt, vec1, getNominalDiameter1(Con2), Con2.lengthC);
+					if (isOver) {
+						pipeCons.clear();
+						return;
+					}
+					if (dis_p3_int < dis_p4_int) {
+						pipes[1].startP = pipeCons.back().points.back();
+						pipes[1].startConnectId = pipeCons.back().id;
+					}
+					else {
+						pipes[1].endP = pipeCons.back().points.back();
+						pipes[1].endConnectId = pipeCons.back().id;
+					}
+				}
+			}
+		}
+	}
+
+	static PipeResult countPipesByPart(vector<Pipe>& pipes, vector<PipeConnect>& pipeCons)
+	{
+		int num = (int)pipes.size();
+		if (num < 2)
+			return PipeResult{ pipes ,pipeCons ,false,"" };
+
+		switch (num) {
+		case 2: {
+			countPipesByPart2Pipe(pipes, pipeCons);
+			break;
+		}
+		default:
+			break;
+		}
+		return PipeResult{ pipes ,pipeCons ,true,"" };
+	}
+};
+

+ 93 - 2
README.md

@@ -1,2 +1,93 @@
-# OCC_TEST
-
+# occ_qt_test
+
+
+
+## Getting started
+
+To make it easy for you to get started with GitLab, here's a list of recommended next steps.
+
+Already a pro? Just edit this README.md and make it your own. Want to make it easy? [Use the template at the bottom](#editing-this-readme)!
+
+## Add your files
+
+- [ ] [Create](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#create-a-file) or [upload](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#upload-a-file) files
+- [ ] [Add files using the command line](https://docs.gitlab.com/topics/git/add_files/#add-files-to-a-git-repository) or push an existing Git repository with the following command:
+
+```
+cd existing_repo
+git remote add origin https://gitlab.com/0job/occ_qt_test.git
+git branch -M main
+git push -uf origin main
+```
+
+## Integrate with your tools
+
+- [ ] [Set up project integrations](https://gitlab.com/0job/occ_qt_test/-/settings/integrations)
+
+## Collaborate with your team
+
+- [ ] [Invite team members and collaborators](https://docs.gitlab.com/ee/user/project/members/)
+- [ ] [Create a new merge request](https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html)
+- [ ] [Automatically close issues from merge requests](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically)
+- [ ] [Enable merge request approvals](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/)
+- [ ] [Set auto-merge](https://docs.gitlab.com/user/project/merge_requests/auto_merge/)
+
+## Test and Deploy
+
+Use the built-in continuous integration in GitLab.
+
+- [ ] [Get started with GitLab CI/CD](https://docs.gitlab.com/ee/ci/quick_start/)
+- [ ] [Analyze your code for known vulnerabilities with Static Application Security Testing (SAST)](https://docs.gitlab.com/ee/user/application_security/sast/)
+- [ ] [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/requirements.html)
+- [ ] [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/ee/user/clusters/agent/)
+- [ ] [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html)
+
+***
+
+# Editing this README
+
+When you're ready to make this README your own, just edit this file and use the handy template below (or feel free to structure it however you want - this is just a starting point!). Thanks to [makeareadme.com](https://www.makeareadme.com/) for this template.
+
+## Suggestions for a good README
+
+Every project is different, so consider which of these sections apply to yours. The sections used in the template are suggestions for most open source projects. Also keep in mind that while a README can be too long and detailed, too long is better than too short. If you think your README is too long, consider utilizing another form of documentation rather than cutting out information.
+
+## Name
+Choose a self-explaining name for your project.
+
+## Description
+Let people know what your project can do specifically. Provide context and add a link to any reference visitors might be unfamiliar with. A list of Features or a Background subsection can also be added here. If there are alternatives to your project, this is a good place to list differentiating factors.
+
+## Badges
+On some READMEs, you may see small images that convey metadata, such as whether or not all the tests are passing for the project. You can use Shields to add some to your README. Many services also have instructions for adding a badge.
+
+## Visuals
+Depending on what you are making, it can be a good idea to include screenshots or even a video (you'll frequently see GIFs rather than actual videos). Tools like ttygif can help, but check out Asciinema for a more sophisticated method.
+
+## Installation
+Within a particular ecosystem, there may be a common way of installing things, such as using Yarn, NuGet, or Homebrew. However, consider the possibility that whoever is reading your README is a novice and would like more guidance. Listing specific steps helps remove ambiguity and gets people to using your project as quickly as possible. If it only runs in a specific context like a particular programming language version or operating system or has dependencies that have to be installed manually, also add a Requirements subsection.
+
+## Usage
+Use examples liberally, and show the expected output if you can. It's helpful to have inline the smallest example of usage that you can demonstrate, while providing links to more sophisticated examples if they are too long to reasonably include in the README.
+
+## Support
+Tell people where they can go to for help. It can be any combination of an issue tracker, a chat room, an email address, etc.
+
+## Roadmap
+If you have ideas for releases in the future, it is a good idea to list them in the README.
+
+## Contributing
+State if you are open to contributions and what your requirements are for accepting them.
+
+For people who want to make changes to your project, it's helpful to have some documentation on how to get started. Perhaps there is a script that they should run or some environment variables that they need to set. Make these steps explicit. These instructions could also be useful to your future self.
+
+You can also document commands to lint the code or run tests. These steps help to ensure high code quality and reduce the likelihood that the changes inadvertently break something. Having instructions for running tests is especially helpful if it requires external setup, such as starting a Selenium server for testing in a browser.
+
+## Authors and acknowledgment
+Show your appreciation to those who have contributed to the project.
+
+## License
+For open source projects, say how it is licensed.
+
+## Project status
+If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers.

+ 1 - 0
base.cpp

@@ -0,0 +1 @@
+#include "base.h"

+ 5 - 0
base.h

@@ -0,0 +1,5 @@
+#pragma once
+class base
+{
+};
+

+ 22 - 0
occ_qt_test.sln

@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.12.35527.113 d17.12
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "occ_qt_test", "occ_qt_test\occ_qt_test.vcxproj", "{4C7F0171-8EEE-4F46-8211-8086640A2E74}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|x64 = Debug|x64
+		Release|x64 = Release|x64
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{4C7F0171-8EEE-4F46-8211-8086640A2E74}.Debug|x64.ActiveCfg = Debug|x64
+		{4C7F0171-8EEE-4F46-8211-8086640A2E74}.Debug|x64.Build.0 = Debug|x64
+		{4C7F0171-8EEE-4F46-8211-8086640A2E74}.Release|x64.ActiveCfg = Release|x64
+		{4C7F0171-8EEE-4F46-8211-8086640A2E74}.Release|x64.Build.0 = Release|x64
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal