I would like to get centre of gravity for SVG path. I am already using paper.js for paths manipulations but I can see any option to calculate this. Is it possible some way?
If you have a Path object (preferably without self-intersections), you can create an approximate polygon clone with the .flatten() function:
const path = ...
//Approximate polyline/polygon:
const poly = path.clone();
poly.flatten(8);
const polyPoints = poly.exportJSON({ asString: false })[1].segments;
Then, there are several resources online that explain how to calculate the centroid of a polygon, for example:
Finding the centroid of a polygon?
How can you find the centroid of a concave irregular polygon in JavaScript?
Full example
I would like to set the gap from the element to some value so that the dimension would be clearly visible. Please find below the screen shot.
Currently it's looking like this.
But I would like to achieve like below.
You are actually in control of the line when you create the dimension. Take a line from Revit then transform it and offset it perpendicular to the line you're interested in: (Given a dbView and a reference array and a curve)
//create your line along the element you want to dimension
Line line = Line.CreateBound(locCurve.Curve.GetEndPoint(0), locCurve.Curve.GetEndPoint(1));
//Compute the perpendicular of that line (I took advantage of the fact that I was working in plan:
XYZ perpendicular = line.ComputeDerivatives(0.5, true).BasisX.CrossProduct(new XYZ(0, 0, 1));
//transform the line to the new offset location:
Line offsetline = line.CreateTransformed(Transform.CreateTranslation(perpendicular.Normalize())) as Line;
//Create the dimension.
revitDoc.Create.NewDimension(dbView, offsetline, aDimensionRefArray);
I have written a code which plots multiple 3d points as spheres. I want to add some text near each sphere in 3D to mention some info about each point. But I have vtkPoints to store points positions which doesn't have GetOutputPort which I need in labelMApper (and also used glyph3d to make spheres)
vtkSmartPointer<vtkLabeledDataMapper> labelMapper = vtkSmartPointer<vtkLabeledDataMapper>::New();
labelMapper->SetInputConnection( vtkpoints->GetOutputPort() ); // No GetOutputPort()
vtkSmartPointer<vtkActor2D> labelActor = vtkSmartPointer<vtkActor2D>::New();
labelActor->SetMapper(labelMapper);
renderer->AddActor(labelActor);
You should construct a vtkPolyData from the points and set it as Input to the label mapper.
Something like this:
vtkNew<vtkPolyData> labelPolyData;
labelPolyData->SetPoints(labelPoints);
labelMapper->SetInput(labelPolyData); // Note: If you're using VTK from master (6.x), this is SetInputData(...)
renderer->AddActor2D(labelActor);
I have a KML file with placemarkers, each of which has polygon coordinates. I'd like to change the fill color of the polygons on the fly, depending on values I read in from a json file. My understanding is that Google caches kml files, so you can't easily change the fill color of polygons on the fly.
So I'm trying to convert my kml polygons into svg paths so that I can use Raphael to place my polygons on my Google map. Then I can change fill colors with javascript.
But how do I convert polygon coordinates to svg paths, does anyone know?
A sample set of coordinates would be:
<Polygon><outerBoundaryIs><LinearRing><coordinates>-80.098181,40.42127 -80.096479,40.421262 -80.096464,40.421409 -80.096448,40.421551 -80.096444,40.421583 -80.096434,40.421666 -80.096406,40.421931 -80.096389,40.422087 -80.096353,40.422423 -80.09583,40.426101 -80.095525,40.428234 -80.095315,40.429714 -80.095276,40.429989 -80.092585,40.428593 -80.092273,40.428431 -80.09069,40.430519 -80.090384,40.430924 -80.08989,40.430618 -80.089699,40.4305 -80.089499,40.430359 -80.088738,40.429886 -80.088418,40.429688 -80.088254,40.429585 -80.087931,40.429384 -80.087086,40.428859 -80.086867,40.428722 -80.086658,40.428592 -80.086493,40.42849 -80.08617,40.428282 -80.086177,40.428265 -80.08621,40.428188 -80.0864,40.427742 -80.086397,40.42749 -80.086394,40.427125 -80.08631,40.426427 -80.086335,40.425887 -80.086235,40.425409 -80.085776,40.425327 -80.085442,40.42527 -80.084993,40.424585 -80.085076,40.42448 -80.085542,40.423842 -80.085679,40.423125 -80.085659,40.423011 -80.085626,40.422827 -80.085191,40.421758 -80.08467,40.420859 -80.084258,40.420336 -80.083828,40.4201 -80.083078,40.420005 -80.082504,40.420072 -80.081444,40.420196 -80.080888,40.420181 -80.080775,40.420178 -80.080604,40.420173 -80.080122,40.420161 -80.079753,40.420151 -80.07947,40.420144 -80.079287,40.420139 -80.078239,40.420296 -80.077661,40.420418 -80.076213,40.420726 -80.075673,40.420766 -80.075298,40.420719 -80.075127,40.420625 -80.074909,40.420307 -80.075028,40.419779 -80.07539,40.419028 -80.07583,40.41836 -80.076065,40.418108 -80.076528,40.417616 -80.077217,40.417124 -80.077503,40.417002 -80.077725,40.416907 -80.078391,40.416622 -80.078614,40.416528 -80.078657,40.41651 -80.078693,40.416491 -80.078755,40.416457 -80.079174,40.416233 -80.079205,40.416217 -80.079292,40.416128 -80.079439,40.415977 -80.079456,40.41596 -80.079614,40.415473 -80.079604,40.415377 -80.079584,40.415179 -80.07958,40.415168 -80.079539,40.415042 -80.079499,40.414915 -80.079407,40.414785 -80.079742,40.414965 -80.08086,40.415568 -80.081458,40.415889 -80.081535,40.41593 -80.082292,40.416343 -80.08238,40.416392 -80.082597,40.41651 -80.082624,40.416525 -80.082787,40.416614 -80.083508,40.417007 -80.083934,40.417239 -80.084422,40.417505 -80.084622,40.417432 -80.084852,40.417348 -80.085329,40.417179 -80.085419,40.417141 -80.085948,40.41695 -80.086252,40.417184 -80.088463,40.418885 -80.088964,40.418631 -80.089036,40.418595 -80.089145,40.418539 -80.089173,40.418525 -80.089346,40.418438 -80.089376,40.418457 -80.089398,40.418471 -80.089964,40.418827 -80.090299,40.419055 -80.091306,40.419739 -80.091642,40.419967 -80.091803,40.420088 -80.091966,40.420043 -80.092445,40.419915 -80.092561,40.419885 -80.096792,40.418748 -80.098853,40.41815 -80.098868,40.418242 -80.09943,40.421273 -80.098181,40.42127</coordinates></LinearRing></outerBoundaryIs></Polygon>
Disclaimer: I'm a bit rusty on geodetics, but think your #1 problem here is the coordinate system - lat, lng are projection-dependent data points, whereas your screen is a flat pixel one. What you need to do is convert these to northing and easting points first.
There is a projection conversion library out there called proj.4 - use this to convert your coordinates. If needed, there is a javascript port of it that you can easily adapt for your use at https://trac.osgeo.org/proj/
Generic conversion process would go like this (LAT, LNG are actual coordinates.)
var source = new Proj4js.Proj('WGS84');
var dest = new Proj4js.Proj('GOOGLE');
var p = new Proj4js.Point( LATITUDE, LONGITUDE ); // replace with actual coords!
var pdest = Proj4js.transform(source, dest, p);
At this point, pdest.x and pdest.y will contain your SVG-compatible coordinates.
After your coordinates are converted to pixel units, simply plot them - and mind the range and units. Northing and easting coordinates will be in 800,000 range, so you will likely be applying some transformations, such as translation and scaling.
End result should look like this (being rusty, I may have messed up and flipped lat/lng around, etc.)
Here's a working jsfiddle with a conversion and plot: http://jsfiddle.net/LPzKV/1/
It seems like given the information in stroke_extents() and the translate(x, y) and scale(x, y) functions, I should be able to take any arbitrary cairo (I'm using pycairo) path and "best fit" it. In other words, center it and expand it to fill the available space.
Before drawing the path, I have scaled the canvas such that the origin is the lower left corner, up is y+, right is x+, and the height and width are both 1. Given these conditions, this code seems to correctly scale the path:
# cr is the canvas
extents = cr.stroke_extents()
x_size = abs(extents[0]) + abs(extents[2])
y_size = abs(extents[1]) + abs(extents[3])
cr.scale(1.0 / x_size, 1.0 / y_size)
I cannot for the life of me figure out the translating though. Is there a simpler approach? How can I "best fit" a cairo path on its canvas?
Please ask for clarification if anything is unclear in this question.
I have found a solution that I like (at least for my purposes). Just create a new surface and paint the old surface on to the new one.
As for the scale only, I have done a similar thing to adjust an image inside a box with a "best-fit" approach. As about scale, here is the code:
available_width = 800
available_height = 600
path_width = 500
figure_height = 700
# formulas
width_ratio = float(available_width)/path_width
height_ratio = float(available_height)/figure_height
scale = min(height_ratio, width_ratio)
# result
new_path_width = path_width*scale
new_figure_height = figure_height*scale
print new_path_width, new_figure_height
The image gets drawn aligned to the origin (top left in my case), so perhaps a similar thing should be done to translate the path.
Also, this best fit is intended to preserve aspect ratio. If you want to stretch the figure, use each of the ratios instead of the 'scale' variable.
Hope I have helped