I'm trying to write a method to change an existing block in an AutoCAD drawing. In this case, I want to change the length of a block by changing its scale factors. The method I've written will accomplish that by deleting the old block and creating a new one with the newly desired scale factors.
private static ObjectId _adjustCapPlate(ObjectId capPlateID, bool isHorizontal, Distance left = null, Distance right = null)
{
BlockReference capPlate = EntityMethods.GetBlockById(capPlateID); //Getting the block to be replaced
Scale3d oldScales = capPlate.ScaleFactors; //Getting the scales of the old block
Point3d originalLocation = capPlate.Location; // ToDo: Replace capPlate.Location with code that will return the coordinates of the insertion point of the block
EntityMethods.DeleteBlockFromDrawingWithId(capPlate.Id); //Deleting the old block
//Using specified splice plate length if method does not specify something else
if (left == null)
{
left = new Distance(SettingsController.SplicePlateLength / 2);
}
if (right == null)
{
right = new Distance(SettingsController.SplicePlateLength);
}
Distance newXScale, newYScale, newZScale;
Point3d newLocation;
if (isHorizontal) //If wall is oriented horizontally
{
newXScale = new Distance(DistanceType.Inch, oldScales.X - right.Inches);
newYScale = new Distance(DistanceType.Inch, oldScales.Y);
newLocation = new Point3d(originalLocation.X + left.Inches, originalLocation.Y, originalLocation.Z);
}
else
{
newXScale = new Distance(DistanceType.Inch, oldScales.X);
newYScale = new Distance(DistanceType.Inch, oldScales.Y - right.Inches);
newLocation = new Point3d(originalLocation.X, originalLocation.Y + left.Inches, originalLocation.Z);
}
newZScale = new Distance(DistanceType.Inch, oldScales.Z);
BlockReference newCapPlate = EntityMethods.InsertBlock("member", newLocation, "0", null, newXScale, newYScale, newZScale);
}
All I need to make this method to work is to replace capPlate.Location with something that will get an existing block's XYZ coordinates in the AutoCAD drawing. It seems ridiculous that there is no obvious way to get a block's coordinates programmatically.
I will not accept answers that change my approach. This has to be done by deleting the old block and replacing it by inserting a new block with new properties where the old block was.
Instead of using capPlate.Location, use capPlate.Position and you should get the desired behavior.
Related
I'm using SFML for C#. I want to create a BackgroundImage Sprite and then start drawing it with an Agent, represented as a Circle, on top of it like that:
static void Main(string[] args)
{
Window = new RenderWindow(new VideoMode((uint)map.Size.X * 30, (uint)map.Size.Y * 30), map.Name + " - MAZE", Styles.Default);
while (Window.IsOpen)
{
Update();
}
}
static public RenderWindow Window { get; private set; }
static Map map = new Map(string.Format(#"C:\Users\{0}\Desktop\Maze.png", Environment.UserName));
static public void Update()
{
Window.Clear(Color.Blue);
DrawBackground();
DrawAgent();
Window.Display();
}
static void DrawAgent()
{
using (CircleShape tempCircle = new CircleShape
{
FillColor = Color.Cyan,
Radius = 15,
Position = new Vector2f(30, 30),
Origin = new Vector2f(30, 30),
Scale = new Vector2f(.5f, .5f)
})
{
Window.Draw(tempCircle);
}
}
static private Sprite BackgroundImage { get; set; }
static void DrawBackground()
{
if (BackgroundImage == null)
BackgroundImage = GetBackground();
Window.Draw(BackgroundImage);
}
static Sprite GetBackground()
{
RenderTexture render = new RenderTexture((uint)map.Size.X * 30, (uint)map.Size.Y * 30);
foreach (var point in map.Grid.Points)
{
RectangleShape pointShape = new RectangleShape(new Vector2f(30, 30));
switch (point.PointType)
{
case PointType.Walkable:
pointShape.FillColor = Color.White;
break;
case PointType.NotWalkable:
pointShape.FillColor = Color.Black;
break;
case PointType.Start:
pointShape.FillColor = Color.Red;
break;
case PointType.Exit:
pointShape.FillColor = Color.Blue;
break;
}
pointShape.Position = new Vector2f(point.Position.X * 30, point.Position.Y * 30);
render.Draw(pointShape);
}
Sprite result = new Sprite(render.Texture);
result.Origin = new Vector2f(0, result.GetLocalBounds().Height);
result.Scale = new Vector2f(1, -1);
return result;
}
Everything works as intended when I start it, but after a few seconds, around the time when process memory reaches 70MB, BackgroundImage turns into completely white sprite. If I change the type of BackgroundImage and GetBackground() to RenderTexture, return "render" object and then change DrawBackground() function like this
void RenderBackground()
{
if (BackgroundImage == null)
BackgroundImage = GetBackground();
using (Sprite result = new Sprite(BackgroundImage.Texture))
{
result.Origin = new Vector2f(0, result.GetLocalBounds().Height);
result.Scale = new Vector2f(1, -1);
Window.Draw(result);
}
}
then the background sprite doesn't turn white, but storing entire RenderTexture, instead of Sprite and then constantly creating new Sprite objects every time we call RenderBackground() function seems like a bad idea.
Is there any way for GetBackground() function to return a Sprite which won't turn white once the function's local "render" variable is destroyed?
You're not completely off with your assumptions. Simplified, SFML knows two types of resources:
Light resources are small objects that are quick to create and destroy. It's not that bad to just drop them and recreate them later. Typical examples would be Sprite, Sound, Text, and basically most SFML classes.
Heavy resourcces are often big objects or objects requiring file access to create or use. Typical examples would be Image, Texture, SoundBuffer, and Font. You shouldn't recreate these and instead keep them alive while you need them. If they're disposed too early, light resources using them will fail in some way or another.
A sprite's texture turning white is – as you've discovered – a typical sign of the assigned texture being freed/disposed.
There are many different approaches to this, but I'd suggest you create some kind of simple resource manager that will load resources just in time or just return them, if they're loaded already.
I haven't used SFML with C# and I haven't really touched C# for quite a while, but for a simple implementation you'd just have a Dictionary<string, Texture>. When you want to load a texture file like texture.png, you look whether there's a dictionary entry with that key name. If there is, just return it. If there isn't, create the new entry and load the texture, then return it.
I'm out of practice, so please consider this pseudo code!
private Dictionary<string, Texture> mTextureCache; // initialized in constructor
public Texture getTexture(file) {
Texture tex;
if (mTextureCache.TryGetValue(file, out tex))
return tex;
tex = new Texture(file);
mTextureCache.add(file, tex);
return tex;
}
// Somewhere else in your code:
Sprite character = new Sprite(getTexture("myCharacter.png"));
If your heavy resource is a RenderTexture, you just have to ensure that it stays alive as long as it's used (e.g. as a separate member).
It turned out the answer was simpler that I expected. All I had to to was create new Texture object and then make a Sprite out of it. So instead of
Sprite result = new Sprite(render.Texture);
I wrote
Sprite result = new Sprite(new Texture(render.Texture));
Now garbage collector doesn't dispose Sprite's texture
I have a helix toolkit project, in WPF, visual studio 2015. Using the example RectSelection I have a 3d viewport in which I can select my objects, which are BoxVisual3D.
What I need to do, is return the 3d position of the selected object. I have:
foreach (var model in models)
{
var geometryModel = model as GeometryModel3D;
if (geometryModel != null)
{
geometryModel.Material = geometryModel.BackMaterial = material;
//do stuff
UserControl1.Point1Position = model.Transform;
UserControl1.returnPoint.X = model.Transform.Value.M14;
UserControl1.returnPoint.Y = geometryModel.Transform.Value.M24;
UserControl1.returnPoint.Z = geometryModel.Transform.Value.M34;
}
}
But the values always return as 0. (I spawn the box myself, so i know they are not 0).
When I step through, there is a selected object, but the transform reads as all zeros. How can i get the position of a BoxVisual3D?
Thanks.
After nearly 3 years maybe not you but someone else could face with this issue. Here is my explanation.
If you created a Model3D with transform attribute you can use OffsetX, OffsetY, OffsetZ. But if you just created your BoxVisual3D with center attributes there will be no transform in it. Hence you just cant reach it. Create your objects with transform attribute. And another issue creating object in the specified Point3D. Here is my code:
my_point = new Point3D(-15,7,5);
var myTransform = new Transform3DGroup();
TranslateTransform3D myTranslate = new TranslateTransform3D(my_point.X, my_point.Y, my_point.Z);
myTransform.Children.Add(myTranslate);
kontrol.Transform = myTransform; //ez
myModel.Children.Add(kontrol);
And here is the getting the Transform back:
Transform3D mytransform = sourceobject.Transform;
Console.WriteLine(mytransform.Value.OffsetX + "," + mytransform.Value.OffsetY+"," + mytransform.Value.OffsetZ);
To get the Position of the Matrix3D you have to use the Offset Properties:
public static Point3D GetPosition(this Matrix3D m)
{
return new Point3D
{
X = m.OffsetX,
Y = m.OffsetY,
Z = m.OffsetZ
};
}
I have a method which finds relationships between two objects, if it exists, I would like to draw two Lineshapes to the link. I have started to implement the first lineshape, however whenever I test the code the lines persist. I have tried multiple methods (as you can see) and these do not refresh the canvas for the new lines to be drawn.
private void DrawRelationshipLines()
{
_canvas = new ShapeContainer {Parent = panelCredentialsVisualisation};
//These methods below do not redraw the canvas
_canvas.Shapes.Remove(_tableinfoLine);
_canvas.Shapes.Clear();
_canvas.Refresh();
_canvas.Update();
//
List<string> relationships = lvSelectedTableInfoCredentialsIntersection.GetAllRelationships();
if (relationships.Capacity == 0)
return;
foreach (string context in relationships)
{
Label contextLabelName = GetLabelByName(context);
_tableinfoLine = new LineShape
{
Parent = _canvas,
BorderWidth = 2,
BorderColor = Color.BlueViolet,
StartPoint = new Point(lblselectedTableinfo.Right, lblselectedTableinfo.Top + 10),
EndPoint = new Point(contextLabelName.Left, contextLabelName.Top + 10)
};
}
The code works fine in searching for relationships and drawing them, however I'd like to be able to clear the canvas before drawing a different relationship, is this possible?
Thanks if anyone can help.
Moving _canvas = new ShapeContainer {Parent = panelCredentialsVisualisation}; outside of the method made this work. Seems like initializing a new ShapeContainer each time was causing issues.
I'm hoping someone can help me out here. My ultimate goal with this code is to extract the color of the sweater I am wearing. Like the title suggests, I'm trying to exctract RBG values from a certain Skeleton point (ie. skeleton.Joint[JointType.Spine].Position). I do this using the following mapping:
All of the following code is within the SensorAllFramesReady event:
private void SensorAllFramesReady(object sender, AllFramesReadyEventArgs e)
{
Skeleton[] skeletons = new Skeleton[0];
using (SkeletonFrame skeletonFrame = e.OpenSkeletonFrame())
{
if (skeletonFrame != null)
{
skeletons = new Skeleton[skeletonFrame.SkeletonArrayLength];
skeletonFrame.CopySkeletonDataTo(skeletons);
}
}
if (skeletons.Length != 0)
{
foreach (Skeleton skel in skeletons)
{
if (skel.TrackingState == SkeletonTrackingState.Tracked)
{
colorPoint = this.SkeletonPointToColor(skel.Joints[JointType.Spine].Position);
}
}
}
}
private Point SkeletonPointToColor(SkeletonPoint skelpoint)
{
ColorImagePoint colorPoint = this.sensor.CoordinateMapper.MapSkeletonPointToColorPoint(skelpoint, ColorImageFormat.RgbResolution640x480Fps30);
return new Point(colorPoint.X, colorPoint.Y);
}
I assign the returned Point to a variable "ColorPoint", and here is how I (somewhat successful) extract the RBG values:
using (ColorImageFrame colorFrame = e.OpenColorImageFrame())
{
if (colorFrame != null)
{
int arrayLength = colorFrame.PixelDataLength;
this.colorPixelData = new byte[arrayLength];
colorFrame.CopyPixelDataTo(this.colorPixelData);
blue = (int)colorPixelData[(int)(4* (colorPoint.X + (colorPoint.Y * colorFrame.Width)))+0];
green = (int)colorPixelData[(int)(4 * (colorPoint.X + (colorPoint.Y * colorFrame.Width))) + 1];
red = (int)colorPixelData[(int)(4 * (colorPoint.X + (colorPoint.Y * colorFrame.Width))) + 2];
}
}
I then draw an ellipse on my Windows Form window using the retrieved RBG values. Now this works, kind of. I do get a color which resembles the color of the sweater I'm wearing, but even if I do my best to stand very still the color is always changing. It's almost as if I'm getting random RBG values within a certain range, and only the range is dictated by the color of my sweater. Why is this? Is there another way I should be solving this problem?
Thank you for reading!
EDIT: I apologise for the formatting, this is my firs time submitting a question and I realise the formatting in the first code block is a bit off. The SkeletonPointToColor method is naturally not within the SensorAllFramesReady method. My apologies
First of all I really recomend you have a look at the Coding4Fun Kinect Toolkit which provides many useful functions for dealing with the Kinect data. There is a for instance an extension for returning a bitmap named ToBitmapSource() which should be of use.
Another observation is that without using some algorithm to get an average of the color values received it's quite normal to have the color values jump around. Also not confident that you can expect the skeleton and image frames to be 100% in sync.
I really cannot get my head around this, so I hope that someone can give me a little hand ^^
I'm trying to detect motion in C# via my webcam.
So far I've tried multiple libraries (AForge Lib), but failed because I did not understand how to use it.
At first I just wanted to compare the pixels from the current frame with the last one, but that turned out to work like utter s**t :I
Right now, my webcam runs an event "webcam_ImageCaptured" every time the picture from the webcam, which is like 5-10 fps.
But I cannot find a simple way to get the difference from the two images, or at least something that works decent.
Has anybody got an idea on how I could do this rather simple (as possible as that is)?
Getting motion detection to work using the libraries you mention is trivial. Following is an AForge (version 2.2.4) example. It works on a video file but you can easily adapt it to the webcam event.
Johannes' is right but I think playing around with these libraries eases the way to understanding basic image processing.
My application processes 720p video at 120FPS on a very fast machine with SSDs and around 50FPS on my development laptop.
public static void Main()
{
float motionLevel = 0F;
System.Drawing.Bitmap bitmap = null;
AForge.Vision.Motion.MotionDetector motionDetector = null;
AForge.Video.FFMPEG.VideoFileReader reader = new AForge.Video.FFMPEG.VideoFileReader();
motionDetector = GetDefaultMotionDetector();
reader.Open(#"C:\Temp.wmv");
while (true)
{
bitmap = reader.ReadVideoFrame();
if (bitmap == null) break;
// motionLevel will indicate the amount of motion as a percentage.
motionLevel = motionDetector.ProcessFrame(bitmap);
// You can also access the detected motion blobs as follows:
// ((AForge.Vision.Motion.BlobCountingObjectsProcessing) motionDetector.Processor).ObjectRectangles [i]...
}
reader.Close();
}
// Play around with this function to tweak results.
public static AForge.Vision.Motion.MotionDetector GetDefaultMotionDetector ()
{
AForge.Vision.Motion.IMotionDetector detector = null;
AForge.Vision.Motion.IMotionProcessing processor = null;
AForge.Vision.Motion.MotionDetector motionDetector = null;
//detector = new AForge.Vision.Motion.TwoFramesDifferenceDetector()
//{
// DifferenceThreshold = 15,
// SuppressNoise = true
//};
//detector = new AForge.Vision.Motion.CustomFrameDifferenceDetector()
//{
// DifferenceThreshold = 15,
// KeepObjectsEdges = true,
// SuppressNoise = true
//};
detector = new AForge.Vision.Motion.SimpleBackgroundModelingDetector()
{
DifferenceThreshold = 10,
FramesPerBackgroundUpdate = 10,
KeepObjectsEdges = true,
MillisecondsPerBackgroundUpdate = 0,
SuppressNoise = true
};
//processor = new AForge.Vision.Motion.GridMotionAreaProcessing()
//{
// HighlightColor = System.Drawing.Color.Red,
// HighlightMotionGrid = true,
// GridWidth = 100,
// GridHeight = 100,
// MotionAmountToHighlight = 100F
//};
processor = new AForge.Vision.Motion.BlobCountingObjectsProcessing()
{
HighlightColor = System.Drawing.Color.Red,
HighlightMotionRegions = true,
MinObjectsHeight = 10,
MinObjectsWidth = 10
};
motionDetector = new AForge.Vision.Motion.MotionDetector(detector, processor);
return (motionDetector);
}
Motion detection is a complex matter, and it requires a lot of computing power.
Try to limit what you want to detect first. With increasing complexity: Do your want to detect whether there is motion or not? Do you want to detect how much motion? Do you want to detect which areas of the image are actually moving?
I assume you just want to know when something changed:
subtract adjacent frames from each other
calc the sum of all squares of all pixel differences
divide by number of pixels
watch the number for your webcam stream. It will have a certain ground noise and will significantly go up when something moves.
try to limit to a certain color channel only, this may improve things