bool VRect::HitTest (const VPoint& inPoint) const { return ((inPoint.GetX() - fX) > -kREAL_PIXEL_PRECISION && (inPoint.GetX() - GetRight()) < kREAL_PIXEL_PRECISION && (inPoint.GetY() - fY) > -kREAL_PIXEL_PRECISION && (inPoint.GetY() - GetBottom()) < kREAL_PIXEL_PRECISION); }
// JM 201206 Boolean VGraphicPath::ScaledHitTest(const VPoint& inPoint, GReal scale) const { #if ENABLE_D2D if (fPathD2D != NULL) { BOOL bContains = FALSE; fPathD2D->StrokeContainsPoint( D2D1::Point2F(inPoint.GetX(), inPoint.GetY()), 4*scale, NULL, NULL, &bContains); return bContains == TRUE; } #endif #if !GRAPHIC_MIXED_GDIPLUS_D2D if (!VWinD2DGraphicContext::IsAvailable()) { #endif Gdiplus::Color black_default_color(0,0,0); Gdiplus::Pen p(black_default_color); p.SetWidth(4 * scale); return fPath->IsOutlineVisible((Gdiplus::REAL)inPoint.GetX(), (Gdiplus::REAL)inPoint.GetY(), &p ); #if !GRAPHIC_MIXED_GDIPLUS_D2D } #endif return false; }
void VRope::createRope(cocos2d::CCPoint pointA, cocos2d::CCPoint pointB, float ropeLenght) { float distance; if (ropeLenght < 0) { distance = ccpDistance(pointA,pointB); }else{ distance = ropeLenght; } int segmentFactor = RopeSegmentFactor; //increase value to have less segments per rope, decrease to have more segments numPoints = distance/segmentFactor; mRopeLength = segmentFactor * numPoints; CCPoint diffVector = ccpSub(pointB,pointA); float multiplier = distance / (numPoints-1); antiSagHack = 0.1f; //HACK: scale down rope points to cheat sag. set to 0 to disable, max suggested value 0.1 for(int i=0;i<numPoints;i++) { CCPoint tmpVector = ccpAdd(pointA, ccpMult(ccpNormalize(diffVector),multiplier*i*(1-antiSagHack))); VPoint* tmpPoint = new VPoint; tmpPoint->setPos(tmpVector.x, tmpVector.y); vPoints.insert(vPoints.end(), tmpPoint); } for(int i=0;i<numPoints-1;i++) { VStick tmpStick; tmpStick.initWith(vPoints[i], vPoints[i+1]); vSticks.insert(vSticks.end(), tmpStick); } if(spriteSheet!=NULL) { for(int i=0;i<numPoints-1;i++) { VPoint* point1 = vSticks[i].getPointA(); VPoint* point2 = vSticks[i].getPointB(); CCPoint stickVector = ccpSub(ccp(point1->x,point1->y),ccp(point2->x,point2->y)); float stickAngle = ccpToAngle(stickVector); CCTexture2D* texture = spriteSheet->getTexture(); RecordSprite* tmpSprite = new RecordSprite; tmpSprite->setTag(Tag_Box_RopeBatchSprite); tmpSprite->autorelease(); tmpSprite->initWithTexture(texture, CCRectMake(0,0,multiplier,texture->getContentSize().height)); ccTexParams params = {GL_LINEAR,GL_LINEAR,GL_REPEAT,GL_REPEAT}; tmpSprite->getTexture()->setTexParameters(¶ms); tmpSprite->setPosition(ccpMidpoint(ccp(point1->x,point1->y),ccp(point2->x,point2->y))); tmpSprite->setRotation(-1 * CC_RADIANS_TO_DEGREES(stickAngle)); spriteSheet->addChild(tmpSprite); ropeSprites.insert(ropeSprites.end(), tmpSprite); } //// LiFeng 添加 //ropeSprites[ropeSprites.size()-1]->setOpacity(100); }else{ CCAssert(false, "not init"); } }
void VRope::resetWithPoints(cocos2d::CCPoint pointA, cocos2d::CCPoint pointB) { float distance = ccpDistance(pointA,pointB); CCPoint diffVector = ccpSub(pointB,pointA); float multiplier = distance / (numPoints - 1); for(int i=0;i<numPoints;i++) { CCPoint tmpVector = ccpAdd(pointA, ccpMult(ccpNormalize(diffVector),multiplier*i*(1-antiSagHack))); VPoint* tmpPoint = vPoints[i]; tmpPoint->setPos(tmpVector.x, tmpVector.y); } }
VRope* VRope::cutRopeInStick(int nPoint, VStick* stick, b2Body* newBodyA, b2Body* newBodyB) { auto range = NSRange{nPoint, numPoints-nPoint-1}; std::vector< VStick *> newRopeSticks( vSticks.begin() + range.location, vSticks.begin() + range.location + range.length ); vSticks.erase(vSticks.begin() + range.location, vSticks.begin() + range.location + range.length); std::vector<Sprite*> newRopeSprites(ropeSprites.begin() + range.location, ropeSprites.begin() + range.location + range.length); ropeSprites.erase(ropeSprites.begin() + range.location, ropeSprites.begin() + range.location + range.length); range.length += 1; std::vector<VPoint*> newRopePoints(vPoints.begin() + range.location, vPoints.begin() + range.location + range.length); vPoints.erase(vPoints.begin() + range.location, vPoints.begin() + range.location + range.length); VPoint *pointOfBreak = newRopePoints.at(0); VPoint *newPoint = new VPoint(); newPoint->setPos(pointOfBreak->x, pointOfBreak->y); vPoints.push_back(newPoint); VStick *lastStick = vSticks.back(); lastStick->setPointB(newPoint); float cutRatio = (float)nPoint / (numPoints - 1); numPoints = nPoint + 1; b2Vec2 newBodiesPosition = b2Vec2(pointOfBreak->x / PTM_RATIO, pointOfBreak->y / PTM_RATIO); b2World *world = newBodyA->GetWorld(); b2RopeJointDef jd; jd.bodyA = joint->GetBodyA(); jd.bodyB = newBodyB; jd.localAnchorA = joint->GetLocalAnchorA(); jd.localAnchorB = b2Vec2(0, 0); jd.maxLength = joint->GetMaxLength() * cutRatio; newBodyB->SetTransform(newBodiesPosition, 0.0); b2RopeJoint *newJoint1 = (b2RopeJoint *)world->CreateJoint(&jd); //create joint jd.bodyA = newBodyA; jd.bodyB = joint->GetBodyB(); jd.localAnchorA = b2Vec2(0, 0); jd.localAnchorB = joint->GetLocalAnchorB(); jd.maxLength = joint->GetMaxLength() * (1 - cutRatio); newBodyA->SetTransform(newBodiesPosition, 0.0); b2RopeJoint *newJoint2 = (b2RopeJoint *)world->CreateJoint(&jd); world->DestroyJoint(joint); joint = newJoint1; VRope* newRope = new VRope(newJoint2,spriteSheet,newRopePoints,newRopeSticks,newRopeSprites); return newRope; }
void showpath() { for(VPoint::iterator it = path.begin(); it != path.end(); ++it) { highlightCube(it->x, it->y, true); pause(50); } pause(250); for(VPoint::iterator it = path.begin(); it != path.end(); ++it) highlightCube(it->x, it->y, false); }
void SearchAll(string &word, string &occupy, int row, int col) { int pos = row * size + col; occupy[pos] = OCCUPY; path.push_back(SPoint(row, col)); word += tolower(board[pos]); if(!english.containsPrefix(word)) { word = word.substr(0, word.size() - 1); occupy[pos] = EMPTY; path.pop_back(); return; } if(word.size() >= 4 && InEnglish(word) && !InHumanWord(word)) { recordWordForPlayer(word, COMPUTER); humanword.push_back(word); showpath(); } //cout << word << ' ' << row << ' ' << col << endl; //Up if(row != 0 && occupy[pos - size] == EMPTY) SearchAll(word, occupy, row - 1, col); //Down if(row != size - 1 && occupy[pos + size] == EMPTY) SearchAll(word, occupy, row + 1, col); //Right if(col != size - 1 && occupy[pos + 1] == EMPTY) SearchAll(word, occupy, row, col + 1); //Left if(col != 0 && occupy[pos - 1] == EMPTY) SearchAll(word, occupy, row, col - 1); //UpRight if(row != 0 && col != size - 1 && occupy[pos - size + 1] == EMPTY) SearchAll(word, occupy, row - 1, col + 1); //UpLeft if(row != 0 && col != 0 && occupy[pos - size - 1] == EMPTY) SearchAll(word, occupy, row - 1, col - 1); //DownLeft if(row != size - 1 && col != 0 && occupy[pos + size - 1] == EMPTY) SearchAll(word, occupy, row + 1, col - 1); //DownRight if(row != size - 1 && col != size - 1 && occupy[pos + size + 1] == EMPTY) SearchAll(word, occupy, row + 1, col + 1); word = word.substr(0, word.size() - 1); path.pop_back(); occupy[pos] = EMPTY; }
/*!If more than one logical operatoin has to be executed over the input shapes the raw data #_shape1 and #_shape2 can be reused, but has to be recycled beforehand This method is traversing both fields and invokes VPoint::reset_visited() in order to reinitialize the CPoint::_visited fields*/ void logicop::logic::reset_visited() { VPoint* centinel = _shape1; VPoint* looper = centinel; do { looper->reset_visited(); looper = looper->next(); } while (centinel != looper); centinel = _shape2; looper = centinel; do { looper->reset_visited(); looper = looper->next(); } while (centinel != looper); }
Boolean VRegion::HitTest (const VPoint& inPoint) const { if (fRegion == NULL) return false; #if !USE_GDIPLUS VPoint testPoint(inPoint); testPoint -= fOffset; if (testPoint.GetX() > kMAX_GDI_RGN_COORD || testPoint.GetY() > kMAX_GDI_RGN_COORD) return false; else return (::PtInRegion(fRegion, testPoint.GetX(), testPoint.GetY()) != 0); #else return fRegion->IsVisible((INT)inPoint.GetX(), (INT)inPoint.GetY()); #endif }
pointlist* logicop::logic::hole2simple(const pointlist& outside, const pointlist& inside) { segmentlist _segl0(outside,0); segmentlist _segl1(inside,1); EventQueue* _eq = new EventQueue(_segl0, _segl1); // create the event queue SweepLine _sl; BindCollection BC; _eq->swipe4bind(_sl, BC); BindSegment* sbc = BC.get_highest(); //insert 2 crossing points and link them BPoint* cpsegA = _segl0.insertbindpoint(sbc->poly0seg(), sbc->poly0pnt()); BPoint* cpsegB = _segl1.insertbindpoint(sbc->poly1seg(), sbc->poly1pnt()); cpsegA->linkto(cpsegB); cpsegB->linkto(cpsegA); // normalize the segment lists _segl0.normalize(outside); _segl1.normalize(inside); // dump the new polygons in VList terms VPoint* outshape = _segl0.dump_points(); _segl1.dump_points(); // traverse and form the resulting shape VPoint* centinel = outshape; pointlist *shgen = new pointlist(); bool direction = true; /*next*/ VPoint* pickup = centinel; VPoint* prev = centinel->prev(); bool modify = false; do { shgen->push_back(TP(pickup->cp()->x(), pickup->cp()->y())); modify = (-1 == prev->visited()); prev = pickup; pickup = pickup->follower(direction, modify); } while (pickup != centinel); // Validate the resulting polygon laydata::valid_poly check(*shgen); // delete shgen; if (!check.valid()) { std::ostringstream ost; ost << ": Resulting shape is invalid - " << check.failtype(); tell_log(console::MT_ERROR, ost.str().c_str()); } else { if (laydata::shp_OK != check.status()) *shgen = check.get_validated(); } return shgen; }
void VGraphicPath::BeginSubPathAt(const VPoint& inLocalPoint) { #if !GRAPHIC_MIXED_GDIPLUS_D2D if (!VWinD2DGraphicContext::IsAvailable()) { #endif fLastPoint = VPoint((GReal)inLocalPoint.GetX(), (GReal)inLocalPoint.GetY()); fPath->StartFigure(); #if !GRAPHIC_MIXED_GDIPLUS_D2D } #endif #if ENABLE_D2D if (VWinD2DGraphicContext::IsAvailable()) { if (!fGeomSink) { Begin(); if (!fGeomSink) return; } if (!fFigureIsClosed) //do not forget to close current figure before opening new figure to prevent really nasty artifacts... fGeomSink->EndFigure( D2D1_FIGURE_END_OPEN); fGeomSink->BeginFigure( D2D1::Point2F( inLocalPoint.GetX(), inLocalPoint.GetY()), D2D1_FIGURE_BEGIN_FILLED); fFigureIsClosed = false; } #endif fPolygon.AddPoint(inLocalPoint); if (fComputeBoundsAccurate) _addPointToBounds( inLocalPoint); _ComputeBounds(); if (fCreateStorageForCrispEdges) fDrawCmds.push_back( VGraphicPathDrawCmd( GPDCT_BEGIN_SUBPATH_AT, inLocalPoint)); }
void VRope::createRope(const CCPoint& pointA, const CCPoint& pointB, float distance) { // float distance = ccpDistance(pointA,pointB); int segmentFactor = 12; // 16; //12; //increase value to have less segments per rope, decrease to have more segments numPoints = (int) distance/segmentFactor; CCPoint diffVector = ccpSub(pointB,pointA); float multiplier = distance / (numPoints-1); antiSagHack = 0.1f; //HACK: scale down rope points to cheat sag. set to 0 to disable, max suggested value 0.1 for(int i=0;i<numPoints;i++) { CCPoint tmpVector = ccpAdd(pointA, ccpMult(ccpNormalize(diffVector), multiplier*i*(1-antiSagHack))); VPoint *tmpPoint = new VPoint(); tmpPoint->setPos(tmpVector.x, tmpVector.y); vPoints.push_back(tmpPoint); } for(int i=0;i<numPoints-1;i++) { VStick* tmpStick = new VStick(vPoints[i], vPoints[i+1]); vSticks.push_back(tmpStick); } if(spriteSheet) { for(int i=0;i<numPoints-1;i++) { VPoint* point1 = vSticks[i]->getPointA(); VPoint* point2 = vSticks[i]->getPointB(); CCPoint stickVector = ccpSub(ccp(point1->x,point1->y),ccp(point2->x,point2->y)); float stickAngle = ccpToAngle(stickVector); float f = spriteSheet->getTextureAtlas()->getTexture()->getPixelsHigh() / CC_CONTENT_SCALE_FACTOR(); CCRect r = CCRectMake(0, 0, multiplier, f); Sprite* tmpSprite = Sprite::createWithTexture(spriteSheet->getTexture(), r); Texture2D::TexParams params = {GL_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT}; tmpSprite->getTexture()->setTexParameters(¶ms); tmpSprite->setPosition(ccpMidpoint(ccp(point1->x, point1->y), ccp(point2->x, point2->y))); tmpSprite->setRotation(-1 * CC_RADIANS_TO_DEGREES(stickAngle)); spriteSheet->addChild(tmpSprite); ropeSprites.push_back(tmpSprite); } } }
void ComputerTurn() { path.clear(); string word = ""; string occupy(size * size, EMPTY); for(int i = 0; i < size; i++) { for(int j = 0; j < size; j++) { SearchAll(word, occupy, i, j); } } }
bool InBoard(const string &word) { path.clear(); string occupy(size * size, EMPTY); for(int i = 0; i < size; i++) { for(int j = 0; j < size; j++) { if(RInBoard(word, occupy, i, j, 0)) return true; } } return false; }
void VGraphicPath::AddLineTo(const VPoint& inDestPoint) { #if !GRAPHIC_MIXED_GDIPLUS_D2D if (!VWinD2DGraphicContext::IsAvailable()) { #endif Gdiplus::PointF d = Gdiplus::PointF(inDestPoint.GetX(), inDestPoint.GetY()); fPath->AddLine(Gdiplus::PointF(fLastPoint.x,fLastPoint.y), d); fLastPoint.x = d.X; fLastPoint.y = d.Y; #if !GRAPHIC_MIXED_GDIPLUS_D2D } #endif #if ENABLE_D2D if (VWinD2DGraphicContext::IsAvailable()) { if (!fGeomSink) { Begin(); if (!fGeomSink) return; } fGeomSink->AddLine( D2D1::Point2F( inDestPoint.GetX(), inDestPoint.GetY())); } #endif fPolygon.AddPoint(inDestPoint); if (fComputeBoundsAccurate) _addPointToBounds( inDestPoint); _ComputeBounds(); if (fCreateStorageForCrispEdges) fDrawCmds.push_back( VGraphicPathDrawCmd( GPDCT_ADD_LINE_TO, inDestPoint)); }
/*!The method uses #_shape1 and #_shape2 structure as an input data and produces one or more polygons representing the result of the logical ANDNOT between the input polygons. Method returns false if no output shapes are generated, and true otherwise*/ bool logicop::logic::ANDNOT(pcollection& plycol) { bool result = false; VPoint* centinel = NULL; if (0 == _crossp) { // If there are no crossing points found, this still does not mean // that the operation will fail. Polygons might be overlapping... // if poly1 is inside poly2, or both are non overlapping -> // resulting shape is null // if poly2 is inside poly1, then we have to generate a polygon // combining both shapes if (_shape2->inside(_poly1)) { plycol.push_back(hole2simple(_poly1, _poly2)); return true; } else return false; } //if crossing points exists, get first external and non crossing point bool direction; centinel = getFirstOutside(_poly1, _shape2); if (NULL == centinel) { centinel = getFirstOutside(_poly2, _shape1); direction = false; /*prev*/ } else direction = true; /*next*/ assert(centinel); // VPoint* collector = centinel; do { if (0 == collector->visited()) { pointlist *shgen = new pointlist(); VPoint* pickup = collector; do { pickup = pickup->follower(direction, true); shgen->push_back(TP(pickup->cp()->x(), pickup->cp()->y())); } while (pickup != collector); plycol.push_back(shgen); result = true; } collector = collector->prev(); } while (collector != centinel); return result; }
/** Returns VTRUE if an existing VPoint object has the same coordinates as this point, VFALSE otherwise.*/ VBOOL IsEqual(VPoint const& pt) const { return (pt.GetX() == m_Point.x && pt.GetY() == m_Point.y) ? VTRUE : VFALSE; }
bool RInBoard(const string &word, string &occupy, int row, int col, int index) { //cout << word << ' ' << row << ' ' << col << ' ' << index << endl; int pos = row * size + col; occupy[pos] = OCCUPY; path.push_back(SPoint(row, col)); if(tolower(word[index]) != tolower(board[pos])) { //cout << word[index] << ' ' << board[pos] << endl; occupy[pos] = EMPTY; path.pop_back(); return false; } //cout << word << endl; if(index == word.size() - 1) { showpath(); return true; } //Up if(row != 0 && occupy[pos - size] == EMPTY) { bool res = RInBoard(word, occupy, row - 1, col, index + 1); if(res) return true; } //Down if(row != size - 1 && occupy[pos + size] == EMPTY) { bool res = RInBoard(word, occupy, row + 1, col, index + 1); if(res) return true; } //Left if(col != 0 && occupy[pos - 1] == EMPTY) { bool res = RInBoard(word, occupy, row, col - 1, index + 1); if(res) return true; } //Right if(col != size - 1 && occupy[pos + 1] == EMPTY) { bool res = RInBoard(word, occupy, row, col + 1, index + 1); if(res) return true; } //UpRight if(row != 0 && col != size - 1 && occupy[pos - size + 1] == EMPTY) { bool res = RInBoard(word, occupy, row - 1, col + 1, index + 1); if(res) return true; } //UpLeft if(row != 0 && col != 0 && occupy[pos - size - 1] == EMPTY) { bool res = RInBoard(word, occupy, row - 1, col - 1, index + 1); if(res) return true; } //DownLeft if(row != size - 1 && col != 0 && occupy[pos + size - 1] == EMPTY) { bool res = RInBoard(word, occupy, row + 1, col - 1, index + 1); if(res) return true; } //DownRight if(row != size - 1 && col != size - 1 && occupy[pos + size + 1] == EMPTY) { bool res = RInBoard(word, occupy, row + 1, col + 1, index + 1); if(res) return true; } occupy[pos] = EMPTY; path.pop_back(); return false; }
void VGraphicPath::AddBezierTo(const VPoint& inStartControl, const VPoint& inDestPoint, const VPoint& inDestControl) { #if !GRAPHIC_MIXED_GDIPLUS_D2D if (!VWinD2DGraphicContext::IsAvailable()) { #endif Gdiplus::PointF d = Gdiplus::PointF(inDestPoint.GetX(), inDestPoint.GetY()); Gdiplus::PointF c1 = Gdiplus::PointF(inStartControl.GetX(), inStartControl.GetY()); Gdiplus::PointF c2 = Gdiplus::PointF(inDestControl.GetX(), inDestControl.GetY()); fPath->AddBezier(Gdiplus::PointF(fLastPoint.x,fLastPoint.y), c1, c2, d); fLastPoint.x = d.X; fLastPoint.y = d.Y; #if !GRAPHIC_MIXED_GDIPLUS_D2D } #endif #if ENABLE_D2D if (VWinD2DGraphicContext::IsAvailable()) { if (!fGeomSink) { Begin(); if (!fGeomSink) return; } D2D1_POINT_2F c1 = D2D1::Point2F(inStartControl.GetX(), inStartControl.GetY()); D2D1_POINT_2F c2 = D2D1::Point2F(inDestControl.GetX(), inDestControl.GetY()); D2D1_POINT_2F d = D2D1::Point2F(inDestPoint.GetX(), inDestPoint.GetY()); fGeomSink->AddBezier( D2D1::BezierSegment(c1, c2, d)); } #endif fPolygon.AddPoint(inDestPoint); if (fComputeBoundsAccurate) _addBezierToBounds( inStartControl, inDestControl, inDestPoint); _ComputeBounds(); fHasBezier = true; if (fCreateStorageForCrispEdges) fDrawCmds.push_back( VGraphicPathDrawCmd( GPDCT_ADD_BEZIER_TO, inStartControl, inDestPoint, inDestControl)); }
/* add arc to the specified graphic path @param inCenter arc ellipse center @param inDestPoint dest point of the arc @param inRX arc ellipse radius along x axis @param inRY arc ellipse radius along y axis if inRY <= 0, inRY = inRX @param inLargeArcFlag (default false) true for draw largest arc @param inXAxisRotation (default 0.0f) arc x axis rotation in degree @remarks this method add a arc starting from current pos to the dest point use MeasureArc method to get start & end point from ellipse start & end angle in degree */ void VGraphicPath::AddArcTo(const VPoint& inCenter, const VPoint& inDestPoint, GReal _inRX, GReal _inRY, bool inLargeArcFlag, GReal inXAxisRotation) { //we need double precision here Real inRx = _inRX, inRy = _inRY; Real inX = fLastPoint.x, inY = fLastPoint.y; Real inEX = inDestPoint.GetX(), inEY = inDestPoint.GetY(); Real sin_th, cos_th; Real a00, a01, a10, a11; Real x0, y0, x1, y1, xc, yc; Real d, sfactor, sfactor_sq; Real th0, th1, th_arc; sLONG i, n_segs; Real dx, dy, dx1, dy1, Pr1, Pr2, Px, Py, check; inRx = fabs(inRx); inRy = fabs(inRy); sin_th = sin(inXAxisRotation * (PI / 180.0)); cos_th = cos(inXAxisRotation * (PI / 180.0)); dx = (inX - inEX) / 2.0; dy = (inY - inEY) / 2.0; dx1 = cos_th * dx + sin_th * dy; dy1 = -sin_th * dx + cos_th * dy; Pr1 = inRx * inRx; Pr2 = inRy * inRy; Px = dx1 * dx1; Py = dy1 * dy1; /* Spec : check if radii are large enough */ check = Px / Pr1 + Py / Pr2; if (check > 1) { inRx = inRx * sqrt(check); inRy = inRy * sqrt(check); } a00 = cos_th / inRx; a01 = sin_th / inRx; a10 = -sin_th / inRy; a11 = cos_th / inRy; x0 = a00 * inX + a01 * inY; y0 = a10 * inX + a11 * inY; x1 = a00 * inEX + a01 * inEY; y1 = a10 * inEX + a11 * inEY; xc = a00 * inCenter.GetX() + a01 * inCenter.GetY(); yc = a10 * inCenter.GetX() + a11 * inCenter.GetY(); /* (x0, y0) is current point in transformed coordinate space. (x1, y1) is new point in transformed coordinate space. (xc, yc) is new center in transformed coordinate space. The arc fits a unit-radius circle in this space. */ /* d = (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0); sfactor_sq = 1.0 / d - 0.25; if (sfactor_sq < 0) sfactor_sq = 0; sfactor = sqrt(sfactor_sq); if (inSweepFlag == inLargeArcFlag) sfactor = -sfactor; xc = 0.5 * (x0 + x1) - sfactor * (y1 - y0); yc = 0.5 * (y0 + y1) + sfactor * (x1 - x0); */ /* (xc, yc) is center of the circle. */ th0 = atan2(y0 - yc, x0 - xc); th1 = atan2(y1 - yc, x1 - xc); th_arc = th1 - th0; if (th0 <= 0.0 && th1 > 0.0 && fabs(th_arc-PI) <= 0.00001) th_arc = -th_arc; //ensure we draw counterclockwise if angle delta = 180° else if (fabs(th_arc)-PI > 0.00001 && !inLargeArcFlag) { if (th_arc > 0) th_arc -= 2 * PI; else th_arc += 2 * PI; } else if (fabs(th_arc) <= PI && inLargeArcFlag) { if (th_arc > 0) th_arc -= 2 * PI; else th_arc += 2 * PI; } //split arc in small arcs <= 90° n_segs = int(ceil(fabs(th_arc / (PI * 0.5 + 0.001)))); for (i = 0; i < n_segs; i++) { _PathAddArcSegment( xc, yc, th0 + i * th_arc / n_segs, th0 + (i + 1) * th_arc / n_segs, inRx, inRy, inXAxisRotation); } }
void VRect::SetPosTo (const VPoint& inPos) { SetPosBy(inPos.GetX() - fX, inPos.GetY() - fY); }
/*! This method returns properly sorted dual linked list of all vertices (including crossing ones) of this segment collection. The method should be called after normalize(). The list created here is used as a source data when the new polygons are generated. All logic operations are using this data. This is effectively the input polygon vertices and the crossing points lined-up conterclockwise*/ logicop::VPoint* logicop::segmentlist::dump_points() { logicop::VPoint* vlist = NULL; for (unsigned i = 0; i < _segs.size(); i++) _segs[i]->dump_points(vlist); logicop::VPoint* lastV = vlist; VPoint* centinel = NULL; while (vlist->prev()) { if (-1 == vlist->visited()) centinel = vlist; vlist = vlist->prev(); } lastV->set_next(vlist); vlist->set_prev(lastV); if (NULL != centinel) { VPoint* vwork = centinel; do { if (-1 == vwork->visited()) { //here visited == 0 means only that the object is Cpoint. VPoint* tbdel = NULL; if ((*vwork->cp()) == (*vwork->prev()->cp())) { tbdel = vwork->prev(); vwork->set_prev(vwork->prev()->prev()); vwork->prev()->set_next(vwork); } else if ((*vwork->cp()) == (*vwork->next()->cp())) { tbdel = vwork->next(); vwork->set_next(vwork->next()->next()); vwork->next()->set_prev(vwork); } vwork = vwork->next(); if (tbdel) delete tbdel; } else vwork = vwork->next(); } while (centinel != vwork); } return vlist; }
/*!The method uses #_shape1 and #_shape2 structure as an input data and produces one or more polygons representing the result of the logical OR between the input polygons. Method returns false if no output shapes are generated, and true otherwise*/ bool logicop::logic::OR(pcollection& plycol) { bool result = false; VPoint* centinel = NULL; if (0 == _crossp) { // If there are no crossing points found, this still does not mean // that the operation will fail. Polygons might be fully overlapping... // Check that a random point from poly1 is inside poly2 ... if (_shape1->inside(_poly2)) centinel = _shape2; // ... if not, check that a random point from poly2 is inside poly1 ... else if (_shape2->inside(_poly1)) centinel = _shape1; // ... if not - polygons does not have any common area else return false; // If we've got here means that one of the polygons is completely // overlapped by the other one. So we need to return the outer one pointlist *shgen = new pointlist(); VPoint* vpnt = centinel; do { shgen->push_back(TP(vpnt->cp()->x(), vpnt->cp()->y())); vpnt = vpnt->next(); }while (centinel != vpnt); plycol.push_back(shgen); return true; } pcollection lclcol; // local collection of the resulting shapes // get first external and non crossing point centinel = getFirstOutside(_poly2, _shape1); if (NULL == centinel) centinel = getFirstOutside(_poly1, _shape2); assert(centinel); VPoint* collector = centinel; bool direction = true; /*next*/ do { if (0 == collector->visited()) { pointlist *shgen = new pointlist(); VPoint* pickup = collector; direction = (0 == lclcol.size()); do { pickup = pickup->follower(direction); shgen->push_back(TP(pickup->cp()->x(), pickup->cp()->y())); } while (pickup != collector); direction = true; lclcol.push_back(shgen); result = true; } collector = collector->next(); } while (collector != centinel); if (!result) return result; // Convert all collected shapes to a single normalized polygon pointlist* respoly = lclcol.front();lclcol.pop_front(); while (0 < lclcol.size()) { respoly = hole2simple(*respoly, *(lclcol.front())); lclcol.pop_front(); } plycol.push_back(respoly); return result; }
/*!The method uses #_shape1 and #_shape2 structure as an input data and produces one or more polygons representing the result of the logical AND between the input polygons. Method returns false if no output shapes are generated, and true otherwise*/ bool logicop::logic::AND(pcollection& plycol) { bool result = false; VPoint* centinel = NULL; if (0 == _crossp) { // If there are no crossing points found, this still does not mean // that the operation will fail. Polygons might be fully overlapping... // Check that a random point from poly1 is inside poly2 ... if (_shape1->inside(_poly2)) centinel = _shape1; // ... if not, check that a random point from poly2 is inside poly1 ... else if (_shape2->inside(_poly1)) centinel = _shape2; // ... if not - polygons does not have any common area else return false; // If we've got here means that one of the polygons is completely // overlapped by the other one. So we need to return the inner one pointlist *shgen = new pointlist(); VPoint* vpnt = centinel; do { shgen->push_back(TP(vpnt->cp()->x(), vpnt->cp()->y())); vpnt = vpnt->next(); }while (centinel != vpnt); plycol.push_back(shgen); return true; } bool direction = true; /*next*/ //if crossing points exists, get first external and non crossing point centinel = getFirstOutside(_poly2, _shape1); if (NULL == centinel) centinel = getFirstOutside(_poly1, _shape2); assert(centinel); VPoint* collector = centinel; do { if (0 == collector->visited()) { pointlist *shgen = new pointlist(); VPoint* pickup = collector; do { pickup = pickup->follower(direction); shgen->push_back(TP(pickup->cp()->x(), pickup->cp()->y())); } while (pickup != collector); plycol.push_back(shgen); result = true; } collector = collector->prev(); } while (collector != centinel); return result; }
void VRadialGradientPattern::_ComputeFactors() { //ensure that focal point lies inside exterior radius //(otherwise gradient drawing is undeterminate) if (fEndRadiusX != 0 && fEndRadiusY != 0 && (fStartPoint.x != fEndPoint.x || fStartPoint.y != fEndPoint.y)) { //map focal to circle coordinate space with center at end point and radius equal to fEndRadiusX GReal fx = fStartPoint.x-fEndPoint.x; GReal fy = (fStartPoint.y-fEndPoint.y)*fEndRadiusX/fEndRadiusY; if ((fx*fx+fy*fy) > fEndRadiusX*fEndRadiusX*(GReal) 0.9999*(GReal) 0.9999) //radius*0.9999 in order to avoid math discrepancy errors { //set focal to intersection with circle GReal angle = atan2(fy,fx); fy = sin(angle)*fEndRadiusX*(GReal) 0.9999; fx = cos(angle)*fEndRadiusX*(GReal) 0.9999; //map focal from circle coordinate space to user coordinate space fStartPoint.x = fx+fEndPoint.x; fStartPoint.y = fy*fEndRadiusY/fEndRadiusX+fEndPoint.y; } } //here end point and radius need to be adjusted for reflect and repeat wrapping modes if (GetWrapMode() != ePatternWrapClamp) { VPoint startPoint = fStartPoint; VPoint endPoint = fEndPoint; //map radius and focal coordinates from ellipsoid coordinate space (user space) to circular coordinate space centered on end point //(more easy to work with circular coordinate space) GReal endRadius = xbox::Max( fEndRadiusX, fEndRadiusY); if (startPoint != endPoint && fEndRadiusX != fEndRadiusY && fEndRadiusX != 0 && fEndRadiusY != 0) { VPoint focal = startPoint-endPoint; if (fEndRadiusX >= fEndRadiusY) focal.y *= fEndRadiusX/fEndRadiusY; else focal.x *= fEndRadiusY/fEndRadiusX; startPoint = endPoint + focal; } //if focal is not centered and as radius is enlarged for tiling wrapping modes, //we must modify center point to ensure ratio (dist focal to radius)/radius keep the same //otherwise drawing will not be correct if (startPoint != endPoint && endRadius != 0) { VPoint vFocalToCenter = endPoint-startPoint; GReal distFocalToCenter = vFocalToCenter.GetLength(); if (distFocalToCenter > endRadius) distFocalToCenter = endRadius; GReal distFocalToRadius = endRadius-distFocalToCenter; vFocalToCenter.Normalize(); endRadius *= kPATTERN_GRADIENT_TILE_MAX_COUNT; endPoint += vFocalToCenter*(endRadius-distFocalToRadius*kPATTERN_GRADIENT_TILE_MAX_COUNT); //ensure that focal still lies in exterior circle : //because of math discrepancy errors (especially near end radius border) we need to check that to avoid Quartz2D artifacts //map focal to circle coordinate space with center at new end point GReal fx = startPoint.x-endPoint.x; GReal fy = startPoint.y-endPoint.y; while ((fx*fx+fy*fy) > endRadius*endRadius*(GReal) 0.9999*(GReal) 0.9999) //radius*0.9999 to deal with math discrepancy errors (value 0.9999 determined by experimentation) endRadius *= (GReal) 1.01; } else //focal is centered: only enlarge radius endRadius *= kPATTERN_GRADIENT_TILE_MAX_COUNT; //update tiling datas fEndRadiusTiling = endRadius; if (endPoint != fEndPoint) { //adjust new end point position (to take account ellipsoid shape) if (fEndRadiusX >= fEndRadiusY) { GReal ratio = fEndRadiusY/fEndRadiusX; startPoint -= endPoint; //map new end point from circular coordinate space centered on last end point to user space //(this will be new origin for circular coordinate space) endPoint -= fEndPoint; endPoint.y *= ratio; fEndPointTiling = fEndPoint+endPoint; #if VERSIONMAC startPoint += fEndPointTiling; //keep start point in circular coordinate space whom origin is equal to end point //(transform to user space is delayed to gradient transform) #else //map start point to user space (ellipsoid coordinate space) startPoint.y *= ratio; startPoint += fEndPointTiling; #endif fStartPointTiling = startPoint; } else { GReal ratio = fEndRadiusX/fEndRadiusY; startPoint -= endPoint; //map new end point from circular coordinate space centered on last end point to user space //(this will be new origin for circular coordinate space) endPoint -= fEndPoint; endPoint.x *= ratio; fEndPointTiling = fEndPoint+endPoint; #if VERSIONMAC startPoint += fEndPointTiling; //keep start point in circular coordinate space whom origin is equal to end point //(transform to user space is delayed to gradient transform) #else //map start point to user space (ellipsoid coordinate space) startPoint.x *= ratio; startPoint += fEndPointTiling; #endif fStartPointTiling = startPoint; } } else { fEndPointTiling = endPoint; fStartPointTiling = startPoint; } #if VERSIONMAC //compute radial gradient transform matrix //remark: we must remap input coordinates if the radial gradient is ellipsoid and not strictly circular fMat.MakeIdentity(); if (fEndRadiusX != fEndRadiusY && fEndRadiusX != 0 && fEndRadiusY != 0) { fMat.Translate( -fEndPointTiling.GetX(), -fEndPointTiling.GetY(), VAffineTransform::MatrixOrderAppend); if (fEndRadiusX > fEndRadiusY) fMat.Scale( 1, fEndRadiusY/fEndRadiusX, VAffineTransform::MatrixOrderAppend); else fMat.Scale( fEndRadiusX/fEndRadiusY, 1, VAffineTransform::MatrixOrderAppend); fMat.Translate( fEndPointTiling.GetX(), fEndPointTiling.GetY(), VAffineTransform::MatrixOrderAppend); } #endif } #if VERSIONMAC else { //compute radial gradient transform matrix //remark: we must remap input coordinates if the radial gradient is ellipsoid and not strictly circular fMat.MakeIdentity(); if (fEndRadiusX != fEndRadiusY && fEndRadiusX != 0 && fEndRadiusY != 0) { fMat.Translate( -fEndPoint.GetX(), -fEndPoint.GetY(), VAffineTransform::MatrixOrderAppend); if (fEndRadiusX > fEndRadiusY) fMat.Scale( 1, fEndRadiusY/fEndRadiusX, VAffineTransform::MatrixOrderAppend); else fMat.Scale( fEndRadiusX/fEndRadiusY, 1, VAffineTransform::MatrixOrderAppend); fMat.Translate( fEndPoint.GetX(), fEndPoint.GetY(), VAffineTransform::MatrixOrderAppend); } } //concat with user transform if any (append in order to allow gradient shearing for instance) if (!fTransform.IsIdentity()) fMat *= fTransform; if (fGradientStyle == GRAD_STYLE_LUT || fGradientStyle == GRAD_STYLE_LUT_FAST) return; GReal startComponent[4]; GReal endComponent[4]; //compute radial gradient factors startComponent[0] = fStartColor.GetRed() / 255.0f; startComponent[1] = fStartColor.GetGreen() / 255.0f; startComponent[2] = fStartColor.GetBlue() / 255.0f; startComponent[3] = fStartColor.GetAlpha() / 255.0f; endComponent[0] = fEndColor.GetRed() / 255.0f; endComponent[1] = fEndColor.GetGreen() / 255.0f; endComponent[2] = fEndColor.GetBlue() / 255.0f; endComponent[3] = fEndColor.GetAlpha() / 255.0f; for (sLONG index = 0; index < 4; index++) { fSpreadFactor[index] = (endComponent[index] - startComponent[index]); fStartComponent[index] = startComponent[index]; } #endif }
/** Set the coordinates of this point to be the values from an existing VPoint object.*/ void Set(VPoint const& pt) { Set(pt.GetPOINT()); }