Author Topic: INSIDEPT - Question  (Read 13412 times)

0 Members and 1 Guest are viewing this topic.

LE

  • Guest
INSIDEPT - Question
« on: March 17, 2006, 11:27:44 PM »
Here is another exercise, in this case is to port an autolisp/vlisp code into ARX from this one:

http://www.theswamp.org/index.php?topic=7785.msg98761#msg98761

Here is my code, please have a look and if possible run some tests and also all the adviced as always is welcome!

Thanks.

Code: [Select]
#include <vector>
#include <math.h>
#include <stdlib.h>

double minimumValue(vector<double> &distances)
{
int length=distances.size();
double minvalue=distances.at(0);
for(int i=1; i<length; i++)
{
if(distances.at(i) < minvalue) {
minvalue=distances.at(i);
}
}
return minvalue;
}

/////////////////

double delta (double a1, double a2) {
double ang;
if (a1 > (a2 + PI)) {
ang = ((a2 + PI + PI) - a1);
}
if (a2 > (a1 + PI)) {
ang = (a2 - a1 - PI - PI);
}
if (!(a1 > (a2 + PI)) && !(a2 > (a1 + PI))) {
ang = (a2 - a1);
}
return ang;
}

/////////////////

int isInside () {
ads_name ename;
ads_point ptres;
Acad::ErrorStatus es;
if (acedEntSel("\nSelect POLYLINE:", ename, ptres) == RTNORM) {

AcDbObjectId objId;
acdbGetObjectId(objId, ename);
AcDbObjectPointer<AcDbPolyline> pPoly( objId, AcDb::kForRead );

if ((es = pPoly.openStatus()) == Acad::eOk) {

// select test point
ads_point tstpt;
if (acedGetPoint(NULL, "\nTest point: ", tstpt) == RTNORM) {

if (pPoly->isClosed()) {

AcGePoint3d Start;
pPoly->getStartPoint(Start);

struct resbuf fromrb, torb;
fromrb.restype = RTSHORT;
fromrb.resval.rint = 1; 
torb.restype = RTSHORT;
torb.resval.rint = 0;

acedTrans(tstpt, &fromrb, &torb, FALSE, tstpt);

AcGePoint3d pt;
pt.set(tstpt[X], tstpt[Y], tstpt[Z]);

AcGePoint3d ClosestPoint;
pPoly->getClosestPointTo(pt, ClosestPoint);

if (pt.isEqualTo(ClosestPoint)) {
return RSERR;
}

double ClosestParam, End;
pPoly->getParamAtPoint(ClosestPoint, ClosestParam);
pPoly->getEndParam(End);

fromrb.restype = RTSHORT;
fromrb.resval.rint = 0; 
torb.restype = RTSHORT;
torb.resval.rint = 1;

ads_point topt;
acedTrans(asDblArray(ClosestPoint), &fromrb, &torb, FALSE, topt);

double Sample=0.2, P1=0.0, P2=Sample, Defl=0.0, a1, a2;

fromrb.restype = RTSHORT;
fromrb.resval.rint = 0; 
torb.restype = RTSHORT;
torb.resval.rint = 1;

ads_point tpt;
acedTrans(asDblArray(Start), &fromrb, &torb, FALSE, tpt);

a1 = acutAngle(tstpt, tpt);

while (P2 <= End) {
////if (P2 < End) {
//// P2 = P2;
////} else {
//// P2 = End;
////}

vector<double> distances;
distances.push_back(P2);
distances.push_back(End);
P2=minimumValue(distances);

if ((P1 < ClosestParam) && (P1 < P2)) {
a2 = acutAngle(tstpt, topt);
Defl = delta(a1,a2);
a1 = a2;
}

AcGePoint3d P;
while (pPoly->getPointAtParam(P2, P) != Acad::eOk) {
P2 = (P2 + Sample);
}// end of while

fromrb.restype = RTSHORT;
fromrb.resval.rint = 0; 
torb.restype = RTSHORT;
torb.resval.rint = 1;

ads_point Pt;
acedTrans(asDblArray(P), &fromrb, &torb, FALSE, Pt);

a2 = acutAngle(tstpt, Pt);
Defl = (Defl + delta(a1,a2));
a1 = a2;
P1 = P2;
P2 = (P2 + Sample);

}// end of while

if (abs(Defl) > 4) {
acutPrintf( "\nPoint inside.");
} else {
acutPrintf( "\nPoint outside.");
}

}//end of if isClosed
}// end of if acedGetPoint
} else {
acutPrintf("\nIt is not a POLYLINE or it can not be opened: %s",
acadErrorStatusText( es ) );
}
}
}

