POV-Ray : Newsgroups : povray.advanced-users : problem using ORs and strcmp() in #switch/#case Server Time
31 Oct 2024 19:02:41 EDT (-0400)
  problem using ORs and strcmp() in #switch/#case (Message 1 to 10 of 36)  
Goto Latest 10 Messages Next 10 Messages >>>
From: Kenneth
Subject: problem using ORs and strcmp() in #switch/#case
Date: 7 Nov 2017 14:35:01
Message: <web.5a0209e9346fc7489df8d30@news.povray.org>
I'm having  a subtle problem that I can't pin down, when trying to use
logical-OR statements inside of #case directives. I'm using the strcmp()
function to compare various strings, plus OR blocks separating those strcmp()
comparisons inside of each #case. Posting my problematic scene code isn't
practical here (it involves lots of image_maps), but I came up with a simplified
test. I'm hoping to glean some insights into these interactions, from more
astute newsgroup observers ;-)

There are four things involved: strings, #switch/#case, the strcmp() function,
and OR.

Here's the test code, before I go into the details. Note that IMG_TYPE and AA
exactly match. The problem is that #switch is falling through to the #else
clause, when it should not do so (because  IMG_TYPE and AA *are* the same.)  If
the #case clause is successful, you'll see a GREEN box; otherwise, a
crosshatched box.  Comment-out the two OR lines for a successful test.
--------------------
#version 3.71; // or 3.7

global_settings{assumed_gamma 1.0 max_trace_level 5}
default{finish{ambient 0 emission 1 diffuse 0}}

camera {
  perspective
  location  <.5, .5, -1.5>
  look_at   <.5, .5, 0>
}

#declare IMG_TYPE = "jpg"
#local AA = "jpg"
#local BB = "png"
#local CC = "tiff"

box{0,<1,1,0>
no_shadow
pigment{
    #switch(1000)
    #case(
    // INDIVIDUALLY, these all work the way they are supposed to-- but not
    // all three at once. The OR's are causing some kind of problem, and
    // the result always fall through to the #else clause.
        (strcmp(IMG_TYPE,AA) + 1000)
        | (strcmp(IMG_TYPE,BB) + 1000)
        | (strcmp(IMG_TYPE,CC) + 1000)
         )
    srgb <0,1,0> // GREEN square
    #debug "\nAt least ONE of the #case clauses is valid.\n\n\n\n"
    #break
    #else
    // A cross-hatch warning image...
    average
    pigment_map{
         [1 gradient x+y
              frequency 6
              color_map{
                  [.25 srgb <1,0,0>]
                  [.25 srgb 0]
                        }
         ]
         [1 gradient x-y
              frequency 6
              color_map{
                  [.25 srgb <1,0,0>]
                  [.25 srgb 0]
                       }
         ]
                }
     #debug "\nNO #case clause is valid.\n\n"
     #end // of #switch
        } // end of pigment
    }
 -----------------------

I assume that a #case clause can USE logical operators like ORs??

What DOES work is to *remove* all of the OR blocks--using just ONE
strcmp() + 1000   in the #case (any one of the three). That results in correct
#switch behavior (either a 'go' of 'no go'.) That's not what I want, of course,
as I need all three in the #case statement. But is it possible that OR is not
the correct logical operator to use? One *guess* I have is that  #case is
'reading' the   strcmp()-plus-OR blocks    left to right-- and finally comes to
strcmp(IMG_TYPE,CC) + 1000,  the result of which does NOT 'match'
#switch(1000)  ... possibly causing the fall-through to the #else clause(?)

My understanding of #switch is that ANY value can be used; it doesn't
specifically need just TRUE/FALSE of 1/0, just so long as a particular #case
result matches it.  But I don't really know its hidden operation. BTW,  I didn't
use 'TRUE' in the #switch() because, when strcmp() finds two strings that
*match*, its numerical output is zero-- which should  be a logical 'false' in a
TRUE/FALSE clause, not 'true.' (AFAIU!)

