10号,不太舒服有点头疼。千万别感冒,补点水饺。

这是《最强大脑》里出现过的一个拼图游戏。这个游戏的自动拼图算法是一个N数码问题。原始图片被切割成n x n个小块,游戏可能出现的总状态数为 n平方的阶乘。

即使最简单的n=3,3阶分割也有(3*3)! = 362880个状态。4阶分割时,拼图状态数飙升到(4*4)! = 20922789888000。那么100阶分割呢,(100*100)! 绝对的天文数字。如何来实现任意阶的拼图算法呢?

方案一:
我们很容易想到的方法,按打乱的顺序逆序还原,有点作弊之嫌。

方案二:
A*算法剪枝, 避免电脑出现一万年也算不完任务的情况。当阶数n足够大的时候效率仍然是堪忧的。

方案三:
本游戏采用的算法,模拟人脑的思路。100*100阶的拼图也能很快求解,而且可以分步执行,即一次只计算一步,很适合游戏ai。 此方法也有一个缺点,不是最优解,求解出来的步数有点长。

算法:先将色块和空格移动到目标位置附近,然后执行相应的公式化步骤。

具体直接看源码吧

//========================================================
//  @Date:     2016.05
//  @File:     SourceDemoClient/Pintu/MiniGamePintu.h
//  @Brief:     MiniGamePintu
//  @Author:     LouLei
//  @Email:  twopointfive@163.com
//  @Copyright (Crapell) - All Rights Reserved
//========================================================#ifndef  __MiniGamePintu__H__
#define  __MiniGamePintu__H__#include "Rpg/MiniGame.h"//拼图1 空格移动
class MiniGameSlidingBlock:public MiniGame
{
public:struct Cell{int texID;int x,y;};struct CellMesh{vec3 vVertex[8];vec2 tVertex[8];};MiniGameSlidingBlock();virtual~MiniGameSlidingBlock();virtual bool Start();virtual bool Stop();virtual bool Render();virtual void RenderUI();virtual bool Update();virtual bool Free();virtual void OnSize();virtual bool KeepResource(bool once,int& circle,String& nextTip);//三种类型结构virtual MiniPlayer*  CreatePlayer();virtual MiniPlayer*  CreateRobot ();virtual MiniPlayer*  CreateRole  ();void  UpdateGameRect();bool  IsEnd();void  MoveEmpty(int key);bool  IsCellOK(int x,int y);bool  IsCellEmpty(int x,int y);Cell* GetCell(int texID);bool  AIMoveSrcUp(int srcX,int srcY,int tarX,int tarY,int empX,int empY);bool  AIMoveSrcDown(int srcX,int srcY,int tarX,int tarY,int empX,int empY);bool  AIMoveSrcLeft(int srcX,int srcY,int tarX,int tarY,int empX,int empY);bool  AIMoveSrcRight(int srcX,int srcY,int tarX,int tarY,int empX,int empY);//protected:float m_accumeTime;TexturePtr  m_texBack;TexturePtr  m_texPic;TexturePtr  m_texFrame;TexturePtr  m_texFrame2;TexturePtr  m_texCloud;int         m_Level;RectF       m_gameRect;RectF       m_rectLevel;vec2I       m_cellNum;int         m_cellNumXY;vec2I       m_cellExtend;Cell*       m_emptyCell;Cell*       m_cells;CellMesh*   m_cellMeshs;Cell        m_movingCell;vec2        m_movingDir;float       m_movingTime;bool        m_workingWithAI;Cell*       m_aiSrcCell;int         m_aiCompleteSize;int         m_stepNum;int         m_aiTryNum;int         m_aiTrys[64];//box 索引int         CellIndex[30];
};extern MiniGameSlidingBlock* G_SlideBlockGame;#endif
//========================================================
//  @Date:     2016.05
//  @File:     SourceDemoClient/Pintu/MiniGamePintu.cpp
//  @Brief:     MiniGamePintu
//  @Author:     LouLei
//  @Email:  twopointfive@163.com
//  @Copyright (Crapell) - All Rights Reserved
//========================================================#include "General/Pch.h"
#include "General/General.h"
#include "General/StringUtil.h"
#include "General/Timer.h"
#include "General/Window.h"
#include "Gui/GuiMgr.h"
#include "Gui/RpgGuis.h"
#include "Gui/GuiControlMisc.h"
#include "Input/InputMgr.h"
#include "MiniGameSlidingBlock.h"
#include "Render/Camera.h"
#include "Render/Font.h"
#include "Render/RendDriver.h"
#include "Render/Terrain.h"
#include "Render/MC_MovieClip.h"
#include "Render/Shader.h"
#include "Sound/SoundManager.h"
#include "General/List.cpp"
#include "General/Pce.h"//static float MovingTime = 0.001f;
static float MovingTime = 0.08f;
static float GameRectWidth2D    = 460;
static float GameRectWidth3D    = 66; MiniGameSlidingBlock* G_SlideBlockGame;MiniGameSlidingBlock::MiniGameSlidingBlock()
:m_cells(NULL)
{G_SlideBlockGame = this;//m_Level = 0;m_Level = 4;//box 索引/*0  12  34  56  7*/int indexs[30] = {0,2,1,1,2,3,3,2,6,3,6,7,1,3,7,1,7,5,0,1,5,0,5,4,2,0,4,2,4,6};memcpy(CellIndex,indexs,sizeof(CellIndex));
}
MiniGameSlidingBlock::~MiniGameSlidingBlock()
{Free();G_SlideBlockGame = NULL;
}
bool MiniGameSlidingBlock::Start()
{//m_myRolePlayer = NULL;if(!MiniGame::Start())return false;m_gameState = MS_Gamming;m_accumeTime = 0;//进入miniplaygui,(选人、选关卡都已在房间里进行完毕)。if(GetStyle()) G_GuiMgr->PushGui(GetStyle()->playGUI.c_str(),GL_DIALOG);G_TextureMgr->AddTexture(m_texBack,    "data/minigame/Pintu/backframe.png");G_TextureMgr->AddTexture(m_texPic,     "data/minigame/Pintu/pic1.png");G_TextureMgr->AddTexture(m_texFrame,    "data/minigame/Pintu/frame.png");G_TextureMgr->AddTexture(m_texFrame2,   "data/minigame/Pintu/frame2.png");//G_TextureMgr->AddTexture(m_texCloud,    "data/environment/clouds/cloud2.png");G_TextureMgr->AddTexture(m_texCloud,    "data/environment/clouds/cloud_1.png");//if (m_movieScene == NULL){LoadConfig loader(LoadConfig::GenDonotReShrinkBound, true, true);m_movieScene = new RendSys::MovieClip;m_movieScene->LoadFromFile("data/minigame/pintu/board.movie", &loader);Frame frame;frame.SetPos(m_startPos);m_movieScene->SetProgramFrame(&frame);m_movieScene->Advance();}if (m_movieScene->IsLoadComplete() == false){m_gameState = MS_End;return false;}m_movieScene->GetMovieClip("preview")->ReAttachTexture(m_texPic);//m_cellNum.x = 6;//m_cellNum.y = 7;m_cellNum.x = 2+m_Level;m_cellNum.y = 2+m_Level;m_cellNumXY = m_cellNum.x*m_cellNum.y;UpdateGameRect();m_workingWithAI=FALSE;m_aiSrcCell = NULL;m_aiTryNum = 0;m_aiCompleteSize = -1;m_stepNum = 0;m_movingTime = 0;m_movingCell.texID = -1;//m_cells = new Cell[m_cellNumXY];for(int i=0;i<m_cellNumXY;i++){m_cells[i].texID =i;m_cells[i].x =i%m_cellNum.x;m_cells[i].y =i/m_cellNum.x;}m_emptyCell = &m_cells[m_cellNumXY - 1];m_emptyCell->texID = -1;//int num = 0;for(int i=1;i<200;i++){int ran1=Rand()%(m_cellNumXY-1);//empty不交换int ran2=Rand()%(m_cellNumXY-1);if(ran1!=ran2){num++;Swap(m_cells[ran1].texID,m_cells[ran2].texID);}}if (num%2==1){//必须交换偶数次Swap(m_cells[0].texID,m_cells[1].texID);}///*0  12  34  56  7*/m_cellMeshs = new CellMesh[m_cellNumXY];TerrainData terrain;//terrain.New(48,48,GameRectWidth3D/48,GameRectWidth3D/48);terrain.New(17,17,GameRectWidth3D/16,GameRectWidth3D/16);terrain.FillFractSurface(0,0,10,0.5f,false,0);Cell* cell;CellMesh* mesh;vec2 cellExtend3D;cellExtend3D.x = GameRectWidth3D/m_cellNum.x;cellExtend3D.y = GameRectWidth3D/m_cellNum.y;for(int i=0;i<m_cellNumXY;i++){cell = &m_cells[i];float X0 = 0;float X1 = cellExtend3D.x;float Z0 = 0;float Z1 = cellExtend3D.y;float Y0 = 0;mesh = &m_cellMeshs[i];mesh->vVertex[0].x = X0;mesh->vVertex[0].y = terrain.GetHeight(cell->x,cell->y);mesh->vVertex[0].z = Z0;mesh->vVertex[4].x = X0;mesh->vVertex[4].y = Y0;mesh->vVertex[4].z = Z0;mesh->vVertex[1].x = X1;mesh->vVertex[1].y = terrain.GetHeight(cell->x+1,cell->y);mesh->vVertex[1].z = Z0;mesh->vVertex[5].x = X1;mesh->vVertex[5].y = Y0;mesh->vVertex[5].z = Z0;mesh->vVertex[2].x = X0;mesh->vVertex[2].y = terrain.GetHeight(cell->x,cell->y+1);mesh->vVertex[2].z = Z1;mesh->vVertex[6].x = X0;mesh->vVertex[6].y = Y0;mesh->vVertex[6].z = Z1;mesh->vVertex[3].x = X1;mesh->vVertex[3].y = terrain.GetHeight(cell->x+1,cell->y+1);mesh->vVertex[3].z = Z1;mesh->vVertex[7].x = X1;mesh->vVertex[7].y = Y0;mesh->vVertex[7].z = Z1;float TX0 = float(cell->x)/m_cellNum.x;float TX1 = float(cell->x+1)/m_cellNum.x;float TZ0 = float(cell->y)/m_cellNum.y;float TZ1 = float(cell->y+1)/m_cellNum.y;mesh->tVertex[0].x = TX0;mesh->tVertex[0].y = TZ0;mesh->tVertex[4].x = TX0;mesh->tVertex[4].y = TZ0;mesh->tVertex[1].x = TX1;mesh->tVertex[1].y = TZ0;mesh->tVertex[5].x = TX1;mesh->tVertex[5].y = TZ0;mesh->tVertex[2].x = TX0;mesh->tVertex[2].y = TZ1;mesh->tVertex[6].x = TX0;mesh->tVertex[6].y = TZ1;mesh->tVertex[3].x = TX1;mesh->tVertex[3].y = TZ1;mesh->tVertex[7].x = TX1;mesh->tVertex[7].y = TZ1;}//for(int i = 0; i < m_allPlayerNum; i++){if(m_miniPlayer[i])m_miniPlayer[i]->Start();}//设置摄像机CameraCtrlerTarget* ctrler = new CameraCtrlerTarget;ctrler->SetDistToTar(60);ctrler->SetTarPos(m_startPos);G_Camera->PushCtrler(ctrler);   G_Camera->SetEuler(0, -60, 0);//片头摄像机PushIntroCamera();return true;
}MiniPlayer* MiniGameSlidingBlock::CreatePlayer()
{return new MiniPlayer;
}MiniPlayer* MiniGameSlidingBlock::CreateRobot()
{return new MiniPlayer;
}MiniPlayer* MiniGameSlidingBlock::CreateRole()
{return new MiniPlayer;
}bool MiniGameSlidingBlock::Stop()
{
//  char buf[256];G_GuiMgr->PopGui("MiPintu_PlayGui");{if (m_myPlayer && m_myPlayer->m_liveNum>0){G_GuiMgr->GetGui<Rpg_ResultDialog>()->ShowResult(true);}else{G_GuiMgr->GetGui<Rpg_ResultDialog>()->ShowResult(false);}G_GuiMgr->PushGui("Rpg_ResultDialog",GL_DIALOGBOTTOM);}MiniGame::Stop();return true;
}bool MiniGameSlidingBlock::Render()
{if (m_3dMode){G_RendDriver->EndUI();if(m_movieScene==NULL||m_movieScene->IsLoadComplete()==false)return false;G_RendDriver->SetRenderStateEnable(RS_DEPTH_TEST,true);m_movieScene->RendClip();画等级//m_rectLevel = RectF(BoardRect2D.x+623, BoardRect2D.y+24, 39, 23);//if(m_rectLevel.IsPointIn(G_Mouse->GetMousePos()))//{// G_RendDriver->Color4f(1, 1, 0, 1);//}//else//{// G_RendDriver->Color4f(1, 0, 0, 1);//}//m_texLcdNumber->Bind();//DrawLcd(3,m_Level+1, m_rectLevel);//G_RendDriver->Color4f(1, 1, 1, 1);画时间和得分//m_texLcdNumber->Bind();//G_RendDriver->Color4f(1, 0, 0, 1);//DrawLcd(3,m_gameTime, RectF(BoardRect2D.x +613, BoardRect2D.y+213, 39, 23));DrawLcd(3,m_life, RectF(m_uiOffset.x+623, m_uiOffset.y +52, 39, 23));//DrawLcd(4,m_stepNum, RectF(BoardRect2D.x+623, BoardRect2D.y +79, 52, 23));//G_RendDriver->Color4f(1.0f, 1.0f, 1.0f, 1.0f);G_RendDriver->SetRenderStateEnable(RS_TEXTURE_2D,true);m_texPic->Bind();//cellCell* cell;CellMesh* mesh;for(int i = 0;i<m_cellNumXY;i++){cell = &m_cells[i];if (cell->texID!=-1&&cell->texID!=m_movingCell.texID){mesh = &m_cellMeshs[cell->texID];G_RendDriver->PushMatrix();G_RendDriver->Translatef(m_gameRect.x+cell->x *m_cellExtend.x,m_startPos.y+9,m_gameRect.y+cell->y *m_cellExtend.y);G_RendDriver->RendTrigon(10,mesh->vVertex,mesh->tVertex,NULL,NULL,CellIndex,8);G_RendDriver->PopMatrix();//G_RendDriver->Color4f(0.0f, 0.0f, 0.0f, 0.5f);//G_RendDriver->DrawRect(RectF(dst.x+3,dst.y+3,20,20));//G_FontMgr->SetColor(Color(1.0f, 1.0f, 1.0f, 1.0f));//sprintf(buf,"%d",cell->texID);//G_FontMgr->TextAtPos(dst,buf);}}//movingif (m_movingCell.texID!=-1){vec2 pos;pos.x = m_movingCell.x *m_cellExtend.x;pos.y = m_movingCell.y *m_cellExtend.y;pos += m_movingDir*vec2(m_cellExtend.x,m_cellExtend.y)*(1-m_movingTime/MovingTime);mesh = &m_cellMeshs[m_movingCell.texID];G_RendDriver->PushMatrix();G_RendDriver->Translatef(m_gameRect.x+pos.x,m_startPos.y+9,m_gameRect.y+pos.y);G_RendDriver->RendTrigon(10,mesh->vVertex,mesh->tVertex,NULL,NULL,CellIndex,8);G_RendDriver->PopMatrix();//  G_RendDriver->Color4f(0.0f, 0.0f, 0.0f, 0.5f);// G_RendDriver->DrawRect(RectF(dst.x+3,dst.y+3,20,20));//    sprintf(buf,"%d",m_movingCell.texID);//   G_FontMgr->SetColor(Color(1.0f, 1.0f, 1.0f, 1.0f));//    G_FontMgr->TextAtPos(dst,buf);}}else{//G_RendDriver->ClearClipRect();G_RendDriver->BeginUI();//frameG_RendDriver->Color4f(1.0f, 1.0f, 1.0f, 1.0f);m_texBack->Bind();G_RendDriver->DrawTextureRect(BoardRect2D, RectF(0, 0, 1, 1));//G_RendDriver->PushMatrix();G_RendDriver->Translatef(m_gameRect.x,-m_gameRect.y,0);vec2 dst;//cellchar buf[128];vec2I tex;//纹理排序后速度微小增加 //pictureCell* cell = m_cells;m_texPic->Bind();G_RendDriver->Color4f(1.0f, 1.0f, 1.0f, 1.0f);if (G_ShaderMgr&& G_ShaderMgr->m_curEffect){G_ShaderMgr->MapChangeParm();}for(int i = 0;i<m_cellNumXY;i++,cell++){if (cell->texID!=-1&&cell->texID!=m_movingCell.texID){tex.x = cell->texID%m_cellNum.x;tex.y = cell->texID/m_cellNum.x;dst.x = cell->x *m_cellExtend.x;dst.y = cell->y *m_cellExtend.y;G_RendDriver->DrawTextureRect(RectF(dst.x,dst.y,m_cellExtend.x,m_cellExtend.y),RectF(float(tex.x)/m_cellNum.x,float(tex.y)/m_cellNum.y,1.0f/m_cellNum.x,1.0f/m_cellNum.y));}}//cloudcell = m_cells;m_texCloud->Bind();for(int i = 0;i<m_cellNumXY;i++,cell++){if (cell->texID!=-1&&cell->texID!=m_movingCell.texID){tex.x = cell->texID%m_cellNum.x;tex.y = cell->texID/m_cellNum.x;dst.x = cell->x *m_cellExtend.x;dst.y = cell->y *m_cellExtend.y;//G_RendDriver->DrawTextureRect(RectF(dst.x,dst.y,m_cellExtend.x,m_cellExtend.y),RectF(float(tex.x)/m_cellNum.x+m_gameTime*0.1f,float(tex.y)/m_cellNum.y,1.0f/m_cellNum.x,1.0f/m_cellNum.y));}}//framecell = m_cells;m_texFrame->Bind();for(int i = 0;i<m_cellNumXY;i++,cell++){if (cell->texID!=-1&&cell->texID!=m_movingCell.texID){tex.x = cell->texID%m_cellNum.x;tex.y = cell->texID/m_cellNum.x;dst.x = cell->x *m_cellExtend.x;dst.y = cell->y *m_cellExtend.y;int t = 0;if (m_workingWithAI && cell==m_aiSrcCell){t = 1;G_RendDriver->DrawTextureRect(RectF(dst.x,dst.y,m_cellExtend.x,m_cellExtend.y),RectF(t/10.0f,0,1/10.0f,1));}else{if (IsCellOK(cell->x,cell->y)){RectF frameRect(dst.x-2,dst.y-2,m_cellExtend.x+4,m_cellExtend.y+4);if (IsCellOK(cell->x-1,cell->y)==false){t = 2;G_RendDriver->DrawTextureRect(frameRect,RectF(t/10.0f,0,1/10.0f,1));}if (IsCellOK(cell->x+1,cell->y)==false){t = 3;G_RendDriver->DrawTextureRect(frameRect,RectF(t/10.0f,0,1/10.0f,1));}if (IsCellOK(cell->x,cell->y-1)==false){t = 4;G_RendDriver->DrawTextureRect(frameRect,RectF(t/10.0f,0,1/10.0f,1));}if (IsCellOK(cell->x,cell->y+1)==false){t = 5;G_RendDriver->DrawTextureRect(frameRect,RectF(t/10.0f,0,1/10.0f,1));}}else{if (IsCellOK(cell->x,cell->y+1)==false){t = 0;G_RendDriver->DrawTextureRect(RectF(dst.x,dst.y,m_cellExtend.x,m_cellExtend.y),RectF(t/10.0f,0,1/10.0f,1));}}}}}//textcell = m_cells;m_texLcdNumber->Bind();for(int i = 0;i<m_cellNumXY;i++,cell++){if (cell->texID!=-1&&cell->texID!=m_movingCell.texID){tex.x = cell->texID%m_cellNum.x;tex.y = cell->texID/m_cellNum.x;dst.x = cell->x *m_cellExtend.x;dst.y = cell->y *m_cellExtend.y;DrawLcd(3,cell->texID, RectF(dst.x+3,dst.y+3,20,10));//slow//G_RendDriver->Color4f(0.0f, 0.0f, 0.0f, 0.5f);//G_RendDriver->DrawRect(RectF(dst.x+3,dst.y+3,20,20));//G_FontMgr->SetColor(Color(1.0f, 1.0f, 1.0f, 1.0f));//sprintf(buf,"%d",cell->texID);//G_FontMgr->TextAtPos(dst,buf);}}//movingif (m_movingCell.texID!=-1){tex.x = m_movingCell.texID%m_cellNum.x;tex.y = m_movingCell.texID/m_cellNum.x;dst.x = m_movingCell.x *m_cellExtend.x;dst.y = m_movingCell.y *m_cellExtend.y;dst += m_movingDir*vec2(m_cellExtend.x,m_cellExtend.y)*(1-m_movingTime/MovingTime);G_RendDriver->Color4f(1.0f, 1.0f, 1.0f, 1.0f);m_texPic->Bind();G_RendDriver->DrawTextureRect(RectF(dst.x,dst.y,m_cellExtend.x,m_cellExtend.y),RectF(float(tex.x)/m_cellNum.x,float(tex.y)/m_cellNum.y,1.0f/m_cellNum.x,1.0f/m_cellNum.y));m_texFrame->Bind();if (IsCellOK(m_movingCell.x,m_movingCell.y)){Cell* cell = &m_movingCell;RectF frameRect(dst.x-2,dst.y-2,m_cellExtend.x+4,m_cellExtend.y+4);int t = 0;if (IsCellOK(cell->x-1,cell->y)==false){t = 2;G_RendDriver->DrawTextureRect(frameRect,RectF(t/10.0f,0,1/10.0f,1));}if (IsCellOK(cell->x+1,cell->y)==false){t = 3;G_RendDriver->DrawTextureRect(frameRect,RectF(t/10.0f,0,1/10.0f,1));}if (IsCellOK(cell->x,cell->y-1)==false){t = 4;G_RendDriver->DrawTextureRect(frameRect,RectF(t/10.0f,0,1/10.0f,1));}if (IsCellOK(cell->x,cell->y+1)==false){t = 5;G_RendDriver->DrawTextureRect(frameRect,RectF(t/10.0f,0,1/10.0f,1));}}else{int t = 0;if (m_workingWithAI && m_aiSrcCell && m_movingCell.texID==m_aiSrcCell->texID)t = 1;G_RendDriver->DrawTextureRect(RectF(dst.x,dst.y,m_cellExtend.x,m_cellExtend.y),RectF(t/10.0f,0,1/10.0f,1));}G_RendDriver->Color4f(0.0f, 0.0f, 0.0f, 0.5f);G_RendDriver->DrawRect(RectF(dst.x+3,dst.y+3,20,20));sprintf(buf,"%d",m_movingCell.texID);G_FontMgr->SetColor(Color(1.0f, 1.0f, 1.0f, 1.0f));G_FontMgr->TextAtPos(dst,buf);}G_RendDriver->PopMatrix();//previewG_RendDriver->Color4f(1.0f, 1.0f, 1.0f, 1.0f);RectF previewRect(BoardRect2D.x+517,BoardRect2D.y+306,175,175.0f/m_texPic->GetWidth()*m_texPic->GetHeight());m_texPic->Bind();G_RendDriver->DrawTextureRect(previewRect, RectF(0, 0, 1, 1));}//if (m_3dMode){G_RendDriver->PushMatrix();G_RendDriver->MultMatrix(mat2Dto3D);}//画等级m_rectLevel = RectF(BoardRect2D.x+633, BoardRect2D.y+36, 39, 23);if(m_rectLevel.IsPointIn(G_Mouse->GetMousePos())){G_RendDriver->Color4f(1, 1, 0, 1);}else{G_RendDriver->Color4f(1, 0, 0, 1);}m_texLcdNumber->Bind();DrawLcd(3,m_Level+1, m_rectLevel);G_RendDriver->Color4f(1, 1, 1, 1);//画时间和得分m_texLcdNumber->Bind();G_RendDriver->Color4f(1, 0, 0, 1);DrawLcd(3,m_gameTime, RectF(BoardRect2D.x +623, BoardRect2D.y+223, 39, 23));DrawLcd(4,m_stepNum, RectF(BoardRect2D.x+633, BoardRect2D.y +89, 52, 23));if (m_3dMode){G_RendDriver->PopMatrix();}return true;
}void MiniGameSlidingBlock::RenderUI()
{Render();G_RendDriver->BeginUI();
}void MiniGameSlidingBlock::UpdateGameRect()
{float width__  = m_texBack->GetWidth(); float height_  = m_texBack->GetHeight(); SetBoardRect(RectF((G_Window->m_iWidth-width__)/2,(G_Window->m_iHeight-height_)/2,width__,height_), RectF(m_startPos.x-50,m_startPos.z-33,100,66),m_startPos.y+10.1f);if (m_3dMode){m_gameRect = RectF(m_startPos.x-38, m_startPos.z-GameRectWidth3D/2, GameRectWidth3D,GameRectWidth3D);}else{m_gameRect = RectF(BoardRect2D.x + 26, BoardRect2D.y + 22, GameRectWidth2D,GameRectWidth2D);}m_cellExtend.x = m_gameRect.width/m_cellNum.x;m_cellExtend.y = m_gameRect.height/m_cellNum.y;//取整if (m_3dMode==false){m_gameRect.width  = m_cellExtend.x*m_cellNum.x;m_gameRect.height = m_cellExtend.y*m_cellNum.y;}
}bool MiniGameSlidingBlock::Update()
{MiniGame::Update();m_movieScene->Advance();UpdateGameRect();if (m_movingCell.texID!=-1){m_movingTime += G_Timer->GetStepTimeLimited();if (m_movingTime>MovingTime){m_movingTime = MovingTime;}}if (G_SlideBlockGame->IsButtonDowning(MOUSE_LEFT)){int click = 0;if (m_3dMode){vec3 dir;vec3 start;G_Camera->GetMouseTray(start,dir);RayMovieCollideRes res;res.vStart = start;res.vEnd = start+PICKLEN*dir;res.justBond = false;if(m_movieScene->GetMovieClip("board")->IntersectTray(res)){vec2 point(res.resPos.x- m_gameRect.x,res.resPos.z- m_gameRect.y);click = int(point.x/m_cellExtend.x) + int(point.y/m_cellExtend.y)*m_cellNum.x;}}else{vec2 point = G_Mouse->GetMousePos()-m_gameRect.GetPos();click = int(point.x/m_cellExtend.x) + int(point.y/m_cellExtend.y)*m_cellNum.x;}int empty = (m_emptyCell->x) + (m_emptyCell->y)*m_cellNum.x;if(click - empty == 1){MoveEmpty(DIK_RIGHT);}else if(click - empty == -1){MoveEmpty(DIK_LEFT);}else if(click - empty == m_cellNum.x){MoveEmpty(DIK_DOWN);}else if(click - empty == -m_cellNum.x){MoveEmpty(DIK_UP);}else{PlaySound__("data/sound/poker/cannot.wav");}if(m_rectLevel.IsPointIn(G_Mouse->GetMousePos())){//重新开始m_Level++;m_Level%=10;//Start();}}if (G_SlideBlockGame->IsKeyDowning(KeyLeft)){MoveEmpty(DIK_LEFT);}else if (G_SlideBlockGame->IsKeyDowning(KeyRight)){MoveEmpty(DIK_RIGHT);} else if (G_SlideBlockGame->IsKeyDowning(KeyUp)){MoveEmpty(DIK_UP);}  else if (G_SlideBlockGame->IsKeyDowning(KeyDown)){MoveEmpty(DIK_DOWN);}//算法优化:毗邻后可以不断的移位大循环圈 而不是小循环圈, 这样可以在大循环圈内构造长的正确序列一起移位 正确序列越长加速效果越好if (m_workingWithAI&&IsEnd()==false&&(m_movingCell.texID==-1||m_movingTime>=MovingTime)){if (m_aiTryNum){m_aiTryNum--;MoveEmpty(m_aiTrys[m_aiTryNum]);}else{//将块srcTexID挪动到tarX,tarYint empX = m_emptyCell->x;int empY = m_emptyCell->y;//最后两排两列if (m_aiCompleteSize>=m_cellNum.x-2-1&&m_aiCompleteSize>=m_cellNum.y-2-1){//找要匹配的色块m_aiSrcCell = NULL;int srcTexID = -1;int aiCompleteSizeX = -1;//底面两排for(int size = 0;size<m_cellNum.x-2;size++){if(IsCellOK(size,m_cellNum.y-2)&&IsCellOK(size,m_cellNum.y-1)){aiCompleteSizeX = size;continue;}int index1 = (m_cellNum.y-2)*m_cellNum.x+size;int index2 = index1 + m_cellNum.x;//正好颠倒,特殊处理避免死循环/*|index2 |any   ||index1 |empty |*/if(m_cells[index2].texID==index1&&m_cells[index1].texID==index2){//if (empY<m_cellNum.y-1){m_aiTrys[m_aiTryNum++] = DIK_DOWN;break;}if (empX>size+1){m_aiTrys[m_aiTryNum++] = DIK_LEFT;break;}m_aiTrys[m_aiTryNum++] = DIK_RIGHT;m_aiTrys[m_aiTryNum++] = DIK_DOWN;m_aiTrys[m_aiTryNum++] = DIK_LEFT;m_aiTrys[m_aiTryNum++] = DIK_UP;m_aiTrys[m_aiTryNum++] = DIK_LEFT;m_aiTrys[m_aiTryNum++] = DIK_DOWN;m_aiTrys[m_aiTryNum++] = DIK_RIGHT;m_aiTrys[m_aiTryNum++] = DIK_RIGHT;m_aiTrys[m_aiTryNum++] = DIK_UP;m_aiTrys[m_aiTryNum++] = DIK_LEFT;m_aiTrys[m_aiTryNum++] = DIK_UP;m_aiTrys[m_aiTryNum++] = DIK_RIGHT;m_aiTrys[m_aiTryNum++] = DIK_RIGHT;m_aiTrys[m_aiTryNum++] = DIK_DOWN;m_aiTrys[m_aiTryNum++] = DIK_LEFT;m_aiTrys[m_aiTryNum++] = DIK_UP;//先移动倒叙插入//for (int i=m_cellNum.y-1-empY;i>0;i--)//{// m_aiTrys[m_aiTryNum++] = DIK_DOWN;//}//for (int i=empX-size-1;i>0;i--)//{//  m_aiTrys[m_aiTryNum++] = DIK_LEFT;//}break;}//特殊处理避免死循环/*|empty  |index2 ||index1 |any    |*/if(m_cells[index2].texID==index1&&m_cells[index1].texID==-1&&m_cells[index1+m_cellNum.x].texID==index2){//变成/*|index2 |any   ||index1 |empty |*/MoveEmpty(DIK_DOWN);break;}if(m_cells[m_cellNumXY-m_cellNum.x+size].texID==index1)//先将index1挪到左下角,再将index2挪到左下角时index1自动归位{/*|empty  |any   ||index1 |index2|  index2归位时index1自动归位*/srcTexID = index2;}else{srcTexID = index1;}//找到色块位置m_aiSrcCell = GetCell(srcTexID);int srcX = m_aiSrcCell->x;int srcY = m_aiSrcCell->y;int tarX = aiCompleteSizeX+1;int tarY = m_cellNum.y-1;//先毗邻if (abs(empX-srcX)>1 || abs(empY-srcY)>1){if (empY<m_cellNum.y-2){//先毗邻yif (empY>srcY+1){MoveEmpty(DIK_UP);} else if (empY<=srcY-1){MoveEmpty(DIK_DOWN);}else if (empX>srcX+1){MoveEmpty(DIK_LEFT);}else if (empX<=srcX-1){MoveEmpty(DIK_RIGHT);}  } else{//先毗邻x (空白从底面两排毗邻到右面两排)if (empX>srcX+1){MoveEmpty(DIK_LEFT);}else if (empX<=srcX-1){MoveEmpty(DIK_RIGHT);} else if (empY>srcY+1){MoveEmpty(DIK_UP);} else if (empY<=srcY-1){MoveEmpty(DIK_DOWN);}}}else{//先挪到底部if (srcY<m_cellNum.y-1){AIMoveSrcDown(srcX,srcY,tarX,tarY,empX,empY);} else if (srcX>tarX){//挪到左边AIMoveSrcLeft(srcX,srcY,tarX,tarY,empX,empY);}}break;}//右面两排int aiCompleteSizeY = -1;if (aiCompleteSizeX>=m_cellNum.x-2-1){for(int size = 0;size<m_cellNum.y-2;size++){if(IsCellOK(m_cellNum.x-2,size)&&IsCellOK(m_cellNum.x-1,size)){aiCompleteSizeY = size;continue;}int index1 = size*m_cellNum.x+(m_cellNum.x-2);int index2 = index1 + 1;//正好颠倒,特殊处理避免死循环/*|index2 |index1||any    |empty |*/if(m_cells[index2].texID==index1&&m_cells[index1].texID==index2){//if (empX<m_cellNum.x-1){m_aiTrys[m_aiTryNum++] = DIK_RIGHT;break;}if (empY>size+1){m_aiTrys[m_aiTryNum++] = DIK_UP;break;}m_aiTrys[m_aiTryNum++] = DIK_DOWN;m_aiTrys[m_aiTryNum++] = DIK_LEFT;m_aiTrys[m_aiTryNum++] = DIK_UP;m_aiTrys[m_aiTryNum++] = DIK_UP;m_aiTrys[m_aiTryNum++] = DIK_RIGHT;m_aiTrys[m_aiTryNum++] = DIK_DOWN;m_aiTrys[m_aiTryNum++] = DIK_LEFT;m_aiTrys[m_aiTryNum++] = DIK_DOWN;m_aiTrys[m_aiTryNum++] = DIK_RIGHT;m_aiTrys[m_aiTryNum++] = DIK_UP;m_aiTrys[m_aiTryNum++] = DIK_UP;m_aiTrys[m_aiTryNum++] = DIK_LEFT;m_aiTrys[m_aiTryNum++] = DIK_DOWN;m_aiTrys[m_aiTryNum++] = DIK_RIGHT;m_aiTrys[m_aiTryNum++] = DIK_DOWN;m_aiTrys[m_aiTryNum++] = DIK_LEFT;m_aiTrys[m_aiTryNum++] = DIK_UP;//先移动倒叙插入//for (int i=m_cellNum.x-1-empX;i>0;i--)//{//    m_aiTrys[m_aiTryNum++] = DIK_RIGHT;//}//for (int i=empY-size-1;i>0;i--)//{// m_aiTrys[m_aiTryNum++] = DIK_UP;//}break;}//特殊处理避免死循环/*|empty |index1||index2|any   |*/if(m_cells[index2].texID==index1&&m_cells[index1].texID==-1&&m_cells[index1+m_cellNum.x].texID==index2){//变成/*|index2 |index1||any    |empty |*/MoveEmpty(DIK_DOWN);break;}if(m_cells[index2].texID==index1)//先将index1挪到右上角,再讲index2挪到右上角时index1自动归位{srcTexID = index2;}else{srcTexID = index1;}//找到色块位置m_aiSrcCell = GetCell(srcTexID);int srcX = m_aiSrcCell->x;int srcY = m_aiSrcCell->y;int tarX = m_cellNum.x-1;int tarY = aiCompleteSizeY+1;//先毗邻if (abs(empX-srcX)>1 || abs(empY-srcY)>1){if (empY<m_cellNum.y-2){//先毗邻yif (empY>srcY+1){MoveEmpty(DIK_UP);} else if (empY<=srcY-1){MoveEmpty(DIK_DOWN);}else if (empX>srcX+1){MoveEmpty(DIK_LEFT);}else if (empX<=srcX-1){MoveEmpty(DIK_RIGHT);}  } else{//先毗邻xif (empX>srcX+1){MoveEmpty(DIK_LEFT);}else if (empX<=srcX-1){MoveEmpty(DIK_RIGHT);} else if (empY>srcY+1){MoveEmpty(DIK_UP);} else if (empY<=srcY-1){MoveEmpty(DIK_DOWN);}}}else{//先挪到右部if (srcX<m_cellNum.x-1){AIMoveSrcRight(srcX,srcY,tarX,tarY,empX,empY);} else if (srcY>tarY){//挪到上边AIMoveSrcUp(srcX,srcY,tarX,tarY,empX,empY);}}break;}}//最后四个if (aiCompleteSizeY>=m_cellNum.y-2-1){//没结束就顺时针转if(empY==m_cellNum.y-2){if (empX==m_cellNum.x-2){MoveEmpty(DIK_RIGHT);}else{MoveEmpty(DIK_DOWN);}}else{if (empX==m_cellNum.x-2){MoveEmpty(DIK_UP);}else{MoveEmpty(DIK_LEFT);}}//if(m_emptyCell->x==m_cellNum.x-2)//{//    MoveEmpty(DIK_RIGHT);//}//else if(m_emptyCell->y==m_cellNum.y-2)//{//  MoveEmpty(DIK_DOWN);//}}}//先拼左上角else{//找到不匹配的色块m_aiSrcCell = NULL;int srcTexID = -1;//for(int i = 0;i<m_cellNumXY-1;i++)//{//   if(m_cells[i].texID !=-1//     && m_cells[i].texID != i)//    {//     srcTexID = i;//        break;//    }//}m_aiCompleteSize = -1;int maxSize = max(m_cellNum.x,m_cellNum.y);for(int size = 0;size<maxSize;size++){int index = 0;for(int i = 0;i<size;i++){index = size*m_cellNum.x+i;if(IsCellOK(i,size)==false){srcTexID = index;break;}if(size>=m_cellNum.y-2 )  //最下面两排另拼{break;}}if (srcTexID!=-1){break;}for(int j = 0;j<=size;j++){index = j*m_cellNum.x+size;if(IsCellOK(size,j)==false){srcTexID = index;break;}if(size>=m_cellNum.x-2)      //最右面两排另拼{break;}}if (srcTexID!=-1){break;}m_aiCompleteSize = size;}//找到色块位置m_aiSrcCell = GetCell(srcTexID);int srcX = m_aiSrcCell->x;int srcY = m_aiSrcCell->y;//int tarX = m_aiSrcCell->texID%m_cellNum.x;int tarY = m_aiSrcCell->texID/m_cellNum.x;if (abs(empX-srcX)>1 || abs(empY-srcY)>1){//先毗邻if (empY<srcY || (empX>=empY && empX>srcX)){//先毗邻yif (empY>srcY+1){MoveEmpty(DIK_UP);} else if (empY<=srcY-1){MoveEmpty(DIK_DOWN);}else if (empX>srcX+1){MoveEmpty(DIK_LEFT);}else if (empX<=srcX-1){MoveEmpty(DIK_RIGHT);}  }else{//先毗邻xif (empX>srcX+1){MoveEmpty(DIK_LEFT);}else if (empX<=srcX-1){MoveEmpty(DIK_RIGHT);} else if (empY>srcY+1){MoveEmpty(DIK_UP);} else if (empY<=srcY-1){MoveEmpty(DIK_DOWN);}}}else{if (srcX>srcY){//先yif(tarY<srcY){AIMoveSrcUp(srcX,srcY,tarX,tarY,empX,empY);}else if(tarY>srcY){AIMoveSrcDown(srcX,srcY,tarX,tarY,empX,empY);}else if(tarX>srcX){AIMoveSrcRight(srcX,srcY,tarX,tarY,empX,empY);return true;}else if(tarX<srcX){AIMoveSrcLeft(srcX,srcY,tarX,tarY,empX,empY);return true;}}else{//先xif(tarX>srcX){AIMoveSrcRight(srcX,srcY,tarX,tarY,empX,empY);return true;}else if(tarX<srcX){AIMoveSrcLeft(srcX,srcY,tarX,tarY,empX,empY);return true;}else if(tarY<srcY){AIMoveSrcUp(srcX,srcY,tarX,tarY,empX,empY);}else if(tarY>srcY){AIMoveSrcDown(srcX,srcY,tarX,tarY,empX,empY);}}}}}}IsEnd();return true;
}bool MiniGameSlidingBlock::AIMoveSrcUp(int srcX,int srcY,int tarX,int tarY,int empX,int empY)
{//将空格转到上侧 //倒叙插入移动m_aiTrys[m_aiTryNum++] = DIK_DOWN;//第1排if(empX==srcX-1 && empY==srcY-1){m_aiTrys[m_aiTryNum++] = DIK_RIGHT;}else if(empX==srcX+1 && empY==srcY-1){m_aiTrys[m_aiTryNum++] = DIK_LEFT;}//第2排else if(empX==srcX-1 && empY==srcY){if (IsCellOK(empX,empY-1)==false){//不会破坏已经拼好的m_aiTrys[m_aiTryNum++] = DIK_RIGHT;m_aiTrys[m_aiTryNum++] = DIK_UP;}else{if (srcY<m_cellNum.y-1){//下面绕过去m_aiTrys[m_aiTryNum++] = DIK_LEFT;m_aiTrys[m_aiTryNum++] = DIK_UP;m_aiTrys[m_aiTryNum++] = DIK_UP;m_aiTrys[m_aiTryNum++] = DIK_RIGHT;m_aiTrys[m_aiTryNum++] = DIK_RIGHT;m_aiTrys[m_aiTryNum++] = DIK_DOWN;}else{//上面绕过去m_aiTrys[m_aiTryNum++] = DIK_RIGHT;m_aiTrys[m_aiTryNum++] = DIK_UP;}}}else if(empX==srcX+1 && empY==srcY){m_aiTrys[m_aiTryNum++] = DIK_LEFT;m_aiTrys[m_aiTryNum++] = DIK_UP;}//第3排else if(empX==srcX-1 && empY==srcY+1){if (srcX<m_cellNum.x-1){//首选右面绕过去m_aiTrys[m_aiTryNum++] = DIK_LEFT;m_aiTrys[m_aiTryNum++] = DIK_UP;m_aiTrys[m_aiTryNum++] = DIK_UP;m_aiTrys[m_aiTryNum++] = DIK_RIGHT;m_aiTrys[m_aiTryNum++] = DIK_RIGHT;}else{//左面绕过去m_aiTrys[m_aiTryNum++] = DIK_RIGHT;m_aiTrys[m_aiTryNum++] = DIK_UP;m_aiTrys[m_aiTryNum++] = DIK_UP;}}else if(empX==srcX && empY==srcY+1){if (srcX<m_cellNum.x-1){//首选右面绕过去m_aiTrys[m_aiTryNum++] = DIK_LEFT;m_aiTrys[m_aiTryNum++] = DIK_UP;m_aiTrys[m_aiTryNum++] = DIK_UP;m_aiTrys[m_aiTryNum++] = DIK_RIGHT;}else{//左面绕过去m_aiTrys[m_aiTryNum++] = DIK_RIGHT;m_aiTrys[m_aiTryNum++] = DIK_UP;m_aiTrys[m_aiTryNum++] = DIK_UP;m_aiTrys[m_aiTryNum++] = DIK_LEFT;}}else if(empX==srcX+1 && empY==srcY+1){m_aiTrys[m_aiTryNum++] = DIK_LEFT;m_aiTrys[m_aiTryNum++] = DIK_UP;m_aiTrys[m_aiTryNum++] = DIK_UP;}return true;
}bool MiniGameSlidingBlock::AIMoveSrcDown(int srcX,int srcY,int tarX,int tarY,int empX,int empY)
{//将空格转到下侧 //倒叙插入移动m_aiTrys[m_aiTryNum++] = DIK_UP;//第1排if(empX==srcX-1 && empY==srcY-1){m_aiTrys[m_aiTryNum++] = DIK_RIGHT;m_aiTrys[m_aiTryNum++] = DIK_DOWN;m_aiTrys[m_aiTryNum++] = DIK_DOWN;}else if(empX==srcX && empY==srcY-1){if (srcX<m_cellNum.x-1){//首选右面绕过去m_aiTrys[m_aiTryNum++] = DIK_LEFT;m_aiTrys[m_aiTryNum++] = DIK_DOWN;m_aiTrys[m_aiTryNum++] = DIK_DOWN;m_aiTrys[m_aiTryNum++] = DIK_RIGHT;}else{//左面绕过去m_aiTrys[m_aiTryNum++] = DIK_RIGHT;m_aiTrys[m_aiTryNum++] = DIK_DOWN;m_aiTrys[m_aiTryNum++] = DIK_DOWN;m_aiTrys[m_aiTryNum++] = DIK_LEFT;}}else if(empX==srcX+1 && empY==srcY-1){m_aiTrys[m_aiTryNum++] = DIK_LEFT;m_aiTrys[m_aiTryNum++] = DIK_DOWN;m_aiTrys[m_aiTryNum++] = DIK_DOWN;}//第2排else if(empX==srcX-1 && empY==srcY){m_aiTrys[m_aiTryNum++] = DIK_RIGHT;m_aiTrys[m_aiTryNum++] = DIK_DOWN;}else if(empX==srcX+1 && empY==srcY){m_aiTrys[m_aiTryNum++] = DIK_LEFT;m_aiTrys[m_aiTryNum++] = DIK_DOWN;}//第3排else if(empX==srcX-1 && empY==srcY+1){m_aiTrys[m_aiTryNum++] = DIK_RIGHT;}else if(empX==srcX+1 && empY==srcY+1){m_aiTrys[m_aiTryNum++] = DIK_LEFT;}return true;
}bool MiniGameSlidingBlock::AIMoveSrcLeft(int srcX,int srcY,int tarX,int tarY,int empX,int empY)
{//将空格转到左侧 //倒叙插入移动m_aiTrys[m_aiTryNum++] = DIK_RIGHT;//第1排if(empX==srcX-1 && empY==srcY-1){m_aiTrys[m_aiTryNum++] = DIK_DOWN;}else if(empX==srcX && empY==srcY-1){if (IsCellOK(empX-1,empY)==false|| srcX>= m_cellNum.x-1) //没法从右绕{//不会破坏已经拼好的m_aiTrys[m_aiTryNum++] = DIK_DOWN;m_aiTrys[m_aiTryNum++] = DIK_LEFT;}else{m_aiTrys[m_aiTryNum++] = DIK_UP;m_aiTrys[m_aiTryNum++] = DIK_LEFT;m_aiTrys[m_aiTryNum++] = DIK_LEFT;m_aiTrys[m_aiTryNum++] = DIK_DOWN;m_aiTrys[m_aiTryNum++] = DIK_DOWN;m_aiTrys[m_aiTryNum++] = DIK_RIGHT;}}else if(empX==srcX+1 && empY==srcY-1){m_aiTrys[m_aiTryNum++] = DIK_UP;m_aiTrys[m_aiTryNum++] = DIK_LEFT;m_aiTrys[m_aiTryNum++] = DIK_LEFT;m_aiTrys[m_aiTryNum++] = DIK_DOWN;m_aiTrys[m_aiTryNum++] = DIK_DOWN;}//第2排else if(empX==srcX+1 && empY==srcY){if (srcY<m_cellNum.y-1){//首选下面绕过去m_aiTrys[m_aiTryNum++] = DIK_UP;m_aiTrys[m_aiTryNum++] = DIK_LEFT;m_aiTrys[m_aiTryNum++] = DIK_LEFT;m_aiTrys[m_aiTryNum++] = DIK_DOWN;}else{//上面绕过去m_aiTrys[m_aiTryNum++] = DIK_DOWN;m_aiTrys[m_aiTryNum++] = DIK_LEFT;m_aiTrys[m_aiTryNum++] = DIK_LEFT;m_aiTrys[m_aiTryNum++] = DIK_UP;}}//第3排else if(empX==srcX+1 && empY==srcY+1){m_aiTrys[m_aiTryNum++] = DIK_UP;m_aiTrys[m_aiTryNum++] = DIK_LEFT;m_aiTrys[m_aiTryNum++] = DIK_LEFT;}else if(empX==srcX && empY==srcY+1){m_aiTrys[m_aiTryNum++] = DIK_UP;m_aiTrys[m_aiTryNum++] = DIK_LEFT;}else if(empX==srcX-1 && empY==srcY+1){m_aiTrys[m_aiTryNum++] = DIK_UP;}return true;
}bool MiniGameSlidingBlock::AIMoveSrcRight(int srcX,int srcY,int tarX,int tarY,int empX,int empY)
{//将空格转到右侧 //倒叙插入移动m_aiTrys[m_aiTryNum++] = DIK_LEFT;//第1排if(empX==srcX-1 && empY==srcY-1){m_aiTrys[m_aiTryNum++] = DIK_DOWN;m_aiTrys[m_aiTryNum++] = DIK_RIGHT;m_aiTrys[m_aiTryNum++] = DIK_RIGHT;}else if(empX==srcX && empY==srcY-1){m_aiTrys[m_aiTryNum++] = DIK_DOWN;m_aiTrys[m_aiTryNum++] = DIK_RIGHT;}else if(empX==srcX+1 && empY==srcY-1){m_aiTrys[m_aiTryNum++] = DIK_DOWN;}//第2排else if(empX==srcX-1 && empY==srcY){if (srcY<m_cellNum.y-1){//首选下面绕过去m_aiTrys[m_aiTryNum++] = DIK_UP;m_aiTrys[m_aiTryNum++] = DIK_RIGHT;m_aiTrys[m_aiTryNum++] = DIK_RIGHT;m_aiTrys[m_aiTryNum++] = DIK_DOWN;}else{//上面绕过去m_aiTrys[m_aiTryNum++] = DIK_DOWN;m_aiTrys[m_aiTryNum++] = DIK_RIGHT;m_aiTrys[m_aiTryNum++] = DIK_RIGHT;m_aiTrys[m_aiTryNum++] = DIK_UP;}}//第3排else if(empX==srcX-1 && empY==srcY+1){m_aiTrys[m_aiTryNum++] = DIK_UP;m_aiTrys[m_aiTryNum++] = DIK_RIGHT;m_aiTrys[m_aiTryNum++] = DIK_RIGHT;}else if(empX==srcX && empY==srcY+1){m_aiTrys[m_aiTryNum++] = DIK_UP;m_aiTrys[m_aiTryNum++] = DIK_RIGHT;}else if(empX==srcX+1 && empY==srcY+1){m_aiTrys[m_aiTryNum++] = DIK_UP;}return true;
}bool MiniGameSlidingBlock::Free()
{MiniGame::Free();SafeDeleteArray(m_cellMeshs);SafeDeleteArray(m_cells);return true;
}void MiniGameSlidingBlock::OnSize()
{
}bool MiniGameSlidingBlock::KeepResource(bool once, int& circle, String& nextTip)
{return true;
}void MiniGameSlidingBlock::MoveEmpty(int key)
{m_stepNum++;Cell* srcCell;Cell* tarCell = m_emptyCell;bool sucess = false;switch(key){case DIK_LEFT:if(m_emptyCell->x>0){srcCell =  m_emptyCell-1;sucess = true;}break;case DIK_RIGHT:if(m_emptyCell->x<m_cellNum.x-1){srcCell =  m_emptyCell+1;           sucess = true;}break;case DIK_UP:if(m_emptyCell->y>0){srcCell = m_emptyCell - m_cellNum.x;sucess = true;}break;case DIK_DOWN:if(m_emptyCell->y<m_cellNum.y-1){srcCell = m_emptyCell + m_cellNum.x;sucess = true;}break;}if (sucess){m_movingDir = vec2(srcCell->x-m_emptyCell->x,srcCell->y-m_emptyCell->y);if (srcCell==m_aiSrcCell){m_aiSrcCell = m_emptyCell;}m_movingCell.x = m_emptyCell->x;m_movingCell.y = m_emptyCell->y;m_movingCell.texID = srcCell->texID;m_movingTime = 0;Swap(tarCell->texID,srcCell->texID);m_emptyCell = srcCell;if (IsCellOK(tarCell->x,tarCell->y)){PlaySound__("data/sound/event_equip.wav");}else{PlaySound__("data/sound/ui_click.wav");}}else{PlaySound__("data/sound/poker/cannot.wav");}
}bool MiniGameSlidingBlock::IsEnd()
{//if (m_gameState==MS_End)//{//  return true;//}int lastState = m_gameState;if (m_cells[m_cellNumXY-1].texID!=-1){return false;}for(int i = 0;i<m_cellNumXY-1;i++){if(m_cells[i].texID != i)return false;}m_gameState = MS_End;if (lastState!=MS_End){m_Level++;m_Level %= 10;}return true;
}bool MiniGameSlidingBlock::IsCellOK(int x,int y)
{if (x<0||x>m_cellNum.x-1||y<0||y>m_cellNum.y-1){return false;}int index = y*m_cellNum.x+x;if(m_cells[index].texID != index)return false;return true;
}bool MiniGameSlidingBlock::IsCellEmpty(int x,int y)
{int index = y*m_cellNum.x+x;if(m_cells[index].texID != -1)return false;return true;
}MiniGameSlidingBlock::Cell* MiniGameSlidingBlock::GetCell(int texID)
{//找到色块位置for(int i = 0;i<m_cellNumXY;i++){if(m_cells[i].texID == texID){return &m_cells[i];}}return NULL;
}

附送一份3D模型切割算法,方便制作3D版拼图游戏:

//========================================================
//  @Date:     2016.05
//  @File:     Include/Render/ReproductMesh.h
//  @Brief:     ReproductMesh
//  @Author:     LouLei
//  @Email:  twopointfive@163.com
//  @Copyright (Crapell) - All Rights Reserved
//========================================================#pragma once#ifndef  __ReproductMesh__H__
#define  __ReproductMesh__H__//#include "Math/Mathlib.h"
#include "Render/RendDriver.h"
#include <vector>class TopoSegment;
class TopoVertex;
class TopoFace;
class TopoVertexSet;
class TopoVertexPtrSet;
class TopoFaceSet;
class Sloid;
class TVertex;class Box;//typedef unsigned int IndexInt;
static const float   _ModellerEpsilon    = 0.001f;//1e-6f;class TVertex
{
public:float u;float v;float w;float r;float g;float b;
};class Line3D
{
public:Line3D();Line3D(TopoFace * face1, TopoFace * face2);Line3D(const vec3 & direction, const vec3 & point);//!到参考点的有向距离float getPointToPointDistance(const vec3 & otherPoint);//!线段交点vec3  getLineIntersection(Line3D * otherLine);//!线面相交vec3  getPlaneIntersection(const vec3 & normal, const vec3 & planePoint, bool & bResult);void  perturbDirection();vec3 m_pos;vec3 m_dir;
};class TopoSegment
{
public:TopoSegment();TopoSegment(Line3D & line, TopoFace & face, int sign1, int sign2, int sign3);enum Status{VERTEX = 1,FACE = 2,EDGE = 3,};//!起点状态:在面的端点上还是边上或面上int startType;//!中段状态:在面的边上或面上int middleType;//!结束点状态int endType;/** nearest vertex from the starting point */TopoVertex * startVertex;TopoVertex * endVertex; //!两个面的交线vec3 startPos;vec3 endPos;//!两个面的交线Line3D line;//int endsNum;/** distance from the segment starting point to the point defining the plane */float startDist;float endDist;bool intersect(const TopoSegment & segment);private:bool setVertex(TopoVertex * vertex);bool setEdge(TopoVertex * vertex1, TopoVertex * vertex2);void swapEnds();
};class TopoVertex
{
public:enum Status{UNKNOWN = 1,INSIDE = 2,OUTSIDE = 3,BOUNDARY = 4,};TopoVertex();TopoVertex(const TopoVertex & v);TopoVertex(const vec3 & position, const TVertex & tVertex, Status eStatus);virtual ~TopoVertex();TopoVertex & operator=(const TopoVertex & v);bool equals(TopoVertex * vertex);void addAdjacentVertex(TopoVertex * adjacentVertex);void mark(Status eStatus);TopoVertexPtrSet * m_adjacentVertices; vec3     pos;TVertex  tVertex;Status   status;};class TopoFace
{
public:enum Status{UNKNOWN     = 1,INSIDE      = 2,//被切割sloid的面 包含于 切割sloid的内部OUTSIDE     = 3,//外部SAME        = 4,//被切割sloid的面 共面于 切割sloid的某个面OPPOSITE    = 5,//被切割sloid的面 反共面于 切割sloid的某个面};TopoFace();TopoFace(const TopoFace & v);TopoFace(TopoVertex * v1, TopoVertex * v2, TopoVertex * v3);~TopoFace();TopoFace& operator=(const TopoFace & face);bool  equals_pointersmatch(TopoFace * pFace);bool  equals(TopoFace * pOtherObject);//!预计算提高速度,不会失效Box*  getBound();vec3& getNormal();float getArea();void invert();bool simpleClassify();void rayTraceClassify(Sloid & object);//!判断点在面内bool hasPoint(const vec3 & point);Status status;Box*   bound;vec3   normal;TopoVertex * v1;TopoVertex * v2;TopoVertex * v3;
};class TopoVertexPtrSet
{
public:TopoVertexPtrSet();virtual ~TopoVertexPtrSet();TopoVertex * GetTopoVertexPtr(int nIndex);void AddTopoVertexPtr(TopoVertex * pPointer);int  GetTopoVertexPtrNum();void ClearTopoVertexPtr();TopoVertex* operator[](int index);private:typedef std::vector<TopoVertex *> Vertices;Vertices m_pPointers;
};class TopoVertexSet
{
public:TopoVertexSet();virtual ~TopoVertexSet();TopoVertex * GetTopoVertex(int nIndex);TopoVertex * AddTopoVertex(const TopoVertex & vertex);int GetTopoVertexNum();TopoVertex& operator[](int index);bool HasTopoVertex(TopoVertex * pVertex);int  IndexOfTopoVertex(TopoVertex * pVertex);void ClearTopoVertex();private:typedef std::vector<TopoVertex *> Vertices;Vertices m_pVertices;
};class TopoFaceSet
{
public:TopoFaceSet();virtual ~TopoFaceSet();TopoFace * GetTopoFace(int i);void       SetTopoFace(int i, TopoFace & vFace);TopoFace * AddTopoFace(TopoFace & vFace);TopoFace * InsertTopoFace(int i, TopoFace & vFace);void       RemoveTopoFace(int i);int  GetTopoFaceNum();void ClearTopoFace();private:TopoFace * m_pFaces;int m_nMaxSize;int m_nSize;
};//==================^_^==================^_^==================^_^==================^_^class Sloid
{
public:Sloid();virtual ~Sloid();//!使用object来切分自身void SplitFaces(Sloid * pObject);void Translate(const vec3 & t);void Render();void RefMesh(RendSys::Mesh* mesh);//private:TopoFace*   AddTopoFace(TopoVertex * v1, TopoVertex * v2, TopoVertex * v3);TopoVertex* AddTopoVertex(const vec3 & pos, const TVertex & tVertex, int status);float ComputeDistance(TopoVertex & vertex, TopoFace & face);void SplitFace(int faceIndex, TopoSegment & segment1, TopoSegment & segment2);//插值纹理坐标void CalTopoVertexTex(TopoVertex * v1, TopoVertex * v2,const vec3 & pos, TopoVertex * result);void CalTopoVertexTex(TopoVertex * v1, TopoVertex * v2,TopoVertex * v3,const vec3 & pos, TopoVertex * result);//一个三角形切割为2、3、4、5个void BreakFaceInTwo(int faceIndex, const vec3 & newPos, int splitEdge);void BreakFaceInTwo(int faceIndex, const vec3 & newPos, TopoVertex & endVertex);void BreakFaceInThree(int faceIndex, const vec3 & newPos1, const vec3 & newPos2, TopoVertex & startVertex, TopoVertex & endVertex);void BreakFaceInThree(int faceIndex, const vec3 & newPos1, const vec3 & newPos2, int splitEdge);void BreakFaceInThree(int faceIndex, const vec3 & newPos, TopoVertex & endVertex);void BreakFaceInThree(int faceIndex, const vec3 & newPos);void BreakFaceInFour (int faceIndex, const vec3 & newPos1, const vec3 & newPos2, TopoVertex & endVertex);void BreakFaceInFive (int faceIndex, const vec3 & newPos1, const vec3 & newPos2, int linedVertex);//!标记面在切割sloid的内部还是外部..void ClassifyFaces(Sloid & pObject);//!反转内部面,减法使用void InvertInsideFaces();void GenTopologyFromRend();void GenRendFromTopology();void Free();TopoVertexSet * m_topoVertexs;TopoFaceSet *   m_topoFaces;Box *           m_bound;int m_indexNum;int m_vVertexNum;int m_tVertexNum;//Vertex*  m_vVertexs;//TVertex* m_tVertexs;//Trigon*  m_trigons;IndexInt* m_indexs;vec3*     m_vertexs;TVertex*  m_tVertexs;};//==================^_^==================^_^==================^_^==================^_^
//!注意所有面逆时针顺序要统一
class BooleanModeller
{
public:Sloid * m_pSloid1;Sloid * m_pSloid2;//!注意初始化后原来的solid topology已经被分割了,可能需要重新GenTopologyDataBooleanModeller(Sloid * solid1, Sloid * solid2);Sloid * GetUnion();Sloid * GetIntersection();Sloid * GetDifference();private:void    MergeSloid(Sloid* pSrcSloid, Sloid* pDstSloid, int faceStatus1, int faceStatus2);void    PreMergeSloid(Sloid* pSrcSloid, Sloid* pDstSloid, int faceStatus1, int faceStatus2);
};#endif//========================================================
//  @Date:     2016.05
//  @File:     SourceLib/Render/ReproductMesh.cpp
//  @Brief:     ReproductMesh
//  @Author:     LouLei
//  @Email:  twopointfive@163.com
//  @Copyright (Crapell) - All Rights Reserved
//========================================================#include "General/Pch.h"
#include "General/General.h"
#include "Render/MC_Misc.h"
#include "Render/MC_MovieClip.h"
#include "Render/MC_Boolean.h"
#include "Math/MathLibAdvance.h"
#include "Ozcollide/box.h"
#include "General/Pce.h"//constructive solid geometry modeller#pragma warning(disable : 4244)
#pragma warning(disable: 4305)Line3D::Line3D()
{m_pos = vec3(0,0,0);m_dir = vec3(1,0,0);
}Line3D::Line3D(const vec3 & directioni, const vec3 & pointi)
{m_dir = directioni;m_dir.Normalize();m_pos = pointi;
}Line3D::Line3D(TopoFace * face1, TopoFace * face2)
{vec3 normalFace1 = face1->getNormal();vec3 normalFace2 = face2->getNormal();m_dir = Cross(normalFace1, normalFace2);//m_direction长度为0,则两个面平行if (!(m_dir.Length()<_ModellerEpsilon)){//getting a line point, zero is set to a coordinate whose direction //component isn't zero (line intersecting its origin plan)float d1 = -normalFace1.Dot(face1->v1->pos);float d2 = -normalFace2.Dot(face2->v1->pos);if(fabs(m_dir.x)>_ModellerEpsilon){m_pos.x = 0;m_pos.y = (d2*normalFace1.z - d1*normalFace2.z)/m_dir.x;m_pos.z = (d1*normalFace2.y - d2*normalFace1.y)/m_dir.x;}else if(fabs(m_dir.y)>_ModellerEpsilon){m_pos.x = (d1*normalFace2.z - d2*normalFace1.z)/m_dir.y;m_pos.y = 0;m_pos.z = (d2*normalFace1.x - d1*normalFace2.x)/m_dir.y;}else{m_pos.x = (d2*normalFace1.y - d1*normalFace2.y)/m_dir.z;m_pos.y = (d1*normalFace2.x - d2*normalFace1.x)/m_dir.z;m_pos.z = 0;}}m_dir.Normalize();
}//到参考点的有向距离
float Line3D::getPointToPointDistance(const vec3 & otherPoint)
{vec3 dif = otherPoint - m_pos;float distance = dif.Length();if ((dif.Dot(m_dir))<0){return -distance;         }else{return distance;}
}//线段交点
vec3 Line3D::getLineIntersection(Line3D * otherLine)
{//x = x1 + a1*t = x2 + b1*s//y = y1 + a2*t = y2 + b2*s//z = z1 + a3*t = z2 + b3*svec3 linePos = otherLine->m_pos; vec3 lineDir = otherLine->m_dir;float t;if(fabs(m_dir.y*lineDir.x-m_dir.x*lineDir.y)>_ModellerEpsilon){t = (-m_pos.y*lineDir.x+linePos.y*lineDir.x+lineDir.y*m_pos.x-lineDir.y*linePos.x)/(m_dir.y*lineDir.x-m_dir.x*lineDir.y);}else if (fabs(-m_dir.x*lineDir.z+m_dir.z*lineDir.x)>_ModellerEpsilon){t=-(-lineDir.z*m_pos.x+lineDir.z*linePos.x+lineDir.x*m_pos.z-lineDir.x*linePos.z)/(-m_dir.x*lineDir.z+m_dir.z*lineDir.x);}else if (fabs(-m_dir.z*lineDir.y+m_dir.y*lineDir.z)>_ModellerEpsilon){t = (m_pos.z*lineDir.y-linePos.z*lineDir.y-lineDir.z*m_pos.y+lineDir.z*linePos.y)/(-m_dir.z*lineDir.y+m_dir.y*lineDir.z);}else{return vec3(0,0,0);}vec3 vResult = m_pos + m_dir * t;return vResult;
}
//线面相交
vec3 Line3D::getPlaneIntersection(const vec3 & normal, const vec3 & planePoint, bool & bResult)
{bResult = true;//Ax + By + Cz + D = 0//x = x0 + t(x1 ?x0)//y = y0 + t(y1 ?y0)//z = z0 + t(z1 ?z0)//(x1 - x0) = dx, (y1 - y0) = dy, (z1 - z0) = dz//t = -(A*x0 + B*y0 + C*z0 )/(A*dx + B*dy + C*dz)float A = normal.x;float B = normal.y;float C = normal.z;float D = (normal.Dot(planePoint)) * -1.0f;float numerator = (normal.Dot(m_pos)) + D;float denominator = (normal.Dot(m_dir));//线面平行if(fabs(denominator)<_ModellerEpsilon){//线在面上if(fabs(numerator)<_ModellerEpsilon){return m_pos;}else{//平行 分离bResult = false;return vec3(0,0,0);}}//线面相交else{float t = -numerator/denominator;vec3 resultPoint = m_pos + m_dir * t;return resultPoint;}
}float LineRandomNum()
{int nRand = Rand() % 10000;float fRand = (float)nRand;fRand *= 0.0001f;fRand *= 2.0f;fRand -= 1.0f;return fRand;
}void Line3D::perturbDirection()
{//direction.x += LineRandomNum();            //direction.y += LineRandomNum();         //direction.z += LineRandomNum();m_dir.x += LineRandomNum() * 0.001f;           m_dir.y += LineRandomNum() * 0.001f;          m_dir.z += LineRandomNum() * 0.001f;//direction.Normalise();
}TopoSegment::TopoSegment()
{
}TopoSegment::TopoSegment(Line3D & line, TopoFace & face, int sign1, int sign2, int sign3)
{(*this).line = line;endsNum = 0;if(sign1 == 0){//点1在面上(距离为0)setVertex(face.v1);//点2 3同侧 - 只有一个点相交 VERTEX-VERTEX VERTEXif(sign2 == sign3){setVertex(face.v1);}}if(sign2 == 0){setVertex(face.v2);if(sign1 == sign3){setVertex(face.v2);}}if(sign3 == 0){setVertex(face.v3);if(sign1 == sign2){setVertex(face.v3);}}//切割边if(endsNum != 2){//点1 2异侧if((sign1==1 && sign2==-1)||(sign1==-1 && sign2==1)){setEdge(face.v1, face.v2);}if((sign2==1 && sign3==-1)||(sign2==-1 && sign3==1)){setEdge(face.v2, face.v3);}if((sign3==1 && sign1==-1)||(sign3==-1 && sign1==1)){setEdge(face.v3, face.v1);}}
}bool TopoSegment::intersect(const TopoSegment & segment)
{if(endDist<segment.startDist+_ModellerEpsilon ||segment.endDist<startDist+_ModellerEpsilon){return false;}else{return true;}
}/*** Sets an end as vertex (starting point if none end were defined, ending point otherwise)* @param vertex the vertex that is an segment end * @return false if all the ends were already defined, true otherwise*/
bool TopoSegment::setVertex(TopoVertex * vertex)
{if(endsNum == 0){//起点startVertex = vertex;startType = VERTEX;startDist = line.getPointToPointDistance(vertex->pos);startPos = startVertex->pos;endsNum++;return true;}if(endsNum == 1){//终点endVertex = vertex;endType = VERTEX;endDist = line.getPointToPointDistance(vertex->pos);endPos = endVertex->pos;endsNum++;//defining middle based on the starting point//VERTEX-VERTEX-VERTEX//if(startVertex.equals(endVertex)) // Need close-enough-to...if(true){middleType = VERTEX;}//VERTEX-EDGE-VERTEXelse if(startType==VERTEX){middleType = EDGE;}//the ending point distance should be smaller than  starting point distance if(startDist>endDist){swapEnds();}return true;}else{return false;}
}/*** @param vertex1 one of the vertices of the intercepted edge * @param vertex2 one of the vertices of the intercepted edge* @return false if all ends were already defined, true otherwise*/
bool TopoSegment::setEdge(TopoVertex * vertex1, TopoVertex * vertex2)
{vec3 point1 = vertex1->pos;vec3 point2 = vertex2->pos;vec3 edgeDirection(point2.x - point1.x, point2.y - point1.y, point2.z - point1.z);Line3D edgeLine(edgeDirection, point1);if(endsNum==0){startVertex = vertex1;startType = EDGE;startPos = line.getLineIntersection(&edgeLine);startDist = line.getPointToPointDistance(startPos);middleType = FACE;endsNum++;return true;       }else if(endsNum==1){endVertex = vertex1;endType = EDGE;endPos = line.getLineIntersection(&edgeLine);endDist = line.getPointToPointDistance(endPos);middleType = FACE;endsNum++;//the ending point distance should be smaller than  starting point distance if(startDist>endDist){swapEnds();}return true;}else{return false;}
}/** Swaps the starting point and the ending point */
void TopoSegment::swapEnds()
{float distTemp = startDist;startDist = endDist;endDist = distTemp;int typeTemp = startType;startType = endType;endType = typeTemp;TopoVertex * vertexTemp = startVertex;startVertex = endVertex;endVertex = vertexTemp;vec3 posTemp = startPos;startPos = endPos;endPos = posTemp;
}//==================^_^==================^_^==================^_^==================^_^
TopoVertex::TopoVertex()
{m_adjacentVertices = new TopoVertexPtrSet();status = UNKNOWN;
}TopoVertex::TopoVertex(const vec3 & position, const TVertex & tVertex_, Status status)
{tVertex = tVertex_;pos = position;m_adjacentVertices = new TopoVertexPtrSet();status = status;
}TopoVertex::TopoVertex(const TopoVertex & v)
{tVertex = v.tVertex;pos = v.pos;m_adjacentVertices = new TopoVertexPtrSet();status = v.status;
}
TopoVertex & TopoVertex::operator=(const TopoVertex & v)
{tVertex = v.tVertex;pos = v.pos;m_adjacentVertices = new TopoVertexPtrSet();status = v.status;return *this;
}
TopoVertex::~TopoVertex()
{SafeDelete(m_adjacentVertices);
}//TopologyVertex & TopologyVertex::operator=(const TopologyVertex & v)
//{
//  for(int i = 0; i < v.m_adjacentVertices->length(); i++)
//  {
//      m_adjacentVertices->add(v.m_adjacentVertices->GetVertexPtr(i));
//  }
//
//  status = v.status;
//  color = v.color;
//  x = v.x;
//  y = v.y;
//  z = v.z;
//  return *this;
//}//判断是否同一个点
bool TopoVertex::equals(TopoVertex * vertex)
{//float _ModellerEpsilon = 1.0f;float _ModellerEpsilon = 0.01f;bool bPositionMatch =(fabs(pos.x-vertex->pos.x)<_ModellerEpsilon &&fabs(pos.y-vertex->pos.y)<_ModellerEpsilon &&fabs(pos.z-vertex->pos.z)<_ModellerEpsilon);bool bColorMatch =(tVertex.r == vertex->tVertex.r) &&(tVertex.g == vertex->tVertex.g) &&(tVertex.b == vertex->tVertex.b);return bPositionMatch && bColorMatch;
}void TopoVertex::addAdjacentVertex(TopoVertex * adjacentVertex)
{bool bAlready = false;for(int i = 0; i < m_adjacentVertices->GetTopoVertexPtrNum(); i++){TopoVertex * pVertexI = m_adjacentVertices->GetTopoVertexPtr(i);//已经存在该指针if(pVertexI == adjacentVertex){bAlready = true;}}if(!bAlready){m_adjacentVertices->AddTopoVertexPtr(adjacentVertex);}
}void TopoVertex::mark(Status status)
{status = status;//return;for(int i = 0; i < m_adjacentVertices->GetTopoVertexPtrNum(); i++){TopoVertex * pVertexI = m_adjacentVertices->GetTopoVertexPtr(i);if(pVertexI->status==TopoVertex::UNKNOWN){pVertexI->mark(status);}}
}//==================^_^==================^_^==================^_^==================^_^TopoVertexPtrSet::TopoVertexPtrSet()
{
}TopoVertexPtrSet::~TopoVertexPtrSet()
{m_pPointers.clear();
}TopoVertex * TopoVertexPtrSet::GetTopoVertexPtr(int nIndex)
{if(nIndex < 0) return 0;if(nIndex >= m_pPointers.size()) return 0;TopoVertex * pVertex = m_pPointers[nIndex];return pVertex;
}int TopoVertexPtrSet::GetTopoVertexPtrNum()
{return m_pPointers.size();
}void TopoVertexPtrSet::AddTopoVertexPtr(TopoVertex * pPointer)
{m_pPointers.push_back(pPointer);
}TopoVertex* TopoVertexPtrSet::operator[](int index)
{if(index < 0) return 0;if(index >= m_pPointers.size()) return 0;TopoVertex * pVertex = m_pPointers[index];return pVertex;
}void TopoVertexPtrSet::ClearTopoVertexPtr()
{m_pPointers.clear();
}//==================^_^==================^_^==================^_^==================^_^TopoVertexSet::TopoVertexSet()
{
}TopoVertexSet::~TopoVertexSet()
{for(int i = 0; i < m_pVertices.size(); i++){delete m_pVertices[i];}m_pVertices.clear();
}TopoVertex * TopoVertexSet::GetTopoVertex(int nIndex)
{if(nIndex < 0) return 0;if(nIndex >= m_pVertices.size()) return 0;TopoVertex * pVertex = m_pVertices[nIndex];return pVertex;
}int TopoVertexSet::GetTopoVertexNum()
{return m_pVertices.size();
}TopoVertex * TopoVertexSet::AddTopoVertex(const TopoVertex & vertex)
{//if(m_nNumVertices >= m_nMaxVertices) return 0;m_pVertices.push_back(new TopoVertex(vertex));return m_pVertices[m_pVertices.size() - 1];//return &m_pVertices[m_nNumVertices - 1];
}TopoVertex& TopoVertexSet::operator[](int index)
{TopoVertex * pVertex = GetTopoVertex(index);return *pVertex;
}bool TopoVertexSet::HasTopoVertex(TopoVertex * pVertex)
{// Match pointers or content??for(int i = 0; i < GetTopoVertexNum(); i++){TopoVertex * pOurVertex = GetTopoVertex(i);if(pOurVertex == pVertex){return true;}}return false;
}int TopoVertexSet::IndexOfTopoVertex(TopoVertex * pVertex)
{for(int i = 0; i < GetTopoVertexNum(); i++){TopoVertex * pOurVertex = GetTopoVertex(i);if(pOurVertex == pVertex){return i;}}return -1;
}void TopoVertexSet::ClearTopoVertex()
{for(int i = 0; i < m_pVertices.size(); i++){delete m_pVertices[i];}m_pVertices.clear();
}//==================^_^==================^_^==================^_^==================^_^
TopoFace::TopoFace()
{v1 = 0;v2 = 0;v3 = 0;status = UNKNOWN;bound = new Box();}
TopoFace::TopoFace(const TopoFace & face)
{status = face.status;v1 = face.v1;v2 = face.v2;v3 = face.v3;bound = new Box();bound->setFromPoints(v1->pos,v2->pos);bound->mergePoint(v3->pos);vec3 xy = v2->pos - v1->pos;vec3 xz = v3->pos - v1->pos;normal = Cross(xy, xz);normal.Normalize();
}
TopoFace::TopoFace(TopoVertex * v1i, TopoVertex * v2i, TopoVertex * v3i)
{v1 = v1i;v2 = v2i;v3 = v3i;status = UNKNOWN;bound = new Box();bound->setFromPoints(v1->pos,v2->pos);bound->mergePoint(v3->pos);vec3 xy = v2->pos - v1->pos;vec3 xz = v3->pos - v1->pos;normal = Cross(xy, xz);normal.Normalize();
}TopoFace::~TopoFace()
{SafeDelete(bound);
}
TopoFace& TopoFace::operator=(const TopoFace & face)
{status = face.status;v1 = face.v1;v2 = face.v2;v3 = face.v3;if(bound==NULL)bound = new Box();bound->setFromPoints(v1->pos,v2->pos);bound->mergePoint(v3->pos);vec3 xy = v2->pos - v1->pos;vec3 xz = v3->pos - v1->pos;normal = Cross(xy, xz);normal.Normalize();return *this;
}
bool TopoFace::equals_pointersmatch(TopoFace * pFace)
{TopoFace & face = *pFace;bool cond = v1 == face.v1 && v2 == face.v2 && v3 == face.v3;return cond;
}bool TopoFace::equals(TopoFace * pFace)
{TopoFace & face = *pFace;bool cond1 = v1->equals(face.v1) && v2->equals(face.v2) && v3->equals(face.v3);bool cond2 = v1->equals(face.v2) && v2->equals(face.v3) && v3->equals(face.v1);bool cond3 = v1->equals(face.v3) && v2->equals(face.v1) && v3->equals(face.v2);return cond1 || cond2 || cond3;
}Box* TopoFace::getBound()
{//只是加点而不减少点 也不改变点所以无需重新计算
#ifdef _DEBUG//Box old = *bound;//bound->setFromPoints(v1->pos,v2->pos);//bound->mergePoint(v3->pos);//if (old.min!=bound->min)//{//    MsgBox(0,"TopoFace::getBound","error",MB_OK);//}//if (old.max!=bound->max)//{// MsgBox(0,"TopoFace::getBound","error",MB_OK);//}
#endifreturn bound;
}vec3& TopoFace::getNormal()
{
#ifdef _DEBUG//vec3 xy = v2->pos - v1->pos;//vec3 xz = v3->pos - v1->pos;//vec3 newnormal = Cross(xy, xz);//newnormal.Normalize();//if (normal!=newnormal)//{// MsgBox(0,"TopoFace::getBound","error",MB_OK);//}
#endifreturn normal;
}float TopoFace::getArea()
{//area = (a * c * sen(B))/2vec3 xy = v2->pos - v1->pos;vec3 xz = v3->pos - v1->pos;vec3 yz = v3->pos - v2->pos;float a = xy.Length();float c = xz.Length();float b = yz.Length();float _ModellerEpsilon = 0.001f;if (a<_ModellerEpsilon||c<_ModellerEpsilon||b<_ModellerEpsilon){//继续计算出来有误差return 0;}xy.Normalize();xz.Normalize();float fDot = xy.Dot(xz);float fAngle = SafeAcos(fDot);return (a * c * sin(fAngle))/2.0f;//float a = xy.LengthSq();//float c = xz.LengthSq();//xy.Normalize();//xz.Normalize();//float fDot = xy.Dot(xz);//return sqrt(a*c*(1-fDot*fDot))/2.0f;
}void TopoFace::invert()
{TopoVertex * vertexTemp = v2;v2 = v1;v1 = vertexTemp;
}bool TopoFace::simpleClassify()
{int status1 = v1->status;int status2 = v2->status;int status3 = v3->status;if(status1==TopoVertex::INSIDE){status = INSIDE;return true; }if(status1==TopoVertex::OUTSIDE){status = OUTSIDE;return true; }if(status2==TopoVertex::INSIDE){status = INSIDE;return true;}if(status2==TopoVertex::OUTSIDE){status = OUTSIDE;return true;}if(status3==TopoVertex::INSIDE){status = INSIDE;return true;}if(status3==TopoVertex::OUTSIDE){status = OUTSIDE;return true;}return false;
}void TopoFace::rayTraceClassify(Sloid & sloid)
{//从面的重心沿法线发射线vec3 p0 = (v1->pos + v2->pos + v3->pos)/3.0f;Line3D ray(getNormal(),p0);bool success;float dotProduct, distance; vec3 intersectPos;TopoFace * closestFace = 0;float closestDistance;//float TOL = 0.0001f;      do{success = true;closestDistance = 99999999.9f;//other solid...for(int i=0;i<sloid.m_topoFaces->GetTopoFaceNum();i++){TopoFace & otherFace = *(sloid.m_topoFaces->GetTopoFace(i));dotProduct = otherFace.getNormal().Dot(ray.m_dir); bool bIntersect = false;intersectPos = ray.getPlaneIntersection(otherFace.getNormal(), otherFace.v1->pos, bIntersect);//相交if(bIntersect){distance = ray.getPointToPointDistance(intersectPos);//整条线在面上..if(fabs(distance)<_ModellerEpsilon && fabs(dotProduct)<_ModellerEpsilon){//disturb the ray in order to not lie into another plane ?ray.perturbDirection();success = false;break;}//只有起点在面上 else if(fabs(distance)<_ModellerEpsilon && fabs(dotProduct)>_ModellerEpsilon){//如果射线和面相交,即交点在面上if(otherFace.hasPoint(intersectPos)){//此时起点距离最近为0closestFace = &otherFace;closestDistance = 0;break;}}//起点也不在面上 且正向相交distance>0else if(fabs(dotProduct)>_ModellerEpsilon && distance>_ModellerEpsilon){//记录最近距离的分割面if(distance<closestDistance){if(otherFace.hasPoint(intersectPos)){closestDistance = distance;closestFace = &otherFace;}}}}}}while(success==false);if(closestFace==0){//和所有的分割面不相交status = OUTSIDE;}else{dotProduct = closestFace->getNormal().Dot(ray.m_dir);//distance = 0: if(fabs(closestDistance)<_ModellerEpsilon){if(dotProduct>_ModellerEpsilon){//共面status = SAME;}else if(dotProduct<-_ModellerEpsilon){//反共面status = OPPOSITE;}}else if(dotProduct>_ModellerEpsilon){//正向相交,内部dot>0status = INSIDE;}else if(dotProduct<-_ModellerEpsilon){status = OUTSIDE;}}
}//判断点在面内
bool TopoFace::hasPoint(const vec3 &  point)
{vec3 u = v2->pos - v1->pos;vec3 v = v3->pos - v1->pos;vec3 w = point - v1->pos;float uu = u.Dot(u);float uv = u.Dot(v);float vv = v.Dot(v);float wu = w.Dot(u);float wv = w.Dot(v);float d = uv * uv - uu * vv;float invD = 1 / d;float s = (uv * wv - vv * wu) * invD;if (s < 0 || s > 1)return false;float t = (uv * wu - uu * wv) * invD;if (t < 0 || (s + t) > 1)return false;return true;
}TopoFaceSet::TopoFaceSet()
{m_nMaxSize = 20000;m_nSize = 0;m_pFaces = new TopoFace[m_nMaxSize];
}TopoFaceSet::~TopoFaceSet()
{delete [] m_pFaces;
}int TopoFaceSet::GetTopoFaceNum()
{return m_nSize;
}TopoFace * TopoFaceSet::GetTopoFace(int i)
{if(i < 0) return 0;if(i >= m_nSize) return 0;return &m_pFaces[i];
}void TopoFaceSet::SetTopoFace(int i, TopoFace & vFace)
{if(i < 0) return;if(i >= m_nSize) return;m_pFaces[i] = vFace;
}TopoFace * TopoFaceSet::AddTopoFace(TopoFace & vFace)
{if(m_nSize >= m_nMaxSize){return 0;}m_pFaces[m_nSize] = vFace;m_nSize++;return &m_pFaces[m_nSize - 1];
}TopoFace * TopoFaceSet::InsertTopoFace(int i, TopoFace & vFace)
{if(m_nSize >= m_nMaxSize){return 0;}// Shift everything alongfor(int j = m_nSize; j >= i+1; j--){m_pFaces[j] = m_pFaces[j-1];}m_pFaces[i] = vFace;m_nSize++;return &m_pFaces[i];
}void TopoFaceSet::RemoveTopoFace(int i)
{if(m_nSize <= 0){return;}for(int j = i; j < m_nSize-1; j++){m_pFaces[j] = m_pFaces[j+1];}m_nSize--;
}void TopoFaceSet::ClearTopoFace()
{m_nSize = 0;
}//==================^_^==================^_^==================^_^==================^_^Sloid::Sloid()
:m_vertexs(NULL)
,m_tVertexs(NULL)
,m_indexs(NULL)
{m_topoVertexs = new TopoVertexSet();m_topoFaces = new TopoFaceSet();m_bound = 0;m_indexNum = 0;m_vVertexNum = 0;m_tVertexNum = 0;
}Sloid::~Sloid()
{Free();SafeDelete(m_topoVertexs) ;SafeDelete(m_topoFaces);SafeDelete(m_bound);
}
void Sloid::Free()
{SafeDeleteArray (m_vertexs);SafeDeleteArray (m_tVertexs);SafeDeleteArray (m_indexs);
}TopoFace * Sloid::AddTopoFace(TopoVertex * v1, TopoVertex * v2, TopoVertex * v3)
{float _ModellerEpsilon = 0.1;if(!(v1->equals(v2)||v1->equals(v3)||v2->equals(v3))){TopoFace face(v1, v2, v3);//不加面积很小的面if(face.getArea()<_ModellerEpsilon)return 0;TopoFace * pAddedFace = (*m_topoFaces).AddTopoFace(face);return pAddedFace;}else{return 0;}
}TopoVertex * Sloid::AddTopoVertex(const vec3 & pos, const TVertex & tVertex, int status)
{int i;TopoVertex * pVertex;TopoVertex vertex(pos, tVertex, (TopoVertex::Status)status);for(i=0;i<m_topoVertexs->GetTopoVertexNum();i++){//已经存在点pVertex = m_topoVertexs->GetTopoVertex(i);if(vertex.equals(pVertex)) {pVertex->status = ((TopoVertex::Status)status);return pVertex;           }}pVertex = m_topoVertexs->AddTopoVertex(vertex);return pVertex;
}//使用object来切分自身
void Sloid::SplitFaces(Sloid * sloid2)
{if(m_bound->isOverlap(*sloid2->m_bound)==false)return;Line3D line;TopoFace * face1;TopoFace * face2;TopoSegment segmentf1p2, segmentf2p1;float distFace1Vert1, distFace1Vert2, distFace1Vert3, distFace2Vert1, distFace2Vert2, distFace2Vert3;int signFace1Vert1, signFace1Vert2, signFace1Vert3, signFace2Vert1, signFace2Vert2, signFace2Vert3;int numFacesBefore = m_topoFaces->GetTopoFaceNum();int numFacesStart = m_topoFaces->GetTopoFaceNum();int facesIgnored = 0;//int faceNum1 = m_topologyFaces->GetSize();for(int i=0;i<m_topoFaces->GetTopoFaceNum();i++){face1 = m_topoFaces->GetTopoFace(i);TopoFace face1Orig = *face1;if(face1->getBound()->isOverlap(*sloid2->m_bound)){//遍历face2for(int j=0;j<sloid2->m_topoFaces->GetTopoFaceNum();j++){face2 = sloid2->m_topoFaces->GetTopoFace(j);TopoFace face2Orig = *face2;if(face1->getBound()->isOverlap(*face2->getBound())){//distance from the face1 vertices to the face2 planedistFace1Vert1 = ComputeDistance(*(face1->v1), *face2);distFace1Vert2 = ComputeDistance(*(face1->v2), *face2);distFace1Vert3 = ComputeDistance(*(face1->v3), *face2);//距离的正负signFace1Vert1 = (distFace1Vert1>_ModellerEpsilon? 1 :(distFace1Vert1<-_ModellerEpsilon? -1 : 0)); signFace1Vert2 = (distFace1Vert2>_ModellerEpsilon? 1 :(distFace1Vert2<-_ModellerEpsilon? -1 : 0));signFace1Vert3 = (distFace1Vert3>_ModellerEpsilon? 1 :(distFace1Vert3<-_ModellerEpsilon? -1 : 0));//全0为共面coplanar//同号不相交,异号相交if (!(signFace1Vert1==signFace1Vert2 && signFace1Vert2==signFace1Vert3)){//distance from the face2 vertices to the face1 planedistFace2Vert1 = ComputeDistance(*(face2->v1), *face1);distFace2Vert2 = ComputeDistance(*(face2->v2), *face1);distFace2Vert3 = ComputeDistance(*(face2->v3), *face1);//距离的正负signFace2Vert1 = (distFace2Vert1>_ModellerEpsilon? 1 :(distFace2Vert1<-_ModellerEpsilon? -1 : 0)); signFace2Vert2 = (distFace2Vert2>_ModellerEpsilon? 1 :(distFace2Vert2<-_ModellerEpsilon? -1 : 0));signFace2Vert3 = (distFace2Vert3>_ModellerEpsilon? 1 :(distFace2Vert3<-_ModellerEpsilon? -1 : 0));//全0为共面coplanar//同号不相交,异号相交if (!(signFace2Vert1==signFace2Vert2 && signFace2Vert2==signFace2Vert3)){line = Line3D(face1, face2);//face1、plane2 的相交线segmentf1p2 = TopoSegment(line, *face1, signFace1Vert1, signFace1Vert2, signFace1Vert3);segmentf2p1 = TopoSegment(line, *face2, signFace2Vert1, signFace2Vert2, signFace2Vert3);//线段相交时 两个面才相交if(segmentf1p2.intersect(segmentf2p1)){//PART II - SUBDIVIDING NON-COPLANAR POLYGONSint lastNumFaces = m_topoFaces->GetTopoFaceNum();SplitFace(i, segmentf1p2, segmentf2p1);                                                    if(numFacesStart*20<m_topoFaces->GetTopoFaceNum()){//可能死循环//return;}// "if the face in the position isn't the same, there was a break"//if(face1!=getFace(i)) if(!(face1->equals_pointersmatch(&face1Orig))){//if 拆分后没变化if(face1Orig.equals(m_topoFaces->GetTopoFace(m_topoFaces->GetTopoFaceNum()-1))){//一般不会进入if(i!=(m_topoFaces->GetTopoFaceNum()-1)){m_topoFaces->RemoveTopoFace(m_topoFaces->GetTopoFaceNum()-1);m_topoFaces->InsertTopoFace(i, face1Orig);}else{continue;}}else{// This is because the whole face list was shunted down when the current face was removed, so// the next face is the face at the current position in the list.i--;break;}}}}}}}}}}/*** Computes closest distance from a vertex to a plane* * @param vertex vertex used to compute the distance* @param face face representing the plane where it is contained* @return the closest distance from the vertex to the plane*/
float Sloid::ComputeDistance(TopoVertex & vertex, TopoFace & face)
{vec3 normal = face.getNormal();return normal.Dot(vertex.pos) - normal.Dot(face.v1->pos);
}/*** @param segment1 segment representing the intersection of the face with the plane* of another face* @return segment2 segment representing the intersection of other face with the* plane of the current face plane*/
void Sloid::SplitFace(int faceIndex, TopoSegment & segment1, TopoSegment & segment2)
{TopoVertex startPosVertex, endPosVertex;vec3 startPos, endPos;int startType, endType, middleType;float startDist, endDist;TopoFace & face = *m_topoFaces->GetTopoFace(faceIndex);TopoVertex * startVertex = segment1.startVertex;TopoVertex * endVertex = segment1.endVertex;//starting point: deeper starting point         if (segment2.startDist > segment1.startDist+_ModellerEpsilon){startDist = segment2.startDist;startType = segment1.middleType;startPos = segment2.startPos;}else{startDist = segment1.startDist;startType = segment1.startType;startPos = segment1.startPos;}//ending point: deepest ending pointif (segment2.endDist < segment1.endDist-_ModellerEpsilon){endDist = segment2.endDist;endType = segment1.middleType;endPos = segment2.endPos;}else{endDist = segment1.endDist;endType = segment1.endType;endPos = segment1.endPos;}       middleType = segment1.middleType;//set vertex to BOUNDARY if it is start type      if (startType == TopoSegment::VERTEX){startVertex->status=(TopoVertex::BOUNDARY);}//set vertex to BOUNDARY if it is end typeif (endType == TopoSegment::VERTEX){endVertex->status=(TopoVertex::BOUNDARY);}//VERTEX-_______-VERTEX if (startType == TopoSegment::VERTEX && endType == TopoSegment::VERTEX){return;}//______-EDGE-______else if (middleType == TopoSegment::EDGE){//gets the edge int splitEdge;if ((startVertex == face.v1 && endVertex == face.v2) || (startVertex == face.v2 && endVertex == face.v1)){splitEdge = 1;}else if ((startVertex == face.v2 && endVertex == face.v3) || (startVertex == face.v3 && endVertex == face.v2)){     splitEdge = 2; } else{splitEdge = 3;} //VERTEX-EDGE-EDGEif (startType == TopoSegment::VERTEX){BreakFaceInTwo(faceIndex, endPos, splitEdge);return;}//EDGE-EDGE-VERTEXelse if (endType == TopoSegment::VERTEX){BreakFaceInTwo(faceIndex, startPos, splitEdge);return;}// EDGE-EDGE-EDGEelse if (startDist == endDist){BreakFaceInTwo(faceIndex, endPos, splitEdge);}else{if((startVertex == face.v1 && endVertex == face.v2) || (startVertex == face.v2 && endVertex == face.v3) || (startVertex == face.v3 && endVertex == face.v1)){BreakFaceInThree(faceIndex, startPos, endPos, splitEdge);}else{BreakFaceInThree(faceIndex, endPos, startPos, splitEdge);}}return;}//______-FACE-______//VERTEX-FACE-EDGEelse if (startType == TopoSegment::VERTEX && endType == TopoSegment::EDGE){BreakFaceInTwo(faceIndex, endPos, *endVertex);//ori//BreakFaceInTwo(faceIndex, endPos, *startVertex);}//EDGE-FACE-VERTEXelse if (startType == TopoSegment::EDGE && endType == TopoSegment::VERTEX){BreakFaceInTwo(faceIndex, startPos, *startVertex);//ori//BreakFaceInTwo(faceIndex, startPos, *endVertex);}//VERTEX-FACE-FACEelse if (startType == TopoSegment::VERTEX && endType == TopoSegment::FACE){BreakFaceInThree(faceIndex, endPos, *startVertex);}//FACE-FACE-VERTEXelse if (startType == TopoSegment::FACE && endType == TopoSegment::VERTEX){BreakFaceInThree(faceIndex, startPos, *endVertex);}//EDGE-FACE-EDGEelse if (startType == TopoSegment::EDGE && endType == TopoSegment::EDGE){BreakFaceInThree(faceIndex, startPos, endPos, *startVertex, *endVertex);}//EDGE-FACE-FACEelse if (startType == TopoSegment::EDGE && endType == TopoSegment::FACE){BreakFaceInFour(faceIndex, startPos, endPos, *startVertex);}//FACE-FACE-EDGEelse if (startType == TopoSegment::FACE && endType == TopoSegment::EDGE){BreakFaceInFour(faceIndex, endPos, startPos, *endVertex);}//FACE-FACE-FACEelse if (startType == TopoSegment::FACE && endType == TopoSegment::FACE){vec3 segmentVector(startPos.x-endPos.x, startPos.y-endPos.y, startPos.z-endPos.z);//if the intersection segment is a point only...if (fabs(segmentVector.x)<_ModellerEpsilon && fabs(segmentVector.y)<_ModellerEpsilon && fabs(segmentVector.z)<_ModellerEpsilon){BreakFaceInThree(faceIndex, startPos);return;}//gets the vertex more lined with the intersection segmentint linedVertex;vec3 linedVertexPos;vec3 vertexVector = endPos - face.v1->pos;vertexVector.Normalize();float dot1 = fabs(segmentVector.Dot(vertexVector));vertexVector = endPos -face.v2->pos;vertexVector.Normalize();float dot2 = fabs(segmentVector.Dot(vertexVector));vertexVector =  endPos -face.v3->pos;vertexVector.Normalize();float dot3 = fabs(segmentVector.Dot(vertexVector));if (dot1 > dot2 && dot1 > dot3){linedVertex = 1;linedVertexPos = face.v1->pos;}else if (dot2 > dot3 && dot2 > dot1){linedVertex = 2;linedVertexPos = face.v2->pos;}else{linedVertex = 3;linedVertexPos = face.v3->pos;}// Now find which of the intersection endpoints is nearest to that vertex.if ((linedVertexPos - startPos).Length() > (linedVertexPos - endPos).Length()){BreakFaceInFive(faceIndex, startPos, endPos, linedVertex);}else{BreakFaceInFive(faceIndex, endPos, startPos, linedVertex);}}
}void Sloid::CalTopoVertexTex(TopoVertex * v1, TopoVertex * v2,const vec3 & pos, TopoVertex * result)
{float rat = 0.5f;float len = (v2->pos-v1->pos).Length();if (len>0){rat = (pos-v1->pos).Length()/len;if (rat>1){rat=1;}}float invRat = 1-rat;result->tVertex.u = rat*v2->tVertex.u + v1->tVertex.u*invRat;result->tVertex.v = rat*v2->tVertex.v + v1->tVertex.v*invRat;result->tVertex.w = rat*v2->tVertex.w + v1->tVertex.w*invRat;
}
void Sloid::CalTopoVertexTex(TopoVertex * v1, TopoVertex * v2,TopoVertex * v3,const vec3 & pos, TopoVertex * result)
{vec2 res = GetUVOnTrigon(v1->pos,v2->pos,v3->pos,vec2(v1->tVertex.u,v1->tVertex.v),vec2(v2->tVertex.u,v2->tVertex.v),vec2(v3->tVertex.u,v3->tVertex.v),pos);result->tVertex.u = res.x;result->tVertex.v = res.y;result->tVertex.w = 1;
}/**
分割线穿过一个顶点和邻边,一个三角形拆分为两个* Face breaker for VERTEX-EDGE-EDGE / EDGE-EDGE-VERTEX* @param faceIndex 待拆的面* @param newPos  拆边上的点* @param splitEdge 待拆的边v1/\/  \e1/    \e3/      \v2/________\v3e2*/
void Sloid::BreakFaceInTwo(int faceIndex, const vec3 & newPos, int splitEdge)
{TopoFace & face = *m_topoFaces->GetTopoFace(faceIndex);TopoVertex * vertex = AddTopoVertex(newPos, face.v1->tVertex, TopoVertex::BOUNDARY);if (splitEdge == 1){//分割线v1~p,p在邻边e1上AddTopoFace(face.v1, vertex, face.v3);AddTopoFace(vertex, face.v2, face.v3);CalTopoVertexTex(face.v1,face.v2,newPos,vertex);}else if (splitEdge == 2){AddTopoFace(face.v2, vertex, face.v1);AddTopoFace(vertex, face.v3, face.v1);CalTopoVertexTex(face.v3,face.v2,newPos,vertex);}else{AddTopoFace(face.v3, vertex, face.v2);AddTopoFace(vertex, face.v1, face.v2);CalTopoVertexTex(face.v1,face.v3,newPos,vertex);}m_topoFaces->RemoveTopoFace(faceIndex);
}/**
分割线穿过一个顶点和对边,一个三角形拆分为两个* Face breaker for VERTEX-FACE-EDGE / EDGE-FACE-VERTEX* @param faceIndex 待拆的面* @param newPos  拆边(对边)上的点* @param endVertex 经过的顶点v1/\/  \e1/    \e3/      \v2/________\v3e2*/
void Sloid::BreakFaceInTwo(int faceIndex, const vec3 & newPos, TopoVertex & endVertex)
{TopoFace & face = *m_topoFaces->GetTopoFace(faceIndex);TopoVertex * vertex = AddTopoVertex(newPos, face.v1->tVertex, TopoVertex::BOUNDARY);if (endVertex.equals(face.v1)){//穿过点1,边2AddTopoFace(face.v1, vertex, face.v3);AddTopoFace(vertex, face.v2, face.v3);CalTopoVertexTex(face.v1,face.v2,newPos,vertex);}else if (endVertex.equals(face.v2)){AddTopoFace(face.v2, vertex, face.v1);AddTopoFace(vertex, face.v3, face.v1);CalTopoVertexTex(face.v3,face.v2,newPos,vertex);}else{AddTopoFace(face.v3, vertex, face.v2);AddTopoFace(vertex, face.v1, face.v2);CalTopoVertexTex(face.v1,face.v3,newPos,vertex);}m_topoFaces->RemoveTopoFace(faceIndex);
}
//???  my
//void Sloid::BreakFaceInTwo(int faceIndex, const vec3 & newPos, Vertex & startVertex)
//{
//  Face & face = *m_topologyFaces->GetFace(faceIndex);
//  Vertex * vertex = addVertex(newPos, face.v1->color, Vertex::BOUNDARY);
//
//  if (startVertex.equals(face.v3))
//  {
//      //穿过点1,边2
//      addFace(face.v1, vertex, face.v3);
//      addFace(vertex, face.v2, face.v3);
//  }
//  else if (startVertex.equals(face.v1))
//  {
//      addFace(face.v2, vertex, face.v1);
//      addFace(vertex, face.v3, face.v1);
//  }
//  else
//  {
//      addFace(face.v3, vertex, face.v2);
//      addFace(vertex, face.v1, face.v2);
//  }
//
//  m_topologyFaces->RemoveFace(faceIndex);
//}/**
分割线包含于一条边,一个三角形拆分为3个* Face breaker for EDGE-EDGE-EDGEv1/\/  \e1/    \e3/      \v2/________\v3e2  */
void Sloid::BreakFaceInThree(int faceIndex, const vec3 & newPos1, const vec3 & newPos2, int splitEdge)
{TopoFace & face = *(m_topoFaces->GetTopoFace(faceIndex));TopoVertex * vertex1 = AddTopoVertex(newPos1, face.v1->tVertex, TopoVertex::BOUNDARY);    TopoVertex * vertex2 = AddTopoVertex(newPos2, face.v1->tVertex, TopoVertex::BOUNDARY);if (splitEdge == 1){AddTopoFace(face.v1, vertex1, face.v3);AddTopoFace(vertex1, vertex2, face.v3);AddTopoFace(vertex2, face.v2, face.v3);CalTopoVertexTex(face.v1,face.v2,newPos1,vertex1);CalTopoVertexTex(face.v1,face.v2,newPos2,vertex2);}else if (splitEdge == 2){AddTopoFace(face.v2, vertex1, face.v1);AddTopoFace(vertex1, vertex2, face.v1);AddTopoFace(vertex2, face.v3, face.v1);CalTopoVertexTex(face.v3,face.v2,newPos1,vertex1);CalTopoVertexTex(face.v3,face.v2,newPos2,vertex2);}else{AddTopoFace(face.v3, vertex1, face.v2);AddTopoFace(vertex1, vertex2, face.v2);AddTopoFace(vertex2, face.v1, face.v2);CalTopoVertexTex(face.v1,face.v3,newPos1,vertex1);CalTopoVertexTex(face.v1,face.v3,newPos2,vertex2);}m_topoFaces->RemoveTopoFace(faceIndex);
}/*** VERTEX-FACE-FACE / FACE-FACE-VERTEX分割线一个点在端点,一个点在面内部v1/\/  \e1/    \e3/      \v2/________\v3e2 */
void Sloid::BreakFaceInThree(int faceIndex, const vec3 & newPos, TopoVertex & endVertex)
{TopoFace & face = *(m_topoFaces->GetTopoFace(faceIndex));TopoVertex * vertex = AddTopoVertex(newPos, face.v1->tVertex, TopoVertex::BOUNDARY);//if (endVertex.equals(face.v1))//{// addFace(face.v1, face.v2, vertex);//    addFace(face.v2, face.v3, vertex);//    addFace(face.v3, face.v1, vertex);//}//else if (endVertex.equals(face.v2))//{// addFace(face.v2, face.v3, vertex);//    addFace(face.v3, face.v1, vertex);//    addFace(face.v1, face.v2, vertex);//}//else{AddTopoFace(face.v3, face.v1, vertex);AddTopoFace(face.v1, face.v2, vertex);AddTopoFace(face.v2, face.v3, vertex);CalTopoVertexTex(face.v1,face.v2,face.v3,newPos,vertex);}m_topoFaces->RemoveTopoFace(faceIndex);
}/*** Face breaker for EDGE-FACE-EDGE分割线切掉一个角v1/\/  \e1/    \e3/      \v2/________\v3e2 */
void Sloid::BreakFaceInThree(int faceIndex, const vec3 & newPos1, const vec3 & newPos2, TopoVertex & startVertex, TopoVertex & endVertex)
{TopoFace & face = *(m_topoFaces->GetTopoFace(faceIndex));TopoVertex * vertex1 = AddTopoVertex(newPos1, face.v1->tVertex, TopoVertex::BOUNDARY);TopoVertex * vertex2 = AddTopoVertex(newPos2, face.v1->tVertex, TopoVertex::BOUNDARY);if (startVertex.equals(face.v1) && endVertex.equals(face.v2)){//切角2AddTopoFace(face.v1, vertex1, vertex2);AddTopoFace(face.v1, vertex2, face.v3);AddTopoFace(vertex1, face.v2, vertex2);CalTopoVertexTex(face.v1,face.v2,newPos1,vertex1);CalTopoVertexTex(face.v2,face.v3,newPos2,vertex2);}else if (startVertex.equals(face.v2) && endVertex.equals(face.v1)){//反切角2AddTopoFace(face.v1, vertex2, vertex1);AddTopoFace(face.v1, vertex1, face.v3);AddTopoFace(vertex2, face.v2, vertex1);CalTopoVertexTex(face.v1,face.v2,newPos1,vertex1);CalTopoVertexTex(face.v2,face.v3,newPos2,vertex2);}else if (startVertex.equals(face.v2) && endVertex.equals(face.v3)){//切角3AddTopoFace(face.v2, vertex1, vertex2);AddTopoFace(face.v2, vertex2, face.v1);AddTopoFace(vertex1, face.v3, vertex2);CalTopoVertexTex(face.v2,face.v3,newPos1,vertex1);CalTopoVertexTex(face.v1,face.v3,newPos2,vertex2);}else if (startVertex.equals(face.v3) && endVertex.equals(face.v2)){AddTopoFace(face.v2, vertex2, vertex1);AddTopoFace(face.v2, vertex1, face.v1);AddTopoFace(vertex2, face.v3, vertex1);CalTopoVertexTex(face.v2,face.v3,newPos1,vertex1);CalTopoVertexTex(face.v1,face.v3,newPos2,vertex2);}else if (startVertex.equals(face.v3) && endVertex.equals(face.v1)){//切角1AddTopoFace(face.v3, vertex1, vertex2);AddTopoFace(face.v3, vertex2, face.v2);AddTopoFace(vertex1, face.v1, vertex2);CalTopoVertexTex(face.v1,face.v3,newPos1,vertex1);CalTopoVertexTex(face.v1,face.v2,newPos2,vertex2);}else{AddTopoFace(face.v3, vertex2, vertex1);AddTopoFace(face.v3, vertex1, face.v2);AddTopoFace(vertex2, face.v1, vertex1);CalTopoVertexTex(face.v1,face.v3,newPos1,vertex1);CalTopoVertexTex(face.v1,face.v2,newPos2,vertex2);}m_topoFaces->RemoveTopoFace(faceIndex);
}/*** Face breaker for FACE-FACE-FACE (a point only)分割线包含于面内?v1/\/  \e1/    \e3/      \v2/________\v3e2  */
void Sloid::BreakFaceInThree(int faceIndex, const vec3 & newPos)
{TopoFace & face = *(m_topoFaces->GetTopoFace(faceIndex));TopoVertex * vertex = AddTopoVertex(newPos, face.v1->tVertex, TopoVertex::BOUNDARY);AddTopoFace(face.v1, face.v2, vertex);AddTopoFace(face.v2, face.v3, vertex);AddTopoFace(face.v3, face.v1, vertex);CalTopoVertexTex(face.v1,face.v3,face.v3,newPos,vertex);m_topoFaces->RemoveTopoFace(faceIndex);
}/*** Face breaker for EDGE-FACE-FACE / FACE-FACE-EDGE分割线一个点在边上,一个点在面内部v1/\/  \e1/    \e3/      \v2/________\v3e2    */
void Sloid::BreakFaceInFour(int faceIndex, const vec3 & newPos1, const vec3 & newPos2, TopoVertex & endVertex)
{TopoFace & face = *(m_topoFaces->GetTopoFace(faceIndex));TopoVertex * vertex1 = AddTopoVertex(newPos1, face.v1->tVertex, TopoVertex::BOUNDARY);TopoVertex * vertex2 = AddTopoVertex(newPos2, face.v1->tVertex, TopoVertex::BOUNDARY);if (endVertex.equals(face.v1)){//vertex2在内部AddTopoFace(face.v1, vertex1, vertex2);AddTopoFace(vertex1, face.v2, vertex2);AddTopoFace(face.v2, face.v3, vertex2);AddTopoFace(face.v3, face.v1, vertex2);CalTopoVertexTex(face.v1,face.v2,newPos1,vertex1);CalTopoVertexTex(face.v1,face.v2,face.v3,newPos2,vertex2);}else if (endVertex.equals(face.v2)){AddTopoFace(face.v2, vertex1, vertex2);AddTopoFace(vertex1, face.v3, vertex2);AddTopoFace(face.v3, face.v1, vertex2);AddTopoFace(face.v1, face.v2, vertex2);CalTopoVertexTex(face.v2,face.v3,newPos1,vertex1);CalTopoVertexTex(face.v1,face.v2,face.v3,newPos2,vertex2);}else{AddTopoFace(face.v3, vertex1, vertex2);AddTopoFace(vertex1, face.v1, vertex2);AddTopoFace(face.v1, face.v2, vertex2);AddTopoFace(face.v2, face.v3, vertex2);CalTopoVertexTex(face.v3,face.v1,newPos1,vertex1);CalTopoVertexTex(face.v1,face.v2,face.v3,newPos2,vertex2);}m_topoFaces->RemoveTopoFace(faceIndex);
}/*** Face breaker for FACE-FACE-FACE分割线一个点在面内部,另一个点也在面内部v1/\/  \e1/    \e3/      \v2/________\v3e2  */
void Sloid::BreakFaceInFive(int faceIndex, const vec3 & newPos1, const vec3 & newPos2, int linedVertex)
{TopoFace & face = *(m_topoFaces->GetTopoFace(faceIndex));  TopoVertex * vertex1 = AddTopoVertex(newPos1, face.v1->tVertex, TopoVertex::BOUNDARY);TopoVertex * vertex2 = AddTopoVertex(newPos2, face.v1->tVertex, TopoVertex::BOUNDARY);CalTopoVertexTex(face.v1,face.v2,face.v3,newPos1,vertex1);CalTopoVertexTex(face.v1,face.v2,face.v3,newPos2,vertex2);float cont = 0;if (linedVertex == 1){AddTopoFace(face.v2, face.v3, vertex1);AddTopoFace(face.v2, vertex1, vertex2);AddTopoFace(face.v3, vertex2, vertex1);AddTopoFace(face.v2, vertex2, face.v1);AddTopoFace(face.v3, face.v1, vertex2);}else if(linedVertex == 2){AddTopoFace(face.v3, face.v1, vertex1);AddTopoFace(face.v3, vertex1, vertex2);AddTopoFace(face.v1, vertex2, vertex1);AddTopoFace(face.v3, vertex2, face.v2);AddTopoFace(face.v1, face.v2, vertex2);}else{AddTopoFace(face.v1, face.v2, vertex1);AddTopoFace(face.v1, vertex1, vertex2);AddTopoFace(face.v2, vertex2, vertex1);AddTopoFace(face.v1, vertex2, face.v3);AddTopoFace(face.v2, face.v3, vertex2);}// Calling it at the end, because the java garbage collection won't destroy it until after the end of the function,// (when there is nothing referencing it anymore)m_topoFaces->RemoveTopoFace(faceIndex);
}//标记面在切割sloid的内部还是外部..
void Sloid::ClassifyFaces(Sloid & sloid)
{//清空重建邻边拓补信息//for(int i=0;i<m_topologyVertexs->GetSize();i++)//{//}//for(int i=0;i<m_topologyFaces->GetSize();i++)//{//  TopologyFace & face = *(m_topologyFaces->GetFace(i));// face.v1->addAdjacentVertex(face.v2);//   face.v1->addAdjacentVertex(face.v3);//   face.v2->addAdjacentVertex(face.v1);//   face.v2->addAdjacentVertex(face.v3);//   face.v3->addAdjacentVertex(face.v1);//   face.v3->addAdjacentVertex(face.v2);//}//for(int i=0;i<m_topoFaces->GetTopoFaceNum();i++){TopoFace & face = *(m_topoFaces->GetTopoFace(i));//if(face.simpleClassify()==false){face.rayTraceClassify(sloid);if(face.v1->status==TopoVertex::UNKNOWN) {face.v1->mark((TopoVertex::Status)face.status);}if(face.v2->status==TopoVertex::UNKNOWN) {face.v2->mark((TopoVertex::Status)face.status);}if(face.v3->status==TopoVertex::UNKNOWN) {face.v3->mark((TopoVertex::Status)face.status);}}}
}//反转内部面,减法使用
void Sloid::InvertInsideFaces()
{TopoFace * face = 0;for(int i=0;i<m_topoFaces->GetTopoFaceNum();i++){face = m_topoFaces->GetTopoFace(i);if(face->status==TopoFace::INSIDE){face->invert();}}
}void Sloid::GenTopologyFromRend()
{///后期拓补处理m_topoVertexs->ClearTopoVertex();m_topoFaces->ClearTopoFace();TopoVertex * v1 = 0;TopoVertex * v2 = 0;TopoVertex * v3 = 0;TopoVertex * topoVertex = 0;TopoVertexPtrSet * tmpTopoVertexPtrSet = new TopoVertexPtrSet();// for(int i=0;i<m_vVertexNum;i++){topoVertex = AddTopoVertex(m_vertexs[i], m_tVertexs[i], TopoVertex::UNKNOWN);tmpTopoVertexPtrSet->AddTopoVertexPtr(topoVertex); }// facesfor(int i=0; i<m_indexNum; i=i+3){v1 = tmpTopoVertexPtrSet->GetTopoVertexPtr(m_indexs[i]);v2 = tmpTopoVertexPtrSet->GetTopoVertexPtr(m_indexs[i+1]);v3 = tmpTopoVertexPtrSet->GetTopoVertexPtr(m_indexs[i+2]);AddTopoFace(v1, v2, v3);}//create boundif (m_bound==NULL){m_bound = new Box();}m_bound->setFromPoints(m_vertexs[0],m_vertexs[1]);for(int i=1;i<m_vVertexNum;i++){m_bound->mergePoint(m_vertexs[i]);}delete tmpTopoVertexPtrSet;
}void Sloid::GenRendFromTopology()
{//m_topologyVertexs->clear();//m_vertices->clear();//for(int i = 0; i < m_topoVertexs->GetNumVertices(); i++)//{//  TopoVertex * pVertex = m_topoVertexs->GetVertex(i);//   //m_vertexs.AddVector(pVertex->pos);//   m_vertexs.SetVector(i,pVertex->pos);//}}void Sloid::Translate(const vec3 & t)
{for(int i = 0; i < m_vVertexNum; i++){vec3 v = m_vertexs[i];v = v + t;m_vertexs[i] = v;}GenTopologyFromRend();
}void Sloid::Render()
{G_RendDriver->SetRenderStateEnable(RS_DEPTH_TEST,true);G_RendDriver->SetRenderStateEnable(RS_TEXTURE_2D,true);G_RendDriver->SetRenderStateEnable(RS_ALPHA_TEST,true);G_RendDriver->SetRenderStateEnable(RS_BLEND,true);G_RendDriver->BlendFunc(RS_SRC_ALPHA,RS_ONE_MINUS_SRC_ALPHA);G_RendDriver->AlphaFunc(RS_GREATER,0.0f);G_RendDriver->Color4f(1,1,1,1);//        for (int i=0;i<8;i++)
//      {
//          G_RendDriver->SetSamplerState(i, SS_MINFILTER, TF_LINEAR);
//          G_RendDriver->SetSamplerState(i, SS_MAGFILTER, TF_LINEAR);
//      }G_RendDriver->RendBegin(RS_TRIANGLES);int nNumTriangles = m_indexNum / 3;for(int i = 0; i < nNumTriangles; i++){int nIndex1 = m_indexs[i * 3 + 0];int nIndex2 = m_indexs[i * 3 + 1];int nIndex3 = m_indexs[i * 3 + 2];vec3 vP1 = m_vertexs[nIndex1];vec3 vP2 = m_vertexs[nIndex2];vec3 vP3 = m_vertexs[nIndex3];TVertex col1 = m_tVertexs[nIndex1];TVertex col2 = m_tVertexs[nIndex2];TVertex col3 = m_tVertexs[nIndex3];//glColor4f(col1.r, col1.g, col1.b, 255);G_RendDriver->TexCoord2f(col1.u, col1.v);G_RendDriver->Vertex3f(vP1.x, vP1.y, vP1.z);//glColor4f(col2.r, col2.g, col2.b, 255);G_RendDriver->TexCoord2f(col2.u, col2.v);G_RendDriver->Vertex3f(vP2.x, vP2.y, vP2.z);//glColor4f(col3.r, col3.g, col3.b, 255);G_RendDriver->TexCoord2f(col3.u, col3.v);G_RendDriver->Vertex3f(vP3.x, vP3.y, vP3.z);}G_RendDriver->RendEnd();//glLineWidth(1);//glDisable(GL_TEXTURE_2D);//glDisable (GL_DEPTH_TEST);//glBegin(GL_LINES);//for(int i = 0; i < nNumTriangles; i++)//{// int nIndex1 = m_indexs[i * 3 + 0];//  int nIndex2 = m_indexs[i * 3 + 1];//  int nIndex3 = m_indexs[i * 3 + 2];//  vec3 vP1 = m_vertexs[nIndex1];//   vec3 vP2 = m_vertexs[nIndex2];//   vec3 vP3 = m_vertexs[nIndex3];//   TVertex col1 = m_tVertexs[nIndex1];//  TVertex col2 = m_tVertexs[nIndex2];//  TVertex col3 = m_tVertexs[nIndex3];//  glColor4ub(200,200,200, 255);// glVertex3d(vP1.x, vP1.y, vP1.z);//  glVertex3d(vP2.x, vP2.y, vP2.z);//  glVertex3d(vP2.x, vP2.y, vP2.z);//  glVertex3d(vP3.x, vP3.y, vP3.z);//  glVertex3d(vP3.x, vP3.y, vP3.z);//  glVertex3d(vP1.x, vP1.y, vP1.z);//}//glEnd();//glLineWidth(1);//glColor4ub(255,255,255, 255);
}void Sloid::RefMesh(RendSys::Mesh* mesh)
{Free();if (mesh){//添加点面m_vVertexNum = mesh->m_vVertexNum;m_vertexs= new vec3[m_vVertexNum];for(int i = 0; i < m_vVertexNum; i++){Mesh::Vertex& v =mesh->m_vVertexs[i];m_vertexs[i] = vec3(v.x,v.y,v.z);}//m_indexNum = mesh->m_trigonNum*3;m_indexs = new IndexInt[m_indexNum];for(int i = 0; i < mesh->m_trigonNum; i++){Mesh::Trigon& f = mesh->m_trigons[i];m_indexs[i*3]   = f.vIndex[0];m_indexs[i*3+1] = f.vIndex[1];m_indexs[i*3+2] = f.vIndex[2];}//m_tVertexs = new TVertex[m_vVertexNum];TVertex col;float colorr = (Rand() % 255)/255.0f;float colorg = (Rand() % 255)/255.0f;float colorb = (Rand() % 255)/255.0f;for(int i = 0; i < m_vVertexNum; i++){float colorr = (Rand() % 255)/255.0f;float colorg = (Rand() % 255)/255.0f;float colorb = (Rand() % 255)/255.0f;Mesh::TVertex& v =mesh->m_tVertexs[i];col.r = colorr;col.g =  colorg;col.b =  colorb;col.u =  v.u;col.v =  v.v;m_tVertexs[i] = (col);}}GenTopologyFromRend();
}//==================^_^==================^_^==================^_^==================^_^BooleanModeller::BooleanModeller(Sloid * solid1, Sloid * solid2)
{m_pSloid1 = solid1;m_pSloid2 = solid2;//切割m_pSloid1->SplitFaces(m_pSloid2);//模拟爆炸不做联合不补面时可以省略分割sloid2m_pSloid2->SplitFaces(m_pSloid1);//classify faces as being inside or outside the other solidm_pSloid1->ClassifyFaces(*m_pSloid2);m_pSloid2->ClassifyFaces(*m_pSloid1);
}Sloid * BooleanModeller::GetUnion()
{Sloid *result = new Sloid();PreMergeSloid(m_pSloid1, result, TopoFace::OUTSIDE, TopoFace::SAME);PreMergeSloid(m_pSloid2, result, TopoFace::OUTSIDE, TopoFace::OUTSIDE);result->m_indexs = new IndexInt[result->m_indexNum];//肯比实际的多少许result->m_vertexs = new vec3[result->m_vVertexNum];result->m_tVertexs = new TVertex[result->m_tVertexNum];result->m_indexNum = 0;result->m_vVertexNum = 0;result->m_tVertexNum = 0;MergeSloid(m_pSloid1, result, TopoFace::OUTSIDE, TopoFace::SAME);MergeSloid(m_pSloid2, result, TopoFace::OUTSIDE, TopoFace::OUTSIDE);//拓扑的面依赖于点指针不遍即时加入//result->GenRendFromTopology();return result;
}Sloid * BooleanModeller::GetIntersection()
{Sloid *result = new Sloid();PreMergeSloid(m_pSloid1, result, TopoFace::INSIDE, TopoFace::SAME);PreMergeSloid(m_pSloid2, result, TopoFace::INSIDE, TopoFace::INSIDE);result->m_indexs = new IndexInt[result->m_indexNum];//肯比实际的多少许result->m_vertexs = new vec3[result->m_vVertexNum];result->m_tVertexs = new TVertex[result->m_tVertexNum];result->m_indexNum = 0;result->m_vVertexNum = 0;result->m_tVertexNum = 0;MergeSloid(m_pSloid1, result, TopoFace::INSIDE, TopoFace::SAME);MergeSloid(m_pSloid2, result, TopoFace::INSIDE, TopoFace::INSIDE);//result->GenRendFromTopology();return result;
}Sloid * BooleanModeller::GetDifference()
{m_pSloid2->InvertInsideFaces();Sloid *result = new Sloid();PreMergeSloid(m_pSloid1, result, TopoFace::OUTSIDE, TopoFace::OPPOSITE);PreMergeSloid(m_pSloid2, result, TopoFace::INSIDE, TopoFace::INSIDE);result->m_indexs = new IndexInt[result->m_indexNum];//肯比实际的多少许result->m_vertexs = new vec3[result->m_vVertexNum];result->m_tVertexs = new TVertex[result->m_tVertexNum];result->m_indexNum = 0;result->m_vVertexNum = 0;result->m_tVertexNum = 0;MergeSloid(m_pSloid1, result, TopoFace::OUTSIDE, TopoFace::OPPOSITE);MergeSloid(m_pSloid2, result, TopoFace::INSIDE, TopoFace::INSIDE);//减法:sloid的内部面作为补面,需要反转法线。//result->GenRendFromTopology();m_pSloid2->InvertInsideFaces();return result;
}void BooleanModeller::MergeSloid(Sloid* pSrcSloid, Sloid* pDstSloid, int faceStatus1, int faceStatus2)
{for(int i=0;i<pSrcSloid->m_topoFaces->GetTopoFaceNum();i++){TopoFace & face = *(pSrcSloid->m_topoFaces->GetTopoFace(i));if(face.status==faceStatus1 || face.status==faceStatus2){TopoVertexPtrSet faceVerts;faceVerts.AddTopoVertexPtr(face.v1);faceVerts.AddTopoVertexPtr(face.v2);faceVerts.AddTopoVertexPtr(face.v3);for(int j=0;j<faceVerts.GetTopoVertexPtrNum();j++){if(pDstSloid->m_topoVertexs->HasTopoVertex(faceVerts[j])){pDstSloid->m_indexs[pDstSloid->m_indexNum] = pDstSloid->m_topoVertexs->IndexOfTopoVertex(faceVerts[j]);pDstSloid->m_indexNum++;}else{pDstSloid->m_indexs[pDstSloid->m_indexNum] = pDstSloid->m_topoVertexs->GetTopoVertexNum();pDstSloid->m_topoVertexs->AddTopoVertex(*faceVerts[j]);pDstSloid->m_vertexs[pDstSloid->m_vVertexNum] = faceVerts[j]->pos;pDstSloid->m_tVertexs[pDstSloid->m_tVertexNum] = faceVerts[j]->tVertex;pDstSloid->m_indexNum++;pDstSloid->m_vVertexNum++;pDstSloid->m_tVertexNum++;}}}}
}void BooleanModeller::PreMergeSloid(Sloid* pSrcSloid, Sloid* pDstSloid, int faceStatus1, int faceStatus2)
{for(int i=0;i<pSrcSloid->m_topoFaces->GetTopoFaceNum();i++){TopoFace & face = *(pSrcSloid->m_topoFaces->GetTopoFace(i));if(face.status==faceStatus1 || face.status==faceStatus2){pDstSloid->m_indexNum+=3;pDstSloid->m_vVertexNum+=3;pDstSloid->m_tVertexNum+=3;}}
}

任意阶拼图游戏及自动求解算法相关推荐

  1. 推箱子游戏的自动求解

    导读: 推箱子游戏的自动求解 简介 推箱子,又称搬运工,是一个十分流行的单人智力游戏.玩家的任务是在一个仓库中操纵一个搬运工人,将N个相同的箱子推到N个相同的目的地.推箱子游戏出现在计算机中最早起源于 ...

  2. 自动拼图android github,GitHub - zero0011/Puzzle: 拼图游戏 , 可自动实现 拼图操作

    拼图游戏 启动 前端 npm i npm run dev 后端 cd server npm i nodemon app.js 实现功能有 普通的拼图功能 自动拼图功能(难点) 游戏聊天室的设计 效果大 ...

  3. 数学大神攻克猜字游戏Wordle,求解算法成绩逼近理论极限,连信息论都用上了...

    梦晨 发自 凹非寺 量子位 | 公众号 QbitAI 免费猜字小游戏Wordle正在席卷全球,火到以数百万美元的价格被收购,全球玩家数量也突破了200万. 如果你在微博.微信等地方看到这些神神秘秘的方 ...

  4. 正在编写推箱子游戏的自动求解程序

    网上搜索了一下,有好多人现成的产品,不少国产的.编写这个程序只是为了回忆一下算法.不能丢了. 自动求解有俩种方案:一个是求最小行走步骤,一个是求最小推箱子数目. 第一种算法简单些,只要将小人推动的四个 ...

  5. Python编写的数字拼图游戏(含爬山算法人机对战功能)

    数字拼图游戏与拼图游戏原理一致,把打乱了的数字或图片经移动,拼成给定的目标数字或图片,其中总有一个空的地方,让相邻(上下左右)的方块移动,直至达到目标. 游戏代码由浙江温州永嘉县教师发展中心应根球老师 ...

  6. python拼图游戏代码的理解_Python编写的数字拼图游戏(含爬山算法人机对战功能)...

    数字拼图游戏与拼图游戏原理一致,把打乱了的数字或图片经移动,拼成给定的目标数字或图片,其中总有一个空的地方,让相邻(上下左右)的方块移动,直至达到目标. 游戏代码由浙江温州永嘉县教师发展中心应根球老师 ...

  7. python拼图游戏代码的理解_有意思的JS(1)拼图游戏 玩法介绍及其代码实现

    我是你们的索儿呀,很幸运我的文章能与你相见,愿萌新能直观的感受到Javascript的趣味性,愿有一定基础者有所收获,愿大佬不吝赐教 拼图游戏是一张图片分为若干块,打乱次序,将其中一块变为空白块,其只 ...

  8. 拼图游戏 玩法介绍及其代码实现(有意思的JS 一)

    我是你们的索儿呀,很幸运我的文章能与你相见 愿萌新能直观的感受到Javascript的趣味性,愿有一定基础者有所收获,愿大佬不吝赐教 拼图游戏是一张图片分为若干块,打乱次序,将其中一块变为空白块,其只 ...

  9. 从拼图游戏开始(十)_项目总结

    项目名:智能拼图游戏Android实现 代码量:2700行 项目地址:http://download.csdn.net/detail/u011638883/6844595 文章列表: 从拼图游戏开始( ...

  10. 使用A* (AStar)算法自动求解拼数字游戏

    原文链接: 使用A* (AStar)算法自动求解拼数字游戏 上一篇: js Heap 的简单使用 下一篇: vue router 技巧 效果 主要思想 设置两个数组 close 保存已经走过的状态 o ...

最新文章

  1. buildConfigField 使用
  2. 习题8_6与习题9_2
  3. Spark之 spark简介、生态圈详解
  4. Anroid-async-http封装网络请求框架源码分析
  5. ecshop的几个小瑕疵
  6. 某8位微型计算机地址总线为16位,微机原理试题和答案
  7. 数据库管理工具DBeaverEE 22 for Mac企业版
  8. LOJ 6278 数列分块入门2
  9. COCOS2D-X 不反复随机数
  10. 生活随记 - 2020国庆第四天
  11. CardView-卡片布局
  12. CDR中神奇的卷页滤镜
  13. oracle dba_hist_snapshot,通过dba_hist_*来进行诊断
  14. ‘C:\Users\Administrator\Desktop\gitSpace\dj-2\dj\vue-manager-dj\node_modules\node-sass\vendor‘
  15. python turtle 海龟绘图,绘制小猪佩奇
  16. 运行期间动态切换Redis数据库
  17. 原生Android平板,Remix OS 深入动手玩,这是一个改变 Android 平板使用体验的好系统...
  18. Omics精进04|临床Gene Panel检测-实验生物信息学分析
  19. linux查找表空间使用情况,表空间的使用情况查询及管理
  20. 华为AC和AP的配置及升级方式

热门文章

  1. 如何干掉腾讯网迷你版
  2. matlab兔子问题,【matlab】狼追击兔子问题的建模
  3. 卡内基梅隆大学计算机研究生水平,卡内基梅隆大学计算机研究生
  4. 卡内基梅隆计算机专业,2019美国大学计算机科学专业排名TOP10一览 卡内基梅隆大学居...
  5. 科技传播杂志科技传播杂志社科技传播编辑部2022年第9期目录
  6. cdr2022更新24.1版CorelDRAW2022稳定版
  7. 工作中常用的英语缩写
  8. 敏感词过滤的算法原理之 Aho-Corasick 算法
  9. python syntactic suger
  10. 【USB笔记】设备功能描述符Device Capability Descriptor