/////////////////

static void LESQsomefunctions_INSIDEPT(void)
{
isInside();
}

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: INSIDEPT - Question
« Reply #1 on: March 18, 2006, 12:23:49 AM »
I am loath to comment on the code, cause I'm not a CPP programmer  ..

but, functionally,

would the functionality be better if split into 2 methods ? ; one to extract the vertex points , and one which is passed the vertex point list and the point in question. If this were done, the routine could be used in the case where there is no actual physical polyline.

regards
kwb
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

--> Donate to theSwamp<--

Alexander Rivilis

  • Bull Frog
  • Posts: 212
  • Programmer from Kyiv (Ukraine)
Re: INSIDEPT - Question
« Reply #2 on: March 18, 2006, 04:16:25 AM »
Simple solution with help of AcDbMPolygon class:
Code: [Select]
enum Status {
  Outside  = -1,  // Point out of contour
  On       =  0,  // Point on contour
  Inside   =  1,  // Point inside contour
  Error    = -99  // Error
};

//////////////////////////////////////////////////////////////////////////
//       is_point_in_curve(AcGePoint3d p, AcDbCurve *pCurv)
//      -----------------------------------------------------
//  Parameters:
//    p      - testing point
//    pCurv  - testing curve (only AcDbPolyline or AcDb2dPolyline or AcDbCircle)
//
//  Return value:
//    Outside  = -1, // Point out of contour
//    On       =  0, // Point on contour   
//    Inside   =  1, // Point inside contour
//    Error    = -99 // Error             
//
//////////////////////////////////////////////////////////////////////////

inline Status is_point_in_curve(AcGePoint3d p, AcDbCurve *pCurv)
{
  double fuzz = AcGeContext::gTol.equalPoint();
  AcGePoint3d pointOnCurve;
  pCurv->getClosestPointTo(p,pointOnCurve);
  if (p.distanceTo(pointOnCurve) <= fuzz) return On;
  AcDbPolyline   *pPoly   = AcDbPolyline::cast(pCurv);
  AcDb2dPolyline *p2Poly  = AcDb2dPolyline::cast(pCurv);
  AcDbCircle     *pCircle = AcDbCircle::cast(pCurv);
  AcDbMPolygon mpol;
  if (pPoly) {
    if (mpol.appendLoopFromBoundary(pPoly)   != Acad::eOk) return Error;
  } else if (p2Poly) {
    if (mpol.appendLoopFromBoundary(p2Poly)  != Acad::eOk) return Error;
  } else if (pCircle) {
    if (mpol.appendLoopFromBoundary(pCircle) != Acad::eOk) return Error;
  } else
    return Error; // Invalid entity
  AcGeIntArray ar;
  if (mpol.isPointInsideMPolygon(p,ar) > 0) return Inside;
  else return Outside;
}
« Last Edit: March 18, 2006, 04:28:11 AM by Rivilis »

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: INSIDEPT - Question
« Reply #3 on: March 18, 2006, 04:45:02 AM »
Alexander,
Does the

isPointInsideMPolygon()
 ?
work for a crossover polygon ;  example : figure 8
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

--> Donate to theSwamp<--

Alexander Rivilis

  • Bull Frog
  • Posts: 212
  • Programmer from Kyiv (Ukraine)
