Hot Door CORE Forum
ArtVectors and iterators - Printable Version

+- Hot Door CORE Forum (http://hotdoorcore.com/forum)
+-- Forum: All forums (http://hotdoorcore.com/forum/forumdisplay.php?fid=1)
+--- Forum: Getting started (http://hotdoorcore.com/forum/forumdisplay.php?fid=6)
+--- Thread: ArtVectors and iterators (/showthread.php?tid=86)



ArtVectors and iterators - Rick Johnson - 07-20-2016

After finding many, many ways not to use iterators to step through ArtVectors (the kind returned by matchingArt, etc.), I'm really curious what the correct way is. Or any way that produces fewer than three build-stopping errors in one simple for statement (I'm not kidding). It's easy to get ArtVectors and even access the Art objects they reference by index number, but I can't for the life of me access the vectors as vectors rather than simple arrays. Several of my plugins will make extensive use of them, iterating though the objects to narrow down a search, for which I sure hope CORE's ArtVectors support the erase function. -- rj


RE: ArtVectors and iterators - Rick Johnson - 07-21-2016

Am I going in the right direction with this? Say I want to find all selected objects at a given point:

Code:
// ArtboardPoint variable pt passed to the function
hdi::core::CurrentDocument* currDoc = HDI_CORE_ILLUSTRATOR->currentDocument();
hdi::core::Art::ArtVector vMatches;
vMatches = currDoc->artAtPoint(Pt, hdi::core::SegPointOrInteriorHitRequest);
bool sel;
for(std::vector<hdi::core::Art*>::iterator iter = vMatches.begin(); iter != vMatches.end(); ++iter)
{
    sel = (*iter)->selected();
    if ( !sel ) vMatches.erase(iter);
}

// do something with the art object

vMatches.clear();

This code seems to work, but I'm flying by the seat of my pants here. The docs say we're responsible for the memory used by the ArtVector; does the clear() function suffice for aforementioned memory management? I saw in hdicoreMemory.h a template (I've never used one of those before!) that deletes each object pointed to in the vector, then performs a .clear(). Isn't the ArtVector returned by matchingArt, etc., analogous to an address list of the relevant objects, rather than complete copies of them? I'd be most grateful if someone can keep me out of trouble with this...


RE: ArtVectors and iterators - Rick Johnson - 07-23-2016

Continuing to work with the ArtVector, in AI6 I click on several one-segment curved or straight paths at the point where they intersect. I get a vector with the correct number of entries. Whether I access the art object or its path directly or via a variable:

thisArt->artType();
or
(*iter)->artType();

I seem to be able to retrieve information such as art type or selected state, but am unable to set its selected property to true. I can access the path and again read information such as number of segments, but cannot perform functions on it such as insertSegPointAtT. It's as though I'm working with a hidden copy of the art, which disappears when my function ends.

Is there a recommended approach I should be using? -- Rick


RE: ArtVectors and iterators - garrett - 07-23-2016

(07-21-2016, 06:02 PM)Rick Johnson Wrote: This code seems to work, but I'm flying by the seat of my pants here. The docs say we're responsible for the memory used by the ArtVector; does the clear() function suffice for aforementioned memory management? I saw in hdicoreMemory.h a template (I've never used one of those before!) that deletes each object pointed to in the vector, then performs a .clear(). Isn't the ArtVector returned by matchingArt, etc., analogous to an address list of the relevant objects, rather than complete copies of them? I'd be most grateful if someone can keep me out of trouble with this...

The vector stores pointers to Art objects, which were dynamically allocated on the heap. As such, by simply clearing the vector, you are leaking the memory being pointed to by the elements in the vector. The templated functions in hdicoreMemory.h are exactly the right tool for this circumstance. Simply pass "vMatches" to the hdi::core::cleanupVector() function and it takes care of everything.

With regards to removing individual elements from a vector, your sample code is very close. However, the iterator object is no longer valid after you have erased the element to which it refers, and so the behavior of the overloaded "++" operator in the "for" loop is undefined. As such, make a copy of the iterator, call the overloaded "++" operator on the original, and then pass the copy to the erase method. Don't forget to delete the memory for the Art pointer before erasing the element, and don't forget that the call to the "++" operator in the "for" loop will mess with this situation, so I recommend switching to a "while" loop.

Otherwise, you could simply create a secondary vector of Art pointers, and push the desired elements from "vMatches" into it. Then, after you have processed the elements in the secondary vector, clear it, and call hdi::core::cleanupVector() - passing "vMatches".


RE: ArtVectors and iterators - Rick Johnson - 07-24-2016

Thanks, Garrett. I'm still puzzled, though. When I run this:

Code:
        // Pt is an ArtboardPoint passed to the function
        hdi::core::Art::ArtVector vMatches;
        vMatches = currDoc->artAtPoint(Pt, hdi::core::SegPointOrInteriorHitRequest);
        for(std::vector<hdi::core::Art*>::iterator iter = vMatches.begin(); iter != vMatches.end(); ++iter)
        {
            hdi::core::HitData pHit(hdi::core::HitData(*iter, Pt, hdi::core::SegPointOrInteriorHitRequest,4.0));
            if (!pHit.isEmpty())
            {
                hdi::core::ArtType typ = pHit.art()->artType();
                std::cout<<typ<<std::endl;
                std::cout <<"segcount "<<pHit.art()->path()->segCount()<<std::endl;
                pHit.art()->path()->insertSegPointAtT(pHit.segIndex(),pHit.tValue());
                std::cout<<"seg no "<<pHit.segIndex()<<std::endl;
                std::cout<<"seg T "<<pHit.tValue()<<std::endl;
                std::cout <<"segcount "<<pHit.art()->path()->segCount()<<std::endl;
            }
        }
        vMatches.clear();
        hdi::core::cleanupVector(vMatches);

My compiler output shows this:

Code:
110
segcount 1
seg no 0
seg T 0.500001
segcount 2
110
segcount 1
seg no 0
seg T 0.500002
segcount 2
110
segcount 1
seg no 0
seg T 0.500003
segcount 2

So each time through the loop, it found a path art with one segment, added a SegmentPoint near the path midpoint (which is where I'd expect given the three intersecting text paths), and confirmed that there were now two segments. Going back to my AI document, nothing has changed. What art did I manipulate? Does the vector contain pointers to existing art or does it create duplicates? Gee, I'm really missing AI's debug screen right now...


RE: ArtVectors and iterators - garrett - 07-24-2016

(07-24-2016, 09:45 AM)Rick Johnson Wrote:
Code:
    hdi::core::HitData pHit(hdi::core::HitData(*iter, Pt, hdi::core::SegPointOrInteriorHitRequest,4.0));

There is no need to create a HitData object and then create a copy of it with the copy constructor. Simply do this instead:
Code:
    hdi::core::HitData pHit(*iter, Pt, hdi::core::SegPointOrInteriorHitRequest,4.0);

(07-24-2016, 09:45 AM)Rick Johnson Wrote:
Code:
    if (!pHit.isEmpty())

As the documentation states, all this does is check whether the HitData object refers to any actual hit data, rather than referring to nothing (which would happen if you constructed a HitData object with the default constructor). Any CORE class which has a "isEmpty()" method behaves like this.

If you want to check whether the HitData object recorded an actual hit, you must use the hdi::core::HitData::hit() method.

(07-24-2016, 09:45 AM)Rick Johnson Wrote:
Code:
        vMatches.clear();
        hdi::core::cleanupVector(vMatches);

If you clear the vector before calling "hdi::core::cleanupVector()" then the vector is already emptied, so the function will not help in any way (i.e. you will still leak the memory for the Art objects). Simply call "hdi::core::cleanupVector()" on its own instead.

(07-24-2016, 09:45 AM)Rick Johnson Wrote: Going back to my AI document, nothing has changed. What art did I manipulate? Does the vector contain pointers to existing art or does it create duplicates? Gee, I'm really missing AI's debug screen right now...

You manipulated the real art. In what type of event did you perform this action? Remember that CORE automatically handles all the strange undo operations the SDK requires during mouse drag events, so no changes will stick unless you additionally perform them in a mouse up event (where no undo operations take place). If I had to take a shot in the dark, I would guess this is your problem.


RE: ArtVectors and iterators - Rick Johnson - 07-24-2016

You're a great shot, Garrett; this was done in a mouseDown event. My tool does one function on the click, and another function as the user drags. I think I can see now that it can (and should) all be handled in the mouseUp event.

Thanks also for clearing up some things I had reservations about. Today now looks like it'll be a very productive one! :-)