How to achieve 'donut holes' with paths in Raphael - vector

I'd like to draw a shape which has holes in it such that I can fill the shape it and not have the holes filled with that colour (leave them transparent).
According to the W3 path spec:
Compound paths (i.e., a path with multiple subpaths) are possible to allow effects such as "donut holes" in objects.
Can somebody please give a very simple example of how to perform this with a vector path in Raphael?
Thanks very much.

This turns out to be quite straightforward if you know the trick. For example this doesn't work:
paper.path("M 50 50 L 50 150 L 150 150 L 150 50 z" +
" M 75 75 L 75 125 L 125 125 L 125 75 z")
.attr("fill", "#f00");
But this does work*:
paper.path("M 50 50 L 50 150 L 150 150 L 150 50 z" +
" M 75 75 L 125 75 L 125 125 L 75 125 z")
.attr("fill", "#f00");
The difference is that for the donut to appear the the inner path has to have it's vertices drawn in reverse order to the outer path (ie. draw one clockwise, the other anti-clockwise). A tidbit I found on the text.xml.svg.devel archives.
(*) At least, it works in Chrome, Opera and Firefox 4.0 beta, but not in 3.6

To make this work in Firefox 3.6, you need to close the hole; i.e. make the coordinates join back to themselves when defining the inner boundary. Curiously, this doesn't appear necessary for the outer boundary.
paper.path("M 50 50 L 50 150 L 150 150 L 150 50 z" +
" M 75 75 L 125 75 L 125 125 L 75 125 L 75 75 z")
.attr("fill", "#f00");
Just a quick note to follow up on the comment - the clockwise/counter-clockwise concept might seem strange at first, but it's pretty standard throughout GIS / CAD technologies.

I think the correct way to do this is setting the attribute "fill-rule" to the value "evenodd". Take a look at the svg spec:
Don't try to set it with "Raphael.Element.attr()". It doesn't work. I use the jQuery.attr() function instead:
// assuming paper is a Raphael.Paper object
path = paper.path('Mx,y{some path commands for the main shape}Z'
+'Mx,y{some path commands for the hole}Z'
);
// this doesn't work
path.attr({'fill-rule': 'evenodd'});
// neither this
path.attr({fillRule: 'evenodd'});
// if you inspect the object returned by paper.path
// you can see it has a reference to the DOM element
console.debug(path)
// so a bit of jQuery and it's done
$(path[0]).attr('fill-rule', 'evenodd');
I have used this on complex paths with successful results.

For anyone looking to do circular donuts, great easy plugin Raphael-donut-plugin
Gist:
Raphael.fn.donut = function(x, y, innerRadius, outerRadius) {
y -= outerRadius;
return this.path('M'+x+' '+y+'a'+outerRadius+' '+outerRadius +
' 0 1 0 1 0m-1 '+
(outerRadius - innerRadius)+
'a'+innerRadius+' '+innerRadius+
' 0 1 1 -1 0');
};

Related

SCILAB code for searching the center of figure

*Hello everyone, I need your help, I'm looking for the center of the figure in green in terms of a point with these coordinates (X, Y) that I posted on the following link: https://imgur.com/6841jk4
I tried to apply Guldin's method? ? , look for the center of gravity, the moment of inertia but in vain.
could you help me and provide me the code in scilab, because I've been looking for the solution in terms of code and mathematical analysis for a long time.
you will find attached the scilab code.
enter code here
function y = h(x)
if x < 50 | 210 < x then
error("Out of range");
elseif x <= 90 then
y= -57.376067 +9.3746343*x -0.2175008*x^2 +0.0013792*x^3
//disp('50-90')
return;
elseif x <=100 then
y= 10330.932 -336.90229*x +3.6300206*x^2 -0.0128709*x^3;
//disp('90-100')
elseif x <= 130 then
y=-6387.7416 +164.65791*x -1.3855814*x^2 +0.0038478*x^3;
//disp('100-130')
return;
else
y = 5028.1996 -98.786888*x +0.640917*x^2 -0.0013484*x^3;
//disp('130-210')
end
endfunction
t=[50:210];
plot(t,feval(t,h),'r*')
l=[50 60 90 100 130 150 210]
k=[40 20 30 70 55 80 60]
plot(l,k,'d')
for i=[40 20 30 70 55 80 60]
teta=[0: 220]
beta=linspace(100,100,221)
plot(teta,beta,'*')
teta1=[100:160:221]
beta1=linspace(100,160-2*rand(),221)
plot2d3(teta1,beta1)
end
a=gca()
a.sub_ticks = [5,5]
a.grid_thickness = [0.05,0.05];
a.grid = [-1,-1]
a.grid_position = "foreground"
//a.grid_thickness = [0.05,0.05]
xgrid(0)
C=[50 60 90 100 130 150 210]
//for j=1:size(C,'c')
//C(j)
//if c(k)<=50 then
// (m=k+1& c(m))
J=numderivative(h,t) /*jacobien*/
//f=C(j)
// J=numderivative(h,i) /*jacobien*/
deff('[z] = h2(k)', 'z = h(k)-100');
// disp(C(j))
//for i=[157.56011:204.1084]
[x,fx,v]=fsolve([150,200],h2)
disp(x)
disp(fx)
plot(x,fx+100,)
disp(v)
//plot(x,h2,'d')
//end
//po=[50 60 90 100 130 150 210]
//co=[40 20 30 70 55 80 60]
lh=linspace(157.56011,204.1084);
lpo=feval(lh,h);
xfpoly(lh,lpo)
e=gce()
e.background=13