Perhaps I shouldn't be using strcmp() at all. It *is* a rather complex beast--
its numerical output depends on where the various strings fall into the 'ASCII
collating sequence.' (I had to re-read the docs to try and understand this,
along with running some experiments.) My use of  +1000  in the #switch clause
(and in the #case arguments) was to try and avoid such problems, as 1000 is way
outside of the ASCII numbering sequence. But no matter *what* numerical value I
use-- while also using the ORs-- the #else clause is always invoked.

And in my real scene, I'm finding that the OR clauses *sometimes* need the added
parentheses around  the various    strcmp() + 1000   statements -- but that
seems to work inconsistently as well  :-/


Post a reply to this message

From: Bald Eagle
Subject: Re: problem using ORs and strcmp() in #switch/#case
Date: 7 Nov 2017 15:10:00
Message: <web.5a0212f11346e9e0c437ac910@news.povray.org>
I've only briefly looked this over, but it seems to me that you've misunderstood
how the switch-case/range-break-end block works.


You define #switch (trigger) - which uses a variable value "trigger" for the
rest of the case/range block to operate on.

Then every case () or range () directive is set up to operate on a specific
value of "trigger" or range of "trigger" values.
#break directives end each sub-block.
Then there's a catch-all else, then the end.

So,

#declare Clock = clock;

#switch (Clock)

#case (0.1)
#debug "The clock is at 0.1 \n"
#break

#case (0.2)
#debug "The clock is at 0.2 \n"
#break

#case (0.3)
#debug "The clock is at 0.3 \n"
#break

#case (0.4)
#debug "The clock is at 0.4 \n"
#break

#case (0.5)
#debug "The clock is at 0.5 \n"
#break

#else
#debug "The clock is over 0.5... \n"

#end


Post a reply to this message

From: Kenneth
Subject: Re: problem using ORs and strcmp() in #switch/#case
Date: 7 Nov 2017 15:50:01
Message: <web.5a021b431346e9e089df8d30@news.povray.org>
"Bald Eagle" <cre### [at] netscapenet> wrote:
> I've only briefly looked this over, but it seems to me that you've
> misunderstood how the switch-case/range-break-end block works.
>
> You define #switch (trigger) - which uses a variable value "trigger" for the
> rest of the case/range block to operate on.

Right; I used 1000 as the value of the 'trigger.'
>
> Then every case () or range () directive is set up to operate on a specific
> value of "trigger" or range of "trigger" values.

Yep. In my example-- and using only ONE comparison in the #case statement (no
ORs)-- #case((strcmp(IMG_TYPE,AA) + 1000)) is the 'correct' match for the
trigger... because strcmp(...) returns the number zero in this comparison,
and 0 + 1000 = 1000. Voila! That's a successful result (or so it seems!)
Alternately, strcmp{IMG_TYPE,BB) returns a numerical value of -6  (BB is
actually the string "png", not "jpg"-- and they are separated in the 'ASCII
numerical sequence' by -6 values or places or whatever.) So -6 + 1000 = 994,
which doesn't match #switch(1000)-- thus it falls through to the #else clause,
as it should.

The problem seems to be with my use of ORs in the #case; they seem to be
screwing up the results somehow. The *successful* (strcmp(IMG_TYPE,AA) + 1000))
comparison value is being ignored or overridden, or something!


Post a reply to this message

From: Bald Eagle
Subject: Re: problem using ORs and strcmp() in #switch/#case
Date: 7 Nov 2017 16:10:01
Message: <web.5a02208b1346e9e0c437ac910@news.povray.org>
"Kenneth" <kdw### [at] gmailcom> wrote:

> The problem seems to be with my use of ORs in the #case; they seem to be
> screwing up the results somehow. The *successful* (strcmp(IMG_TYPE,AA) + 1000))
> comparison value is being ignored or overridden, or something!

Right - I think that you can't use case() like that.

I think the Boolean comparison might yield a 0 or a 1, thus nothing ever returns
1000.

Maybe you ought to do a regular
#if (comparison1 | comparison2 | comparison3)
#declare Trigger = 1000;
#end

Then proceed as you're doing.

Or whatever else that leads you to recoding...


Post a reply to this message

From: Kenneth
Subject: Re: problem using ORs and strcmp() in #switch/#case
Date: 7 Nov 2017 16:40:01
Message: <web.5a0226a21346e9e089df8d30@news.povray.org>
"Bald Eagle" <cre### [at] netscapenet> wrote:
> "Kenneth" <kdw### [at] gmailcom> wrote:
>
> > The problem seems to be with my use of ORs in the #case; they seem to be
> > screwing up the results somehow. The *successful* (strcmp(IMG_TYPE,AA) + 1000))
> > comparison value is being ignored or overridden, or something!
>
> Right - I think that you can't use case() like that.
>
> I think the Boolean comparison might yield a 0 or a 1, thus nothing
> ever returns 1000.

Well, both of these seem to work correctly (when not using the troublesome ORs,
that is)...
#switch(0)
#case(strcmp(IMG_TYPE,AA))

#switch(1000)
#case((strcmp(IMG_TYPE,AA) + 1000)

