How to implement a pipeline? - c#

The idea of this module is the be able to graphically represent data inside of a pipeline.
For example, data can look like this:
1,4
This would be a function y=f(x), where:
4=f(1)
I need to use this line
TODO: WritePointToHTML(rawData);
The basic idea of this is to generate HTML file, with code which will draw required line.
I tried to draw a line using html, but I am not able to understand how to represent it in a pipeline
var canvas = document.getElementById('Canvas');
var context = canvas.getContext('2d');

I'm assuming that the original poster is looking to draw lines, not use c# pipelines.
var can;
var ctx;
function init(){
can=document.getElementById("Canvas");
ctx=can.getContext("2d");
ctx.canvas.width = window.innerWidth;
ctx.canvas.height = window.innerHeight;
DrawSlope(1,20);
}
function DrawSlope(x,y)
{
var firstPoint = [x,0];
var secondPoint = [1,x+y];
WritePointToHTML(firstPoint[0],firstPoint[1],secondPoint[0],secondPoint[1]);
}
function WritePointToHTML(x,y,xTwo,yTwo)
{
ctx.beginPath();
ctx.moveTo(x, y);
ctx.lineTo(xTwo, yTwo);
ctx.stroke();
}
// added "draw slope" to factor in slope formula.
https://codepen.io/hollyeplyler/pen/gqYyZx

Related

LibreOffice Calc C# SDK: program to insert images into cells, stuck trying to create XGraphic

