bool ApplyScale(m2::PointD const & pixelScaleCenter, double factor, ScreenBase & screen) { m2::PointD const globalScaleCenter = screen.PtoG(screen.P3dtoP(pixelScaleCenter)); ScreenBase tmp = screen; tmp.Scale(factor); tmp.MatchGandP3d(globalScaleCenter, pixelScaleCenter); if (!CheckMinScale(tmp)) return false; m2::RectD const & worldR = df::GetWorldRect(); if (!CheckBorders(tmp)) { if (CanShrinkInto(tmp, worldR)) tmp = ShrinkInto(tmp, worldR); else return false; } if (!CheckMaxScale(tmp)) return false; // re-checking the borders, as we might violate them a bit (don't know why). if (!CheckBorders(tmp)) tmp = ScaleInto(tmp, worldR); screen = tmp; return true; }
void Navigator::DoDrag(m2::PointD const & pt, double /*timeInSec*/) { if (m_LastPt1 == pt) return; ScreenBase const s = ShrinkInto(m_StartScreen, m_scales.GetWorldRect()); double dx = pt.x - m_StartPt1.x; double dy = pt.y - m_StartPt1.y; ScreenBase tmp = s; tmp.Move(dx, 0); if (!CheckBorders(tmp)) dx = 0; tmp = s; tmp.Move(0, dy); if (!CheckBorders(tmp)) dy = 0; tmp = s; tmp.Move(dx, dy); if (CheckBorders(tmp)) { m_StartScreen = tmp; m_StartPt1 = pt; m_LastPt1 = pt; m_Screen = tmp; } }
void Navigator::SetOrg(m2::PointD const & org) { ScreenBase tmp = m_Screen; tmp.SetOrg(org); if (CheckBorders(tmp)) m_Screen = tmp; }
bool MapMaster::IsTransparent(int posx, int posy, int posz) { if (!CheckBorders(&posx, &posy, &posz)) { return false; } return squares_[posx][posy][posz]->IsTransparent(); }
bool Navigator::ScaleImpl(m2::PointD const & newPt1, m2::PointD const & newPt2, m2::PointD const & oldPt1, m2::PointD const & oldPt2, bool skipMinScaleAndBordersCheck, bool doRotateScreen) { math::Matrix<double, 3, 3> newM = m_Screen.GtoPMatrix() * ScreenBase::CalcTransform(oldPt1, oldPt2, newPt1, newPt2); double oldAngle = m_Screen.GetAngle(); ScreenBase tmp = m_Screen; tmp.SetGtoPMatrix(newM); if (!doRotateScreen) tmp.Rotate(-(tmp.GetAngle() - oldAngle)); if (!skipMinScaleAndBordersCheck && !CheckMinScale(tmp)) return false; m2::RectD const & worldR = m_scales.GetWorldRect(); if (!skipMinScaleAndBordersCheck && !CheckBorders(tmp)) { if (CanShrinkInto(tmp, worldR)) tmp = ShrinkInto(tmp, worldR); else return false; } if (!CheckMaxScale(tmp)) return false; // re-checking the borders, as we might violate them a bit (don't know why). if (!CheckBorders(tmp)) tmp = ScaleInto(tmp, worldR); m_Screen = tmp; return true; }
void MakeDecimatedMap(int *NumNodes, int *NumTris, NODE **pNode, TRI **pTri) { int compare(TRITABLE *, TRITABLE *); int Bisect(NODE *, int, int, int); void CalcAngles(NODE *, int *, float *); void EdgeOnSide(int *, int *, int *); int tricall(int, NODE *, int *, TRI **, TRI **, const char *); int CheckBorders(int *,int,NODE *,int *,TRI **); float biggesterror; int i, j, N; int j0, j1, j2; int NumNodesToSave; int NumNodesUsed; NODE *Node; TRI *Tri; TRITABLE *TriTable; if(Decimate <= 0) return; /* ghCursorCurrent = LoadCursor(NULL,IDC_WAIT); SetCursor(ghCursorCurrent); */ dh = (Hur-Hll)/NH; dv = (Vur-Vll)/NV; NVP1 = NV+1; NumNodes[0] = (NH+1)*(NVP1); *pNode = (NODE *) malloc(NumNodes[0] * sizeof(NODE)); Node = *pNode; memset(Node,0,NumNodes[0]*sizeof(NODE)); // Copy [NH][NV] vertex array to our working node array for(i=0,N=0; i<=NH; i++) { for(j=0; j<=NV; j++, N++) { Node[N].p[0] = (float)xyz[i][j].p[0]; Node[N].p[1] = (float)xyz[i][j].p[1]; Node[N].p[2] = (float)xyz[i][j].p[2]; Node[N].fixed = xyz[i][j].fixed; } } // Start things off with the corner values Node[ 0].used = 1; Node[NV].used = 1; Node[NH*NVP1].used = 1; Node[NH*NVP1+NV].used = 1; NumNodesUsed = 4; tricall(NumNodes[0], Node, NumTris, NULL, pTri, "cnzBNPY"); Tri = *pTri; // Which coordinates are we triangulating on? switch(Plane) { case PLANE_XZ0: case PLANE_XZ1: j0 = 1; j1 = 0; j2 = 2; break; case PLANE_YZ0: case PLANE_YZ1: j0 = 0; j1 = 1; j2 = 2; break; default: j0 = 2; j1 = 0; j2 = 1; } // TriTable stores the largest error in a triangle and the node where that // error occurs TriTable = (TRITABLE *) malloc(NH*NV*2 * sizeof(TRITABLE)); NumNodesToSave = min(NumNodes[0], (int)(0.01*(100-Decimate)*(NumNodes[0]-NumNodesUsed)+NumNodesUsed)); while(NumNodesUsed < NumNodesToSave) { for(i=0; i<NumTris[0]; i++) Tri[i].flag = 0; // For every node that's not currently used, find what triangle it // lies on, and the error at this node for(i=0, biggesterror=0; i<NumNodes[0]; i++) { if(Node[i].used) continue; for(j=0, Node[i].tri=-1; (j<NumTris[0]) && (Node[i].tri==-1); j++) { if( side(Node[i].p[j1], Node[i].p[j2], Node[Tri[j].v[0]].p[j1],Node[Tri[j].v[0]].p[j2], Node[Tri[j].v[1]].p[j1],Node[Tri[j].v[1]].p[j2]) < 0. ) continue; if( side(Node[i].p[j1], Node[i].p[j2], Node[Tri[j].v[1]].p[j1],Node[Tri[j].v[1]].p[j2], Node[Tri[j].v[2]].p[j1],Node[Tri[j].v[2]].p[j2]) < 0. ) continue; if( side(Node[i].p[j1], Node[i].p[j2], Node[Tri[j].v[2]].p[j1],Node[Tri[j].v[2]].p[j2], Node[Tri[j].v[0]].p[j1],Node[Tri[j].v[0]].p[j2]) < 0. ) continue; Node[i].tri = j; } if(Node[i].tri < 0) { /* ghCursorCurrent = ghCursorDefault; SetCursor(ghCursorCurrent); */ g_FuncTable.m_pfnMessageBox(g_pRadiantWnd, "Error: Couldn't find the triangle bounding a point.", "Decimation Error",MB_ICONEXCLAMATION, NULL); return; } if(!Tri[Node[i].tri].flag) { PlaneFromPoints(Node[Tri[Node[i].tri].v[0]].p, Node[Tri[Node[i].tri].v[1]].p, Node[Tri[Node[i].tri].v[2]].p, &Tri[Node[i].tri].plane); Tri[Node[i].tri].flag = 1; } Node[i].error = Node[i].p[j0] - (Tri[Node[i].tri].plane.dist - Tri[Node[i].tri].plane.normal[j1]*Node[i].p[j1] - Tri[Node[i].tri].plane.normal[j2]*Node[i].p[j2] )/ Tri[Node[i].tri].plane.normal[j0]; biggesterror = max(biggesterror,Absolute(Node[i].error)); } if(biggesterror == 0) NumNodesToSave = NumNodesUsed; else { // For all current triangles, build a list of worst-case nodes memset(TriTable,0,NH*NV*2*sizeof(TRITABLE)); for(i=0; i<NumNodes[0]; i++) { if(Node[i].used) continue; if(Absolute(Node[i].error) > TriTable[Node[i].tri].error) { TriTable[Node[i].tri].error = (float)(Absolute(Node[i].error)); TriTable[Node[i].tri].node = i; } } qsort( (void *)TriTable, (size_t)(NumTris[0]), sizeof(TRITABLE), (int (*)(const void *, const void *))compare ); for(i=0; i<NumTris[0] && NumNodesUsed < NumNodesToSave && TriTable[i].error > 0.5*biggesterror; i++) { if(Node[TriTable[i].node].used) continue; // shouldn't happen NumNodesUsed++; Node[TriTable[i].node].used++; } free(Tri); tricall(NumNodes[0], Node, NumTris, NULL, pTri, "cnzBNPY"); Tri = *pTri; // Sliver-check along borders. Since borders are often linear, the errors // along borders will often be zero, so no new points will be added. This // tends to produce long, thin brushes. For all border triangles, check // that minimum angle isn't less than SLIVER_ANGLE. If it is, add another // vertex. while(CheckBorders(&NumNodesUsed,NumNodes[0],Node,NumTris,pTri) > 0) { } Tri = *pTri; } } free(TriTable); // One last time (because we're pessimistic), check border triangles // CheckBorders(&NumNodesUsed,NumNodes[0],Node,NumTris,pTri); // Tri = *pTri; // Check that all fixed points are exact. If not, add them to the mix. // First check to see if we have any fixed points that aren't already used. for(i=0, N=0; i<NumNodes[0] && !N; i++) { if(Node[i].used) continue; if(Node[i].fixed) N++; } if(N) { // Zero out the flag member of all triangles, indicating that // the plane equation has not been found. for(i=0; i<NumTris[0]; i++) Tri[i].flag = 0; for(i=0; i<NumNodes[0]; i++) { if(Node[i].used) continue; if(!Node[i].fixed) continue; Node[i].tri = -1; for(j=0; j<NumTris[0] && Node[i].tri==-1; j++) { if( side(Node[i].p[j1], Node[i].p[j2], Node[Tri[j].v[0]].p[j1],Node[Tri[j].v[0]].p[j2], Node[Tri[j].v[1]].p[j1],Node[Tri[j].v[1]].p[j2]) < 0. ) continue; if( side(Node[i].p[j1], Node[i].p[j2], Node[Tri[j].v[1]].p[j1],Node[Tri[j].v[1]].p[j2], Node[Tri[j].v[2]].p[j1],Node[Tri[j].v[2]].p[j2]) < 0. ) continue; if( side(Node[i].p[j1], Node[i].p[j2], Node[Tri[j].v[2]].p[j1],Node[Tri[j].v[2]].p[j2], Node[Tri[j].v[0]].p[j1],Node[Tri[j].v[0]].p[j2]) < 0. ) continue; Node[i].tri = j; } if(Node[i].tri < 0) { /* ghCursorCurrent = ghCursorDefault; SetCursor(ghCursorCurrent); */ g_FuncTable.m_pfnMessageBox(g_pRadiantWnd, "Error: Couldn't find the triangle bounding a point.", "Decimation Error",MB_ICONEXCLAMATION, NULL); return; } if(!Tri[Node[i].tri].flag) { PlaneFromPoints(Node[Tri[Node[i].tri].v[0]].p, Node[Tri[Node[i].tri].v[1]].p, Node[Tri[Node[i].tri].v[2]].p, &Tri[Node[i].tri].plane); Tri[Node[i].tri].flag = 1; } Node[i].error = Node[i].p[j0] - (Tri[Node[i].tri].plane.dist - Tri[Node[i].tri].plane.normal[j1]*Node[i].p[j1] - Tri[Node[i].tri].plane.normal[j2]*Node[i].p[j2] )/ Tri[Node[i].tri].plane.normal[j0]; if(Absolute(Node[i].error) > 0.5) { NumNodesUsed++; Node[i].used++; free(Tri); tricall(NumNodes[0], Node, NumTris, NULL, pTri, "cnzBNPY"); Tri = *pTri; } } } // Swap node orders for surfaces facing down, north or west so that // they are counterclockwise when facing the surface if((Plane == PLANE_XY1) || (Plane == PLANE_XZ0) || (Plane == PLANE_YZ1) ) { for(i=0; i<NumTris[0]; i++) { j = Tri[i].v[1]; Tri[i].v[1] = Tri[i].v[2]; Tri[i].v[2] = j; } } // Store bounding box coords for(i=0; i<NumTris[0]; i++) { Tri[i].min[0] = Node[Tri[i].v[0]].p[0]; Tri[i].min[0] = min(Tri[i].min[0],Node[Tri[i].v[1]].p[0]); Tri[i].min[0] = min(Tri[i].min[0],Node[Tri[i].v[2]].p[0]); Tri[i].min[1] = Node[Tri[i].v[0]].p[1]; Tri[i].min[1] = min(Tri[i].min[1],Node[Tri[i].v[1]].p[1]); Tri[i].min[1] = min(Tri[i].min[1],Node[Tri[i].v[2]].p[1]); Tri[i].min[2] = Node[Tri[i].v[0]].p[2]; Tri[i].min[2] = min(Tri[i].min[2],Node[Tri[i].v[1]].p[2]); Tri[i].min[2] = min(Tri[i].min[2],Node[Tri[i].v[2]].p[2]); Tri[i].max[0] = Node[Tri[i].v[0]].p[0]; Tri[i].max[0] = max(Tri[i].max[0],Node[Tri[i].v[1]].p[0]); Tri[i].max[0] = max(Tri[i].max[0],Node[Tri[i].v[2]].p[0]); Tri[i].max[1] = Node[Tri[i].v[0]].p[1]; Tri[i].max[1] = max(Tri[i].max[1],Node[Tri[i].v[1]].p[1]); Tri[i].max[1] = max(Tri[i].max[1],Node[Tri[i].v[2]].p[1]); Tri[i].max[2] = Node[Tri[i].v[0]].p[2]; Tri[i].max[2] = max(Tri[i].max[2],Node[Tri[i].v[1]].p[2]); Tri[i].max[2] = max(Tri[i].max[2],Node[Tri[i].v[2]].p[2]); } /* ghCursorCurrent = ghCursorDefault; SetCursor(ghCursorCurrent); */ }