Rotating a group of objects around their center in JSModeler - jsmodeler

I am using JSModeler with three.js extension. My viewer is JSM.ThreeViewer(). The codepen is: https://codepen.io/Dharnidharka/pen/QRzBQa
What I am trying to achieve is a rotation of the concentric circles around their center, but currently the rotation is about the world center.
In three.js, this could be done by having a parent Object3D, and adding all the meshes to that object, centering that object by using geometry.center() and then having the rotation. But I could not find an Object3D extension for JSModeler.
Another way in three.js could be to group objects around a common pivot but even that approach did not work for me.
A third approach I tried was the solution in What's the right way to rotate an object around a point in three.js?, in the Update() loop but that doesn't work as well
I used the following to move the object to the pivot point:
meshes = JSM.ConvertModelToThreeMeshes (model);
viewer.AddMeshes (meshes);
for(var i =3; i<10; i++) {
meshes[i].geometry.computeBoundingBox();
meshes[i].geometry.boundingBox.getCenter(center);
meshes[i].geometry.center();
var newPos = new THREE.Vector3(-center.x, -center.y, -center.z);
meshes[i].position.copy(newPos);
}
The expected output is that the 2 circles are rotating about the common center, which also would be the world center. Currently, they are rotating about the world center, but not about their common center.

Finally figured it out.
In the code posted above, I was centering the geometry and then moving them back to their original positions. What was needed was to center the geometry and then move the meshes around the center relative to each other so that the configuration did not mess up. There are 2 mesh groups. The mid has to be computed for each and then the geometry translated accordingly. The solution in codes:
var center = new THREE.Vector3();
var mid1 = new THREE.Vector3();
for(var i =0; i<len1; i++) {
viewer.GetMesh(i).geometry.computeBoundingBox();
viewer.GetMesh(i).geometry.boundingBox.getCenter(center);
viewer.GetMesh(i).geometry.verticesNeedUpdate = true;
mid1.x += center.x;
mid1.y += center.y;
mid1.z += center.z;
}
mid1.x = mid1.x / len1;
mid1.y = mid1.y / len1;
mid1.z = mid1.z / len1;
for(var i = 0; i<len1; i++) {
viewer.GetMesh(i).geometry.computeBoundingBox();
viewer.GetMesh(i).geometry.boundingBox.getCenter(center);
viewer.GetMesh(i).geometry.center();
var newPos = new THREE.Vector3(center.x - mid1.x, center.y - mid1.y, center.z - mid1.z);
viewer.GetMesh(i).geometry.translate(newPos.x, newPos.y, newPos.z);
}

Related

How to fill Oxyplot AreaSeries in different areas?

I would like to create a AreaSeries series in Oxyplot that consists of a set of intervals.
See picture of what I would like to achieve:
AreaSeries
This is the code I use to fill in an area of the chart. The series is composed of 2 linear axis.
seriesArea = new AreaSeries { Title = "2Hz" };
for (var j = 0; j < 30; j++)
{
//Draw a vertical line from a specific value.
//This represents the starting point of the area series.
//eg: triggers[0]=0; triggers[1]=236 first area (see picture)
seriesArea.Points.Add(new DataPoint(triggers[0], j));
}
for (var j = 0; j < 30; j++)
{
//This time the ending point of the area series.
seriesArea.Points.Add(new DataPoint(triggers[1], j));
}
seriesArea.Color = OxyColors.LightPink;
seriesArea.Fill = OxyColors.LightPink;
plotModel.Series.Add(seriesArea);
I cannot seem to figure out what I have to do in order to draw the same series and full only the intervals that I want. If I use the above code, the series fills up also the areas that I would like to leave blank.
I tried to use seriesArea.Points2.Add(new DataPoint(i, j)); in places where I want it to not draw and draw the seriesArea.Points2 transparent, but it seem to not work as I expected.
Please let me know if there is a way that I could draw different intervals in a Oxyplot chart with the same series.

Drawing multiple lines with DrawLines and DrawLine produces different result

