Using SVG curves to imitate rounded corners - svg

I have a series of backwards-'L' shapes drawn in Raphael in SVG path notation -- just a collection of datapoints each represented by a horizontal line then a vertical line, of varying lengths.
<div id="canvas"></div>​
<script>
var data = [
[{x: 32, y: 207}, {x: 50, y: 371}],
[{x: 34, y: 209}, {x: 39, y: 34}],
[{x: 32, y: 216}, {x: 58, y: 38}],
[{x: 70, y: 221}, {x: 93, y: 40}],
[{x: 89, y: 223}, {x: 105, y: 41}],
[{x: 113, y: 225}, {x: 150, y: 42}],
[{x: 132, y: 228}, {x: 173, y: 43}],
[{x: 305, y: 230}, {x: 354, y: 45}]
],
paper = Raphael("canvas", 400, 300),
path;
for (var c = 0; c < data.length; c += 1) {
path = "M" + data[c][0].x + "," + data[c][0].y;
path += "H" + data[c][1].x;
path += "V" + data[c][2].y;
paper.path(path).attr({"stroke": "#900", "stroke-width": 2})
}
</script>
jsFiddle
I would like to give these shapes rounded corners of a radius of 5 or so. Do I have to manually draw the horizontal line to 5px short of its destinatation, program a curve up PI/2 radians, then draw the rest of the vertical line?
I'm hoping there's a way to do this with a single SVG curve with a small radius, such that the shape proceeds in a straight line until shortly before its end and then curves upward -- exactly the behavior of a rounded rectangle in Raphael or CSS3.
I have examined the SVG path guidelines but am having difficulty working through the details.
Thank you!

This should do the trick (at least in the example cases):
http://jsfiddle.net/jYGrq/3/
Change this
path += "H" + (data[c][1].x)
to this:
path += "H" + (data[c][1].x-5);
And add these lines after it:
if (data[c][0].y > data[c][1].y) path += "s 5 0 5 -5";
else if (data[c][0].y < data[c][1].y) path += "s 5 0 5 5";
This covers all the cases in example, but if you want to round corners despite of the orientation, make more ifs. Hope this helps a little.
By the way, I assume that shorthand relative cubic (s) is the curve type that is most suitable in your case.

Related

Add Words to ax.set_xticks

I am writing code for my internship and I am adding the latitude and longitude of the area we are viewing. The section of code giving me trouble looks like this. I want to be able to have the number and then a W to show it is degrees west for my X axis and a N for my Y axis to show that it is degrees north. I have tried to use plt.ylabel("Degrees North") and that did not work as well. Any help would be greatly appreciated.
ax.set_xticks([-94, -96, -98, -100, -102, -104])
ax.set_yticks([28, 30, 32, 34, 36])
secax = ax.secondary_yaxis(1.0)
secax.set_yticks([28, 30, 32, 34, 36])
This is what the output of my code looks like
Once you plot your graph, you can get the labels using get_xticks(). Add a ' W' or ' N' and use set_yticklabels to update the labels. As your labels are int, you will need to convert them to str just before plotting. As the map is that of Texas, assuming there only North and West to be added.
Sample below has a blank matplotlib plot which gets updated.
Code
fig, ax=plt.subplots(figsize=(6,6))
plt.setp(ax, xlim = (-104, -94))
plt.setp(ax, ylim = (28, 36))
ax.set_xticks([-94, -96, -98, -100, -102, -104])
ax.set_yticks([28, 30, 32, 34, 36])
secax = ax.secondary_yaxis(1.0)
secax.set_yticks([28, 30, 32, 34, 36])
#For x-axis
labels=ax.get_xticks().tolist()
new_labels = [str(l) + " W" for l in labels]
ax.set_xticklabels(new_labels)
#For y-axis (left)
labels=ax.get_yticks().tolist()
new_labels = [str(l) + " N" for l in labels]
ax.set_yticklabels(new_labels)
#For y-axis (right)
labels=secax.get_yticks().tolist()
new_labels = [str(l) + " N" for l in labels]
secax.set_yticklabels(new_labels)
Output plot

Pyglet Bordered Circle