Re: INSIDEPT - Question
« Reply #4 on: March 18, 2006, 04:53:17 AM »
Alexander,
Does the

isPointInsideMPolygon()
 ?
work for a crossover polygon ;  example : figure 8
No.  For crossover polygon mpol.appendLoopFromBoundary(pCircle) return Acad::eAmbiguousInput


Oops! With this changes this function also working with crossover polygon:

Code: [Select]
  inline Status is_point_in_curve(AcGePoint3d p, AcDbCurve *pCurv)
  {
    double fuzz = AcGeContext::gTol.equalPoint();
    AcGePoint3d pointOnCurve;
    pCurv->getClosestPointTo(p,pointOnCurve);
    if (p.distanceTo(pointOnCurve) <= fuzz) return On;
    AcDbPolyline   *pPoly   = AcDbPolyline::cast(pCurv);
    AcDb2dPolyline *p2Poly  = AcDb2dPolyline::cast(pCurv);
    AcDbCircle     *pCircle = AcDbCircle::cast(pCurv);
    AcDbMPolygon mpol;
    if (pPoly) {
      if (mpol.appendLoopFromBoundary(pPoly,false)   != Acad::eOk) return Error;
    } else if (p2Poly) {
      if (mpol.appendLoopFromBoundary(p2Poly,false)  != Acad::eOk) return Error;
    } else if (pCircle) {
      if (mpol.appendLoopFromBoundary(pCircle,false) != Acad::eOk) return Error;
    } else
      return Error; // Invalid entity
    AcGeIntArray ar;
    if (mpol.isPointInsideMPolygon(p,ar) > 0) return Inside;
    else return Outside;
  }

« Last Edit: March 18, 2006, 05:02:28 AM by Rivilis »

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: INSIDEPT - Question
« Reply #5 on: March 18, 2006, 05:03:01 AM »
Thanks :-)
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

--> Donate to theSwamp<--

LE

  • Guest
Re: INSIDEPT - Question
« Reply #6 on: March 18, 2006, 11:00:56 AM »
Hi Alex;

Very good sample...

Now, please if you can, in AutoCAD draw any closed polyline or circle, call the command UCS and the option OBJect.

Then, call your routine and select the object and the test point, what are the results?


Thanks!

Alexander Rivilis

  • Bull Frog
  • Posts: 212
  • Programmer from Kyiv (Ukraine)
Re: INSIDEPT - Question
« Reply #7 on: March 18, 2006, 11:49:32 AM »
Now, please if you can, in AutoCAD draw any closed polyline or circle, call the command UCS and the option OBJect.
Then, call your routine and select the object and the test point, what are the results?
Hi, Luis! This function working well in any UCS, but you must understand, that point parameter p must be in WCS and
must be projected on plan of contour:
Code: [Select]
static void CurvePointInCurve(void)
{
  ads_name en;
  AcGePoint3d p;
  Acad::ErrorStatus es;
  AcDbObjectId objId;
  AcDbCurve *pEnt = NULL;
  if (acedEntSel("\nSelect curve: ",en,asDblArray(p)) != RTNORM) return;
  if (acedGetPoint(NULL,"\nPick testing point: ",asDblArray(p)) != RTNORM) return;
  if (acdbGetObjectId(objId,en) != Acad::eOk) return;
  acdbUcs2Wcs(asDblArray(p),asDblArray(p),false);
  AcDbObjectPointer<AcDbCurve> pCurv(objId,AcDb::kForRead);
  if (pCurv.openStatus() == Acad::eOk) {
    AcGeVector3d vDir = AcGeVector3d::kZAxis;
    resbuf rb; acedGetVar("viewdir",&rb); // View direction
    vDir = asVec3d(rb.resval.rpoint);
    AcDb::Planarity plan_type;
    AcGePlane plane;   pCurv->getPlane(plane,plan_type);
    p = p.project(plane,vDir); // Project point on curve plan
    Status st = is_point_in_curve(p,pCurv.object());
    switch(st) {
      case Inside:  acutPrintf("\nInside!"); break;
      case Outside: acutPrintf("\nOutside!"); break;
      case On:      acutPrintf("\nOn!"); break;
      default:      acutPrintf("\nError!"); break;
    }
  }
}


