Files
Work/mesh/mesh.cpp
2024-08-07 09:16:27 -04:00

496 lines
16 KiB
C++

#include <mesh/mesh.hpp>
#include <mesh/main.hpp>
#include <common/stdio.hpp>
#include <common/math.hpp>
#include <common/rect.hpp>
#include <common/purehdc.hpp>
char GridMesh::szClassName[]="MESH97A";
char GridMesh::szMenuName[]={'\0'};
GridMesh::GridMesh(HWND hParent,int width,int height,GridShow visibility)
: mhParent(hParent), mStatus(InActive), mGridLines(GridLines),
mIsSuspended(FALSE), mhInstance(Main::processInstance()),
mDrawingPen(RGBColor(0,0,0),1)
{
mCreateHandler.setCallback(this,&GridMesh::createHandler);
mPaintHandler.setCallback(this,&GridMesh::paintHandler);
mLeftButtonUpHandler.setCallback(this,&GridMesh::leftButtonUpHandler);
mLeftButtonDownHandler.setCallback(this,&GridMesh::leftButtonDownHandler);
mMouseMoveHandler.setCallback(this,&GridMesh::mouseMoveHandler);
mDestroyHandler.setCallback(this,&GridMesh::destroyHandler);
insertHandlers();
mVersionInfo=szClassName;
registerClass();
Rect winRect(CW_USEDEFAULT,CW_USEDEFAULT,width,height);
createWindow(WS_EX_TRANSPARENT,szClassName,String(),WS_CHILD|WS_CLIPSIBLINGS,winRect,mhParent,(HMENU)0,processInstance(),(LPSTR)(Window*)this);
if(GridMesh::Show!=visibility)return;
show(SW_SHOW);
update();
}
GridMesh::~GridMesh()
{
Window::destroy();
removeHandlers();
}
void GridMesh::insertHandlers(void)
{
insertHandler(VectorHandler::CreateHandler,&mCreateHandler);
insertHandler(VectorHandler::PaintHandler,&mPaintHandler);
insertHandler(VectorHandler::LeftButtonUpHandler,&mLeftButtonUpHandler);
insertHandler(VectorHandler::LeftButtonDownHandler,&mLeftButtonDownHandler);
insertHandler(VectorHandler::MouseMoveHandler,&mMouseMoveHandler);
insertHandler(VectorHandler::DestroyHandler,&mDestroyHandler);
}
void GridMesh::removeHandlers(void)
{
removeHandler(VectorHandler::CreateHandler,&mCreateHandler);
removeHandler(VectorHandler::PaintHandler,&mPaintHandler);
removeHandler(VectorHandler::LeftButtonUpHandler,&mLeftButtonUpHandler);
removeHandler(VectorHandler::LeftButtonDownHandler,&mLeftButtonDownHandler);
removeHandler(VectorHandler::MouseMoveHandler,&mMouseMoveHandler);
removeHandler(VectorHandler::DestroyHandler,&mDestroyHandler);
}
void GridMesh::registerClass(void)
{
WNDCLASS wndClass;
if(::GetClassInfo(mhInstance,szClassName,(WNDCLASS FAR *)&wndClass))return;
wndClass.style =CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS;
wndClass.lpfnWndProc =(WNDPROC)Window::WndProc;
wndClass.cbClsExtra =0;
wndClass.cbWndExtra =sizeof(GridMesh*);
wndClass.hInstance =mhInstance;
wndClass.hIcon =0;
wndClass.hCursor =::LoadCursor(NULL,IDC_ARROW);
wndClass.hbrBackground =(HBRUSH)::GetStockObject(NULL_BRUSH);;
wndClass.lpszMenuName =szMenuName;
wndClass.lpszClassName =szClassName;
::RegisterClass(&wndClass);
}
CallbackData::ReturnType GridMesh::createHandler(CallbackData &/*someCallbackData*/)
{
sendMessage(WM_NCACTIVATE,TRUE,0L);
newMesh();
return (CallbackData::ReturnType)FALSE;
}
CallbackData::ReturnType GridMesh::paintHandler(CallbackData &someCallbackData)
{
int segmentCount((int)Array<Segment>::size());
PaintInformation *pPaintInfo=(PaintInformation*)someCallbackData.lParam();
PureDevice &pureDevice=*pPaintInfo;
for(int itemIndex=0;itemIndex<segmentCount;itemIndex++)
(Array<Segment>::operator[](itemIndex)).drawSegment((PureDevice&)*pPaintInfo,mDrawingPen);
return (CallbackData::ReturnType)FALSE;
}
CallbackData::ReturnType GridMesh::leftButtonUpHandler(CallbackData &someCallbackData)
{
mouseUp(someCallbackData.loWord(),someCallbackData.hiWord());
return (CallbackData::ReturnType)FALSE;
}
CallbackData::ReturnType GridMesh::leftButtonDownHandler(CallbackData &someCallbackData)
{
mouseDown(someCallbackData.loWord(),someCallbackData.hiWord());
return (CallbackData::ReturnType)FALSE;
}
CallbackData::ReturnType GridMesh::mouseMoveHandler(CallbackData &someCallbackData)
{
mouseMove(someCallbackData.loWord(),someCallbackData.hiWord());
return FALSE;
}
CallbackData::ReturnType GridMesh::destroyHandler(CallbackData &someCallbackData)
{
return (CallbackData::ReturnType)FALSE;
}
void GridMesh::showWindow(int visible)
{
show(visible?SW_SHOW:SW_HIDE);
invalidate();
}
void GridMesh::newMesh(WORD gridLines)
{
createMesh(gridLines,(Array<Segment>&)*this);
::InvalidateRect(mhParent,0,TRUE);
invalidate();
}
void GridMesh::createMesh(WORD gridLines,Array<Segment> &someSegmentVector)
{
RECT clientRect;
WORD xLength;
WORD yLength;
GDIPoint tempFirstPoint;
GDIPoint tempSecondPoint;
WORD vectorSize(0);
Index vectorIndex(0);
if(gridLines>MaxGridLines)mGridLines=GridLines;
else mGridLines=gridLines;
::GetClientRect(*this,(RECT FAR *)&clientRect);
xLength=clientRect.right/(mGridLines+1);
yLength=clientRect.bottom/(mGridLines+1);
for(int x=0,xCount=0;xCount<=mGridLines;x+=xLength,xCount++)
for(int y=0,yCount=0;yCount<=mGridLines;y+=yLength,yCount++)vectorSize+=2;
someSegmentVector.size(vectorSize);
for(x=0,xCount=0;xCount<=mGridLines;x+=xLength,xCount++)
{
for(int y=0,yCount=0;yCount<=mGridLines;y+=yLength,yCount++)
{
tempFirstPoint.setPoint(x+xLength,y+yLength);
tempSecondPoint.setPoint(x+xLength,y);
someSegmentVector[vectorIndex]=Segment(tempFirstPoint,tempSecondPoint,(WORD)vectorIndex);
vectorIndex++;
tempSecondPoint.setPoint(x,y+yLength);
someSegmentVector[vectorIndex]=Segment(tempFirstPoint,tempSecondPoint,(WORD)vectorIndex);
vectorIndex++;
}
}
}
void GridMesh::mouseDown(int x,int y)
{
GDIPoint mousePoint;
size_t size;
if(mIsSuspended)return;
mCurrentIntersection.remove();
mousePoint.setPoint(x,y);
if(!closestIntersection(mCurrentIntersection,mousePoint))
{
mStatus=InActive;
::MessageBeep(-1);
return;
}
mStatus=Active;
PureDevice displayDevice(*this);
size=(int)mCurrentIntersection.size();
for(int i=0;i<size;i++)mCurrentIntersection[i].drawSegment(displayDevice,mDrawingPen);
for(i=0;i<size;i++)mCurrentIntersection[i].drawSegment(displayDevice,mDrawingPen);
}
void GridMesh::mouseMove(int x,int y)
{
GDIPoint mousePoint;
Rect boundingRect;
size_t size;
int index;
if(InActive==mStatus)return;
PureDevice displayDevice(*this);
mousePoint.setPoint(x,y);
size=(int)mCurrentIntersection.size();
getBoundingRect(mCurrentIntersection,boundingRect);
if(!boundingRect.ptInRect(mousePoint))return;
for(index=0;index<size;index++)mCurrentIntersection[index].drawSegment(displayDevice,mDrawingPen);
for(index=0;index<size;index++)mCurrentIntersection[index].firstPoint(mousePoint);
for(index=0;index<size;index++)mCurrentIntersection[index].drawSegment(displayDevice,mDrawingPen);
}
void GridMesh::mouseUp(int x,int y)
{
Rect boundingRect;
GDIPoint swapPoint;
GDIPoint mousePoint;
size_t size;
int index;
if(InActive==mStatus)return;
mStatus=InActive;
mousePoint.setPoint(x,y);
size=(int)mCurrentIntersection.size();
for(index=0;index<size;index++)Array<Segment>::operator[](mCurrentIntersection[index].vectorIndex())=mCurrentIntersection[index];
}
WORD GridMesh::closestIntersection(Block<Segment> &filterBlock,GDIPoint &mousePoint)
{
size_t size((int)Array<Segment>::size());
DWORD tempDistance;
DWORD leastDistance;
Segment tempSegment;
Segment minSegment;
if(!size)return FALSE;
filterBlock.remove();
while(IntersectionSegments!=filterBlock.size())
{
for(int index=0;index<size;index++)
{
if(!index)
{
tempSegment=Array<Segment>::operator[](index);
while(isInBlock(filterBlock,tempSegment))tempSegment=Array<Segment>::operator[](++index);
leastDistance=minDistance(tempSegment,mousePoint);
}
else
{
tempDistance=minDistance(Array<Segment>::operator[](index),mousePoint);
if(tempDistance<leastDistance)
{
minSegment=Array<Segment>::operator[](index);
if(!isInBlock(filterBlock,minSegment))
{
tempSegment=minSegment;
leastDistance=tempDistance;
}
}
}
}
filterBlock.insert(&tempSegment);
}
return orderIntersection(filterBlock);
}
WORD GridMesh::orderIntersection(Block<Segment> &intersection)
{
GDIPoint tempPoint;
GDIPoint swapPoint;
size_t size((int)intersection.size());
int firstSection(0);
int secondSection(0);
int index;
if(IntersectionSegments!=size)return FALSE;
tempPoint=intersection[0].firstPoint();
firstSection=(tempPoint==intersection[1].firstPoint());
if(!firstSection)firstSection=(tempPoint==intersection[1].secondPoint());
if(!firstSection)
{
tempPoint=intersection[0].secondPoint();
secondSection=tempPoint==intersection[1].firstPoint();
if(!secondSection)secondSection=tempPoint==intersection[1].secondPoint();
}
if(!firstSection && !secondSection)return FALSE;
for(index=1;index<size;index++)
{
if(!(tempPoint==intersection[index].firstPoint())&&
!(tempPoint==intersection[index].secondPoint()))return FALSE;
}
if(secondSection)
{
swapPoint=intersection[0].firstPoint();
intersection[0].firstPoint(intersection[0].secondPoint());
intersection[0].secondPoint(swapPoint);
}
for(index=1;index<size;index++)
{
if(!(tempPoint==intersection[index].firstPoint()))
{
intersection[index].secondPoint(intersection[index].firstPoint());
intersection[index].firstPoint(tempPoint);
}
}
return TRUE;
}
WORD GridMesh::isInBlock(Block<Segment> &source,Segment &someSegment)
{
size_t size((int)source.size());
for(int i=0;i<size;i++)if(source[i]==someSegment)return TRUE;
return FALSE;
}
DWORD GridMesh::minDistance(const Segment &someSegment,const GDIPoint &somePoint)
{
LONG yTemp;
LONG xTemp;
LONG midy;
LONG midx;
LONG distancePointOne;
LONG distancePointTwo;
LONG distancePointThree;
yTemp=((LONG)someSegment.yFirst()-(LONG)somePoint.y())*((LONG)someSegment.yFirst()-(LONG)somePoint.y());
xTemp=((LONG)someSegment.xFirst()-(LONG)somePoint.x())*((LONG)someSegment.xFirst()-(LONG)somePoint.x());
distancePointOne=Math::sqrt(yTemp+xTemp);
yTemp=((LONG)someSegment.ySecond()-(LONG)somePoint.y())*((LONG)someSegment.ySecond()-(LONG)somePoint.y());
xTemp=((LONG)someSegment.xSecond()-(LONG)somePoint.x())*((LONG)someSegment.xSecond()-(LONG)somePoint.x());
distancePointTwo=Math::sqrt(yTemp+xTemp);
midx=((LONG)someSegment.xFirst()+(LONG)someSegment.xSecond())/2;
midy=((LONG)someSegment.yFirst()+(LONG)someSegment.ySecond())/2;
yTemp=((LONG)midy-(LONG)somePoint.y())*((LONG)midy-(LONG)somePoint.y());
xTemp=((LONG)midx-(LONG)somePoint.x())*((LONG)midx-(LONG)somePoint.x());
distancePointThree=Math::sqrt(yTemp+xTemp);
if(distancePointThree<=distancePointTwo&&distancePointTwo<=distancePointOne)
return distancePointThree;
if(distancePointTwo<=distancePointThree&&distancePointThree<=distancePointOne)
return distancePointTwo;
return distancePointOne;
}
WORD GridMesh::saveMesh(String &pathFileName)
{
FILE *fp;
GDIPoint tempPoint;
size_t size((int)Array<Segment>::size());
if(!size)return FALSE;
if(0==(fp=::fopen((LPSTR)pathFileName,"wb")))return FALSE;
::fwrite((void*)(LPSTR)mVersionInfo,::strlen(mVersionInfo),1,fp);
::fwrite((void*)&size,sizeof(size),1,fp);
::fwrite((void*)&mGridLines,sizeof(mGridLines),1,fp);
for(int i=0;i<size;i++)
{
tempPoint=Array<Segment>::operator[](i).firstPoint();
::fwrite((void *)&tempPoint,sizeof(GDIPoint),1,fp);
tempPoint=Array<Segment>::operator[](i).secondPoint();
::fwrite((void*)&tempPoint,sizeof(Point),1,fp);
}
::fclose(fp);
return TRUE;
}
WORD GridMesh::loadMesh(String &pathFileName)
{
FILE *fp;
GDIPoint firstPoint;
GDIPoint secondPoint;
String versionString;
int vectorIndex(0);
size_t size;
if(0==(fp=::fopen((LPSTR)pathFileName,"rb")))return upgradeStatus(FALSE);
versionString.reserve(String::MaxString);
::fread((void*)(LPSTR)versionString,::strlen(mVersionInfo),1,fp);
if(versionString!=mVersionInfo)
{
::fclose(fp);
return upgradeStatus(FALSE);
}
::fread((void*)&size,sizeof(size),1,fp);
::fread((void*)&mGridLines,sizeof(mGridLines),1,fp);
Array<Segment>::size(size);
for(int i=0;i<size;i++)
{
::fread((void*)&firstPoint,sizeof(Point),1,fp);
::fread((void*)&secondPoint,sizeof(Point),1,fp);
Array<Segment>::operator[](vectorIndex)=Segment(firstPoint,secondPoint,vectorIndex);
vectorIndex++;
}
::fclose(fp);
return upgradeStatus(TRUE);
}
WORD GridMesh::upgradeStatus(WORD retCode)const
{
if(!isVisible())show(SW_SHOW);
::InvalidateRect(mhParent,0,TRUE);
invalidate();
return retCode;
}
WORD GridMesh::retrieveMesh(Array<GDIPoint> &sourcePoints,Array<GDIPoint> &destPoints)
{
Array<Segment> sourceSegments;
createMesh(mGridLines,sourceSegments);
retrieveMesh(sourcePoints,sourceSegments);
retrieveMesh(destPoints,(Array<Segment>&)*this);
if(sourcePoints.size()!=destPoints.size())return FALSE;
return (WORD)sourcePoints.size();
}
WORD GridMesh::retrieveMesh(Array<GDIPoint> &meshPoints,Array<Segment> &someSegmentVector)const
{
Segment tempSegment;
int vectorIndex;
int pointIndex(0);
size_t vectorSize((int)someSegmentVector.size());
int haveFirstColumn(FALSE);
Array<Point> dummyPoint;
meshPoints.size(0);
meshPoints.size((mGridLines+2)*(mGridLines+2));
for(vectorIndex=0;vectorIndex<vectorSize;vectorIndex+=2)
{
if(!(vectorIndex%(mGridLines+1)))
{
if(!vectorIndex&&!haveFirstColumn)meshPoints[pointIndex++]=GDIPoint(0,0);
else if(haveFirstColumn)
{
if(someSegmentVector[vectorIndex].firstPoint().y()<
someSegmentVector[vectorIndex].secondPoint().y())
meshPoints[pointIndex++]=someSegmentVector[vectorIndex].firstPoint();
else
meshPoints[pointIndex++]=someSegmentVector[vectorIndex].secondPoint();
}
}
else if(vectorIndex<=(mGridLines*2)&&!haveFirstColumn)
{
tempSegment=someSegmentVector[vectorIndex-1];
if(tempSegment.firstPoint()==someSegmentVector[vectorIndex].firstPoint()||
tempSegment.firstPoint()==someSegmentVector[vectorIndex].secondPoint())
meshPoints[pointIndex++]=tempSegment.secondPoint();
else
meshPoints[pointIndex++]=tempSegment.firstPoint();
if(vectorIndex==mGridLines*2)
{
if(someSegmentVector[vectorIndex].firstPoint().y()<
someSegmentVector[vectorIndex].secondPoint().y())
meshPoints[pointIndex++]=GDIPoint(0,someSegmentVector[vectorIndex].secondPoint().y());
else
meshPoints[pointIndex++]=GDIPoint(0,someSegmentVector[vectorIndex].firstPoint().y());
}
}
else
{
if(!haveFirstColumn){haveFirstColumn=TRUE;vectorIndex=-2;continue;}
if(someSegmentVector[vectorIndex].firstPoint().y()<
someSegmentVector[vectorIndex].secondPoint().y())
meshPoints[pointIndex++]=someSegmentVector[vectorIndex].firstPoint();
else
meshPoints[pointIndex++]=someSegmentVector[vectorIndex].secondPoint();
if(!((vectorIndex+2)%(mGridLines+1)))
{
if(someSegmentVector[vectorIndex].firstPoint().y()<
someSegmentVector[vectorIndex].secondPoint().y())
meshPoints[pointIndex++]=someSegmentVector[vectorIndex].secondPoint();
else
meshPoints[pointIndex++]=someSegmentVector[vectorIndex].firstPoint();
}
}
}
return (WORD)meshPoints.size();
}
void GridMesh::getBoundingRect(Block<Segment> &currentIntersection,Rect &boundingRect)
{
for(int itemIndex=0;itemIndex<currentIntersection.size();itemIndex++)
{
const GDIPoint &firstPoint=currentIntersection[itemIndex].firstPoint();
const GDIPoint &secondPoint=currentIntersection[itemIndex].secondPoint();
if(!itemIndex)
{
boundingRect.left(firstPoint.x()<secondPoint.x()?firstPoint.x():secondPoint.x());
boundingRect.top(firstPoint.y()<secondPoint.y()?firstPoint.y():secondPoint.y());
boundingRect.right(firstPoint.x()>secondPoint.x()?firstPoint.x():secondPoint.x());
boundingRect.bottom(firstPoint.y()<secondPoint.y()?firstPoint.y():secondPoint.y());
}
else
{
GDIPoint minPoint;
GDIPoint maxPoint;
minPoint.x(firstPoint.x()<secondPoint.x()?firstPoint.x():secondPoint.x());
minPoint.y(firstPoint.y()<secondPoint.y()?firstPoint.y():secondPoint.y());
maxPoint.x(firstPoint.x()>secondPoint.x()?firstPoint.x():secondPoint.x());
maxPoint.y(firstPoint.y()>secondPoint.y()?firstPoint.y():secondPoint.y());
if(minPoint.x()<boundingRect.left())boundingRect.left(minPoint.x());
if(minPoint.y()<boundingRect.top())boundingRect.top(minPoint.y());
if(maxPoint.x()>boundingRect.right())boundingRect.right(maxPoint.x());
if(maxPoint.y()>boundingRect.bottom())boundingRect.bottom(maxPoint.y());
}
}
}