SceneKit draw curved line - uibezierpath

I'd like to draw a bezier curved line with SceneKit and thought this would work:
func drawCurvedLine() {
let scene = SCNScene()
let scnView = self.view as! SCNView
scnView.scene = scene
scnView.allowsCameraControl = true
let path = UIBezierPath()
path.moveToPoint(CGPoint(x: -20, y: -20))
path.addCurveToPoint(CGPoint(x: 20, y: 20),
controlPoint1: CGPoint(x: 5, y: 5),
controlPoint2: CGPoint(x: 15, y: 15))
path.closePath()
path.flatness = 0.3
var scnShape:SCNShape = SCNShape(path: path, extrusionDepth: 2)
scnShape.firstMaterial?.diffuse.contents = UIColor.purpleColor()
let shapeNode = SCNNode(geometry: scnShape)
scene.rootNode.addChildNode(shapeNode)
}
However my results are like this screenshot:
Does anyone know why the curveTo control points are ignored or how to switch them on? Or any other method to draw a curved line in SceneKit?
Edit Updating the path coordinates to:
path.moveToPoint(CGPoint(x: -20, y: -20))
path.addCurveToPoint(CGPoint(x: 20, y: 20),
controlPoint1: CGPoint(x: 10, y: 0),
controlPoint2: CGPoint(x: 10, y: 0))
I can get this:
However I guess I'm looking to NOT fill the shape. Ideally a curved tubular line is what I'm trying to achieve here. ( Imagine a power cable or some such ... ). I guess I would love to have the equivalent of SCNLine or SCNTube "render on bezier path"

SCNShape just be built from closed Bézier paths and will always be filled (with the exception of holes). These paths can be completely custom but will always be extruded along a segment along the z axis. What you want is to extrude a circle along an arbitrary path, and that's not supported.
SCNGeometry exposes APIs that allow you to build arbitrary geometries.

It is working! Very well, I might add.
The problem is, all your points lie on the same line, y=x
Try changing your control points to have values where y!=x
ex,
path.addCurveToPoint(CGPoint(x: 20, y: 20),
controlPoint1: CGPoint(x: 15, y: 0),
controlPoint2: CGPoint(x: 20, y: 10))

Related

labeling values over the link and nodes in Sankey Diagram with networkD3 [duplicate]