Background: I'm trying to write a program to insert an image into a cell of a spreadsheet. LibreOffice recently changed how this is done, and all the samples I could find use the old method which no longer works.
Technically I know that you can't "insert" an image into a cell and that such an image is an overlay on a DrawPage that sits on top of the spreadsheet to "decorate" it.
One of the first steps in doing this (the new way) is to create an XGraphic object which contains the image. The process is to create an XGraphicProvider and call it with MediaProperties that specify the image file URL to be loaded. I have a program that is supposed to do this but the resulting XGraphic is null. The LO SDK gives pretty much no information when you do something wrong; it just doesn't work.
Here is the code I have, with all the headers removed:
// addpic
// add picture to spreadsheet - debug version
class OpenOfficeApp {
[STAThread]
static void Main(string[] args) {
bool lreadonly;
string pqfile;
string pqURL;
string pqpic;
pqfile = "file:///D:/Documents/NSexeye/ODS%20File%20Access/"+
"addpix/addpic.ods";
pqpic = "addpic2";
pqURL = pqpic+".jpg";
lreadonly = false;
Console.WriteLine("Using: "+pqfile);
// get the desktop
XComponentContext XCC = uno.util.Bootstrap.bootstrap();
XMultiComponentFactory XMCF =
(XMultiComponentFactory)XCC.getServiceManager();
XMultiServiceFactory XMSF = (XMultiServiceFactory)XCC.getServiceManager();
XComponentLoader XCL =
(XComponentLoader)XMSF.createInstance("com.sun.star.frame.Desktop");
// open the spreadsheet
PropertyValue[] pPV = new PropertyValue[2];
pPV[0] = new PropertyValue();
pPV[0].Name = "Hidden";
pPV[0].Value = new uno.Any(true);
pPV[1] = new PropertyValue();
pPV[1].Name = "ReadOnly";
if (lreadonly) pPV[1].Value = new uno.Any(true);
else pPV[1].Value = new uno.Any(false);
XComponent XCo = XCL.loadComponentFromURL(pqfile,"_blank",0,pPV);
// create graphic object containing image
object oGP = XMCF.createInstanceWithContext(
"com.sun.star.graphic.GraphicProvider",XCC);
if (oGP == null) {
Console.WriteLine("oGP is null. Aborting.");
return;
}
XGraphicProvider XGP = (XGraphicProvider)oGP;
if (XGP == null) {
Console.WriteLine("XGP is null. Aborting.");
return;
}
pPV = new PropertyValue[1];
pPV[0] = new PropertyValue();
pPV[0].Name = "URL";
pPV[0].Value = new uno.Any(pqURL);
Console.WriteLine("Creating XGraphic containing "+pqURL);
XGraphic XG = XGP.queryGraphic(pPV);
// *** XG is null here
if (XG == null) {
Console.WriteLine("XG is null. Aborting.");
return;
}
// ... lots of stuff to be added here
// save and close the spreadsheet
XModifiable XM = (XModifiable)XCo;
XM.setModified(true);
XStorable XSt = (XStorable)XCo;
XSt.store();
XCloseable XCl = (XCloseable)XCo;
XCl.close(true);
// terminate LibreOffice
// *** I want this to not terminate it if something else is open
XDesktop XD = (XDesktop)XCL;
if (XD != null) XD.terminate();
}
}
I get a null for the XGraphic, in the place indicated in the comments. I don't know if the call to create it is failing, or if one of the earlier steps of the process are incorrect.
My goal here, in addition to getting my program working, is to create a sample program showing how to add an image to a Calc spreadsheet cell, and to manipulate such images. There are a fair number of people asking questions about this and none of the examples I've found will work. I think a good working sample will be of value.
I've spent a lot of time searching for information and code samples for this, with nothing that helps. I've tried to find ways to verify the validity of the XGraphicProvider interface with no luck. I've run out of things to try.
I'm hoping someone who knows about the LibreOffice SDK can take a look and maybe see what I'm doing wrong.
Update: I figured out what I was doing wrong: I was passing a bare filename in the "URL" property to XGraphicProvider. It has to be the same format (starting with "file:///") as the spreadsheet's file name specification.
Now I'm stuck with another property problem. The XGraphic has to be specified as a parameter to the GraphicObjectShape's Graphic property, but the setPropertyValue() function requires that it be a uno.Any type. I can't figure out how to specify an interface name like XGraphic as a uno.Any.
Here is the piece of code that won't compile, complaining that it can't convert an XGraphic to a uno.Any, in the first setPropertyValue call:
// set image XGraphic
XPropertySet XPS = (XPropertySet)XS;
XPS.setPropertyValue("Graphic",XG);
XPS.setPropertyValue("Name",new uno.Any(pqpic));
XG is an XGraphic type. Using "new uno.Any(XG)" doesn't work either, giving a similar compiler error.
After trying unsuccessfully for a few hours to get the latest LO SDK up and running, let me offer some untested ideas.
First of all, here is some working Basic code, no doubt similar to what you're translating from. The important line is oShape.Graphic = oProvider.queryGraphic(Props()).
oDoc = ThisComponent
oSheet = oDoc.CurrentController.ActiveSheet
pqURL = "file:///C:/Users/JimK/Desktop/addpic.jpg"
oProvider = createUnoService("com.sun.star.graphic.GraphicProvider")
oShape = oDoc.createInstance("com.sun.star.drawing.GraphicObjectShape")
Dim Props(0) as new com.sun.star.beans.PropertyValue
Props(0).Name= "URL"
Props(0).Value = pqURL
oShape.Graphic = oProvider.queryGraphic(Props())
oCell = oSheet.getCellByPosition(5,5)
oShape.Name = oCell.AbsoluteName + "##" + Props(0).Value
oShape.Anchor = oCell
oSheet.DrawPage.add(oShape)
'Resize
w = oShape.Graphic.Size.Width
h = oShape.Graphic.Size.Height
wcl = oCell.Size.Width
hcl = oCell.Size.Height
If w<>0 and h<>0 then
oCell.String=""
Dim Size as new com.sun.star.awt.Size
Size.Width = wcl
Size.Height = h*wcl/w
If Size.Height > hcl then
Size.Width = hcl*w/h
Size.Height = hcl
Endif
oShape.setSize(Size)
oShape.setPosition(oCell.Position)
erase oShape
Else
oShape.dispose()
Endif
Now, how to translate this to C#? It looks like you may need to explicitly specify the type. In the SDK example, there are calls like this.
xFieldProp.setPropertyValue(
"Orientation",
new uno.Any(
typeof (unoidl.com.sun.star.sheet.DataPilotFieldOrientation),
unoidl.com.sun.star.sheet.DataPilotFieldOrientation.DATA ) );
So in your case, something like this:
XPS.setPropertyValue(
"Graphic"
new uno.Any(
typeof(unoidl.com.sun.star.graphic.XGraphic),
XG));
Alternatively, follow the suggestion here: set GraphicURL, which should load the image and set Graphic for you.