-- which in itself is actually kind of surprising, as I assumed #switch(0) would
be the equivalent of a 'false' statement Boolean-wise or in a TRUE/FALSE
comparison. That's why I didn't use #switch(TRUE)-- also because, with *that*,
the overal results--when USING the ORs--were screwy in a different way!
>
> Maybe you ought to do a regular
> #if (comparison1 | comparison2 | comparison3)
> #declare Trigger = 1000;
> #end
>

..... or just separate the various comparisons into individual #cases. I was
trying to avoid such stuff, simply because it didn't look... compact and elegant
 ;-)


Post a reply to this message

From: Kenneth
Subject: Re: problem using ORs and strcmp() in #switch/#case
Date: 7 Nov 2017 16:50:00
Message: <web.5a022a191346e9e089df8d30@news.povray.org>
By the way...
Add these three #debug statements to my code example, right before the final
closing curly bracket. They return messages about the numerical 'differences'
(in the 'ASCII numbering sequence') between IMG_TYPE and AA,BB,CC.

#debug concat("\n","numerical value of strcmp(IMG_TYPE,AA) is
",str(strcmp(IMG_TYPE,AA),0,5),"\n\n")
#debug concat("\n","numerical value of strcmp(IMG_TYPE,BB) is
",str(strcmp(IMG_TYPE,BB),0,5),"\n\n")
#debug concat("\n","numerical value of strcmp(IMG_TYPE,CC) is
",str(strcmp(IMG_TYPE,CC),0,5),"\n\n")


Post a reply to this message

From: Kenneth
Subject: Re: problem using ORs and strcmp() in #switch/#case
Date: 7 Nov 2017 17:25:00
Message: <web.5a022f2a1346e9e089df8d30@news.povray.org>
"Kenneth" <kdw### [at] gmailcom> wrote:
> ...That's why I didn't use #switch(TRUE)-- also because, with *that*,
> the overal results--when USING the ORs--were screwy in a different way!
>

An interesting example of that:

In my code, change...
#switch(1000)
#case((strcmp(IMG_TYPE,AA) + 1000)
       | (strcmp(IMG_TYPE,BB) + 1000)
       | (strcmp(IMG_TYPE,CC) + 1000)
     )

to...
#switch(true)
#case(
       // no (strcmp(IMG_TYPE,AA), which is the only 'correct' match
       (strcmp(IMG_TYPE,BB))
       | (strcmp(IMG_TYPE,CC))
     )

This still produces a 'true' result (the GREEN box), when neither of the #case
comparisons actually 'match'. BUT... it occurs to me that a matching 'true'
value could be ANY number (positive or negative!), just so long as it's not a
zero-- which would be a 'false' result.


Post a reply to this message

From: Bald Eagle
Subject: Re: problem using ORs and strcmp() in #switch/#case
Date: 7 Nov 2017 18:20:01
Message: <web.5a023e9f1346e9e05cafe28e0@news.povray.org>
You're ---- thinking about #switch and #case() in an --- odd way.

I see where it's going wrong, and this will give you an idea of why:

    #switch(true)

    #case(1)
     rgb <0, 0, 0.2>
    #break

    #case(
       // no (strcmp(IMG_TYPE,AA), which is the only 'correct' match
       (strcmp(IMG_TYPE,BB))
       | (strcmp(IMG_TYPE,CC))
     )

#switch(true) is a very strange usage, and I'm sure clipka could give some
source-code explanation of why it works the way it does.
But basically, as I suspected, it just selects the FIRST #case() regardless of
what it is.

In fact, check out:

    #switch(strcmp(IMG_TYPE,BB) | strcmp(IMG_TYPE,CC) )

     #case(-10)
     rgb <1, 1, 0>
    #break

     #case(-6)
     rgb <1, 1, 1>
    #break

    #case(1)
     rgb <0, 0, 0.2>
    #break

    #case(1000)

It selects the blue pigment, which corresponds to 1.


So, I think you need to do something along the lines of

#declare IMG_TYPE = (some string operator on your filename)
#if IMG_TYPE = "jpg"  #local AA = 1; #end
#if IMG_TYPE = "png"  #local AA = 2; #end
#if IMG_TYPE = "tiff" #local AA = 3; #end

#select (AA)

.....


OR, since if any one of the cases you want to select for is going to yield a
value of zero for strcmp(),

#declare Pig = strcmp(IMG_TYPE,AA) * strcmp(IMG_TYPE,BB) * strcmp(IMG_TYPE,CC);