LE

  • Guest
Re: INSIDEPT - Question
« Reply #8 on: March 18, 2006, 12:04:03 PM »
I was just trying to be picky.... you know... he he

It works as expected... !

Thanks, now I know why you work for MAESTRO.... you are one...  :kewl:

. . .

Have fun.
« Last Edit: March 19, 2006, 01:19:46 PM by LE »

Alexander Rivilis

  • Bull Frog
  • Posts: 212
  • Programmer from Kyiv (Ukraine)
Re: INSIDEPT - Question
« Reply #9 on: March 18, 2006, 12:19:34 PM »
Alex, if you can, and have some free time, please test GBPOLY, I would like to hear from a master like you.
:) Ok! And if you can, and have some time, please look at this topic: http://www.theswamp.org/index.php?topic=9133.0
As I've understood, before writing arx-program, you were lisp-programmer. Is it true?


LE

  • Guest
Re: INSIDEPT - Question
« Reply #10 on: March 18, 2006, 12:29:57 PM »
Alex, if you can, and have some free time, please test GBPOLY, I would like to hear from a master like you.
:) Ok! And if you can, and have some time, please look at this topic: http://www.theswamp.org/index.php?topic=9133.0
As I've understood, before writing arx-program, you were lisp-programmer. Is it true?



Yes, I have tested your sample for the DYN_TEST command, very good, I like the ability of having in lisp the grread, not loosing the dragging, something not possible in plain autolisp as far as I know...

I am fairly new with ARX just about 14 or 15 months now, most of the previous code I did was ADS or half-half ADS/ARX... I am now in the route to learn more about just plain ARX... as you can see I'm still in diapers...  :-)

Yes I used to write a lot in lisp....

Alexander Rivilis

  • Bull Frog
  • Posts: 212
  • Programmer from Kyiv (Ukraine)
Re: INSIDEPT - Question
« Reply #11 on: March 18, 2006, 01:00:33 PM »
Yes, I have tested your sample for the DYN_TEST command, very good, I like the ability of having in lisp the grread, not loosing the dragging, something not possible in plain autolisp as far as I know...
Yes. In plain autolisp you can not use object snap, menu, and many other things that you can use with this function. That is why I wrote this function.
I am fairly new with ARX just about 14 or 15 months now, most of the previous code I did was ADS or half-half ADS/ARX... I am now in the route to learn more about just plain ARX... as you can see I'm still in diapers...  :-)
I've began writing with C++ (ADS,ARX,ObjectARX) in AutoCAD R11 (in AutoCAD R10 I can only used AutoLisp)

P.S.: What about to make function which testing contour in contour? With help of class AcDbMPolygon it is not very difficult. :-)

LE

  • Guest
Re: INSIDEPT - Question
« Reply #12 on: March 18, 2006, 01:02:53 PM »
but, functionally,

the routine could be used in the case where there is no actual physical polyline.

Hi Kerry;

I would go the math route for that one, but we have masters on ARX now here, and it might be already something available in the ARX classes...

Arc/Curve data can be a problem... but it sound like an excellent exercise.... [do you have an specific case, where it would be needed something like this?]
« Last Edit: March 18, 2006, 01:05:57 PM by LE »

Alexander Rivilis

  • Bull Frog
  • Posts: 212
  • Programmer from Kyiv (Ukraine)
Re: INSIDEPT - Question
« Reply #13 on: March 18, 2006, 01:09:46 PM »
but, functionally,
the routine could be used in the case where there is no actual physical polyline.
I think this code do it for any contour, which can be represent with array of vertexes and array of bulges.
If all bulges == 0.0 you need to create array of bulges which length is the length of vertexes array and
set zero value for every element of bulges array:

Code: [Select]
inline Status is_point_in_curve(AcGePoint3d p, AcGePoint2dArray &pts)
{
  AcDbMPolygon mpol;
  // If contour is not closed - close it!
  if (pts.first() != pts.last()) {
    pts.append(pts.first());
  }
  // Set  bulges for all vertexes to 0.0
  AcGeDoubleArray blgs; blgs.setLogicalLength(pts.length());
  for (int i=0; i<blgs.length(); i++) blgs[i]=0.0;
  if (mpol.appendMPolygonLoop(pts,blgs) != Acad::eOk) return Error;
  AcGeIntArray ar;
  if (mpol.isPointOnLoopBoundary(p,0)) return On;
  if (mpol.isPointInsideMPolygon(p,ar) > 0) return Inside;
  else return Outside;
}

inline Status is_point_in_curve(AcGePoint3d p, AcGePoint2dArray &pts, AcGeDoubleArray &blgs)
{
  AcDbMPolygon mpol;
  // If contour is not closed - close it!
  if (pts.first() != pts.last()) {
    pts.append(pts.first());
    blgs.append(0.0);
  }
  if (mpol.appendMPolygonLoop(pts,blgs,false) != Acad::eOk) return Error;
  AcGeIntArray ar;
  if (mpol.isPointOnLoopBoundary(p,0)) return On;
  if (mpol.isPointInsideMPolygon(p,ar) > 0) return Inside;
  else return Outside;
}
:)
« Last Edit: March 18, 2006, 01:44:17 PM by Rivilis »

LE

  • Guest
Re: INSIDEPT - Question
« Reply #14 on: March 18, 2006, 03:41:12 PM »
P.S.: What about to make function which testing contour in contour? With help of class AcDbMPolygon it is not very difficult. :-)

Maybe for you, you are master on C++/ARX  :-)

Here is one approach:

Code: [Select]
static void LESQsomefunctions_PINP(void)
{
ads_name en;
AcGePoint3d p;
Acad::ErrorStatus es;
AcDbObjectId objId1, objId2;
AcDbCurve *pEnt = NULL;
if (acedEntSel("\nSelect first curve: ",en,asDblArray(p)) != RTNORM) return;

if (acdbGetObjectId(objId1,en) != Acad::eOk) return;
AcDbObjectPointer<AcDbCurve> pCurv1(objId1,AcDb::kForRead);

if (acedEntSel("\nSelect second curve: ",en,asDblArray(p)) != RTNORM) return;

if (acdbGetObjectId(objId2,en) != Acad::eOk) return;
AcDbObjectPointer<AcDbCurve> pCurv2(objId2,AcDb::kForRead);

if ((pCurv1.openStatus() == Acad::eOk) &&
(pCurv2.openStatus() == Acad::eOk)) {

AcDbPolyline *pPoly1 = AcDbPolyline::cast(pCurv1.object());
AcDbPolyline *pPoly2 = AcDbPolyline::cast(pCurv2.object());

AcGePoint3dArray points;
es = pPoly1->intersectWith(pPoly2, AcDb::kOnBothOperands, points);
int len;
if ((es != Acad::eOk) || ((len = points.length()) == 0)) {

AcGePoint3d point;
double params;
unsigned int num = pPoly2->numVerts();

AcDbMPolygon mpol;
AcGeIntArray ar;

mpol.appendLoopFromBoundary(pPoly1,false);

long cont;
for (cont=0; cont < (num - 1); cont++) {
pPoly2->getPointAtParam((double)cont, point);
if (mpol.isPointInsideMPolygon(point, ar) > 0) {
acutPrintf("\nInside!");
} else {
acutPrintf("\nNOT Inside!");
}
}
} else {
acutPrintf("\nNOT Inside!");
}
}
}//end of command PINP

Kind of Mickey Mouse if you ask me.... he he