Display point cloud continuous c# Intel Realsense

This maybe a continuation of my previous question about displaying ply file with Helix toolkit in c#. The problem I have with that solution is that it is not continuous and if a ply file is made it slows down the program a lot.
My code for making the point cloud looks like:
// CopyVertices is extensible, any of these will do:
var vertices = new float[points.Count * 3];
// var vertices = new Intel.RealSense.Math.Vertex[points.Count];
// var vertices = new UnityEngine.Vector3[points.Count];
// var vertices = new System.Numerics.Vector3[points.Count]; // SIMD
// var vertices = new GlmSharp.vec3[points.Count];
// var vertices = new byte[points.Count * 3 * sizeof(float)];
points.CopyVertices(vertices);
And the ply file is made with the line:
points.ExportToPLY("pointcloud.ply", colorFrame);
The helix toolkit is used like this:
Model3DGroup model1 = import.Load("pointcloud.ply");
model.Content = model1;
the rest of the code is like the C# wrapper of librealsense:
https://github.com/IntelRealSense/librealsense/tree/master/wrappers/csharp
Does anyone have an idea on how to make this pointcloud display continuous?
Are you using HelixToolkit.Wpf or HelixToolkit.SharpDX.Wpf?
Try to use HelixToolkit.SharpDX version if your point cloud is big.
Also try to avoid export and import while doing continuous update. You can convert your point cloud directly into helixtoolkit supported points format and update the point model.

How to create an AutoCAD object through a Lambda expression and return it