How to compute floor(log2(5**x)) without floating point arithmetic or long integer computation

The problem is how do we compute the integer value of floor(log2(5^x)) without floating point arithmetic or long integer computation? I'm looking for a simple, efficient and mathematically elegant way.
Observations:
The formula is just the number of bits in 5**x (plus 1)
Attempts:
I tried to simplify it to:
floor(x*log2(5))
In my use case, x is not extremely large, probably just 1-100. While an elegant formula that works for small values would suffice me, I would be interested in a formula/algorithm that works for any value of x
I'm making a reference software implementation of universal numbers (type III). I want to make everything easily convertible to microcode by purely using bitwise and basic operations. This is one of the formulas i need to simplify.
As you correctly note, log2(5**x) == x * log2(5). log2(5) is a constant, which can be approximated to 2.3219281.
However, floats aren't allowed per the question. Not an issue!
log2_5 = 23219281;
scale = 10000000; // note log2_5/scale is the actual value
result = x * log2_5;
output = (result - (result % scale)) / scale;
By reducing result by result % scale, dividing it by scale will be an integer division, not a float.
for a simple, efficient and mathematically elegant way... floor(x*log2(5))
Since x has integer values 1 to 100, various tests can to made to find the "best" that uses an integer multiply and a divide by power_of_2.
f(x) = x*a integer_divide power_of_2
For
f(x) = floor(x*log2(5)) = floor(x*some_float_c) the value of some_float_c is bounded by 100 minimum and maximums below.
x f(x) mn mx
f(x)/x (f(x) + 1)/x
1 2 2.00000 3.00000
2 4 2.00000 2.50000
3 6 2.00000 2.33333
...
59 136 2.30508 2.32203
...
87 202 2.32184 2.33333
...
98 227 2.31633 2.32653
99 229 2.31313 2.32323
100 232 2.32000 2.33000
The maximum min is 2.32184 and the minimum max is 2.32203, :
2.32184... <= some_float_c < 2.32203...
Since we cannot use float, find some_integer/some_power_of_2
2.32184... <= some_integer/some_power_of_2 < 2.32203...
ceil(some_power_of_2 * 2.32184...) <= some_integer < floor(some_power_of_2 * 2.32203...)
min max
2.32184 2.32203
2 5 4
4 10 9
8 19 18
...
1024 2378 2377
2048 4756 4755
4096 9511 9511 < first one where min <= max
8192 19021 19022
So 9511/4096 is the "simplest" and is a "best" candidate.
f(x) = (x*9511) integer_divide_by_power_of_2 4096
// In C
unsigned y = (x*9511u) >> 12;
Here is a very rough approximation, but it can help if you want to obtain it mentally
5^3 = 125
2^7 = 128
So for raising to the power of n:
5^n ~~ 2^(7n/3)
So 5^12 is near 2^28 might require up to 29 bits.
It's a bit overestimated because 2^7 > 5^3, so 28 bits are enough, a good usage is to simply round the fraction upper.
If I evaluate in Smalltalk:
(1 to: 50) reject: [:i | (5 raisedTo: i) highBit = (i*7/3) ceiling].
I get:
#(31 34 37 40 43 46 49)
You see that the very simple formulation works up to 5^30 which is not that bad.

