Hot Door CORE Forum
transforming patterns - Printable Version

+- Hot Door CORE Forum (http://hotdoorcore.com/forum)
+-- Forum: All forums (http://hotdoorcore.com/forum/forumdisplay.php?fid=1)
+--- Forum: Bugs (http://hotdoorcore.com/forum/forumdisplay.php?fid=5)
+--- Thread: transforming patterns (/showthread.php?tid=125)



transforming patterns - Rick Johnson - 04-08-2017

Following C code that's worked perfectly to reset a pattern's transformations, I did the CORE equivalent when iterating through an artVector. I'm reporting this as a bug because although there's no indication to that effect in the header notes, Xcode tells me the four marked properties are "not assignable:"

Code:
// switch (hdi::core::ArtType typ) {

case hdi::core::ArtTypePath:{
    hdi::core::PathStyle pStyl = (*iter)->path()->style();
    if (pStyl.fill.color.colorType() == hdi::core::ArtColor::TypePattern){
        pStyl.fill.color.pattern().transform.setIdentity(); // <======  see more notes below
        pStyl.fill.color.pattern().shiftDistance = 0.0; // <========= won't assign value
        pStyl.fill.color.pattern().shiftAngle = hdi::core::Angle::Zero();
        pStyl.fill.color.pattern().scaleX = 1.0; // <=========== won't assign value
        pStyl.fill.color.pattern().scaleY = 1.0; // <============= won't assign value
        pStyl.fill.color.pattern().rotation = 0.0;
        pStyl.fill.color.pattern().reflect = false; // <============ won't assign value
        pStyl.fill.color.pattern().reflectAngle = 0.0;
        pStyl.fill.color.pattern().shearAngle = 0.0;
        pStyl.fill.color.pattern().shearAxis = 0.0;
        (*iter)->path()->setStyle(pStyl);
    {

I could, of course, mix SDK with CORE, but I'd really rather not make a patchwork of two libraries, and I figured if this wasn't the behavior you had intended, you'd want to fix it.

In doing more experiments to try to understand the unexpected behaviors of matrices in CORE, I added several std::cout statements and found this:

Code:
hdi::core::TransformMatrix tmx = (*iter)->path()->style().fill.color.pattern().transform;
// original matrix tmx = tx ty a b c d: 0 -64 1 0 0 1

if (pStyl.fill.color.pattern().transform.invert(tmx)){
    // inverted matrix = -0 64 1 -0 -0 1

    (*iter)->transformWithOptions(tmx, hdi::core::Art::TransformOptionFillPatterns);
    // transformed matrix = 0 -128 1 0 0 1, expected to see 0 0 1 0 0 1

    (*iter)->path()->style().fill.color.pattern().transform.setIdentity();
    // matrix set to identity = 0 -128 1 0 0 1
}

Shouldn't tx be 0 rather than 128? Running the same code again, tx is usually the inverse double but, I might also get this:

matrix inverted = -0 128 1 -0 -0 1
matrix transformed = 0 -146.358 1 0 0 1
matrix set to identity = 0 -146.358 1 0 0 1

This code, however, works as expected:

Code:
tmx.concatTranslate(h,v);
(*iter)->transformWithOptions(tmx, hdi::core::Art::TransformOptionFillPatterns);

Thanks! -- Rick


RE: transforming patterns - garrett - 04-08-2017

The docs for hdi::core::ArtColor::pattern() says it returns "a new PatternStyle struct for the target ArtColor". It truly means "new". The returned object is created anew every time you call the method. As such, trying to set new values for its members will not be retained through subsequent calls, and the new values will have no effect on the actual pattern art at all.

If you want to change the actual pattern art, create a new ArtColor object from a PatternStyle object via the appropriate constructor. Then apply said ArtColor object to the fill or stroke of the art's path style.


RE: transforming patterns - Rick Johnson - 04-09-2017

Thanks for the clarification, Garrett. The problem with the first code snippet makes perfect sense now.

As for code snippet 2, the docs for inverting a matrix says "If the inverse of the target matrix were concatenated with the target itself, the result would be an identity matrix." That's exactly the result I want. If I perform a transformWithOptions as in the third code snippet using an identity matrix with a pattern that has been manipulated, it does nothing, which is what I would expect; it appears that the function doesn't apply the matrix, it concatenates it. When I simply concat translations to an identity matrix, it works fine. When I get (a copy of) the art's matrix and invert it, its values appear to be correct. For example, [ 3 3 1 0 0 1 ] becomes [ -3 -3 1 -0 -0 1 ]. When I transformWithOptions using this matrix, wouldn't one expect the pattern to shift back to [ 0 0 1 0 0 1 ]? Instead its ty becomes 6. It's interesting that the error always appears in the ty value and that transform.invert() will return true and invert an identity matrix. Here's the code I ran on a transformed pattern fill. Even if the matrix variable is a copy, I'm sure it's always a fresh copy of the original.

Code:
hdi::core::TransformMatrix tmx;
std::cout<<"new matrix "<<tmx.tx<<" "<<tmx.ty<<" "<<tmx.a<<" "<<tmx.b<<" "<<tmx.c<<" "<<tmx.d<<std::endl;
tmx = (*iter)->path()->style().fill.color.pattern().transform;
std::cout<<"original matrix "<<tmx.tx<<" "<<tmx.ty<<" "<<tmx.a<<" "<<tmx.b<<" "<<tmx.c<<" "<<tmx.d<<std::endl;
if ((*iter)->path()->style().fill.color.pattern().transform.invert(tmx)){
    std::cout<<"matrix inverted "<<tmx.tx<<" "<<tmx.ty<<" "<<tmx.a<<" "<<tmx.b<<" "<<tmx.c<<" "<<tmx.d<<std::endl;
    (*iter)->transformWithOptions(tmx, hdi::core::Art::TransformOptionFillPatterns);
    tmx = (*iter)->path()->style().fill.color.pattern().transform;
    std::cout<<"matrix transformed "<<tmx.tx<<" "<<tmx.ty<<" "<<tmx.a<<" "<<tmx.b<<" "<<tmx.c<<" "<<tmx.d<<std::endl<<std::endl;
}

I've been studying and experimenting for hours now trying to construct a new ArtColor object from a PatternStyle object. There are constructors for various color models, but none for gradients or patterns. Assignment with "=" doesn't work, nor do statements like hdi::core::ArtColor myColor(myPattern) because of type differences. Can you please advise how to do that? It would be really nice to be able to simply apply an identity transformation matrix to a pattern fill or point text object as in AppleScript where it removes all transformations.


RE: transforming patterns - garrett - 04-10-2017

Regarding the TransformationMatrix issue, I strongly suspect that's a bug with Illustrator when using the TransformOptionFillPatterns option. We successfully utilize transformation matrices (and inversions thereof) prolifically in our plugins with no issues, but not in regards to patterns (so we've not encountered the possible bug before).

To create an ArtColor from a pattern, you first must create a PatternStyle object to pass to the right ArtColor constructor. To create a PatternStyle object, you first must acquire the Pattern object in question so you can utilize PatternStyle's constructor. Use the hdi::core::CurrentDocument::patternAtIndex() function to get the pattern you're after. You can create an entirely new pattern with the hdi::core:Tongueattern::create() static method.


RE: transforming patterns - Rick Johnson - 04-10-2017

I think I understand the first and last steps, but there's a chasm in between that's eluding me. Say I start with:

hdi::core:TongueathStyle pStyl = (*iter)->path()->style();
hdi::core::ArtColor:TongueatternStyle patStyl(pStyl.fill.color.pattern());

Now I have a copy of the original PathStyle, and a copy of the PatternStyle. I modify the PatternStyle like so:

patStyl.transform.setIdentity();
patStyl.shiftDistance = 0.0;
patStyl.shiftAngle = hdi::core::Angle::Zero();
etc.

Next, my choices for ArtColor constructors that I see in hdicoreArtColor.h are:

* ArtColor(const ArtColor& c_);

So I try many variations like this:

pStyl.fill.color = hdi::core::ArtColor(patStyl);
pStyl.fill = hdi::core::FillStyle(patStyl);


All I've tried give "no matching conversion" errors.

* ArtColor(const double grayVal_);
* ArtColor(const double rVal_, const double gVal_, const double bVal_);
* ArtColor(const double cVal_, const double mVal_, const double yVal_, const double kVal_);

Obviously none of these is appropriate.

* ArtColor();

This generic route seems to be a possibility, but I can't find a way to coerce the PatternStyle into it. Besides, the existing copy is already of type TypePattern, a setting I can't find a way to programmatically set in an empty object.

* ArtColor& operator=(const ArtColor& rhs_); // doesn't work either

Once I somehow plug the PatternStyle into the temporary PathStyle, I can assign it back to the original art like so:

(*iter)->path()->setStyle(pStyl);

Could you please show me the code I need (in place of the lines above in blue) to add my PatternStyle to the ArtColor in my PaintStyle variable so I can apply it? It would be a huge help.


RE: transforming patterns - garrett - 04-11-2017

Make sure you have the latest version of CORE. Perhaps the issue is that you're using an older version that does not have the proper functions at all.

The latest version has the following on line 821 of hdicoreArtColor.h:

Code:
/**
    \brief    Constructs an ArtColor object from a PatternStyle
    \author    GW
    \date    11/2016
    
    \param    ps_        The PatternStyle object, from which the ArtColor will be derived
*/
ArtColor(const PatternStyle& ps_);

That constructor obviously takes a PatternStyle object. This is from line 719 of hdicoreArtColor.h:

Code:
/**
    \brief    Constructs a new PatternStyle object with the given values
    \author    GW
    \date    12/2013
    
    \param    pattern_        (See pattern member description)
    \param    shiftDist_        (See shiftDistance member description)
    \param    shiftAngle_        (See shiftAngle member description)
    \param    scaleX_            (See scaleX member description)
    \param    scaleY_            (See scaleY member description)
    \param    rotation_        (See rotation member description)
    \param    reflect_        (See reflect member description)
    \param    reflectAngle_    (See reflectAngle member description)
    \param    shearAngle_        (See shearAngle member description)
    \param    shearAxis_        (See shearAxis member description)
    \param    transform_        (See transform member description)
*/
PatternStyle(
    const core::Pattern& pattern_,
    const double shiftDist_,
    const core::Angle& shiftAngle_,
    const double scaleX_,
    const double scaleY_,
    const core::Angle& rotation_,
    const bool reflect_,
    const core::Angle& reflectAngle_,
    const core::Angle& shearAngle_,
    const core::Angle& shearAxis_,
    const core::TransformMatrix& transform_
);

To acquire a Pattern object, use the following from line 806 of hdicoreCurrentDocument.h:

Code:
/**
    \brief        Gets a given pattern, by its index, in the current doc
    \author        GW
    \date        11/2013

    \param        index_    Index number of the pattern in question
    \returns    The Pattern object with the specified index
*/
std::auto_ptr<Pattern> patternAtIndex(const uint32_t index_) const;

Or, you can create an entirely new Pattern object using the following from line 63 of hdicorePattern.h:

Code:
/**
    \brief        Creates a new Pattern object (and Illustrator pattern); set the source art for it with
                the setSourceArt() method
    \author        GW
    \date        11/2013
    
    \returns    A new Pattern object
*/
static Pattern create();

Hopefully that helps.


RE: transforming patterns - Rick Johnson - 04-11-2017

Thanks, Garrett! This is exactly what I need. I was using CORE 0.6.3 and the pattern constructor wasn't there. I downloaded the brand new 0.7.0 (you've been busy...) and update my project, and the constructor worked perfectly! Thank you so very, very much for all you do!