Can't find info on how to just draw a border around a circle. Simply looking to draw a circle with a black border just like the BorderedRectangle function.
import pyglet
from pyglet import shapes
def display_get_width():
display = pyglet.canvas.get_display()
screen = display.get_default_screen()
return screen.width
def display_get_height():
display = pyglet.canvas.get_display()
screen = display.get_default_screen()
return screen.height
screen_width = display_get_width()
screen_height = display_get_height()
print(screen_width, screen_height)
window = pyglet.window.Window(screen_width//2,screen_height//2)
batch = pyglet.graphics.Batch()
rectangle = shapes.BorderedRectangle(250, 300, 600, 300, border=1, color=(255, 255, 255), border_color=(100, 100, 100), batch=batch)
rectangle2 = shapes.BorderedRectangle(300, 350, 300, 150, border=1, color=(255, 255, 255), border_color=(100, 100, 100), batch=batch)
circle = shapes.Circle(550, 450, 100, color=(50, 225, 30), batch=batch)
#window.event
def on_draw():
window.clear()
batch.draw()
pyglet.app.run()
It's been a year and half, but I had the same question a moment ago. I solved it by drawing shapes.ARC and setting width with a GL function:
pyglet.gl.glLineWidth(5)
arc = shapes.Arc(200, 200, 150, color=(255, 0, 0), batch = batch)
Omitting "angle" parameter while creating an Arc instance assumes angle is 2π - a full circle.
You can make a circle inside another circle:
circle = shapes.Circle(550, 450, 100, color=(50, 225, 30), batch=batch)
insideCircle = shapes.Circle(550, 450, 80, color=(30, 205, 10), batch=batch)

set_source_surface from RecordingSurface to PDFSurface with origin translation gives a PNG but empty PDF

in this example I am drawing some line elements 30px away from the origin in the Y coordinate while moving along he X coordinate. This is drawn on a recording surface because in my real code I don't know the extend before I start. After drawing is done I repeat the drawing on the PDFSurface but since I want my PDF and PNG to end flush with my drawn elements I set the boundaries of the PDFSurface to the height and width of the ink_extents of the RecordingSurface. Next because I was drawing 30px lower with only empty space above I translate my drawing in set_source_surface -30px. Now when writing the PNG all works fine but the PDF is empty. If I extend the height to 100px manually the PDF is drawn correctly with the correct origin. If I start drawing at Y 0px instead of Y 30px it also works. Do I miss anything or is it a bug?
Thanks for your help. Here is a test code:
import cairocffi as cairo
rs = cairo.RecordingSurface(cairo.CONTENT_COLOR_ALPHA, None)
ctxRS = cairo.Context(rs)
items = ([0], [28, 29], [39], [42], [64], [67], [70, 71, 72], [76, 77], [79, 80], [86], [90], [104, 105],
[131], [134, 135, 136, 137, 138, 139], [145, 146, 147], [150, 151], [156], [174], [188], [191],
[199, 200], [203], [212], [216], [229, 230], [240, 241, 242, 243], [262])
for item in items:
initialPosition = item[0]
numberOfItems = len(item)
offset = initialPosition * 10
lineLength = 10 * numberOfItems
ctxRS.set_source_rgba(1.0, 0.0, 0.0, 1.0)
ctxRS.set_line_width(0)
ctxRS.move_to(offset, 30)
ctxRS.line_to(offset, 40)
ctxRS.line_to(offset + lineLength, 40)
ctxRS.line_to(offset + lineLength, 30)
ctxRS.close_path()
ctxRS.stroke_preserve()
ctxRS.set_source_rgba(1.0, 0.0, 0.0, 1.0)
ctxRS.fill()
x, y, width, height = rs.ink_extents()
ps = cairo.PDFSurface("cairoTest.pdf", width, height)
ctxPS = cairo.Context(ps)
ctxPS.set_source_surface(rs, -x, -y)
ctxPS.paint()
ps.write_to_png("cairoTest.png")
ps.finish()

how to fix width of line drawn on canvas using fabric.js

I am using fabric.JS to draw a line. I can draw a line successfully but the problem is, that whenever I scale that line, the length of the line should only increase and not the width. Any one know any property related to that?
line = new fabric.Line([250, 125, 250, 175], {
left: 170,
top: 150,
strokeWidth: 4,
fill: 'red',
stroke: 'red',
flipX: 'false'
});
line.strokeWidth
is defining your line width, you are doing incorrect scaling.
do this:
var beforeWidth = line.strokeWidth;
//scaling process
line.strokeWidth = beforeWidth;

Plotting a smoothed area on a map from a set of points in R

how do I plot an area around a set of points on a map in R? e.g.
map('world')
map.axes()
p <- matrix(c(50, 50, 80, 100, 70, 40, 25, 60), ncol=2) # make some points
points(p, pch=19, col="red")
polygon(p, col="blue")
... which gives me a polygon with a vertex at each of the points, but it looks rather crappy. Is there any way to "smooth" the polygon into some sort of curve?
One option is to make a polygon bounded by a Bézier curve, using the bezier function in the Hmisc package. However I cannot get the start/end point to join up neatly. For example:
## make some points
p <- matrix(c(50, 50, 80, 100, 70, 40, 25, 60), ncol=2)
## add the starting point to the end
p2 <- cbind(1:5,p[c(1:4,1),])
## linear interpolation between these points
t.coarse <- seq(1,5,0.05)
x.coarse <- approx(p2[,1],p2[,2],xout=t.coarse)$y
y.coarse <- approx(p2[,1],p2[,3],xout=t.coarse)$y
## create a Bezier curve
library(Hmisc)
bz <- bezier(x.coarse,y.coarse)
library(maps)
map('world')
map.axes()
polygon(bz$x,bz$y, col=rgb(0,0,1,0.5),border=NA)
Here's one way, draw the polygon and make it as pretty as you like. This really has nothing to do with areas on maps, more about how you generate the vertices of your polygon.
library(maps)
p <- matrix(c(50, 50, 80, 100, 70, 40, 25, 60), ncol=2)
plot(p, pch = 16, col = "red", cex = 3, xlim = range(p[,1]) + c(-10,10), ylim = range(p[,2]) + c(-5, 5))
map(add = TRUE)
#click until happy, right-click "stop" to finish
p <- locator(type = "l")
map()
polygon(cbind(p$x, p$y), col = "blue")
Otherwise you could interpolate intermediate vertices and smooth them somehow, and in the context of a lon/lat map maybe with use reprojection to get more realistic line segments - but depends on your purpose.

Resources