I am new-ish to C# programming (and programming in general) but I'm getting my feet wet with AutoCAD development using the AutoDesk .NET API for projects at work.
There are certain repetitive tasks in AutoCAD dev that I've been creating helper methods for to simplify my code. In order to create an object(lines, polylines, annotation, etc...) in AutoCAD through the .API, the programmer has to write a fairly convoluted statement that accesses the AutoCAD environment, gets the current drawing, gets the database of the current drawing file, starts a transaction with the database, //do work, then append the created entities to the database before finally committing and closing the transaction.
So I wrote the following code to simplify this task:
public static void CreateObjectActionWithinTransaction(Action<Transaction, Database, BlockTable, BlockTableRecord> action)
{
var document = Application.DocumentManager.MdiActiveDocument;
var database = document.Database;
using (var transaction = document.TransactionManager.StartTransaction())
{
BlockTable blocktable = transaction.GetObject(database.BlockTableId, OpenMode.ForRead) as BlockTable;
BlockTableRecord blockTableRecord = transaction.GetObject(blocktable[BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord;
action(transaction, database, blocktable, blockTableRecord);
transaction.Commit();
}
}
Then my Lambda expression that creates a generic MText and sets up some parameters for it:
public static void createMtext(Point3d location, AttachmentPoint attachmentpoint, string contents, double height, short color, bool usebackgroundmask, bool usebackgroundcolor, double backgroundscale)
{
CreateObjectActionWithinTransaction((transaction, database, blocktable, blocktablerecord) =>
{
MText mt = new MText();
mt.SetDatabaseDefaults();
mt.Location = location;
mt.Attachment = attachmentpoint;
mt.Contents = contents;
mt.Height = height;
mt.Color = Color.FromColorIndex(ColorMethod.ByAci, color);
mt.BackgroundFill = usebackgroundmask;
mt.UseBackgroundColor = usebackgroundcolor;
mt.BackgroundScaleFactor = backgroundscale;
blocktablerecord.AppendEntity(mt);
transaction.AddNewlyCreatedDBObject(mt, true);
});
}
And then finally, when I'm actually creating MText somewhere, I can create it in one line, and pass in values for all the parameters without having to write out the huge transaction code for it:
Helpers.createMtext(insertpoint, AttachmentPoint.MiddleLeft, "hello world", .08, colors.AutoCAD_Red, true, true, 1.2);
So this is great and it works when I want to create an MText by itself and put it somewhere. However, there are certain other situations where instead of just creating an MText and placing it in the drawing, I want to create an MText using the same basic premise as above, but return it as a value to be used somewhere else.
AutoCAD has annotation objects called Multileaders which are essentially just an MText just like above, but attached to some lines and an arrow to point at something in the drawing. In the API you need to define an MText and attach it to the Multileader object. However my above code can't be used because it doesn't return anything.
So my question boils down to, how can I create a method like above to create an object, but instead of just creating that object, have it return that object to be used by another piece of code?
Also are there any good resources for beginners on Lambda expressions? Books, websites, YouTube?
Instead of using delegates, I'd rather use extension methods called from within a transaction in the calling method.
static class ExtensionMethods
{
public static BlockTableRecord GetModelSpace(this Database db, OpenMode mode = OpenMode.ForRead)
{
var tr = db.TransactionManager.TopTransaction;
if (tr == null)
throw new Autodesk.AutoCAD.Runtime.Exception(ErrorStatus.NoActiveTransactions);
return (BlockTableRecord)tr.GetObject(SymbolUtilityServices.GetBlockModelSpaceId(db), mode);
}
public static void Add(this BlockTableRecord btr, Entity entity)
{
var tr = btr.Database.TransactionManager.TopTransaction;
if (tr == null)
throw new Autodesk.AutoCAD.Runtime.Exception(ErrorStatus.NoActiveTransactions);
btr.AppendEntity(entity);
tr.AddNewlyCreatedDBObject(entity, true);
}
public static MText AddMtext(this BlockTableRecord btr,
Point3d location,
AttachmentPoint attachmentpoint,
string contents,
double height,
short color = 256,
bool usebackgroundmask = false,
bool usebackgroundcolor = false,
double backgroundscale = 1.5)
{
MText mt = new MText();
mt.SetDatabaseDefaults();
mt.Location = location;
mt.Attachment = attachmentpoint;
mt.Contents = contents;
mt.Height = height;
mt.ColorIndex = color;
mt.BackgroundFill = usebackgroundmask;
mt.UseBackgroundColor = usebackgroundcolor;
mt.BackgroundScaleFactor = backgroundscale;
btr.Add(mt);
return mt;
}
}
Using example:
public static void Test()
{
var doc = AcAp.DocumentManager.MdiActiveDocument;
var db = doc.Database;
using (var tr = db.TransactionManager.StartTransaction())
{
var ms = db.GetModelSpace(OpenMode.ForWrite);
var mt = ms.AddMtext(Point3d.Origin, AttachmentPoint.TopLeft, "foobar", 2.5);
// do what you want with 'mt'
tr.Commit();
}
}
For the AutoCAD part:
As Miiir stated in the comment, do not return an object, but rather ObjectId. An object instance belongs to a transaction, so if you open the object using some transaction, commit the transaction and try and use that object in another transaction, AutoCAD will basically just crash.
Working with AutoCAD API always follows this basic pattern:
Start transaction
Create new object or use transaction to get an existing object. This is done by either having an ObjectID or by looping over tables and looking for whatever attributes you are interested in (i.e. BlockTable, BlockTableRecord, LayerTable, etc.)
Do stuff to the object.
Commit or Abort transaction.
If you try and bypass steps 1 and 2, it will not work out so well. So, return ObjectID, and then use the id to get the object in another transaction.
As for the C# part:
If you are looking to return a value using a delegate, Action<T> is not your friend. Action does not return a value, it only "acts", thus the name. If you want to use a delegate to return a value you have 2 options:
Define a custom delegate type.
Use the generic delegate supplied by the .NET framework Func<T1,T2,T3,T4,TResult>.
Which one should you use? In your case, I'd probably go with option 1, for the simple reason that your code will just be much cleaner as easier to maintain. I will use that in this example. Using Func would work the exact same way, except your function signatures would look a bit ugly.
Custom delegate:
//somewhere in your code inside a namespace (rather than a class)
public delegate ObjectId MyCreateDelegate(Transaction transaction, Database db,
BlockTable blockTable, BlockTableRecord blockTableRecord);
Then your general method
public static ObjectId CreateObjectActionWithinTransaction(MyCreateDelegate createDel)
{
ObjectId ret;
var document = Application.DocumentManager.MdiActiveDocument;
var database = document.Database;
using (var transaction = document.TransactionManager.StartTransaction())
{
BlockTable blocktable = transaction.GetObject(database.BlockTableId, OpenMode.ForRead) as BlockTable;
BlockTableRecord blockTableRecord = transaction.GetObject(blocktable[BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord;
//here createMtext will get called in this case, and return ObjectID
ret = createDel(transaction, database, blocktable, blockTableRecord);
transaction.Commit();
}
return ret;
}
and the specific method with the lambda:
public ObjectId createMtext(Point3d location, AttachmentPoint attachmentpoint, string contents, double height, short color, bool usebackgroundmask, bool usebackgroundcolor, double backgroundscale)
{
//here you can return the result the general function
return CreateObjectActionWithinTransaction((transaction, database, blocktable, blocktablerecord) =>
{
MText mt = new MText();
mt.SetDatabaseDefaults();
mt.Location = location;
mt.Attachment = attachmentpoint;
mt.Contents = contents;
mt.Height = height;
mt.Color = Color.FromColorIndex(ColorMethod.ByAci, color);
mt.BackgroundFill = usebackgroundmask;
mt.UseBackgroundColor = usebackgroundcolor;
mt.BackgroundScaleFactor = backgroundscale;
blocktablerecord.AppendEntity(mt);
transaction.AddNewlyCreatedDBObject(mt, true);
//make sure to get ObjectId only AFTER adding to db.
return mt.ObjectId;
});
}
And lastly, use it like this
ObjectId mtId = Helpers.createMtext(insertpoint, AttachmentPoint.MiddleLeft, "hello world", .08, colors.AutoCAD_Red, true, true, 1.2);
//now use another transaction to open the object and do stuff to it.
Learning Resources:
And lastly, to understand lambda expressions, you need to start with understanding delegates, if you don't already. All lambdas are is syntactic sugar for instantiating a delegate object that either points to a method or an anonymous method as you've done in your example. This tutorial looks pretty good. And remember, delegates such as Action, Func and Predicate, or no different. So whether you define your own delegate or use the out-of-the box solution, lambda expressions do not care.
For a lambda overview, check out this tutorial.
Do not limit yourself to the two source I provided. Just Google it, and the top 10 hits will all be fairly good information. You can also check out Pluralsight. I do a lot of my learning there.
I am not familiar with AutoCad API, but it appears that "transaction.Commit()" is the line that actually performs the action of placing the MText on your model.
if this is the case; i would do something like the following:
public MText CreateMTextObject({parameters})
{
//code
Return textObject
}
public PlaceTextObject({parameters})
{
CreateTextObject(parameters).Commit()
}
This way, you can choose to keep the textobject for further manipulation, while still allowing the option to apply it in one go. It will also have only one codeblock for making the object, making sure that there are no differences in implementation between the two methods

How to get a coordinator (x, y) from specific letter in PDF using iTextSharp?

I'm working with PDF and using iTexhSharp. So far, I could get data from a specific area already. But, I would like to make more flexible by make a it find the coordinator of the first letter(or number) of desired word and then from that coordinator make rectangle to crop around desired word. It would be good if anyone can give me a short example. Thank you.
The basic idea here is to use IEventListener to get notified of TextRenderInfo events. Then split these into CharacterRenderInfo, and then ask for the bounding box of each of those.
class CharacterRenderInfoGetter implements IEventListener {
private List<CharacterRenderInfo> characterRenderInfoList = new ArrayList<>();
#Override
public void eventOccurred(IEventData iEventData, EventType eventType) {
if(eventType == EventType.RENDER_TEXT)
{
TextRenderInfo tri = (TextRenderInfo) iEventData;
for(TextRenderInfo subTri : tri.getCharacterRenderInfos())
{
characterRenderInfoList.add(new CharacterRenderInfo(subTri));
}
}
}
public List<CharacterRenderInfo> getCharacterRenderInfoList()
{
java.util.Collections.sort(characterRenderInfoList);
return characterRenderInfoList;
}
#Override
public Set<EventType> getSupportedEvents() {
return null;
}
}
You can then use this class like so:
File inputFile = getInputFiles()[0]; // provide your own implementation of course
// create an iText PdfDocument out of the File
PdfDocument pdfDocument = new PdfDocument(new PdfReader(inputFile));
// construct the IEventListener that will measure character distances
CharacterRenderInfoGetter characterRenderInfoGetter = new CharacterRenderInfoGetter();
PdfCanvasProcessor processor = new PdfCanvasProcessor(characterRenderInfoGetter);
/* Here we explicitly tell the IEventListener to process page 1 (the first page of the document
* you can loop over all pages if you want to repeat this
*/
processor.processPageContent(pdfDocument.getPage(1));
I know this code is written in Java. But the .NET equivalent should be very similar. At the very least it's good pseudo-code.

How to chain together multiple NAudio ISampleProvider Effects

I have some DSP effects coded in the ISampleProvider model. To apply one effect I do this and it works fine.
string filename = "C:\myaudio.mp3";
MediaFoundationReader mediaFileReader = new MediaFoundationReader(filename);
ISampleProvider sampProvider = mediaFileReader.ToSampleProvider();
ReverbSampleProvider reverbSamplr = new ReverbSampleProvider(sampProvider);
IWavePlayer waveOutDevice.Init(reverbSamplr);
waveOutDevice.Play();
How can I apply multiple effects to the same input file simultaneously?
For example, if i have a Reverb effect and Distortion effect providers, how can I chain them together to apply them at the same time to one input file?
Effects can be chained together by passing one as the "source" for the next. So if you wanted your audio to go first through a reverb, and then distortion, you might do something like this, passing the original audio into the Reverb effect, the output of the reverb into the distortion effect and then sending the distortion to the waveOut device.
var reverb = new ReverbSampleProvider(sampProvider);
var distortion = new DistortionSampleProvider(reverb);
waveOutDevice.Init(distortion);
(n.b. NAudio does not come with built in reverb/distortion effects - you must make these yourself or source them from elsewhere)
Mark's answer is correct, but that approach is a pain if you're copy and pasting things around in different orders, because you have to change the variables that you're passing through.
For example, if you start with:
var lpf = new LowPassEffectStream(input);
var reverb = new ReverbEffectStream(lpf);
var stereo = new StereoEffectStream(reverb);
var vol = new VolumeSampleProvider(stereo);
waveOutDevice.Init(vol);
And you want to swap reverb and stereo, a quick copy-paste leaves you with the input variables backwards:
var lpf = new LowPassEffectStream(input);
var stereo = new StereoEffectStream(reverb); // <--
var reverb = new ReverbEffectStream(lpf); // <--
var vol = new VolumeSampleProvider(stereo);
waveOutDevice.Init(vol);
It also makes it easy to fix a parameter but forget to fix another, e.g. fixing the stereo effect to have lpf as its input, but forgetting to fix the reverb effect. This often results in skipped effects in the chain leading to frustrated debugging when the effect appears not to work.
To make things easier and less error-prone when I'm stacking effects together and re-ordering them, I created the following helper class:
class EffectChain : ISampleProvider
{
public EffectChain(ISampleProvider source)
{
this._sourceStream = source;
}
private readonly ISampleProvider _sourceStream;
private readonly List<ISampleProvider> _chain = new List<ISampleProvider>();
public ISampleProvider Head
{
get
{
return _chain.LastOrDefault() ?? _sourceStream;
}
}
public WaveFormat WaveFormat
{
get
{
return Head.WaveFormat;
}
}
public void AddEffect(ISampleProvider effect)
{
_chain.Add(effect);
}
public int Read(float[] buffer, int offset, int count)
{
return Head.Read(buffer, offset, count);
}
}
You can use it like this:
var effectChain = new EffectChain(input);
var lpf = new LowPassEffectStream(effectChain.Head);
effectChain.AddEffect(lpf);
var stereo = new StereoEffectStream(effectChain.Head);
effectChain.AddEffect(stereo);
var reverb = new ReverbEffectStream(effectChain.Head);
effectChain.AddEffect(reverb);
var vol = new VolumeSampleProvider(effectChain.Head);
effectChain.AddEffect(vol);
waveOutDevice.Init(effectChain);
This allows you to quickly re-order effects in the chain, as each effect takes the effect chain's head as an input. If you don't add any effects it just acts as a pass-through. You could easily expand this class to have more methods for managing the contained effects if you wanted to, but as it stands it works quite cleanly.

Categories

Resources