and then #select (Pig)

(that works for me)


Post a reply to this message

From: clipka
Subject: Re: problem using ORs and strcmp() in #switch/#case
Date: 7 Nov 2017 20:44:53
Message: <5a026195$1@news.povray.org>
Am 07.11.2017 um 20:32 schrieb Kenneth:

>     #switch(1000)
>     #case(
>     // INDIVIDUALLY, these all work the way they are supposed to-- but not
>     // all three at once. The OR's are causing some kind of problem, and
>     // the result always fall through to the #else clause.
>         (strcmp(IMG_TYPE,AA) + 1000)
>         | (strcmp(IMG_TYPE,BB) + 1000)
>         | (strcmp(IMG_TYPE,CC) + 1000)
>          )

Ah... yes... no, don't do that.

The `#switch`/`#case` construct is designed to be used as follows:

    // (A)
    #switch(VARIABLE)
      #case(CONST1)
        // go here if VARIABLE = CONST1
      #break
      #case(CONST2)
        // go here if VARIABLE = CONST2
      #break
      ...
    #end

It so happens that the `#case` values /can/ be other variables (and of
course the `#switch` value /can/ be a constant), allowing for a hack to
co-opt the statement as a replacement for pathologic `#if... #else #if
... #end #end` nesting:

    // (B)
    #switch(true)
      #case(CONDITION1)
        // go here if CONDITION1 is true
      #break
      #case(CONDITION2)
        // otherwise go here if CONDITION2 is true
      #break
      ...
    #end

If the conditions are string equality tests (`strcmp(...)=0`), the
following similar construct is also possible:

    // (C)
    #switch(0)
      #case(strcmp(STRING,CONST1))
        // go here if STRING = CONST1
      #break
      #case(strcmp(STRING,CONST2))
        // otherwise go here if STRING = CONST2
      #break
      ...
    #end

Note however that (B) and (C) *do not mix* nicely -- you have to decide
whether you want your `#case` expressions to be logical tests (allowing
for logical OR, AND etc.) or `strcmp()` results. You can't just try to
mix them (unless you know exactly what you're doing).

Also, there's a much easier way to achieve a logical OR in any `#switch`
construct: Just place multiple `#case` statements without a `#break` in
between, like so:

    #switch(0)
      #case(strcmp(STRING,CONST1A))
      #case(strcmp(STRING,CONST1B))
        // go here if STRING = CONST1A or CONST1B
      #break
      #case(strcmp(STRING,CONST2A))
      #case(strcmp(STRING,CONST2B))
        // otherwise go here if STRING = CONST2A or CONST2B
      #break


Finally, note that as of v3.7, (B) and (C) can be rewritten as:

    // (B)
    #if(CONDITION1)
      // go here if CONDITION1 is true
    #elseif(CONDITION2)
      // otherwise go here if CONDITION2 is true
    ...
    #end

    // (C)
    #if(STRING = CONST1)
      // go here if STRING = CONST1
    #elseif(STRING = CONST2)
      // otherwise go here if STRING = CONST2
    ...
    #end


> Perhaps I shouldn't be using strcmp() at all. It *is* a rather complex beast--

Indeed (though with the `+1000` term you're overcomplicating things).

As of v3.7, the various comparison operators (`=`, `<` etc.) are a much
better choice in most cases, now that they also support strings.


Post a reply to this message

From: Bald Eagle
Subject: Re: problem using ORs and strcmp() in #switch/#case
Date: 7 Nov 2017 21:50:00
Message: <web.5a026fc91346e9e05cafe28e0@news.povray.org>
clipka <ano### [at] anonymousorg> wrote:

> Also, there's a much easier way to achieve a logical OR in any `#switch`
> construct: Just place multiple `#case` statements without a `#break` in
> between, like so:
>
>     #switch(0)
>       #case(strcmp(STRING,CONST1A))
>       #case(strcmp(STRING,CONST1B))
>         // go here if STRING = CONST1A or CONST1B
>       #break
>       #case(strcmp(STRING,CONST2A))
>       #case(strcmp(STRING,CONST2B))
>         // otherwise go here if STRING = CONST2A or CONST2B
>       #break

Yes, I had considered mentioning this possibility (I've discovered it
accidentally by failing to include the #break(s)  :O, so I'm glad you provided
this example.

Thanks for all of the other examples - useful stuff and a very good supplement
to the official docs   :)


Post a reply to this message

Goto Latest 10 Messages Next 10 Messages >>>

Copyright 2003-2023 Persistence of Vision Raytracer Pty. Ltd.