void clipPoint(Point p, Boundary winEdge, Point wMin, Point wMax, Point * pOut, int * cnt, Point* first[], Point * s) { Point iPt; if (!first[winEdge]) { Point * np = new Point; *np = p; first[winEdge] = np; } else if (cross(p, s[winEdge], winEdge, wMin, wMax)) { iPt = intersect( p, s[winEdge], winEdge, wMin, wMax); if (winEdge < Top) clipPoint(iPt, (Boundary)((int)winEdge + 1), wMin, wMax, pOut, cnt, first, s); else { pOut[*cnt] = iPt; (*cnt)++; } } s[winEdge] = p; if(insideP(p, winEdge, wMin, wMax)) if(winEdge < Top) clipPoint(p, (Boundary)((int)winEdge + 1), wMin, wMax, pOut, cnt, first, s); else { pOut[*cnt] = p; (*cnt)++; } }
bool Clipping::clipCurve(Object *obj){ auto& coords = obj->getNCoords(); Coordinates newPath; bool prevInside = true; Coordinate prev; for(unsigned int i = 0; i < coords.size(); i++){ if(clipPoint(coords[i])){ if(!prevInside){ clipLine(prev, coords[i]); newPath.push_back(prev); } newPath.push_back(coords[i]); prevInside = true; }else{ if(prevInside && newPath.size() != 0){ clipLine(prev, coords[i]); newPath.push_back(coords[i]); } prevInside = false; } prev = coords[i]; } if(newPath.size() == 0) return false; obj->setNCoord(newPath); return true; }
bool Clipping::clip(Object* obj){ switch(obj->getType()){ case ObjType::OBJECT: break; case ObjType::POINT: return clipPoint(obj->getNCoord(0)); case ObjType::LINE: return clipLine(obj->getNCoord(0), obj->getNCoord(1)); case ObjType::POLYGON: return clipPolygon(obj); case ObjType::BEZIER_CURVE: case ObjType::BSPLINE_CURVE: return clipCurve(obj); case ObjType::OBJECT3D:{ Object3D *obj3d = (Object3D*) obj; bool draw = false; for(auto &face : obj3d->getFaceList()){ bool tmp = clipPolygon(&face); if(!tmp){ face.getNCoords().clear(); } draw |= tmp; } return draw; }case ObjType::BEZIER_SURFACE: case ObjType::BSPLINE_SURFACE:{ Surface *surf = (Surface*) obj; bool draw = false; for(auto &curve : surf->getCurveList()){ bool tmp = clipCurve(&curve); if(!tmp){ curve.getNCoords().clear(); } draw |= tmp; } return draw; }} return false; }
FORCEINLINE void GFX3D_Clipper::clipSegmentVsPlane(VERT** verts, const int coord, int which) { bool out0, out1; if(which==-1) out0 = verts[0]->coord[coord] < -verts[0]->coord[3]; else out0 = verts[0]->coord[coord] > verts[0]->coord[3]; if(which==-1) out1 = verts[1]->coord[coord] < -verts[1]->coord[3]; else out1 = verts[1]->coord[coord] > verts[1]->coord[3]; //CONSIDER: should we try and clip things behind the eye? does this code even successfully do it? not sure. //if(coord==2 && which==1) { // out0 = verts[0]->coord[2] < 0; // out1 = verts[1]->coord[2] < 0; //} //both outside: insert no points if(out0 && out1) { CLIPLOG(" both outside\n"); } //both inside: insert the first point if(!out0 && !out1) { CLIPLOG(" both inside\n"); outClippedPoly.clipVerts[outClippedPoly.type++] = *verts[1]; } //exiting volume: insert the clipped point and the first (interior) point if(!out0 && out1) { CLIPLOG(" exiting\n"); outClippedPoly.clipVerts[outClippedPoly.type++] = clipPoint(verts[0],verts[1], coord, which); } //entering volume: insert clipped point if(out0 && !out1) { CLIPLOG(" entering\n"); outClippedPoly.clipVerts[outClippedPoly.type++] = clipPoint(verts[1],verts[0], coord, which); outClippedPoly.clipVerts[outClippedPoly.type++] = *verts[1]; } }
int polygonClipSuthHodg(Point wMin, Point wMax, int n, Point* pIn, Point *pOut) { Point* first[nClip] = { 0,0,0,0 }, s[nClip]; int k, cnt = 0; for (k = 0; k < n; k++) clipPoint(pIn[k], Left, wMin, wMax, pOut, &cnt, first, s); closeClip(wMin, wMax, pOut, &cnt, first, s); return cnt; }
bool Clipping::clip(Object* obj){ switch(obj->getType()){ case ObjType::POINT: return clipPoint(obj->getNCoord(0)); case ObjType::LINE: return clipLine(obj->getNCoord(0), obj->getNCoord(1)); case ObjType::POLYGON: return clipPolygon(obj); case ObjType::BEZIER_CURVE: return clipCurve(obj); default: return false; } }
void closeClip(Point wMin, Point wMax, Point *pOut, int *cnt, Point* first[], Point *s) { Point pt; Boundary winEdge; for (winEdge = Left; winEdge <= Top; winEdge++) { if(cross(s[winEdge], *first[winEdge], winEdge, wMin, wMax)) { pt = intersect(s[winEdge],*first[winEdge],winEdge,wMin,wMax); if(winEdge < Top) clipPoint(pt, (Boundary)((int)winEdge + 1), wMin, wMax, pOut, cnt, first, s); else { pOut[*cnt] = pt; (*cnt)++; } } } }
bool Clipping::CohenSutherlandLineClip(Coordinate& c1, Coordinate& c2){ if(c1 == c2) return clipPoint(c1); int rc1 = getCoordRC(c1); int rc2 = getCoordRC(c2); while(true){ if( (rc1 | rc2) == 0 )// Dentro return true; else if( (rc1 & rc2) != 0 )// Fora return false; double x,y; int rc = rc1 ? rc1 : rc2;// (rc1 == 0) => Dentro double m = (c2.y-c1.y)/(c2.x-c1.x); if(rc & Clipping::RC::TOP){ x = c1.x + 1/m * (m_w->maxY-c1.y); y = m_w->maxY; }else if(rc & Clipping::RC::BOTTOM){ x = c1.x + 1/m * (m_w->minY-c1.y); y = m_w->minY; }else if(rc & Clipping::RC::RIGHT){ y = m * (m_w->maxX-c1.x) + c1.y; x = m_w->maxX; }else if(rc & Clipping::RC::LEFT){ y = m * (m_w->minX-c1.x) + c1.y; x = m_w->minX; } if(rc == rc1){ c1.x = x; c1.y = y; rc1 = getCoordRC(c1); }else{ c2.x = x; c2.y = y; rc2 = getCoordRC(c2); } } }
//http://www.skytopia.com/project/articles/compsci/clipping.html bool Clipping::LiangBaskyLineClip(Coordinate& c1, Coordinate& c2){ if(c1 == c2) return clipPoint(c1); auto delta = c2 - c1; double p,q,r; double u1 = 0.0, u2 = 1.0; for(int pos = 0; pos<4; pos++){ if (pos == 0){ p = -delta.x; q = c1.x - m_w->minX; } else if(pos == 1){ p = delta.x; q = m_w->maxX - c1.x; } else if(pos == 2){ p = -delta.y; q = c1.y - m_w->minY; } else if(pos == 3){ p = delta.y; q = m_w->maxY - c1.y; } if(p == 0 && q < 0) return false; r = q/p; if(p < 0){ if(r > u1) u1 = r; }else if(p > 0){ if(r < u2) u2 = r; } } if(u1 > u2) return false; if(u2 < 1){ c2.x = c1.x + u2*delta.x; c2.y = c1.y + u2*delta.y; } if(u1 > 0){ c1.x = c1.x + u1*delta.x; c1.y = c1.y + u1*delta.y; } return true; }
void ClippingService::clip(ViewWindow* window, DrawableObject *object) { clipping_type type = window->getClippingType(); list<Coordinate> coordinatesWindow = object->getCoordinatesWindow(); int size = coordinatesWindow.size(); switch (size) { case 1: // point { switch(type) { case PC: case PC_CS: case PC_LB: case PC_CS_SH: case PC_LB_SH: case PC_SH: { clipPoint(window, object); break; } default: { goto DO_NOT_CLIP; } } break; } case 2: // line { switch (type) { case CS: case PC_CS: case PC_CS_SH: case CS_SH: { clipCohenSutherland(window, object); break; } case LB: case PC_LB: case PC_LB_SH: case LB_SH: { clipLiangBarsky(window, object); break; } default: { goto DO_NOT_CLIP; } } break; } default: // wireframe / object3d / curve2d { if (object->getType() == OBJECT3D) { switch (type) { case CS: case PC_CS: case PC_CS_SH: case CS_SH: { clipCohenSutherland(window, object); break; } case LB: case PC_LB: case PC_LB_SH: case LB_SH: { clipLiangBarsky(window, object); break; } default: { goto DO_NOT_CLIP; } } break; } else { switch (type) { case SH: case PC_CS_SH: case PC_LB_SH: case PC_SH: case CS_SH: case LB_SH: { clipSutherlandHodgman(window, object); break; } default: { goto DO_NOT_CLIP; } } } } } return; DO_NOT_CLIP: object->setCoordinatesClipped(object->getCoordinatesWindow()); }