Drawing multiple circular arcs dynamically using SVG - svg

I've got SVG image (code below):
<svg height="500" width="500">
<!-- Inner line -->
<path d="M100,50 L 100,100 A 45,45 0 1,0 150,150 L 200 150" style="stroke:#000; stroke-width:6; fill:none;" />
<!-- Outer line -->
<path d="M 90,50 L 90,92.5 A 54.5,54.5 0 0,0 90,197.5 L 90, 240.5" style="stroke:#000; stroke-width:1; fill:none;" />
<circle cx="105" cy="145" r="35" stroke="black" stroke-width="1" fill="green" />
I cannot see any pattern while drawing curved lines that are separated by the same margin (I've made the image above just by "guessing"). The number of lines is dynamic so I need a formula to count every M L A parameter. E.g. I can take inner line as static (showing just the d attribute),
d="M100,50 L 100,100 A 45,45 0 1,0 150,150 L 200 150"
but then first outer should be calculated somehow, to get d:
d="M 90,50 L 90,92.5 A 54.5,54.5 0 0,0 90,197.5 L 90, 240.5"

SVG arcs are drawn with A rx ry rotation large-arc-flag sweep-flag x y
The key parameters here are rx and ry: the radii of the arc and x and y which are the final point in the arc.
For example, if you have a circle centred on (cx, cy) with radius r, you can create and arc around it, d units from the edge of the circle with:
<path d="M cx cy+r+d A r+d r+d 0 0 0 cx+r+d cy" />
This arc will be in the lower, right quadrant because of where it starts (cx, cy+r+d) and ends (cx+r+d, cy).
So call the radius of the inner arc r and the radius of the outer arc r + d. Now we need to know where to start and stop the arc. The x-coordinate of the start and stop points is d units to the left of the cx. We can find the y-coordinate by using Pythagoras's theorem to calculate the height of the triangle with a hypotenuse of r+d and a base of d:
h = sqrt((r + d)^2 - d^2).
The code for the arc will therefore be:
d="M cx-d, 50 L cx-d, cy-h A r+d r+d 0 0 0 cx-d, cy+h L cx-d, 240"
For example, with (cx, cy) = (100, 150), r = 50, and d = 10
<path d="M100,50 L 100,100 A 50,50 0 1,0 150,150 L 200 150" style="stroke:#000; stroke-width:6; fill:none;" />
<path d="M 90,50 L 90,90.8 A 60,60 0 0,0 90,209.1 L 90, 240.5" style="stroke:#000; stroke-width:1; fill:none;" />
<circle cx="100" cy="150" r="40" stroke="black" stroke-width="1" fill="green" />
Does that make sense?

Related

Radial gradient SwiftUI using SVG file input

How can I add radial gradient in SwiftUI using provided SVG file?
All I have got is below SVG file which has gradient inforamtion:
<defs>
<clipPath id>
<path d="M1890, 0 L1890, 888 L0, 888 L0, 0L1890, 0 Z" />
</clipPath>
<radialGradient id: "grad1" cx = "0px" cy = "0px" r = "1000px" gradientTransform = "scale(1.0.0.56)" gradientUnits="userSpaceOnUse">
<stop stop-color = "rgba(0,0,0,0.6)" offset="0%" />
<stop stop-color = "rgba(0,0,0,0)" offset="100%" />
</radialGradient>
<clipPath id>
<path d="0, 0 1890, 0 1890, 888 0, 888 0, 0" />
</clipPath>
</defs>
My SwiftUI code has image which needs above gradient:
Image(room.thumbnailImage)
.resizable()
.frame(maxWidth: 400, maxHeight: 140.0)

D3 path line is 0x0 size (no "d" attr is being added)

I was wondering why this D3 code just does not work:
...
console.log(data["SAT"]);
/************* Generic line definition ************/
var line = d3.line()
.x(d => xScale(d.x))
.y(d => yScale1(d.y));
/******************* SAT line *****************/
var SATPath = svg.append("g")
.attr("class", "SAT-curve")
.selectAll("path")
.data(data["SAT"])
.enter().append('path')
.attr("fill", "none")
.attr("stroke-width", 1.5)
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.attr("d", d => line(d))
.attr("stroke", colors.purple);
The console.log() line just shows data in apparently correct way:
[0 … 99]
0: {x: 0.0011, y: 178.75}
1: {x: 0.0011, y: 180.75}
...
94: {x: 0.0014, y: 366.75}
95: {x: 0.0014, y: 368.75}
96: {x: 0.0014, y: 370.75}
97: {x: 0.0014, y: 372.75}
98: {x: 0.0014, y: 374.75}
99: {x: 0.0015, y: 376.75}
[100 … 199]
[200 … 299]
[300 … 307]
length: 308
[[Prototype]]: Array(0)
... And all margin.*, xScale and yScale1 axes are correctly defined (or I think so) because they are correctly rendered.
The problem is that it generates all 308 paths with all attributes, EXCEPT the d one, and then the path results in 0x0 size:
<g class="SAT-curve">
<path fill="none" stroke-width="1.5" transform="translate(50,30)" stroke="#8e69b3"></path>
<path fill="none" stroke-width="1.5" transform="translate(50,30)" stroke="#8e69b3"></path>
<path fill="none" stroke-width="1.5" transform="translate(50,30)" stroke="#8e69b3"></path>
<path fill="none" stroke-width="1.5" transform="translate(50,30)" stroke="#8e69b3"></path>
....
<path fill="none" stroke-width="1.5" transform="translate(50,30)" stroke="#8e69b3"></path>
</g>
No JS console errors.
Any ideas?
Thanks in advance.
The data() method binds one array element to one DOM element. That said, you don't want 308 paths, you want just one path with 308 data points. Therefore, wrap everything in an outer array, witch has just one element:
.data([data["SAT"]])

Add svg path on image using vips

I am using vips PHP library. I want to add svg path on my image. I implemented below code for that but it's not giving me expected output. The problem is how can I set svg path according to the actual image height & width. I tried using resize and thumbnail but it doesn't give me expected output. Also I want to fill the grey color on my actual image blocks like in expected output image.
The expected output image generated using imagick
$background = Vips\Image::newFromFile($arg[1], ['access' => 'sequential']);
$svg = Vips\Image::svgload_buffer('<svg>
<path
d="M0 200 v-200 h200
a100,100 90 0,1 0,200
a100,100 90 0,1 -200,0
z" stroke="#fff" fill="transparent"/>
</svg>');
// $svg = $svg->resize(2.5);
$svg = $svg->thumbnail_image(700, ['height' => 700, 'size' => 'both']);
$image = $background->composite($svg, 'dest-in');
$image->writeToFile([$arg2], ['background' => [128, 128, 128], 'Q' => 100]);
Below is the image on which I added my svg path
My vips output image
Expected output image
Try:
#!/usr/bin/php
<?php
require __DIR__ . '/vendor/autoload.php';
use Jcupitt\Vips;
$background = Vips\Image::newFromFile($argv[1], ['access' => 'sequential']);
$width = $background->width;
$height = $background->height;
$svg = Vips\Image::svgload_buffer(<<<EOF
<svg
viewBox="0 0 300 300"
width="$width"
height="$height">
<path
d="M0 200 v-200 h200
a100,100 90 0,1 0,200
a100,100 90 0,1 -200,0
z" stroke="#fff" fill="white"/>
</svg>
EOF);
$image = $background->colourspace('b-w')->composite($svg, 'dest-in');
$image->writeToFile($argv[2], ['background' => [128, 128, 128], 'Q' => 100]);
Associated github issue: https://github.com/libvips/php-vips/issues/109

How to transform the right side of SVG blocks a bit to the back?

How do i transform/rotate(?) the right side of these SVG blocks to appear more the back?
The right side of the tiles should not be higher but more to the back giving it more dept.
This is my SVG.
width="1250.345px" height="350.345px" viewBox="-30 -30 1250.345 350.345" style="enable-background:new 0 0 1250.574 350.574;"
xml:space="preserve">
<g>
<path d="M 14,19 L14,100 l 100,0 l 0,-80 Z" style="fill:#B1BCB6;" />
<path d="M 117,20 L117,100 l 100,0 l 0,-80 Z" style="fill:#B1BCB6;" />
<path d="M 220,20 L220,100 l 100,0 l 0,-80 Z" style="fill:#B1BCB6;" />
</g>
<g>
<path d="M 14,103 L14,183 l 100,0 l 0,-80 Z" style="fill:#B1BCB6;" />
<path d="M 117,103 L117,183 l 100,0 l 0,-80 Z" style="fill:#B1BCB6;" />
<path d="M 220,103 L220,183 l 100,0 l 0,-80 Z" style="fill:#B1BCB6;" />
</g>
<g>
<path d="M 14,187 L14,267 l 100,0 l 0,-80 Z" style="fill:#B1BCB6;" />
<path d="M 117,187 L 117,267 l 100,0 l 0,-80 Z" style="fill:#B1BCB6;" />
<path d="M 220,187 L 220,267 l 100,0 l 0,-80 Z" style="fill:#B1BCB6;" />
</g>
</svg> ```
I don't know what you mean by
The right side of the tiles should not be higher but more to the back giving it more dept.
when that appears to be exactly what you have drawn.
You can reproduce your drawing using a skewY() transform.
<svg version="1.1" id="scgblocks" xmlns="http://www.w3.org/2000/svg"
width="1250.345px" height="350.345px" viewBox="-30 -30 1250.345 350.345">
<g transform="skewY(-9)">
<g>
<path d="M 14,19 L14,100 l 100,0 l 0,-80 Z" style="fill:#B1BCB6;" />
<path d="M 117,20 L117,100 l 100,0 l 0,-80 Z" style="fill:#B1BCB6;" />
<path d="M 220,20 L220,100 l 100,0 l 0,-80 Z" style="fill:#B1BCB6;" />
</g>
<g>
<path d="M 14,103 L14,183 l 100,0 l 0,-80 Z" style="fill:#B1BCB6;" />
<path d="M 117,103 L117,183 l 100,0 l 0,-80 Z" style="fill:#B1BCB6;" />
<path d="M 220,103 L220,183 l 100,0 l 0,-80 Z" style="fill:#B1BCB6;" />
</g>
<g>
<path d="M 14,187 L14,267 l 100,0 l 0,-80 Z" style="fill:#B1BCB6;" />
<path d="M 117,187 L 117,267 l 100,0 l 0,-80 Z" style="fill:#B1BCB6;" />
<path d="M 220,187 L 220,267 l 100,0 l 0,-80 Z" style="fill:#B1BCB6;" />
</g>
</g>
</svg>
Is that what you wanted?
However, if instead you mean that you want it to have perspective, then you need to do it a slightly different way. You can't use perspective transforms (yet) inside an SVG, but perspective transforms are allowed on HTML elements. So, as long as the SVG is in an web page, then you can apply a perspective transform to the entire <svg> element because browsers treat top level <svg> elements like other HTML elements.
svg {
transform: perspective(1800px) rotateY(50deg);
}
<svg version="1.1" id="scgblocks" xmlns="http://www.w3.org/2000/svg"
width="1250.345px" height="350.345px" viewBox="-30 -30 1250.345 350.345">
<g>
<path d="M 14,19 L14,100 l 100,0 l 0,-80 Z" style="fill:#B1BCB6;" />
<path d="M 117,20 L117,100 l 100,0 l 0,-80 Z" style="fill:#B1BCB6;" />
<path d="M 220,20 L220,100 l 100,0 l 0,-80 Z" style="fill:#B1BCB6;" />
</g>
<g>
<path d="M 14,103 L14,183 l 100,0 l 0,-80 Z" style="fill:#B1BCB6;" />
<path d="M 117,103 L117,183 l 100,0 l 0,-80 Z" style="fill:#B1BCB6;" />
<path d="M 220,103 L220,183 l 100,0 l 0,-80 Z" style="fill:#B1BCB6;" />
</g>
<g>
<path d="M 14,187 L14,267 l 100,0 l 0,-80 Z" style="fill:#B1BCB6;" />
<path d="M 117,187 L 117,267 l 100,0 l 0,-80 Z" style="fill:#B1BCB6;" />
<path d="M 220,187 L 220,267 l 100,0 l 0,-80 Z" style="fill:#B1BCB6;" />
</g>
</svg>

Validating an SVG file from RDKit

I am attempting to produce an SVG image from the package RDKit. A minimum reproducable example:
from rdkit import Chem
from rdkit.Chem import Draw
img = Draw.MolsToGridImage([Chem.MolFromSmiles(x) for x in ['C', 'CO', 'CN']], useSVG = True)
print(img)
The output is below, but doesn't render any image in any browser or image viewer I have tried. Is this a valid SVG file, or is the package producing an invalid format? Or is there some other error I cannot see?
<?xml version='1.0' encoding='iso-8859-1'?>
<svg version='1.1' baseProfile='full'
xmlns='http://www.w3.org/2000/svg'
xmlns:rdkit='http://www.rdkit.org/xml'
xmlns:xlink='http://www.w3.org/1999/xlink'
xml:space='preserve'
width='600px' height='200px' >
<!-- END OF HEADER -->
<rect style='opacity:1.0;fill:#FFFFFF;stroke:none' width='600' height='200' x='0' y='0'> </rect>
<text x='0' y='200' style='font-size:0px;font-style:normal;font-weight:normal;fill-opacity:1;stroke:none;font-family:sans-serif;text-anchor:start;fill:#000000' ><tspan>CH</tspan><tspan style='baseline-shift:sub;font-size:0px;'>4</tspan><tspan></tspan></text>
<path class='bond-0' d='M 200,200 200,200' style='fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1' />
<path class='bond-0' d='M 200,200 200,200' style='fill:none;fill-rule:evenodd;stroke:#FF0000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1' />
<text x='200' y='200' style='font-size:0px;font-style:normal;font-weight:normal;fill-opacity:1;stroke:none;font-family:sans-serif;text-anchor:start;fill:#FF0000' ><tspan>OH</tspan></text>
<path d='M 200,200 200,200 200,200 200,200 200,200' style='fill:none;stroke:#FF0000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1' />
<path class='bond-0' d='M 400,200 400,200' style='fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1' />
<path class='bond-0' d='M 400,200 400,200' style='fill:none;fill-rule:evenodd;stroke:#0000FF;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1' />
<text x='400' y='200' style='font-size:0px;font-style:normal;font-weight:normal;fill-opacity:1;stroke:none;font-family:sans-serif;text-anchor:start;fill:#0000FF' ><tspan>NH</tspan><tspan style='baseline-shift:sub;font-size:0px;'>2</tspan><tspan></tspan></text>
<path d='M 400,200 400,200 400,200 400,200 400,200' style='fill:none;stroke:#FF0000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1' />
</svg>
RDKit is for an unknown reason producing SVG code which doesn't show anything. However, changing the list of molecules does result in SVG code which produces a visible image.
This works:
from rdkit import Chem
from rdkit.Chem import Draw
img = Draw.MolsToGridImage([Chem.MolFromSmiles(x) for x in ['C', 'CO', 'CN', 'CCC']], useSVG = True)
print(img)
A bug has been opened here: https://github.com/rdkit/rdkit/issues/2641

Resources