I am trying to draw multiple lines on a winforms panel using it's graphics object in paint event. I am actually drawing a number of lines joining given points. So, first of all I did this,
private void panel1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawLines(new Pen(new SolidBrush(Color.Crimson), 3), PointFs.ToArray());
float width = 10;
float height = 10;
var circleBrush = new SolidBrush(Color.Crimson);
foreach (var point in PointFs)
{
float rectangleX = point.X - width / 2;
float rectangleY = point.Y - height / 2;
var r = new RectangleF(rectangleX, rectangleY, width, height);
e.Graphics.FillEllipse(circleBrush, r);
}
}
Which produces a result like the image below,
As you can see lines are drawn with having a little bit of extension at sharp turns, which is not expected. So, I changed the drawlines code to,
var pen = new Pen(new SolidBrush(Color.Crimson), 3);
for (int i = 1; i < PointFs.Count; i++)
{
e.Graphics.DrawLine(pen, PointFs[i - 1], PointFs[i]);
}
And now the drawing works fine.
Can anyone tell the difference between the two approaches?
I have just had the same problem (stumbled upon this question during my research), but I have now found the solution.
The problem is caused by the LineJoin property on the Pen used. This DevX page explains the different LineJoin types (see Figure 1 for illustrations). It seems that Miter is the default type, and that causes the "overshoot" when you have sharp angles.
I solved my problem by setting the LineJoin property to Bevel:
var pen = new Pen(new SolidBrush(Color.Crimson), 3);
pen.LineJoin = Drawing2D.LineJoin.Bevel;
Now DrawLines no longer overshoot the points.

Snapping a SurfaceListBox

I'm looking to create a scrolling surfacelistbox which automatically snaps into a position after a drag is finished so that the center item on the screen is centered itself in the viewport.
I've gotten the center item, but now as usual the way that WPF deals with sizes, screen positions, and offsets has me perplexed.
At the moment I've chosen to subscribe to the SurfaceScrollViewer's ManipulationCompleted event, as that seems to consistently fire after I've finished a scroll gesture (whereas the ScrollChanged event tends to fire early).
void ManipCompleted(object sender, ManipulationCompletedEventArgs e)
{
FocusTaker.Focus(); //reset focus to a dummy element
List<FrameworkElement> visibleElements = new List<FrameworkElement>();
for (int i = 0; i < List.Items.Count; i++)
{
SurfaceListBoxItem item = List.ItemContainerGenerator.ContainerFromIndex(i) as SurfaceListBoxItem;
if (ViewportHelper.IsInViewport(item) && (List.Items[i] as string != "Dummy"))
{
FrameworkElement el = item as FrameworkElement;
visibleElements.Add(el);
}
}
int centerItemIdx = visibleElements.Count / 2;
FrameworkElement centerItem = visibleElements[centerItemIdx];
double center = ss.ViewportWidth / 2;
//ss is the SurfaceScrollViewer
Point itemPosition = centerItem.TransformToAncestor(ss).Transform(new Point(0, 0));
double desiredOffset = ss.HorizontalOffset + (center - itemPosition.X);
ss.ScrollToHorizontalOffset(desiredOffset);
centerItem.Focus(); //this also doesn't seem to work, but whatever.
}
The list snaps, but where it snaps seems to be somewhat chaotic. I have a line down the center of the screen, and sometimes it looks right down the middle of the item, but other times it's off to the side or even between items. Can't quite nail it down, but it seems that the first and fourth quartile of the list work well, but the second and third are progressively more off toward the center.
Just looking for some help on how to use positioning in WPF. All of the relativity and the difference between percentage-based coordinates and 'screen-unit' coordinates has me somewhat confused at this point.
After a lot of trial and error I ended up with this:
void ManipCompleted(object sender, ManipulationCompletedEventArgs e)
{
FocusTaker.Focus(); //reset focus
List<FrameworkElement> visibleElements = new List<FrameworkElement>();
for (int i = 0; i < List.Items.Count; i++)
{
SurfaceListBoxItem item = List.ItemContainerGenerator.ContainerFromIndex(i) as SurfaceListBoxItem;
if (ViewportHelper.IsInViewport(item))
{
FrameworkElement el = item as FrameworkElement;
visibleElements.Add(el);
}
}
Window window = Window.GetWindow(this);
double center = ss.ViewportWidth / 2;
double closestCenterOffset = double.MaxValue;
FrameworkElement centerItem = visibleElements[0];
foreach (FrameworkElement el in visibleElements)
{
double centerOffset = Math.Abs(el.TransformToAncestor(window).Transform(new Point(0, 0)).X + (el.ActualWidth / 2) - center);
if (centerOffset < closestCenterOffset)
{
closestCenterOffset = centerOffset;
centerItem = el;
}
}
Point itemPosition = centerItem.TransformToAncestor(window).Transform(new Point(0, 0));
double desiredOffset = ss.HorizontalOffset - (center - itemPosition.X) + (centerItem.ActualWidth / 2);
ss.ScrollToHorizontalOffset(desiredOffset);
centerItem.Focus();
}
This block of code effectively determines which visible list element is overlapping the center line of the list and snaps that element to the exact center position. The snapping is a little abrupt, so I'll have to look into some kind of animation, but otherwise I'm fairly happy with it! I'll probably use something from here for animations: http://blogs.msdn.com/b/delay/archive/2009/08/04/scrolling-so-smooth-like-the-butter-on-a-muffin-how-to-animate-the-horizontal-verticaloffset-properties-of-a-scrollviewer.aspx
Edit: Well that didn't take long. I expanded the ScrollViewerOffsetMediator to include HorizontalOffset and then simply created the animation as suggested in the above post. Works like a charm. Hope this helps someone eventually.
Edit2: Here's the full code for SnapList:
SnapList.xaml
SnapList.xaml.cs
Note that I got pretty lazy as this project went on an hard-coded some of it. Some discretion will be needed to determine what you do and don't want from this code. Still, I think this should work pretty well as a starting point for anyone who wants this functionality.
The code has also changed from what I pasted above; I found that using Windows.GetWindow gave bad results when the list was housed in a control that could move. I made it so you can assign a control for your movement to be relative to (recommended that be the control just above your list in the hierarchy). I think a few other things changed as well; I've added a lot of customization options including being able to define a custom focal point for the list.