Analog to Digital input scaling equation works in codeblocks but not on Microcontroller

I'm so lost on how to fix this, it should be so simple. I'm using a pic16F1526 and trying to scale the analog to digital reading from 0-255 to 50-100 roughly. I am using this equation
result = ((user_input + 200) * 200) / 800;
In code blocks and on my calculator it works at all numbers from 0-255 and it works perfectly whether I use 8 bit, 16 bit variables in code bloacks.
I've already verified that the AtoD input is working correctly sending the data to the UART. Even if I enter static numbers in place of the sample I get weird results.
When the acd reads a 255 or I enter a 255 the equation gives me a 31 in decimal instead of 100 like it's supposed to. The only thing I can think of is something is getting messed up in the way an 8 bit PIC does it's math since it's an a bit micro.
Sounds like you are getting the correct results on in codeblack because of integer promotion and getting the incorrect results in the hardware because of variable overflow.
uint8_t Can contain 0 to 255
int8_t Can contain -126 125
uint16_t Can contain 0 to 65635
...
Assuming you have uint16_t, the micro's math will go as follows:
((255 + 200) * 200) / 800
(455 * 200) / 800 : 455 * 200 Overflows the 16 bit variable!
( 25464 ) / 800: Note that 91000 & 0xFFFF == 25464
31
You can work around this issue by simplifying your equation :
(user_input + 200) / 4 is equivalent to ((user_input + 200) * 200) / 800 and will not overflow at 16 bits although your accuracy is not very high as ImaginaryHuman072889 pointed out.
If I understand your question correctly, you want to linearly map the numbers 0-255 to the numbers 50-100.
Back to good old y = mx + b algebra.
When x = 0, y = 50. Therefore:
y = mx + b
50 = m*0 + b
b = 50
When x = 255, y = 100. Therefore:
y = mx + 50
100 = m*255 +50
m*255 = 50
m = 50/255 = 10/51
Therefore, the precise answer is:
y = (10/51)*x + 50
On a side note, I have no idea how you got the result of 31 when plugging in 100 into your formula. See below.
(255+200)*200/800 = 113.75

How to calculate coordinates of the gunpoint

Good whatever time of day! I have some sprite:
A point has coordinates Actor.x; Actor.y.
AB length = 96
BC length = 86
AC length = 42
All calculations are approximate, I made it with help the ruler in Photoshop.
Sprite always towards mouse, angle (in radians) stores in Actor.direction variable. I draw sprite with scale 0.3.
All bullets toward mouse (that is Bullet.direction == Actor.direction). I need to create bullets in the B point. How I can calculate coordinates of the B point with any angle?
UPD
If I will create bullets in the coordinates:
x = Actor.x + 96 * math.cos(Actor.direction) * 0.3
y = Actor.y + 96 * math.sin(Actor.direction) * 0.3
I get it:
Excuse my bad English! It isn't my native language. Thank you in advance!
Let
cs = math.cos(Actor.direction)
sn = math.sin(Actor.direction)
point B will be shifted from A by
dx = - 42 * sn + 86 * cs
dy = 42 * cs + 86 * sn
Perhaps you will need to change signs before both 42s
(I did not account for scale)

How to print output of .bas file to text