Background
I was trying the create a Sankey graph like the following figure. Actually, I wanted to get a output where values (10, 20, 30, 40) will be set in the paths (from one node to another node).
How Did I Try?
At first, I tried using the Plotly library of Python. However, somewhere I have seen that it is not possible to set the values in the links or the paths of Sankey graph in Plotly (of Python). Later, I switched to R (for some other reasons also) where more resources are available (I think). However, here, I am also facing the same problem. I have checked many tutorials (e.g., this one), Q&A (e.g., 1, 2, 3) of SO which are in R. Still, I could not to find a tutorial or resources where the values are displayed in the paths!
My Question
How can I display the values on the links/paths of Sankey Graph, in R?
Note: This and this questions of SO seems to be similar. However, I failed to understand the way to incorporate those in my codes.
Example Code (collected from here)
# install.packages('networkD3')
library(networkD3)
nodes = data.frame("name" =
c("Node A", # Node 0
"Node B", # Node 1
"Node C", # Node 2
"Node D"))# Node 3
links = as.data.frame(matrix(c(
0, 1, 10, # Each row represents a link. The first number
0, 2, 20, # represents the node being conntected from.
1, 3, 30, # the second number represents the node connected to.
2, 3, 40),# The third number is the value of the node
byrow = TRUE, ncol = 3))
names(links) = c("source", "target", "value")
sankeyNetwork(Links = links, Nodes = nodes,
Source = "source", Target = "target",
Value = "value", NodeID = "name",
fontSize= 50, nodeWidth = 30)
This can be achieved by injecting custom JavaScript code when it's rendered using htmlwidgets::onRender(). The example below will initially position the link labels appropriately, but if the nodes are manually moved, the link labels will not automatically update accordingly. To achieve that, you would probably have to also override the default dragmove behaviour.
library(htmlwidgets)
library(networkD3)
nodes <-
data.frame(
name = c("Node A", "Node B", "Node C", "Node D")
)
links <-
data.frame(
source = c(0, 0, 1, 2),
target = c(1, 2, 3, 3),
value = c(10, 20, 30, 40)
)
p <- sankeyNetwork(Links = links, Nodes = nodes,
Source = "source", Target = "target",
Value = "value", NodeID = "name",
fontSize= 20, nodeWidth = 30)
htmlwidgets::onRender(p, '
function(el) {
var nodeWidth = this.sankey.nodeWidth();
var links = this.sankey.links();
links.forEach((d, i) => {
var startX = d.source.x + nodeWidth;
var endX = d.target.x;
var startY = d.source.y + d.sy + d.dy / 2;
var endY = d.target.y + d.ty + d.dy / 2;
d3.select(el).select("svg g")
.append("text")
.attr("text-anchor", "middle")
.attr("alignment-baseline", "middle")
.attr("x", startX + ((endX - startX) / 2))
.attr("y", startY + ((endY - startY) / 2))
.text(d.value);
})
}
')

RangeSlider does not work with scatter plot

Is it possible to make the range slider work with a scatter plot? The slider works if I change the scatter to a line plot but that does not work for me as I can not use the box select tool with line plots. The snippet below is simplified to demonstrate the issue. I suspect the embedded JavaScript is the issue but I may be wrong as it works just fine with a line plot. Thanks.
from bokeh.io import show
from bokeh.models import CustomJS, RangeSlider, Column, Row
from bokeh.plotting import figure
x = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
y = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
scatter_plot = figure(width=250, plot_height=600)
scatter_plot.scatter(x, y)
callback = CustomJS(args=dict(y_range=scatter_plot.y_range), code="""
var start = cb_obj.value
y_range.start = start[0]
y_range.end = start[1]
""")
depth_slider = RangeSlider(width=250, show_value=False, start=-20, end=120, value=(20, 80), step=20,
title="Y Scale")
depth_slider.js_on_change('value', callback)
layout = Column(Row(depth_slider), scatter_plot, )
show(layout)
There seems to be some race condition going on or a discrepancy between how Python and JS version of Bokeh work.
By default, all ranges are instances of DataRange1d class which recompute start and end when needed. In this case, it for some reason recomputes the values after you set them manually.
To fix it, specify the range manually from the get go:
scatter_plot = figure(..., y_range=(20, 80))

Boundary constrain leads to internal loop, what happens here and why?

My Script ceases to work for my easy conduction problem. Could somebody explain to me why the following line of code T.faceValue.constrain(alp/lam*(Tu-T.faceValue),where=mesh.exteriorFaces) # Boundary Condition for Solver results in fipy giving up on me?
Full Code:
cv=900.
lam=5.
alp=300.
T0 = 25.
Tu = 400.
cellSize = 0.05
radius = 1.
mesh = Gmsh2D('''
cellSize = %(cellSize)g;
radius = %(radius)g;
Point(1) = {0, 0, 0, cellSize};
Point(2) = {-radius, 0, 0, cellSize};
Point(3) = {0, radius, 0, cellSize};
Point(4) = {radius, 0, 0, cellSize};
Point(5) = {0, -radius, 0, cellSize};
Circle(6) = {2, 1, 3};
Circle(7) = {3, 1, 4};
Circle(8) = {4, 1, 5};
Circle(9) = {5, 1, 2};
Line Loop(10) = {6, 7, 8, 9};
Plane Surface(11) = {10};
''' % locals()) # doctest: +GMSH
T = CellVariable(name = "HeatingUp",mesh = mesh,value = T0)
viewer = None
if __name__ == '__main__':
try:
viewer = Viewer(vars=T, datamin=T0, datamax=Tu)
viewer.plotMesh()
input("Irregular circular mesh. Press <return> to proceed") # doctest: +GMSH
except:
print("Unable to create a viewer for an irregular mesh (try Matplotlib2DViewer or MayaviViewer)")
# =============================================================================
eq = TransientTerm(coeff=rho*cv)==DiffusionTerm(coeff=lam)
T.faceValue.constrain(alp/lam*(Tu-T.faceValue),where=mesh.exteriorFaces) # Boundary Condition for Solver
timeStepDuration = 0.1
steps = 10
for step in range(steps):
eq.solve(var=T, dt=timeStepDuration) # doctest: +GMSH
if viewer is not None:
viewer.plot() # doctest: +GMSH
``
You've written that T.faceValue depends on T.faceValue, which depends on T.faceValue, which depends on T.faceValue, ... FiPy has dutifully provided you with the infinite loop that you requested.
Just write T.faceValue.constrain(Tu * (alp/lam) / (1 + alp/lam), where=mesh.exteriorFaces).
In the more likely event that you wanted to relate the gradient to the value at the boundary, please see the discussion on Robin conditions.

Trapezoid Integration in Scilab - Polygon Color Fill Stops

I have been working on a program in Scilab that numerically integrates a function by the trapezoidal rule (without using the built-in function). I have no problem with the integration or plotting the function, but I want to overlay the real function on a plot of the trapezoids, colored in.
For some reason, when I set the bounds a = 0 to b = 3, no problem, I get exactly what I want. However, when I set the bounds above 3, the trapezoids will still plot (by lines), but they won't be colored in. In the code below, the color stops at 3. If I plot 0 to 6, for example, the color stops half-way through. 3 to 6, and there is no color at all.
Here are the relevant sections of code:
deff('[y] = f(x)','y = e^(x^2)'); // Definition of function
a = 0; // Lower bound
b = 4; // Upper bound
n = 20; // Number of intervals
h = ((b - a)/n); // Interval spacing
x = a:h:b; // Array of positions for division
and
for i = 1:n+1
y(i) = f(x(i));
end
and
for i = 1:n // Plot colored trapezoids
x_start = a+(h*(i-1));
x_end = a+(h*(i));
y_start = y(i);
y_end = y(i+1);
xpts = [x_start, x_end, x_end, x_start];
ypts = [y_start, y_end, 0, 0];
xfpoly(xpts,ypts,3);
end
This is the plot output for a = 0, b = 3
What version of Scilab are you using?
I tried your code with Scilab 5.4.1 (64bit) and I got uncolored trapezoids, but with 5.5.2 (64bit) all the shapes are nice green.
So maybe there was some bugfix between these versions.
I also changed your function definition from 'y = e^(x^2)' to 'y = %e^(x^2)' since the Euler number is a predefined variable (at least in 5.5.2).
clc;
clear;
deff('[y] = f(x)','y = %e^(x^2)'); // Definition of function
a = 0; // Lower bound
b = 6; // Upper bound
n = 100; // Number of intervals
h = ((b - a)/n); // Interval spacing
x = a:h:b; // Array of positions for division
for i = 1:n+1
y(i) = f(x(i));
end
scf(0);
clf(0);
plot2d(x,y);
for i = 1:n // Plot colored trapezoids
x_start = a+(h*(i-1));
x_end = a+(h*(i));
y_start = y(i);
y_end = y(i+1);
xpts = [x_start, x_end, x_end, x_start];
ypts = [y_start, y_end, 0, 0];
xfpoly(xpts,ypts,3);
end

how to write text inside a rectangle in R

I want each rectangle to contain a number, so that the first plotted rectangle would contain : rect 1 the second rect 2 and so on, but i don't know how to insert text inside rectangles.
require(grDevices)
## set up the plot region:
plot(c(0, 250), c(0, 250), type = "n",
main = "Exercise 1: R-Tree Index Question C")
rect(0.0,0.0,40.0,35.0, , text= "transparent")
rect(10.0,210.0,45.0,230.0)
rect(170.0,50.0,240.0,150.0)
rect(75.0,110.0,125.0,125.0)
rect(50.0,130.0,65.0,160.0)
rect(15.0,140.0,30.0,150.0)
rect(100.0,50.0,130.0,90.0)
rect(150.0,40.0,155.0,60.0)
rect(52.0,80.0,75.0,90.0)
rect(62.0,65.0,85.0,75.0)
rect(20.0,75.0,25.0,80.0)
rect(30.0,40.0,50.0,80.0)
rect(102.0,155.0,113.0,217.0)
par(op)
Like the other answers mention, you can use the coordinates that you give to rect to place the text somewhere relative.
plot(c(0, 250), c(0, 250), type = "n",
main = "Exercise 1: R-Tree Index Question C")
rect(0.0,0.0,40.0,35.0)
center <- c(mean(c(0, 40)), mean(c(0, 35)))
text(center[1], center[2], labels = 'hi')
You can easily put this into a function to save yourself some typing/errors
recttext <- function(xl, yb, xr, yt, text, rectArgs = NULL, textArgs = NULL) {
center <- c(mean(c(xl, xr)), mean(c(yb, yt)))
do.call('rect', c(list(xleft = xl, ybottom = yb, xright = xr, ytop = yt), rectArgs))
do.call('text', c(list(x = center[1], y = center[2], labels = text), textArgs))
}
Use it like this
recttext(50, 0, 100, 35, 'hello',
rectArgs = list(col = 'red', lty = 'dashed'),
textArgs = list(col = 'blue', cex = 1.5))
You need to use text() as a separate graphics call.
coords <- matrix(
c(0.0,0.0,40.0,35.0,
10.0,210.0,45.0,230.0,
170.0,50.0,240.0,150.0,
75.0,110.0,125.0,125.0,
50.0,130.0,65.0,160.0,
15.0,140.0,30.0,150.0,
100.0,50.0,130.0,90.0,
150.0,40.0,155.0,60.0,
52.0,80.0,75.0,90.0,
62.0,65.0,85.0,75.0,
20.0,75.0,25.0,80.0,
30.0,40.0,50.0,80.0,
102.0,155.0,113.0,217.0),
ncol=4,byrow=TRUE)
plot(c(0, 250), c(0, 250), type = "n",
main = "Exercise 1: R-Tree Index Question C")
rfun <- function(x,i) {
do.call(rect,as.list(x))
}
apply(coords,1,rfun)
text((coords[,1]+coords[,3])/2,
(coords[,2]+coords[,4])/2,
seq(nrow(coords)))
text( (0.0+40.0)/2, (0.0+35.0)/2 , 'transparent')
where we chose x,y to be the centroid of your rectangle. You could define a function to draw the rect then place the text at its centroid.
Note: these coords are large; this will display outside your normal view. So you'll either need to zoom to see it, or scale coords to the range 0.0..1.0
By the way, read 12.2 Low-level plotting commands

Resources