Creating a Chess Board using Windows Forms

What is the best way to create chess board using Windows Forms?
I am still new to graphics coding in winforms and I am not sure, which control to use for that?
The user should be able to put chess pieces into the board.
I am trying to write Chess Diagram Editor.
Thank you
There are a lot of ways. Here's an alternative that gets you started with some WinForms concepts:
(It uses a 2D grid of Panel controls to create a chessboard. To extend it you might change the background picture of each Panel to show chess pieces. The game play is up to you to define.)
// class member array of Panels to track chessboard tiles
private Panel[,] _chessBoardPanels;
// event handler of Form Load... init things here
private void Form_Load(object sender, EventArgs e)
{
const int tileSize = 40;
const int gridSize = 12;
var clr1 = Color.DarkGray;
var clr2 = Color.White;
// initialize the "chess board"
_chessBoardPanels = new Panel[gridSize, gridSize];
// double for loop to handle all rows and columns
for (var n = 0; n < gridSize; n++)
{
for (var m = 0; m < gridSize; m++)
{
// create new Panel control which will be one
// chess board tile
var newPanel = new Panel
{
Size = new Size(tileSize, tileSize),
Location = new Point(tileSize * n, tileSize * m)
};
// add to Form's Controls so that they show up
Controls.Add(newPanel);
// add to our 2d array of panels for future use
_chessBoardPanels[n, m] = newPanel;
// color the backgrounds
if (n % 2 == 0)
newPanel.BackColor = m % 2 != 0 ? clr1 : clr2;
else
newPanel.BackColor = m % 2 != 0 ? clr2 : clr1;
}
}
}
Best way is to use a 'chess starter kit': http://www.chessbin.com/page/Chess-Game-Starer-Kit.aspx (alternative project: http://www.codeproject.com/KB/game/SrcChess.aspx)
Nowadays a lot of things have starter kits (for C#) which gives you a sample to get started on.
In the controls OnPaint eventhandler, you start out by drawing the chessboard pattern either implicitly using the formula (floor(x * 8) mod 2) = (floor(y * 8) mod 2) or by just drawing the squares with Graphics.FillRectangle. The second step would be to draw the pieces on top with Graphics.DrawImage.
I don't know what you want to do with this chess board, but if it's only a background to display after pieces, your best shot is to set a background image.

How to model a scrolling line graph in WPF?

I'm trying to re-learn WPF and I've started a little project that has a line graph, kind of like the CPU performance one you would see in Taskmanager. The graph is basically a canvas that has a punch of lines added to it's children and is based on an Avalon sample I found here http://msdn.microsoft.com/en-us/library/aa480159.aspx
Currently, when I get to the far right edge of the graph I clear my data set and reset my x-coordinate back to zero and the graph starts redrawing from the left hand side after a clear.
y = value;
x = x + 1;
if (x == samples)
{
CpuGraphAnimation2d.Children.RemoveRange(0, samples);
x = 0;
}
What I want to do is have the graph 'scroll' to the left as new values arrive, and effectively have all the old values shuffle to the left and drop the left most value.
What would be the most efficient way to achieve this effect in WPF?
You could try creating a StreamGeometry as follows, removing the first element of yourarray before doing the following:
StreamGeometry sg = new StreamGeometry();
using (StreamGeometryContext context = sg.Open())
{
context.BeginFigure(new Point(0, yourarray[0]), false, false);
for (int x = 0; x < len; x++)
{
context.LineTo(new Point(x, yourarray[x], true, true);
}
sg.Freeze();
System.Windows.Shapes.Path path = new System.Windows.Shapes.Path();
path.Data = sg;
path.Stroke = Brushes.Red;
}
which is a fast way of regenerating your graph each pass. the path created at the end of the code would need to be added to a control or panel in your window.

Resources