I am trying to print coordinate outputs of a program to a text file in order to use it in another program but I don't really know anything about GWBASIC and its my first time using MS-DOS. I need it to open a text file named plot.txt and print output there and save it without actually plotting on GWBASIC. Here is the program which I found in an old magazine.
810 REM MAKE A GLOBULAR
12 REM
14 R0=20: R2=R0*R0: R3=R2*R0
16 P1=3.14159265#
18 C0=P1*P1*R3/4
20 R1=R0/SQR(2)
22 XM=512: YM=512
24 X2=XM/2: Y2=YM/2: S=5
26 INPUT "HOW MANY STARS ";T
27 RANDOMIZE TIMER
28 CLS: REM CLEAR SCREEN
30 FOR I=1 TO T
32 C=C0*RND: R=R1
34 REM
36 REM NOW FIND R
38 FOR K=1 TO 5
40 GOSUB 100
42 R=R+(C-C1)/D
44 NEXT K
46 REM 3-DIMENSIONAL PLACE
48 X=RND-.5
50 Y=RND-.5
52 Z=RND-.5
54 S1=SQR(X*X+Y*Y+Z*Z)
56 IF S1>.5 THEN GOTO 48
58 REM POINT IS NOW IN SPHERE
60 R=R*S1: X=X*R: Y=Y*R: Z=Z*R
62 GOSUB 200
64 NEXT I
66 END
68 REM
100 REM NEWTON-RAPHSON ITERATION
105 A=R/R0
110 C1=ATN(A)*.5*R3
115 A=1+A*A
120 C1=C1+R*.5*R2/A
125 C1=P1*(C1-R*R2/(A*A))
130 D=4*P1*R*R/(A*A*A)
135 RETURN
140 REM
200 REM 2-DIMENSIONAL PLOT
203 SCREEN 9
205 X=X*S+X2: Y=Y*S+Y2
210 IF X<0 OR Y<0 THEN 225
215 IF X>=XM OR Y>=YM THEN 225
220 PSET(X,Y)
225 RETURN
230 REM ------------------------
240 REM APPEARED IN ASTRONOMICAL
250 REM COMPUTING, SKY & TELE-
260 REM SCOPE, APRIL, 1986
270 REM ------------------------
Here is a Python 3 paraphrase:
#globular.py
#Python paraphrase of model.bas from
#http://www.skyandtelescope.com/wp-content/uploads/model.bas
from math import pi, sqrt, atan
from random import uniform, random
#Global variables:
r0 = 20.0
r2 = r0**2
r3 = r0**3
c0 = pi**2*r3/4
r1 = r0/sqrt(2)
def NRI(c,r):
#Newton-Raphson Iteration
a = r/r0
c1 = atan(a)*0.5*r3
a = 1+a**2
c1 += r*0.5*r2/a
c1 = pi*(c1-r*r2/a**2)
d = 4*pi*r**2/a**3
return (c1,d)
def makeStars(t):
stars = []
for i in range(t):
c = c0*random()
r = r1
for k in range(5):
c1,d = NRI(c,r)
r += (c-c1)/d
while True:
x = uniform(-0.5,0.5)
y = uniform(-0.5,0.5)
z = uniform(-0.5,0.5)
s1 = sqrt(x**2 + y**2 + z**2)
if s1 <= 0.5: break
r *= s1
x *= r
y *= r
z *= r
stars.append((x,y,z))
return stars
def starsToFile(t,fname):
stars = makeStars(t)
f = open(fname,'w')
for star in stars:
print(*star, sep = ', ',file = f)
f.close()
I skipped the part about printing x and y and instead wrote a function makeStars to return a list of (x,y,z) tuples, as well as a related function which takes such an output and sends it to a text file. This last function is the only thing that used Python 3 instead of Python 2. If you are using Python 2 you can import Python 3's print function from the future.
Typing starsToFile(100,'stars.txt') in the Python shell gave me a text file which begins:
-0.32838465248713156, -0.3294895266926551, -1.2963580524762535
14.20224408569865, 1.4434961933043464, 6.450969593697097
1.6525937589658193, -0.24447292610082685, 1.0543647986350608
1.5707528567123823, 5.190972598268825, -2.0054790217091134
I don't have good 3-d scatter-plot graphing at my finger tips, but here is a screen shot of 50 points generated by the function and plotted using a computer algebra system called Derive:
Final remark: I wonder if there is a typo in the source code. The line
C0=P1*P1*R3/4
strikes me as suspicious since it is fairly rare in mathematics for pi to appear squared -- though it does happen. Maybe there should be only 1 factor of pi there (which would then have the effect of setting C0 proportional to the volume of the sphere of radius R0). On the other hand, I don't know exactly what is happening here, so I left it in. If the results seem problematic, you could maybe experiment with that line.
If you want a copy of the calculated coordinates simply add these lines:
1 OPEN "PLOT.TXT" FOR OUTPUT AS #1
65 CLOSE #1
221 PRINT #1, X + "," + Y
The program will work as before but in addition to this it outputs the coordinate to a file named plot.txt
Put them in an image with 640x350 size (that size is demanded by SCREEN 9) and you get the same result.

Resources